Merge "Upgrade libpcap to libpcap-1.10.0"
diff --git a/.appveyor.yml b/.appveyor.yml
index a644151..15e1824 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -9,21 +9,84 @@
   - cinst winflexbison
   - win_flex --version
   - win_bison --version
-  - appveyor DownloadFile http://www.winpcap.org/install/bin/WpdPack_4_1_2.zip
+  - appveyor DownloadFile https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip
   - 7z x .\WpdPack_4_1_2.zip -oc:\projects\libpcap\Win32
-  - appveyor DownloadFile https://nmap.org/npcap/dist/npcap-sdk-0.1.zip
-  - 7z x .\npcap-sdk-0.1.zip -oc:\projects\libpcap\Win32
+  - appveyor DownloadFile https://nmap.org/npcap/dist/npcap-sdk-1.05.zip
+  - 7z x .\npcap-sdk-1.05.zip -oc:\projects\libpcap\Win32\npcap-sdk-1.05
+  - appveyor DownloadFile https://support.riverbed.com/bin/support/download?sid=l3vk3eu649usgu3rj60uncjqqu -FileName AirPcap_Devpack.zip
+  - 7z x .\AirPcap_Devpack.zip -oc:\projects\libpcap\Win32
 
 environment:
   matrix:
-    - GENERATOR: "Visual Studio 12 2013"
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      GENERATOR: "MinGW Makefiles"
       SDK: WpdPack
-    - GENERATOR: "Visual Studio 12 2013 Win64"
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+      MINGW_ROOT: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      GENERATOR: "MinGW Makefiles"
+      SDK: npcap-sdk-1.05
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+      MINGW_ROOT: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      GENERATOR: "Visual Studio 14 2015"
       SDK: WpdPack
-    - GENERATOR: "Visual Studio 12 2013"
-      SDK: npcap-sdk-0.1
-    - GENERATOR: "Visual Studio 12 2013 Win64"
-      SDK: npcap-sdk-0.1
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      GENERATOR: "Visual Studio 14 2015 Win64"
+      SDK: WpdPack
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      GENERATOR: "Visual Studio 14 2015"
+      SDK: npcap-sdk-1.05
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      GENERATOR: "Visual Studio 14 2015 Win64"
+      SDK: npcap-sdk-1.05
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      GENERATOR: "Visual Studio 15 2017"
+      SDK: WpdPack
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      GENERATOR: "Visual Studio 15 2017 Win64"
+      SDK: WpdPack
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      GENERATOR: "Visual Studio 15 2017"
+      SDK: npcap-sdk-1.05
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      GENERATOR: "Visual Studio 15 2017 Win64"
+      SDK: npcap-sdk-1.05
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      GENERATOR: "Visual Studio 15 2017 Win64"
+      SDK: npcap-sdk-1.05
+      AIRPCAP: -DDISABLE_AIRPCAP=NO
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      GENERATOR: "Visual Studio 16 2019"
+      PLATFORM: Win32
+      SDK: WpdPack
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      GENERATOR: "Visual Studio 16 2019"
+      PLATFORM: x64
+      SDK: WpdPack
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      GENERATOR: "Visual Studio 16 2019"
+      PLATFORM: Win32
+      SDK: npcap-sdk-1.05
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      GENERATOR: "Visual Studio 16 2019"
+      PLATFORM: x64
+      SDK: npcap-sdk-1.05
+      AIRPCAP: -DDISABLE_AIRPCAP=YES
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      GENERATOR: "Visual Studio 16 2019"
+      PLATFORM: x64
+      SDK: npcap-sdk-1.05
+      AIRPCAP: -DDISABLE_AIRPCAP=NO
 
 build_script:
   #
@@ -32,5 +95,15 @@
   - type NUL >.devel
   - md build
   - cd build
-  - cmake -DCMAKE_PREFIX_PATH=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" ..
-  - msbuild /m /nologo /p:Configuration=Release pcap.sln
+  # Remove the default MinGW path
+  - if "%GENERATOR%"=="MinGW Makefiles" set PATH=%PATH:C:\MinGW\bin;=%
+  # Add the specified MinGW path
+  - if "%GENERATOR%"=="MinGW Makefiles" set PATH=%MINGW_ROOT%\mingw64\bin;%PATH%
+  # Remove the path to Git, so that we don't pick up its sh.exe, as
+  # that breaks MinGW builds - CMake checks for that and fails in the
+  # configuration stage
+  - if "%GENERATOR%"=="MinGW Makefiles" set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
+  - if NOT DEFINED PLATFORM  cmake %AIRPCAP% -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" -DAirPcap_ROOT=c:\projects\libpcap\Win32\Airpcap_Devpack -G"%GENERATOR%" ..
+  - if DEFINED PLATFORM cmake %AIRPCAP% -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" -DAirPcap_ROOT=c:\projects\libpcap\Win32\Airpcap_Devpack -G"%GENERATOR%" -A %PLATFORM% ..
+  - if NOT "%GENERATOR%"=="MinGW Makefiles" msbuild /m /nologo /p:Configuration=Release pcap.sln
+  - if "%GENERATOR%"=="MinGW Makefiles" mingw32-make
diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 0000000..0f71d89
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,25 @@
+# The internal git client reads CIRRUS_CLONE_DEPTH.
+env:
+  CIRRUS_CLONE_DEPTH: 3
+  MAXJOBS: 2
+  IGNORE_OSVERSION: yes
+
+task:
+  freebsd_instance:
+    image_family: $IMAGE_FAMILY
+  env:
+    matrix:
+      - IMAGE_FAMILY: freebsd-11-4
+      - IMAGE_FAMILY: freebsd-12-2
+      - IMAGE_FAMILY: freebsd-13-0-snap
+  script:
+    - freebsd-version
+    - pkg install -qy autoconf
+    - touch .devel
+    - ./configure --enable-remote --prefix=/tmp
+    - make -s all
+    - make -s testprogs
+    - make install
+    - make releasetar
+    - testprogs/findalldevstest
+
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..b654739
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,28 @@
+Assar Westerlund <assar@sics.se> assar <assar>
+Bill Fenner <fenner@gmail.com> fenner <fenner>
+Denis Ovsienko <denis@ovsienko.info> <infrastation@yandex.ru>
+Francois-Xavier Le Bail <devel.fx.lebail@orange.fr> fxlb <fx.lebail@yahoo.com>
+Francois-Xavier Le Bail <devel.fx.lebail@orange.fr> <fx.lebail@yahoo.com>
+Fulvio Risso <risso@polito.it> risso <risso>
+Gianluca Varenni <gianluca.varenni@gmail.com> gianluca <gianluca>
+Guy Harris <gharris@sonic.net> <gharris@localhost.localdomain>
+Guy Harris <gharris@sonic.net> <gharris@steve.local>
+Guy Harris <gharris@sonic.net> <gharris@ubu9-10.(none)>
+Guy Harris <gharris@sonic.net> <guy@alum.mit.edu>
+Guy Harris <gharris@sonic.net> Guy (Core OS) Harris <gharris@gharris.apple.com>
+Guy Harris <gharris@sonic.net> guy <guy>
+Hannes Gredler <hannes@gredler.at> hannes <hannes>
+Hannes Gredler <hannes@gredler.at> <hannes@juniper.net>
+Jun-ichiro itojun Hagino <itojun@iijlab.net> itojun <itojun>
+Ken Hornstein <kenh@cmf.nrl.navy.mil> kenh <kenh>
+Loris Degioanni <loris@netgroup-serv.polito.it> loris <loris>
+Michael Richardson <mcr@sandelman.ca> <mcr@credil.org>
+Michael Richardson <mcr@sandelman.ca> <mcr@finepoint.com>
+Michael Richardson <mcr@sandelman.ca> mcr <mcr>
+Michael Richardson <mcr@sandelman.ca> <mcr@sandelman.ottawa.on.ca>
+Michael Richardson <mcr@sandelman.ca> <mcr@tcpdump.org>
+Stephen Donnelly <stephen.donnelly@emulex.com> <sfd@nzhmlwks0033.(none)>
+Stephen Donnelly <stephen.donnelly@emulex.com> sfd <stephen.donnelly@emulex.com>
+Stephen Donnelly <stephen.donnelly@emulex.com> sfd <stephen.donnelly@endace.com>
+Stephen Donnelly <stephen.donnelly@emulex.com> <stephen.donnelly@endace.com>
+Torsten Landschoff <t.landschoff@gmx.net> torsten <torsten>
diff --git a/.travis.yml b/.travis.yml
index 086765f..b840a66 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,49 @@
-sudo: false
 language: c
 
+#
+# Try building on these 4 architectures; all are 64-bit, and all but
+# "s390x", a/k/a z/Architecture, are little-endian.
+#
+arch:
+  - amd64
+  - ppc64le
+  - s390x
+  - arm64
+
 os:
   - linux
   - osx
 
+dist: bionic
+
 compiler:
   - gcc
   - clang
 
+#
+# Linux runs on all of the architectures listed above; macOS currently
+# runs only on 64-bit x86, although the Spaceshipologists are all in a
+# tizzy about the possibility of Arm-based Macs.  Suppress the macOS
+# builds that don't work.
+#
+# In addition, with newer versions of macOS, Apple ships a "gcc" that's
+# just another front end to Clang, presumably for backwards
+# compatibility with build scripts etc. that expect the compiler to be
+# "gcc", so don't bother doing "gcc" builds on macOS.
+#
+jobs:
+  exclude:
+  - arch: ppc64le
+    os: osx
+  - arch: s390x
+    os: osx
+  - arch: arm64
+    os: osx
+  - compiler: gcc
+    os: osx
+
+cache: ccache
+
 env:
   global:
     # encrypted COVERITY_SCAN_TOKEN from
@@ -16,10 +51,11 @@
     - secure: "SwNcek+I4lMVcnb5EGGmNm6ljWN6C/mnXzBr82a5rEQNKxAoJfdvvPpKIp0iEfg5j0PtYlcRHoIDyVZ/6QM/WEw0wrio9Z0cio9hkOS6kV8g2QouXfnoNtKJ5nNso7UD2GPJ9+M0GIR1GZ0Edvxr81sHlNAkpVKydYGBwCIMGyg="
     # Coverity run condition (avoid matrix multiple runs), need customized
     # build script. Need an update if new matrix cases.
-    - coverity_scan_run_condition='"$TRAVIS_OS_NAME" = linux -a "$CC" = gcc -a "$REMOTE" = enable -a "$CMAKE" = no'
+    - coverity_scan_run_condition='"$TRAVIS_CPU_ARCH" = amd64 -a "$TRAVIS_OS_NAME" = linux -a "$CC" = gcc -a "$REMOTE" = enable -a "$CMAKE" = no'
     # Coverity script test mode (if true no uploading, avoid reaching the quota)
     # usual processing: false.
     - coverity_scan_script_test_mode=false
+    - MAKEFLAGS='-j 2' # Travis CI VMs come with 2 cores
   matrix:
     - REMOTE=disable CMAKE=no
     - ENABLE_REMOTE="" CMAKE=yes
@@ -49,8 +85,7 @@
     branch_pattern: coverity_scan
   apt:
     packages:
-      - libusb-1.0-0-dev
-      - libdbus-glib-1-dev
+      - libdbus-1-dev
       - libbluetooth-dev
       - libnl-genl-3-dev
       - libibverbs-dev
@@ -62,24 +97,39 @@
 before_install:
   - uname -a
   - date
+  - if [ "$TRAVIS_OS_NAME" = linux ]; then apt list --installed 'lib*-dev'; fi
 
 install:
 
 before_script:
 
 script:
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then touch .devel configure; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = no ]; then echo '$ ./configure [...]' && echo -n travis_fold:start:script.configure; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = no ]; then ./configure --prefix=/tmp "--${REMOTE}-remote"; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = yes ]; then mkdir build; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = yes ]; then cd build; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = yes ]; then cmake -DCMAKE_INSTALL_PREFIX=/tmp $ENABLE_REMOTE ..; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then echo -n travis_fold:end:script.configure; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -s all; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -s testprogs; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then echo '$ make install [...]' && echo -n travis_fold:start:script.make_install; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then PATH=$PATH make install; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then echo -n travis_fold:end:script.make_install; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = no ]; then testprogs/findalldevstest; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = yes ]; then run/findalldevstest; fi
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = no ]; then make releasetar; fi
+  - if [ "$COVERITY_SCAN_BRANCH" = 1 ]; then echo "Coverity build - nothing more to do"; exit 0; fi
+  - touch .devel configure
+  - if [ "$CMAKE" = no ]; then echo '$ ./configure [...]' && echo travis_fold:start:script.configure; fi
+  - if [ "$CMAKE" = no ]; then ./configure --prefix=/tmp "--${REMOTE}-remote"; fi
+  - if [ "$CMAKE" = no ]; then echo -n travis_fold:end:script.configure; fi
+  - if [ "$CMAKE" = yes ]; then mkdir build; fi
+  - if [ "$CMAKE" = yes ]; then cd build; fi
+  - if [ "$CMAKE" = yes ]; then echo travis_fold:start:script.cmake; fi
+  - if [ "$CMAKE" = yes ]; then cmake -DCMAKE_INSTALL_PREFIX=/tmp $ENABLE_REMOTE ..; fi
+  - if [ "$CMAKE" = yes ]; then echo -n travis_fold:end:script.cmake; fi
+  - make -s
+  - make -s testprogs
+  - echo '$ make install [...]' && echo travis_fold:start:script.make_install
+  - PATH=$PATH make install
+  - echo -n travis_fold:end:script.make_install
+  - if [ "$CMAKE" = no ]; then testprogs/findalldevstest; fi
+  - if [ "$CMAKE" = yes ]; then run/findalldevstest; fi
+  - if [ "$CMAKE" = no ]; then make releasetar; fi
+  - echo '$ cat Makefile [...]'; echo travis_fold:start:script.cat_makefile
+  - if [ "$CMAKE" = no ]; then cat Makefile | sed -n '1,/DO NOT DELETE THIS LINE -- mkdep uses it/p'; fi
+  - if [ "$CMAKE" = yes ]; then cat Makefile; fi
+  - echo -n travis_fold:end:script.cat_makefile
+  - echo '$ cat config.h'; echo travis_fold:start:script.cat_config_h
+  - cat config.h
+  - echo -n travis_fold:end:script.cat_config_h
+  - if [ "$CMAKE" = no ]; then echo '$ cat config.log'; echo travis_fold:start:script.cat_config_log; fi
+  - if [ "$CMAKE" = no ]; then cat config.log; fi
+  - if [ "$CMAKE" = no ]; then echo -n travis_fold:end:script.cat_config_log; fi
+  - if [ "$TRAVIS_OS_NAME" = osx ]; then sleep 10; fi
diff --git a/CHANGES b/CHANGES
index 89e739c..4dd30f1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,111 @@
+Tuesday, December 29, 2020
+  Summary for 1.10.0 libpcap release
+    Require, and assume, some level of C99 support in the C compiler
+    Require Visual Studio 2015 or later if using Visual Studio
+    Add support for capturing on DPDK devices
+    rpcap: support rpcap-over-TLS
+    Windows: report the system error for PacketSetHwFilter() failures
+    Label most APIs by the first release in which they're available
+    Add support for getting and setting packet time stamp types
+        with Npcap
+    Add pcap_init(), and add support for UTF-8 strings, including error
+        messages, on Windows
+    Improve man pages, including adding backward compatibility notes
+    Fix configure script issues, including with libnl on Linux
+    Fix CMake issues
+    Squelch complaints from Bison about "%define api.pure" being
+        deprecated
+    Fix some memory leaks, including in pcap_compile()
+    Linux: handle systems without AF_INET or AF_UNIX socket support
+    Catch invalid IPv4 addresses in filters
+    AIX: fix loading of BPF kernel extension
+    rpcapd: fix core dumps with invalid configuration file
+    Show special Linux BPF offsets symbolically in bpf_image() and
+        bpf_dump()
+    Add some overflow checks in the optimizer
+    Add pcap_datalink_val_to_description_or_dlt()
+    Windows: make the snapshot length work even if pcap_setfilter()
+        isn't called
+    Linux: get rid of Wireless Extensions for turning monitor mode on
+    Handle the pcap private data in a fashion that makes fewer
+       assumptions about memory layouts (might fix GitHub issue #940
+       on ARM)
+    Fix "unknown ether proto 'aarp'"
+    Fix some issues found by cppcheck.
+    Linux: proper memory sync for PACKET_MMAP (may prevent GitHub issue
+        #898)
+    Remove undocumented and rather old "ether proto" protocols
+    Fix some thread safety issues
+    Windows: add pcap_handle(), and deprecate pcap_fileno()
+    AirPcap: add AirPcap support in a module, rather than using
+        WinPcap/Npcap's support for it
+    Linux: drop support for libnl 1 and 2.
+    Linux: Require PF_PACKET support, and kernel 2.6.27 or later
+    Add DLT_LINUX_SLL2
+    Add a new filter "ifindex" for DLT_LINUX_SLL2 files and live
+        Linux captures
+    optimizer: add a hack to try to catch certain optimizer loops
+        (should prevent GitHub issue #112)
+    Probe CONFIGURATION descriptor of connected USB devices
+    macOS: cope with getting EPWROFF from SIOCGIFMEDIA
+    Linux: return error on interface going away, but not if it just went
+        down
+    Windows: fix compilation on Cygwin/MSYS
+    Linux: set socket protocol only after packet ring configured,
+        reducing bogus packet drop reports
+    pcap_findalldevs(): don't sort interfaces by unit number
+    Linux: get ifdrop stats from sysfs.
+    Fix various security issues reported by Charles Smith at Tangible
+        Security
+    Fix various security issues reported by Include Security
+    rpcapd: on UN*X, don't tell the client why authentication failed
+    Linux: when adjusting BPF programs, do not subtract the
+        SLL[2]_HDR_LEN if the location is negative (special metadata
+        offset)
+    Preserve references to metadata when adjusting the program;
+        see https://github.com/the-tcpdump-group/tcpdump/issues/480#issuecomment-486827278
+    Always return a list of supported time-stamp types, even if only
+        host time stamps are supported
+    Linux: with a timeout of zero, wait indefinitely
+    Linux: clean up support for some non-GNU libc C libraries
+    Increase the maximum snaplen for LINKTYPE_USBPCAP/DLT_USBPCAP
+    Fix handling of some ioctls that fail with "permission denied" even
+        when the ioctl isn't supported at all
+    Added support for ICMPv6 types 1-4 as tokens in filters
+    Windows: Report PCAP_ERROR_NO_SUCH_DEVICE for a non-existent device
+    Windows: return an appropriate error message for device removed or
+        device unusable due to a suspend/resume
+    BPF: treat both ENXIO (everybody but OpenBSD) and EIO (OpenBSD) as
+        meaning "the interface was removed"
+    BPF: report "the interface disappeared", not "the interface went
+        down", if the interface was removed during a capture
+    Linux, Windows: report a warning for unknown link-layer header types
+    Create the file in pcap_dump_open_append() if it doesn't exist
+    Linux, NPF: have pcap_breakloop() forcibly break out of a sleeping
+        capture loop
+    Report the DLT description in error messages
+    Linux: Add support for DSA data link types
+    Linux USB: use the snapshot length to set the buffer size, and set
+        the len field to reflect the length in the URB (GitHub issue
+        #808)
+    rpcapd: allow rpcapd to rebind more rapidly (GitHub issue #765)
+    Windows: clean up building DLL
+    Fix compilation of pcap-tc.c
+    Add Haiku pcap implementation
+    Windows: handle CRT mismatch for pcap_dump_fopen()
+    Windows: map NdisMediumWirelessWan to DLT_RAW
+    rpcap: add some new authentication libpcap error codes for
+        specific errors
+    rpcap: redo protocol version negotiation to avoid problems with old
+        servers (it still works with servers using the old negotiation,
+        as well as servers not supporting negotiation)
+    rpcap: error handling cleanups
+    rpcapd: fix some inetd issues
+    Don't assume ARM supports unaligned accesses
+    Remove (unused) SITA support here.
+    Correctly handle pcapng captures with more than one IDB with a
+        snspshot length greater than the supported maximum
+
 Sunday, July 22, 2018
   Summary for 1.9.1 libpcap release
     Mention pcap_get_required_select_timeout() in the main pcap man page
@@ -93,7 +201,7 @@
     Make VLAN filter handle both metadata and inline tags
     D-Bus captures can now be up to 128MB in size
     Added LORATAP DLT value
-    Added DLT_VSOCK for http://qemu-project.org/Features/VirtioVsock
+    Added DLT_VSOCK for https://qemu-project.org/Features/VirtioVsock
     probe_devices() fixes not to overrun buffer for name of device
     Add linux-specific pcap_set_protocol_linux() to allow specifying a specific capture protocol.
     RDMA sniffing support for pcap
@@ -275,7 +383,7 @@
 	    than the mcr repository
 	Checks added for malloc()/realloc()/etc. failures
 	Fixed build on Solaris 11
-	Support filtering filtering E1 SS7 traffic on MTP2 layer Annex A
+	Support filtering E1 SS7 traffic on MTP2 layer Annex A
 	Use "ln -s" to link man pages by default
         Add support for getting nanosecond-resolution time stamps when
 	    capturing and reading capture files
@@ -336,7 +444,7 @@
 Friday  December 9, 2011.  guy@alum.mit.edu.
 Summary for 1.2.1 libpcap release
 	Update README file.
-	Fix typoes in README.linux file.
+	Fix typos in README.linux file.
 	Clean up some compiler warnings.
 	Fix Linux compile problems and tests for ethtool.h.
 	Treat Debian/kFreeBSD and GNU/Hurd as systems with GNU
@@ -369,7 +477,7 @@
         Noted real nature of LINKTYPE_ARCNET.
         Add a link-layer type for DVB-CI.
         Fix configure-script discovery of VLAN acceleration support.
-         see http://netoptimizer.blogspot.com/2010/09/tcpdump-vs-vlan-tags.html
+         see https://netoptimizer.blogspot.com/2010/09/tcpdump-vs-vlan-tags.html
         Linux, HP-UX, AIX, NetBSD and OpenBSD compilation/conflict fixes.
         Protect against including AIX 5.x's <net/bpf.h> having been included.
         Add DLT_DBUS, for raw D-Bus messages.
@@ -568,7 +676,7 @@
 	 beginning+link-layer
 	Add DLT/LINKTYPE for carrying FRF.16 Multi-link Frame Relay
 	Fix allocation of buffer for list of link-layer types
-	Added a new DLT and LINKTYPE value for ARINC 653 Interpartition Communcation Messages
+	Added a new DLT and LINKTYPE value for ARINC 653 Interpartition Communication Messages
 	Fixed a typo in a DLT value: it should start with DLT_ and not LINKTYPE_
 	Redefined DLT_CAN20B and LINKTYPE_CAN20B as #190 (as this is the right value for CAN).
 	Added definition for DLT_A429 and LINKTYPE_A429 as #184.
@@ -682,7 +790,7 @@
 
 	Header files fixed to allow use in C++ programs.
 
-	Removed dependancy on native headers for packet layout.
+	Removed dependency on native headers for packet layout.
 	Removed Linux specific headers that were shipped.
 
 	Security fixes: Strcpy replaced with strlcpy, sprintf replaced
@@ -820,7 +928,7 @@
 
 v0.2.1 Sun Jul 14 03:02:26 PDT 1996
 
-- Fixes for HP-UX 10. Thanks in part to to Thomas Wolfram
+- Fixes for HP-UX 10. Thanks in part to Thomas Wolfram
   (wolf@prz.tu-berlin.de) and Rick Jones (raj@hpisrdq.cup.hp.com)
 
 - Added support for SINIX. Thanks to Andrej Borsenkow
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 55b93f1..50bf171 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,11 @@
-cmake_minimum_required(VERSION 2.8.6)
+if(WIN32)
+    #
+    # We need 3.12 or later, so that we can set policy CMP0074; see
+    # below.
+    cmake_minimum_required(VERSION 3.12)
+else(WIN32)
+    cmake_minimum_required(VERSION 2.8.6)
+endif(WIN32)
 
 #
 # Apple doesn't build with an install_name starting with @rpath, and
@@ -9,44 +16,34 @@
     cmake_policy(SET CMP0042 OLD)
 endif()
 
+#
+# Squelch noise about quoted strings in if() statements.
+# WE KNOW WHAT WE'RE DOING, WE'RE DOING EVERYTHING THE WAY THAT NEWER
+# VERSIONS OF CMAKE EXPECT BY DEFAULT, DON'T WASTE OUR TIME WITH NOISE.
+#
+if(POLICY CMP0054)
+    cmake_policy(SET CMP0054 NEW)
+endif()
+
+#
+# We want find_file() and find_library() to honor {packagename}_ROOT,
+# as that appears to be the only way, with the Visual Studio 2019 IDE
+# and its CMake support, to tell CMake where to look for the Npcap
+# or WinPcap SDK.
+#
+if(POLICY CMP0074)
+    cmake_policy(SET CMP0074 NEW)
+endif()
+
 set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
 
 project(pcap)
 
-#
-# Try to enable as many C99 features as we can.
-# At minimum, we want C++/C99-style // comments.
-#
-# Newer versions of compilers might default to supporting C99, but older
-# versions may require a special flag.
-#
-# Prior to CMake 3.1, setting CMAKE_C_STANDARD will not have any effect,
-# so, unless and until we require CMake 3.1 or later, we have to do it
-# ourselves on pre-3.1 CMake, so we just do it ourselves on all versions
-# of CMake.
-#
-# Note: with CMake 3.1 through 3.5, the only compilers for which CMake
-# handles CMAKE_C_STANDARD are GCC and Clang.  3.6 adds support only
-# for Intel C; 3.9 adds support for PGI C, Sun C, and IBM XL C, and
-# 3.10 adds support for Cray C and IAR C, but no version of CMake has
-# support for HP C.  Therefore, even if we use CMAKE_C_STANDARD with
-# compilers for which CMake supports it, we may still have to do it
-# ourselves on other compilers.
-#
-# See the CMake documentation for the CMAKE_<LANG>_COMPILER_ID variables
-# for a list of compiler IDs.
-#
-# We don't worry about MSVC; it doesn't have such a flag - either it
-# doesn't support the C99 features we need at all, or it supports them
-# regardless of the compiler flag.
-#
-# XXX - this just tests whether the option works and adds it if it does.
-# We don't test whether it's necessary in order to get the C99 features
-# that we use; if we ever have a user who tries to compile with a compiler
-# that can't be made to support those features, we can add a test to make
-# sure we actually *have* C99 support.
-#
 include(CheckCCompilerFlag)
+
+#
+# For checking if a compiler flag works and adding it if it does.
+#
 macro(check_and_add_compiler_option _option)
     message(STATUS "Checking C compiler flag ${_option}")
     string(REPLACE "=" "-" _temp_option_variable ${_option})
@@ -57,23 +54,103 @@
     endif()
 endmacro()
 
+#
+# If we're building with Visual Studio, we require Visual Studio 2015,
+# in order to get sufficient C99 compatibility.  Check for that.
+#
+# If not, try the appropriate flag for the compiler to enable C99
+# features.
+#
 set(C_ADDITIONAL_FLAGS "")
-if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR
-   CMAKE_C_COMPILER_ID MATCHES "Clang")
-    check_and_add_compiler_option("-std=gnu99")
-elseif(CMAKE_C_COMPILER_ID MATCHES "XL")
+if(MSVC)
+    if(MSVC_VERSION LESS 1900)
+        message(FATAL_ERROR "Visual Studio 2015 or later is required")
+    endif()
+
     #
-    # We want support for extensions picked up for GNU C compatibility,
-    # so we use -qlanglvl=extc99.
+    # Treat source files as being in UTF-8 with MSVC if it's not using
+    # the Clang front end.
+    # We assume that UTF-8 source is OK with other compilers and with
+    # MSVC if it's using the Clang front end.
     #
-    check_and_add_compiler_option("-qlanglvl=extc99")
-elseif(CMAKE_C_COMPILER_ID MATCHES "HP")
-    check_and_add_compiler_option("-AC99")
-elseif(CMAKE_C_COMPILER_ID MATCHES "Sun")
-    check_and_add_compiler_option("-xc99")
-elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
-    check_and_add_compiler_option("-c99")
-endif()
+    if(NOT ${CMAKE_C_COMPILER} MATCHES "clang*")
+        set(C_ADDITIONAL_FLAGS "${C_ADDITIONAL_FLAGS} /utf-8")
+    endif(NOT ${CMAKE_C_COMPILER} MATCHES "clang*")
+else(MSVC)
+    #
+    # For checking if a compiler flag works, failing if it doesn't,
+    # and adding it otherwise.
+    #
+    macro(require_and_add_compiler_option _option)
+        message(STATUS "Checking C compiler flag ${_option}")
+        string(REPLACE "=" "-" _temp_option_variable ${_option})
+        string(REGEX REPLACE "^-" "" _option_variable ${_temp_option_variable})
+        check_c_compiler_flag("${_option}" ${_option_variable})
+        if(${${_option_variable}})
+            set(C_ADDITIONAL_FLAGS "${C_ADDITIONAL_FLAGS} ${_option}")
+        else()
+            message(FATAL_ERROR "C99 support is required, but the compiler doesn't support a compiler flag to enable it")
+        endif()
+    endmacro()
+
+    #
+    # Try to enable as many C99 features as we can.
+    # At minimum, we want C++/C99-style // comments.
+    #
+    # Newer versions of compilers might default to supporting C99, but
+    # older versions may require a special flag.
+    #
+    # Prior to CMake 3.1, setting CMAKE_C_STANDARD will not have any effect,
+    # so, unless and until we require CMake 3.1 or later, we have to do it
+    # ourselves on pre-3.1 CMake, so we just do it ourselves on all versions
+    # of CMake.
+    #
+    # Note: with CMake 3.1 through 3.5, the only compilers for which CMake
+    # handles CMAKE_C_STANDARD are GCC and Clang.  3.6 adds support only
+    # for Intel C; 3.9 adds support for PGI C, Sun C, and IBM XL C, and
+    # 3.10 adds support for Cray C and IAR C, but no version of CMake has
+    # support for HP C.  Therefore, even if we use CMAKE_C_STANDARD with
+    # compilers for which CMake supports it, we may still have to do it
+    # ourselves on other compilers.
+    #
+    # See the CMake documentation for the CMAKE_<LANG>_COMPILER_ID variables
+    # for a list of compiler IDs.
+    #
+    # XXX - this just tests whether the option works, fails if it doesn't,
+    # and adds it if it does.  We don't test whether it's necessary in order
+    # to get the C99 features that we use, or whether, if it's used, it
+    # enables all the features that we require.
+    #
+    if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR
+       CMAKE_C_COMPILER_ID MATCHES "Clang")
+        require_and_add_compiler_option("-std=gnu99")
+    elseif(CMAKE_C_COMPILER_ID MATCHES "XL")
+        #
+        # We want support for extensions picked up for GNU C compatibility,
+        # so we use -qlanglvl=extc99.
+        #
+        require_and_add_compiler_option("-qlanglvl=extc99")
+    elseif(CMAKE_C_COMPILER_ID MATCHES "HP")
+        require_and_add_compiler_option("-AC99")
+    elseif(CMAKE_C_COMPILER_ID MATCHES "Sun")
+        require_and_add_compiler_option("-xc99")
+    elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
+        require_and_add_compiler_option("-c99")
+    endif()
+endif(MSVC)
+
+#
+# If we're building with MinGW, we need to specify _WIN32_WINNT as
+# 0x0600 ("NT 6.0", a/k/a Vista/Windows Server 2008) in order to
+# get the full IPv6 API, including inet_ntop().
+#
+# NOTE: pcap does *NOT* work with msvcrt.dll; it must link with
+# a newer version of the C library, i.e. Visual Studio 2015 or
+# later, as it depends on C99 features introduced in VS 2015.
+#
+if(MINGW)
+    add_definitions(-D_WIN32_WINNT=0x0600)
+endif(MINGW)
 
 #
 # Build all runtimes in the top-level binary directory; that way,
@@ -107,9 +184,12 @@
 endif(WIN32)
 option(BUILD_SHARED_LIBS "Build shared libraries" ON)
 if(WIN32)
-    set(PACKET_DLL_DIR "" CACHE PATH "Path to directory with include and lib subdirectories for packet.dll")
+    set(Packet_ROOT "" CACHE PATH "Path to directory with include and lib subdirectories for packet.dll")
+    set(AirPcap_ROOT "" CACHE PATH "Path to directory with include and lib subdirectories for airpcap.dll")
 endif(WIN32)
 
+option(ENABLE_PROFILING "Enable code profiling" OFF)
+
 # To pacify those who hate the protochain instruction
 option(NO_PROTOCHAIN "Disable protochain instruction" OFF)
 
@@ -131,16 +211,19 @@
 endif(WIN32)
 
 if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-    option(PCAP_SUPPORT_PACKET_RING "Enable Linux packet ring support" ON)
     option(BUILD_WITH_LIBNL "Build with libnl" ON)
 endif()
 
 #
 # Additional capture modules.
 #
-option(DISABLE_USB "Disable USB sniffing support" OFF)
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    option(DISABLE_LINUX_USBMON "Disable Linux usbmon USB sniffing support" OFF)
+endif()
 option(DISABLE_BLUETOOTH "Disable Bluetooth sniffing support" OFF)
 option(DISABLE_NETMAP "Disable netmap support" OFF)
+option(DISABLE_DPDK "Disable DPDK support" OFF)
+
 #
 # We don't support D-Bus sniffing on macOS; see
 #
@@ -231,15 +314,16 @@
         cmake_push_check_state()
         set(CMAKE_REQUIRED_LIBRARIES ${PACKET_LIBRARIES})
         check_function_exists(PacketIsLoopbackAdapter HAVE_PACKET_IS_LOOPBACK_ADAPTER)
+        check_function_exists(PacketGetTimestampModes HAVE_PACKET_GET_TIMESTAMP_MODES)
         cmake_pop_check_state()
     endif(PACKET_FOUND)
 
     message(STATUS "checking for Npcap's version.h")
     check_symbol_exists(WINPCAP_PRODUCT_NAME "../../version.h" HAVE_VERSION_H)
     if(HAVE_VERSION_H)
-	    message(STATUS "HAVE version.h")
+        message(STATUS "HAVE version.h")
     else(HAVE_VERSION_H)
-	    message(STATUS "MISSING version.h")
+        message(STATUS "MISSING version.h")
     endif(HAVE_VERSION_H)
 
 endif(WIN32)
@@ -294,9 +378,7 @@
     check_include_file(sys/ioccom.h HAVE_SYS_IOCCOM_H)
     check_include_file(sys/sockio.h HAVE_SYS_SOCKIO_H)
     check_include_file(sys/select.h HAVE_SYS_SELECT_H)
-endif(NOT WIN32)
-check_include_file(limits.h HAVE_LIMITS_H)
-if(NOT WIN32)
+
     check_include_file(netpacket/packet.h HAVE_NETPACKET_PACKET_H)
     check_include_files("sys/types.h;sys/socket.h;net/if.h;net/pfvar.h" HAVE_NET_PFVAR_H)
     if(HAVE_NET_PFVAR_H)
@@ -318,13 +400,6 @@
             HAVE_PF_NAT_THROUGH_PF_NORDR)
     endif(HAVE_NET_PFVAR_H)
     check_include_file(netinet/if_ether.h HAVE_NETINET_IF_ETHER_H)
-    if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-        check_include_file(linux/sockios.h HAVE_LINUX_SOCKIOS_H)
-        #
-        # linux/if_bonding.h requires sys/socket.h.
-        #
-        check_include_files("sys/socket.h;linux/if_bonding.h" HAVE_LINUX_IF_BONDING_H)
-    endif()
 endif(NOT WIN32)
 
 #
@@ -356,14 +431,28 @@
     endif(NOT HAVE_GNU_STRERROR_R)
 else(HAVE_STRERROR_R)
     #
-    # We don't have strerror_r; do we have strerror_s?
+    # We don't have strerror_r; do we have _wcserror_s?
     #
-    check_function_exists(strerror_s HAVE_STRERROR_S)
+    check_function_exists(_wcserror_s HAVE__WCSERROR_S)
 endif(HAVE_STRERROR_R)
+
+#
+# Make sure we have vsnprintf() and snprintf(); we require them.
+# We use check_symbol_exists(), as they aren't necessarily external
+# functions - in Visual Studio, for example, they're inline functions
+# calling a common external function.
+#
+check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF)
+if(NOT HAVE_VSNPRINTF)
+    message(FATAL_ERROR "vsnprintf() is required but wasn't found")
+endif(NOT HAVE_VSNPRINTF)
+check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
+if(NOT HAVE_SNPRINTF)
+    message(FATAL_ERROR "snprintf() is required but wasn't found")
+endif()
+
 check_function_exists(strlcpy HAVE_STRLCPY)
 check_function_exists(strlcat HAVE_STRLCAT)
-check_function_exists(snprintf HAVE_SNPRINTF)
-check_function_exists(vsnprintf HAVE_VSNPRINTF)
 check_function_exists(asprintf HAVE_ASPRINTF)
 check_function_exists(vasprintf HAVE_VASPRINTF)
 check_function_exists(strtok_r HAVE_STRTOK_R)
@@ -433,10 +522,18 @@
             #
             set(PCAP_LINK_LIBRARIES socket nsl ${PCAP_LINK_LIBRARIES})
         else(LIBSOCKET_HAS_GETADDRINFO)
-            #
-            # We didn't find it.
-            #
-            message(FATAL_ERROR "getaddrinfo is required, but wasn't found")
+            check_library_exists(network getaddrinfo "" LIBNETWORK_HAS_GETADDRINFO)
+            if(LIBNETWORK_HAS_GETADDRINFO)
+                #
+                # OK, we found it in libnetwork (Haiku).
+                #
+                set(PCAP_LINK_LIBRARIES network ${PCAP_LINK_LIBRARIES})
+            else(LIBNETWORK_HAS_GETADDRINFO)
+                #
+                # We didn't find it.
+                #
+                message(FATAL_ERROR "getaddrinfo is required, but wasn't found")
+            endif(LIBNETWORK_HAS_GETADDRINFO)
         endif(LIBSOCKET_HAS_GETADDRINFO)
 
         #
@@ -812,6 +909,125 @@
   endif(NOT CMAKE_USE_PTHREADS_INIT)
 endif(NOT WIN32)
 
+if(ENABLE_PROFILING)
+    if(NOT MSVC)
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
+    endif()
+endif()
+
+#
+# Based on
+#
+#    https://github.com/commonmark/cmark/blob/master/FindAsan.cmake
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2013 Matthew Arsenault
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# Test if the each of the sanitizers in the ENABLE_SANITIZERS list are
+# supported by the compiler, and, if so, adds the appropriate flags to
+# CMAKE_C_FLAGS, CMAKE_CXX_FLAGS, and SANITIZER_FLAGS.  If not, it fails.
+#
+# Do this last, in the hope that it will prevent configuration on Linux
+# from somehow deciding it doesn't need -lpthread when building rpcapd
+# (it does require it, but somehow, in some mysterious fashion that no
+# obvious CMake debugging flag reveals, it doesn't realize that if we
+# turn sanitizer stuff on).
+#
+set(SANITIZER_FLAGS "")
+foreach(sanitizer IN LISTS ENABLE_SANITIZERS)
+    # Set -Werror to catch "argument unused during compilation" warnings
+
+    message(STATUS "Checking sanitizer ${sanitizer}")
+    set(sanitizer_variable "sanitize_${sanitizer}")
+    set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize=${sanitizer}")
+    check_c_compiler_flag("-fsanitize=${sanitizer}" ${sanitizer_variable})
+    if(${${sanitizer_variable}})
+        set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=${sanitizer}")
+        message(STATUS "${sanitizer} sanitizer supported using -fsanitizer=${sanitizer}")
+    else()
+        #
+        # Try the versions supported prior to Clang 3.2.
+        # If the sanitizer is "address", try -fsanitize-address.
+        # If it's "undefined", try -fcatch-undefined-behavior.
+        # Otherwise, give up.
+        #
+        set(sanitizer_variable "OLD_${sanitizer_variable}")
+        if ("${sanitizer}" STREQUAL "address")
+            set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize-address")
+            check_c_compiler_flag("-fsanitize-address" ${sanitizer_variable})
+            if(${${sanitizer_variable}})
+                set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize-address")
+                message(STATUS "${sanitizer} sanitizer supported using -fsanitize-address")
+            else()
+                message(FATAL_ERROR "${sanitizer} isn't a supported sanitizer")
+            endif()
+        elseif("${sanitizer}" STREQUAL "undefined")
+            set(CMAKE_REQUIRED_FLAGS "-Werror -fcatch-undefined-behavior")
+            check_c_compiler_flag("-fcatch-undefined-behavior" ${sanitizer_variable})
+            if(${${sanitizer_variable}})
+                set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fcatch-undefined-behavior")
+                message(STATUS "${sanitizer} sanitizer supported using catch-undefined-behavior")
+            else()
+                message(FATAL_ERROR "${sanitizer} isn't a supported sanitizer")
+            endif()
+        else()
+            message(FATAL_ERROR "${sanitizer} isn't a supported sanitizer")
+        endif()
+    endif()
+
+    unset(CMAKE_REQUIRED_FLAGS)
+endforeach()
+
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O1 -g ${SANITIZER_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1 -g ${SANITIZER_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls")
+endif()
+
+#
+# OpenSSL/libressl.
+#
+find_package(OpenSSL)
+if(OPENSSL_FOUND)
+  #
+  # We have OpenSSL.
+  #
+  include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
+  set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${OPENSSL_LIBRARIES})
+  set(HAVE_OPENSSL YES)
+endif(OPENSSL_FOUND)
+
+#
+# Additional linker flags.
+#
+set(LINKER_FLAGS "${SANITIZER_FLAGS}")
+if(ENABLE_PROFILING)
+    if(MSVC)
+        set(LINKER_FLAGS " /PROFILE")
+    else()
+        set(LINKER_FLAGS " -pg")
+    endif()
+endif()
+
 ######################################
 # Input files
 ######################################
@@ -834,52 +1050,16 @@
 
 if(WIN32)
     #
-    # For now, we assume we don't have snprintf() or that it's not one
-    # that behaves enough like C99's snprintf() for our purposes (i.e.,
-    # it doesn't null-terminate the string if it truncates it to fit in
-    # the buffer), so we have to provide our own (a wrapper around
-    # _snprintf() that null-terminates the buffer).
+    # We add the character set conversion routines; they're Windows-only
+    # for now.
     #
-    # We also assume we don't have asprintf(), and provide an implementation
+    # We assume we don't have asprintf(), and provide an implementation
     # that uses _vscprintf() to determine how big the string needs to be.
     #
     set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C}
-        missing/win_snprintf.c missing/win_asprintf.c)
+        charconv.c missing/win_asprintf.c)
 else()
-    #
-    # Either:
-    #
-    #	we have snprintf() and vsnprintf(), and have asprintf() and
-    #	vasprintf();
-    #
-    #	we have snprintf() and vsnprintf(), but don't have asprintf()
-    #	or vasprintf();
-    #
-    #	we have neither snprintf() nor vsnprintf(), and don't have
-    #	asprintf() or vasprintf(), either.
-    #
-    # We assume that if we have asprintf() we have vasprintf(), as well
-    # as snprintf() and vsnprintf(), and that if we have snprintf() we
-    # have vsnprintf().
-    #
-    # For the first case, we don't need any replacement routines.
-    # For the second case, we need replacement asprintf()/vasprintf()
-    # routines.
-    # For the third case, we need replacement snprintf()/vsnprintf() and
-    # asprintf()/vasprintf() routines.
-    #
-    if(NOT HAVE_SNPRINTF)
-        #
-        # We assume we have none of them; missing/snprintf.c supplies
-        # all of them.
-        #
-        set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/snprintf.c)
-    elif(NOT HAVE_ASPRINTF)
-        #
-        # We assume we have snprintf()/vsnprintf() but lack
-        # asprintf()/vasprintf(); missing/asprintf.c supplies
-        # the latter (using vsnprintf()).
-        #
+    if(NOT HAVE_ASPRINTF)
         set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/asprintf.c)
     endif()
     if(NOT HAVE_STRLCAT)
@@ -985,6 +1165,7 @@
         check_include_file(linux/socket.h HAVE_LINUX_SOCKET_H)
         check_include_file(net/raw.h HAVE_NET_RAW_H)
         check_include_file(sys/dlpi.h HAVE_SYS_DLPI_H)
+        check_include_file(config/HaikuConfig.h HAVE_CONFIG_HAIKUCONFIG_H)
 
         if(BPF_H_DEFINES_BIOCSETIF)
             #
@@ -1028,6 +1209,11 @@
             # DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others.
             #
             set(PCAP_TYPE dlpi)
+        elseif(HAVE_CONFIG_HAIKUCONFIG_H)
+            #
+            # Haiku.
+            #
+            set(PCAP_TYPE haiku)
         else()
             #
             # Nothing we support.
@@ -1038,18 +1224,20 @@
 endif(WIN32)
 message(STATUS "Packet capture mechanism type: ${PCAP_TYPE}")
 
+find_package(PkgConfig QUIET)
+
 #
 # Do capture-mechanism-dependent tests.
 #
 if(WIN32)
     if(PCAP_TYPE STREQUAL "npf")
         #
-        # Link with packet.dll before WinSock2.
+        # Link with packet.dll before Winsock2.
         #
         set(PCAP_LINK_LIBRARIES ${PACKET_LIBRARIES} ${PCAP_LINK_LIBRARIES})
     elseif(PCAP_TYPE STREQUAL "null")
     else()
-        message(ERROR "${PCAP_TYPE} is not a valid pcap type")
+        message(FATAL_ERROR "${PCAP_TYPE} is not a valid pcap type")
     endif()
 else(WIN32)
     if(PCAP_TYPE STREQUAL "dlpi")
@@ -1109,70 +1297,34 @@
 
         #
         # Do we have libnl?
+        # We only want version 3.  Version 2 was, apparently,
+        # short-lived, and version 1 is source and binary
+        # incompatible with version 3, and it appears that,
+        # these days, everybody's using version 3.  We're
+        # not supporting older versions of the Linux kernel;
+        # let's drop support for older versions of libnl, too.
         #
         if(BUILD_WITH_LIBNL)
-            #
-            # Try libnl 3.x first.
-            #
-            cmake_push_check_state()
-            set(CMAKE_REQUIRED_LIBRARIES nl-3)
-            check_function_exists(nl_socket_alloc HAVE_LIBNL)
-            cmake_pop_check_state()
-            if(HAVE_LIBNL)
-                #
-                # Yes, we have libnl 3.x.
-                #
-                set(PCAP_LINK_LIBRARIES nl-genl-3 nl-3 ${PCAP_LINK_LIBRARIES})
-                set(HAVE_LIBNL_3_x ON)
-                set(HAVE_LIBNL_NLE ON)
-                set(HAVE_LIBNL_SOCKETS ON)
-                include_directories("/usr/include/libnl3")
+            pkg_check_modules(LIBNL libnl-3.0)
+            if(LIBNL_FOUND)
+                set(PCAP_LINK_LIBRARIES ${LIBNL_LIBRARIES} ${PCAP_LINK_LIBRARIES})
             else()
-                #
-                # Try libnl 2.x.
-                #
                 cmake_push_check_state()
-                set(CMAKE_REQUIRED_LIBRARIES nl)
+                set(CMAKE_REQUIRED_LIBRARIES nl-3)
                 check_function_exists(nl_socket_alloc HAVE_LIBNL)
                 cmake_pop_check_state()
                 if(HAVE_LIBNL)
                     #
-                    # Yes, we have libnl 2.x.
+                    # Yes, we have libnl 3.x.
                     #
-                    set(PCAP_LINK_LIBRARIES nl-genl nl ${PCAP_LINK_LIBRARIES})
-                    set(HAVE_LIBNL_2_x ON)
-                    set(HAVE_LIBNL_NLE ON)
-                    set(HAVE_LIBNL_SOCKETS ON)
-                else()
-                    #
-                    # No, we don't; do we have libnl 1.x?
-                    #
-                    cmake_push_check_state()
-                    set(CMAKE_REQUIRED_LIBRARIES nl)
-                    check_function_exists(nl_handle_alloc HAVE_LIBNL)
-                    cmake_pop_check_state()
-                    if(HAVE_LIBNL)
-                        set(PCAP_LINK_LIBRARIES nl ${PCAP_LINK_LIBRARIES})
-                    endif()
+                    set(PCAP_LINK_LIBRARIES nl-genl-3 nl-3 ${PCAP_LINK_LIBRARIES})
+                    include_directories("/usr/include/libnl3")
                 endif()
             endif()
+        else()
+            unset(HAVE_LIBNL CACHE) # check_function_exists stores results in cache
         endif()
 
-        check_include_file(linux/ethtool.h HAVE_LINUX_ETHTOOL_H)
-
-        #
-        # Checks to see if tpacket_stats is defined in linux/if_packet.h
-        # If so then pcap-linux.c can use this to report proper statistics.
-        #
-        # XXX - there's no check_type() macro that's like check_type_size()
-        # except that it only checks for the existence of the structure type,
-        # so we use check_type_size() and ignore the size.
-        #
-        cmake_push_check_state()
-        set(CMAKE_EXTRA_INCLUDE_FILES linux/if_packet.h)
-        check_type_size("struct tpacket_stats" STRUCT_TPACKET_STATS)
-        cmake_pop_check_state()
-
         check_struct_has_member("struct tpacket_auxdata" tp_vlan_tci linux/if_packet.h HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
     elseif(PCAP_TYPE STREQUAL "bpf")
         #
@@ -1196,13 +1348,23 @@
             check_type_size("struct BPF_TIMEVAL" STRUCT_BPF_TIMEVAL)
         endif()
         cmake_pop_check_state()
+    elseif(PCAP_TYPE STREQUAL "haiku")
+        #
+        # Check for some headers just in case.
+        #
+        check_include_files("net/if.h;net/if_dl.h;net/if_types.h" HAVE_NET_IF_TYPES_H)
+        set(PCAP_SRC pcap-${PCAP_TYPE}.cpp)
     elseif(PCAP_TYPE STREQUAL "null")
     else()
         message(FATAL_ERROR "${PCAP_TYPE} is not a valid pcap type")
     endif()
 endif(WIN32)
 
-set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-${PCAP_TYPE}.c)
+if(NOT DEFINED PCAP_SRC)
+set(PCAP_SRC pcap-${PCAP_TYPE}.c)
+endif()
+
+set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} ${PCAP_SRC})
 
 #
 # Now figure out how we get a list of interfaces and addresses,
@@ -1308,11 +1470,13 @@
 # Check for additional native sniffing capabilities.
 #
 
-# Check for USB sniffing support on Linux.
-# On FreeBSD, it uses BPF, so we don't need to do anything special here.
-if(NOT DISABLE_USB)
-    if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-        set(PCAP_SUPPORT_USB TRUE)
+#
+# Various Linux-specific mechanisms.
+#
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    # Check for usbmon USB sniffing support.
+    if(NOT DISABLE_LINUX_USBMON)
+        set(PCAP_SUPPORT_LINUX_USBMON TRUE)
         set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-usb-linux.c)
         set(LINUX_USB_MON_DEV /dev/usbmon)
         #
@@ -1342,10 +1506,9 @@
             endif(HAVE_LINUX_COMPILER_H)
         endif()
     endif()
-endif()
 
-# Check for netfilter sniffing support.
-if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    #
+    # Check for netfilter sniffing support.
     #
     # Life's too short to deal with trying to get this to compile
     # if you don't get the right types defined with
@@ -1401,6 +1564,48 @@
     endif(PCAP_SUPPORT_NETMAP)
 endif()
 
+# Check for DPDK sniffing support
+if(NOT DISABLE_DPDK)
+    find_package(dpdk)
+    if(dpdk_FOUND)
+        #
+        # We include rte_bus.h, and older versions of DPDK didn't have
+        # it, so check for it.
+        #
+        # Also, we call rte_eth_dev_count_avail(), and older versions
+        # of DPDK didn't have it, so check for it.
+        #
+        cmake_push_check_state()
+        set(CMAKE_REQUIRED_INCLUDES ${dpdk_INCLUDE_DIRS})
+        check_include_file(rte_bus.h HAVE_RTE_BUS_H)
+        set(CMAKE_REQUIRED_LIBRARIES ${dpdk_LIBRARIES})
+        check_function_exists(rte_eth_dev_count_avail HAVE_RTE_ETH_DEV_COUNT_AVAIL)
+        cmake_pop_check_state()
+        if(HAVE_RTE_BUS_H AND HAVE_RTE_ETH_DEV_COUNT_AVAIL)
+            set(DPDK_C_FLAGS "-march=native")
+            set(DPDK_LIB dpdk rt m numa dl)
+            set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} ${DPDK_C_FLAGS})
+            include_directories(AFTER ${dpdk_INCLUDE_DIRS})
+            link_directories(AFTER ${dpdk_LIBRARIES})
+            set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${dpdk_LIBRARIES})
+            set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-dpdk.c)
+            set(PCAP_SUPPORT_DPDK TRUE)
+
+            #
+            # Check whether the rte_ether.h file defines
+            # struct ether_addr or struct rte_ether_addr.
+            #
+            # ("API compatibility?  That's for losers!")
+            #
+            cmake_push_check_state()
+            set(CMAKE_REQUIRED_INCLUDES ${dpdk_INCLUDE_DIRS})
+            set(CMAKE_EXTRA_INCLUDE_FILES rte_ether.h)
+            check_type_size("struct rte_ether_addr" STRUCT_RTE_ETHER_ADDR)
+            cmake_pop_check_state()
+        endif()
+    endif()
+endif()
+
 # Check for Bluetooth sniffing support
 if(NOT DISABLE_BLUETOOTH)
     if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
@@ -1439,9 +1644,11 @@
             endif(HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL)
         endif(HAVE_BLUETOOTH_BLUETOOTH_H)
     endif()
+else()
+    unset(PCAP_SUPPORT_BT_MONITOR CACHE)
 endif()
 
-# Check for Bluetooth sniffing support
+# Check for D-Bus sniffing support
 if(NOT DISABLE_DBUS)
     #
     # We don't support D-Bus sniffing on macOS; see
@@ -1451,7 +1658,6 @@
     if(APPLE)
         message(FATAL_ERROR "Due to freedesktop.org bug 74029, D-Bus capture support is not available on macOS")
     endif(APPLE)
-    include(FindPkgConfig)
     pkg_check_modules(DBUS dbus-1)
     if(DBUS_FOUND)
         set(PCAP_SUPPORT_DBUS TRUE)
@@ -1586,6 +1792,27 @@
     endif()
 endif()
 
+# Check for Riverbed AirPcap support.
+if(NOT DISABLE_AIRPCAP)
+    #
+    # Try to find the AirPcap header file and library.
+    #
+    find_package(AirPcap)
+
+    #
+    # Did we succeed?
+    #
+    if(AIRPCAP_FOUND)
+        #
+        # Yes.
+        #
+        include_directories(AFTER ${AIRPCAP_INCLUDE_DIRS})
+        set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-airpcap.c)
+        set(HAVE_AIRPCAP_API TRUE)
+        set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${AIRPCAP_LIBRARIES})
+    endif()
+endif()
+
 # Check for Riverbed TurboCap support.
 if(NOT DISABLE_TC)
     #
@@ -1603,7 +1830,7 @@
         include_directories(AFTER ${TC_INCLUDE_DIRS})
         set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-tc.c)
         set(HAVE_TC_API TRUE)
-        set(PCAP_LINK_LIBRARIES "${PCAP_LINK_LIBRARIES} ${TC_LIBRARIES} ${CMAKE_USE_PTHREADS_INIT} stdc++")
+        set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${TC_LIBRARIES} ${CMAKE_USE_PTHREADS_INIT} stdc++)
     endif()
 endif()
 
@@ -1629,7 +1856,7 @@
     check_struct_has_member("struct msghdr" msg_flags "ftmacros.h;sys/socket.h" HAVE_STRUCT_MSGHDR_MSG_FLAGS)
     cmake_pop_check_state()
     set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C}
-        pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c)
+        pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c)
 endif(ENABLE_REMOTE)
 
 ###################################################################
@@ -1698,6 +1925,20 @@
         # structure members.
         #
         check_and_add_compiler_option(-wd4820)
+        #
+        # We do *not* care about every single place the compiler would
+        # have inserted Spectre mitigation if only we had told it to
+        # do so with /Qspectre.  Maybe it's worth it, as that's in
+        # Bison-generated code that we don't control.
+        #
+        # XXX - add /Qspectre if that is really worth doing.
+        #
+        check_and_add_compiler_option(-wd5045)
+
+        #
+        # Treat all (remaining) warnings as errors.
+        #
+        check_and_add_compiler_option(-WX)
     else()
         #
         # Other compilers, including MSVC with a Clang front end and
@@ -1705,21 +1946,23 @@
         # they might support GCC-style -W options.
         #
         check_and_add_compiler_option(-Wall)
-        check_and_add_compiler_option(-Wsign-compare)
-        check_and_add_compiler_option(-Wmissing-prototypes)
-        check_and_add_compiler_option(-Wstrict-prototypes)
-        check_and_add_compiler_option(-Wshadow)
-        check_and_add_compiler_option(-Wdeclaration-after-statement)
-        check_and_add_compiler_option(-Wused-but-marked-unused)
-        check_and_add_compiler_option(-Wdocumentation)
         check_and_add_compiler_option(-Wcomma)
-        check_and_add_compiler_option(-Wmissing-noreturn)
         # Warns about safeguards added in case the enums are extended
         # check_and_add_compiler_option(-Wcovered-switch-default)
-        check_and_add_compiler_option(-Wmissing-variable-declarations)
-        check_and_add_compiler_option(-Wunused-parameter)
+        check_and_add_compiler_option(-Wdocumentation)
         check_and_add_compiler_option(-Wformat-nonliteral)
+        check_and_add_compiler_option(-Wmissing-noreturn)
+        check_and_add_compiler_option(-Wmissing-prototypes)
+        check_and_add_compiler_option(-Wmissing-variable-declarations)
+        check_and_add_compiler_option(-Wpointer-arith)
+        check_and_add_compiler_option(-Wpointer-sign)
+        check_and_add_compiler_option(-Wshadow)
+        check_and_add_compiler_option(-Wsign-compare)
+        check_and_add_compiler_option(-Wshorten-64-to-32)
+        check_and_add_compiler_option(-Wstrict-prototypes)
         check_and_add_compiler_option(-Wunreachable-code)
+        check_and_add_compiler_option(-Wunused-parameter)
+        check_and_add_compiler_option(-Wused-but-marked-unused)
     endif()
 endif()
 
@@ -1816,6 +2059,27 @@
 if(YACC_EXECUTABLE STREQUAL "YACC_EXECUTABLE-NOTFOUND")
     message(FATAL_ERROR "Neither bison nor win_bison nor byacc nor yacc was found.")
 endif()
+
+if(YACC_EXECUTABLE MATCHES "byacc" OR YACC_EXECUTABLE MATCHES "yacc")
+    #
+    # Berkeley YACC doesn't support "%define api.pure", so use
+    # "%pure-parser".
+    #
+    set(REENTRANT_PARSER "%pure-parser")
+else()
+    #
+    # Bison prior to 2.4(.1) doesn't support "%define api.pure", so use
+    # "%pure-parser".
+    #
+    execute_process(COMMAND ${YACC_EXECUTABLE} -V OUTPUT_VARIABLE bison_full_version)
+    string(REGEX MATCH "[1-9][0-9]*[.][1-9][0-9]*" bison_major_minor ${bison_full_version})
+    if (bison_major_minor VERSION_LESS "2.4")
+        set(REENTRANT_PARSER "%pure-parser")
+    else()
+        set(REENTRANT_PARSER "%define api.pure")
+    endif()
+endif()
+
 message(STATUS "Parser generator: ${YACC_EXECUTABLE}")
 
 #
@@ -1829,9 +2093,9 @@
 endif()
 add_custom_command(
     OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/grammar.c ${CMAKE_CURRENT_BINARY_DIR}/grammar.h
-    SOURCE ${pcap_SOURCE_DIR}/grammar.y
-    COMMAND ${YACC_EXECUTABLE} ${YACC_COMPATIBILITY_FLAG} -p pcap_ -o ${CMAKE_CURRENT_BINARY_DIR}/grammar.c -d ${pcap_SOURCE_DIR}/grammar.y
-    DEPENDS ${pcap_SOURCE_DIR}/grammar.y
+    SOURCE ${pcap_BINARY_DIR}/grammar.y
+    COMMAND ${YACC_EXECUTABLE} ${YACC_COMPATIBILITY_FLAG} -p pcap_ -o ${CMAKE_CURRENT_BINARY_DIR}/grammar.c -d ${pcap_BINARY_DIR}/grammar.y
+    DEPENDS ${pcap_BINARY_DIR}/grammar.y
 )
 
 #
@@ -1939,6 +2203,11 @@
         set(MAN_MISC_INFO 5)
         set(MAN_DEVICES 7D)
     endif()
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
+    #
+    # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them.
+    #
+    add_definitions(-D_BSD_SOURCE)
 endif()
 
 source_group("Source Files" FILES ${PROJECT_SOURCE_LIST_C})
@@ -1969,7 +2238,7 @@
 #
 # See
 #
-#  http://public.kitware.com/pipermail/cmake/2013-August/055510.html
+#  https://public.kitware.com/pipermail/cmake/2013-August/055510.html
 #
 add_custom_target(SerializeTarget
     DEPENDS
@@ -2000,6 +2269,10 @@
     #
     set_target_properties(${LIBRARY_NAME} PROPERTIES
         DEFINE_SYMBOL pcap_EXPORTS)
+    if(NOT "${LINKER_FLAGS}" STREQUAL "")
+        set_target_properties(${LIBRARY_NAME} PROPERTIES
+            LINK_FLAGS "${LINKER_FLAGS}")
+    endif()
 endif(BUILD_SHARED_LIBS)
 
 add_library(${LIBRARY_NAME}_static STATIC
@@ -2150,13 +2423,20 @@
         # for 32-bit x86 code and if and when Apple adds
         # ARM-based Macs.  (You're on your own for iOS etc.)
         #
-        # XXX - check whether we *can* build for i386 and, if not,
-        # suggest that the user install the /usr/include headers if
-        # they want to build fat.
+        # First, check whether we're building with OpenSSL.
+        # If so, don't bother trying to build fat.
         #
-        cmake_push_check_state()
-        set(CMAKE_REQUIRED_FLAGS "-arch i386")
-        check_c_source_compiles(
+        if(HAVE_OPENSSL)
+          set(X86_32_BIT_SUPPORTED NO)
+          set(OSX_LIBRARY_ARCHITECTURES "x86_64")
+          message(WARNING "We're assuming the OpenSSL libraries are 64-bit only, so we're not compiling for 32-bit x86")
+        else()
+          #
+          # Now, check whether we *can* build for i386.
+          #
+          cmake_push_check_state()
+          set(CMAKE_REQUIRED_FLAGS "-arch i386")
+          check_c_source_compiles(
 "int
 main(void)
 {
@@ -2164,20 +2444,25 @@
 }
 "
                    X86_32_BIT_SUPPORTED)
-        cmake_pop_check_state()
-        if(X86_32_BIT_SUPPORTED)
-            set(OSX_LIBRARY_ARCHITECTURES "x86_64;i386")
-        else()
-            set(OSX_LIBRARY_ARCHITECTURES "x86_64")
-            if(SYSTEM_VERSION_MAJOR LESS 18)
-                #
-                # Pre-Mojave; the command-line tools should be sufficient to
-                # enable 32-bit x86 builds.
-                #
-                message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools")
-            else()
-                message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package")
-            endif()
+          cmake_pop_check_state()
+          if(X86_32_BIT_SUPPORTED)
+              set(OSX_LIBRARY_ARCHITECTURES "x86_64;i386")
+          else()
+              set(OSX_LIBRARY_ARCHITECTURES "x86_64")
+              #
+              # We can't build fat; suggest that the user install the
+              # /usr/include headers if they want to build fat.
+              #
+              if(SYSTEM_VERSION_MAJOR LESS 18)
+                  #
+                  # Pre-Mojave; the command-line tools should be sufficient to
+                  # enable 32-bit x86 builds.
+                  #
+                  message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools")
+              else()
+                  message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package")
+              endif()
+          endif()
         endif()
     endif()
     if(BUILD_SHARED_LIBS)
@@ -2195,6 +2480,12 @@
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmakeconfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
 
 ######################################
+# Write out the grammar.y file
+######################################
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/grammar.y.in ${CMAKE_CURRENT_BINARY_DIR}/grammar.y @ONLY)
+
+######################################
 # Install pcap library, include files, and man pages
 ######################################
 
@@ -2209,12 +2500,11 @@
 
 function(install_manpage_symlink SOURCE TARGET MANDIR)
     if(MINGW)
-        find_program(LINK_EXECUTABLE ln)
-            if(LINK_EXECUTABLE)
-                set(LINK_COMMAND "\"${LINK_EXECUTABLE}\" \"-s\" \"${SOURCE}\" \"${TARGET}\"")
-            else(LINK_EXECUTABLE)
-                message(FATAL_ERROR "ln (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ln.html) not found.")
-            endif(LINK_EXECUTABLE)
+        #
+        # If we haven't found an ln executable with MinGW, we don't try
+        # generating and installing the man pages, so if we get here,
+        # we've found that executable.
+        set(LINK_COMMAND "\"${LINK_EXECUTABLE}\" \"-s\" \"${SOURCE}\" \"${TARGET}\"")
     else(MINGW)
         set(LINK_COMMAND "\"${CMAKE_COMMAND}\" \"-E\" \"create_symlink\" \"${SOURCE}\" \"${TARGET}\"")
     endif(MINGW)
@@ -2271,6 +2561,7 @@
     pcap_get_required_select_timeout.3pcap
     pcap_get_selectable_fd.3pcap
     pcap_geterr.3pcap
+    pcap_init.3pcap
     pcap_inject.3pcap
     pcap_is_swapped.3pcap
     pcap_lib_version.3pcap
@@ -2312,19 +2603,19 @@
 if(WIN32)
     if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
         #
-        # Install 64-bit code built with MSVC in the amd64 subdirectories,
+        # Install 64-bit code built with MSVC in the x64 subdirectories,
         # as that's where it expects it to be.
         #
         install(TARGETS ${LIBRARY_NAME} ${LIBRARY_NAME_STATIC}
-                RUNTIME DESTINATION bin/amd64
-                LIBRARY DESTINATION lib/amd64
-                ARCHIVE DESTINATION lib/amd64)
+                RUNTIME DESTINATION bin/x64
+                LIBRARY DESTINATION lib/x64
+                ARCHIVE DESTINATION lib/x64)
         if(NOT MINGW)
             install(FILES $<TARGET_FILE_DIR:${LIBRARY_NAME_STATIC}>/${LIBRARY_NAME_STATIC}.pdb
-                    DESTINATION bin/amd64 OPTIONAL)
+                    DESTINATION bin/x64 OPTIONAL)
             if(BUILD_SHARED_LIBS)
                 install(FILES $<TARGET_PDB_FILE:${LIBRARY_NAME}>
-                        DESTINATION bin/amd64 OPTIONAL)
+                        DESTINATION bin/x64 OPTIONAL)
             endif(BUILD_SHARED_LIBS)
         endif(NOT MINGW)
     else(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -2362,7 +2653,7 @@
     set(prefix ${CMAKE_INSTALL_PREFIX})
     set(exec_prefix "\${prefix}")
     set(includedir "\${prefix}/include")
-    set(libdir "\${exec_prefix}/lib")
+    set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
     if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
        CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
        CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR
@@ -2404,54 +2695,64 @@
     # For each section of the manual for which we have man pages
     # that require macro expansion, do the expansion.
     #
-    set(MAN1 "")
-    foreach(MANPAGE ${MAN1_NOEXPAND})
-        set(MAN1 ${MAN1} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE})
-    endforeach(MANPAGE)
-    install(FILES ${MAN1} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
+    # If this is MinGW, maybe we have a UN*X-style ln command and
+    # maybe we don't.  (No, we do *NOT* require MSYS!)  If we don't
+    # have it, don't do the man pages.
+    #
+    if(MINGW)
+        find_program(LINK_EXECUTABLE ln)
+    endif(MINGW)
+    if(UNIX OR (MINGW AND LINK_EXECUTABLE))
+        set(MAN1 "")
+        foreach(MANPAGE ${MAN1_NOEXPAND})
+            set(MAN1 ${MAN1} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE})
+        endforeach(MANPAGE)
+        install(FILES ${MAN1} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
 
-    set(MAN3PCAP "")
-    foreach(MANPAGE ${MAN3PCAP_NOEXPAND})
-        set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE})
-    endforeach(MANPAGE)
-    foreach(TEMPLATE_MANPAGE ${MAN3PCAP_EXPAND})
-        string(REPLACE ".in" "" MANPAGE ${TEMPLATE_MANPAGE})
-        configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
-        set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
-    endforeach(TEMPLATE_MANPAGE)
-    install(FILES ${MAN3PCAP} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_datalink_val_to_name.3pcap pcap_datalink_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_dump_open.3pcap pcap_dump_fopen.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_findalldevs.3pcap pcap_freealldevs.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_geterr.3pcap pcap_perror.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_inject.3pcap pcap_sendpacket.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_loop.3pcap pcap_dispatch.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_major_version.3pcap pcap_minor_version.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_next_ex.3pcap pcap_next.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_open_dead.3pcap pcap_open_dead_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-    install_manpage_symlink(pcap_setnonblock.3pcap pcap_getnonblock.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        set(MAN3PCAP "")
+        foreach(MANPAGE ${MAN3PCAP_NOEXPAND})
+            set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE})
+        endforeach(MANPAGE)
+        foreach(TEMPLATE_MANPAGE ${MAN3PCAP_EXPAND})
+            string(REPLACE ".in" "" MANPAGE ${TEMPLATE_MANPAGE})
+            configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
+            set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
+        endforeach(TEMPLATE_MANPAGE)
+        install(FILES ${MAN3PCAP} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_datalink_val_to_name.3pcap pcap_datalink_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_datalink_val_to_name.3pcap pcap_datalink_val_to_description_or_dlt.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_dump_open.3pcap pcap_dump_fopen.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_findalldevs.3pcap pcap_freealldevs.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_geterr.3pcap pcap_perror.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_inject.3pcap pcap_sendpacket.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_loop.3pcap pcap_dispatch.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_major_version.3pcap pcap_minor_version.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_next_ex.3pcap pcap_next.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_open_dead.3pcap pcap_open_dead_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+        install_manpage_symlink(pcap_setnonblock.3pcap pcap_getnonblock.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
 
-    set(MANFILE "")
-    foreach(TEMPLATE_MANPAGE ${MANFILE_EXPAND})
-        string(REPLACE ".manfile.in" ".${MAN_FILE_FORMATS}" MANPAGE ${TEMPLATE_MANPAGE})
-        configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
-        set(MANFILE ${MANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
-    endforeach(TEMPLATE_MANPAGE)
-    install(FILES ${MANFILE} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_FILE_FORMATS})
+        set(MANFILE "")
+        foreach(TEMPLATE_MANPAGE ${MANFILE_EXPAND})
+            string(REPLACE ".manfile.in" ".${MAN_FILE_FORMATS}" MANPAGE ${TEMPLATE_MANPAGE})
+            configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
+            set(MANFILE ${MANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
+        endforeach(TEMPLATE_MANPAGE)
+        install(FILES ${MANFILE} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_FILE_FORMATS})
 
-    set(MANMISC "")
-    foreach(TEMPLATE_MANPAGE ${MANMISC_EXPAND})
-        string(REPLACE ".manmisc.in" ".${MAN_MISC_INFO}" MANPAGE ${TEMPLATE_MANPAGE})
-        configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
-        set(MANMISC ${MANMISC} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
-    endforeach(TEMPLATE_MANPAGE)
-    install(FILES ${MANMISC} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_MISC_INFO})
+        set(MANMISC "")
+        foreach(TEMPLATE_MANPAGE ${MANMISC_EXPAND})
+            string(REPLACE ".manmisc.in" ".${MAN_MISC_INFO}" MANPAGE ${TEMPLATE_MANPAGE})
+            configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
+            set(MANMISC ${MANMISC} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
+        endforeach(TEMPLATE_MANPAGE)
+        install(FILES ${MANMISC} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_MISC_INFO})
+    endif(UNIX OR (MINGW AND LINK_EXECUTABLE))
 endif(NOT MSVC)
 
 # uninstall target
diff --git a/CREDITS b/CREDITS
index f7abc1f..d01e832 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3,29 +3,42 @@
 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                    <guy at alum dot mit dot edu>
+    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>
@@ -34,15 +47,22 @@
     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>
@@ -50,8 +70,12 @@
     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>
@@ -59,6 +83,7 @@
     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>
@@ -71,47 +96,64 @@
     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>
@@ -119,25 +161,36 @@
     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>
@@ -145,9 +198,9 @@
     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>
-    Rongxi Li                     <rongxi dot li at chaitin dot com>
     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>
@@ -156,22 +209,37 @@
     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:
diff --git a/INSTALL.md b/INSTALL.md
index 3a303fe..ba8b8f9 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -41,8 +41,8 @@
 compatible with them (if any exist), to build libpcap.  The configure
 script will abort if there isn't any such program.  If you don't have
 any such program, the current version of Bison can be found at
-http://ftp.gnu.org/gnu/bison/ and the current version of Berkeley YACC
-can be found at http://invisible-island.net/byacc/.
+https://ftp.gnu.org/gnu/bison/ and the current version of Berkeley YACC
+can be found at https://invisible-island.net/byacc/.
 
 Sometimes the stock C compiler does not interact well with Flex and
 Bison. The list of problems includes undefined references for alloca.
@@ -188,7 +188,7 @@
 release. It is known to compile and run on SINIX-Y/N 5.42 with the C-DS
 V1.0 or V1.1 compiler. But note that in some releases of SINIX, yacc
 emits incorrect code; if grammar.y fails to compile, change every
-occurence of:
+occurrence of:
 
 	#ifdef YYDEBUG
 
@@ -206,7 +206,7 @@
 network traffic.  SCO do not appear to provide tcpdump binaries for
 OpenServer 5 or OpenServer 6 as part of SCO Skunkware:
 
-	http://www.sco.com/skunkware/
+  http://www.sco.com/skunkware/
 
 If you use UnixWare, you might be able to build libpcap from this
 release, or you might not.  We do not have a machine running UnixWare,
@@ -221,7 +221,7 @@
 higher is recommended (1.14 is known to cause problems 1.16 is known to
 work). Either pick up a current version from:
 
-	http://ftp.gnu.org/gnu/bison/
+  https://ftp.gnu.org/gnu/bison/
 
 or hack around it by inserting the lines:
 
@@ -248,105 +248,104 @@
 
 FILES
 -----
-CHANGES		- description of differences between releases
-ChmodBPF/*	- macOS startup item to set ownership and permissions
-		  on /dev/bpf*
-CMakeLists.txt	- CMake file
-CONTRIBUTING	- guidelines for contributing
-CREDITS		- people that have helped libpcap along
-INSTALL.md	- this file
-LICENSE		- the license under which tcpdump is distributed
-Makefile.in	- compilation rules (input to the configure script)
-README.md	- description of distribution
-doc/README.aix	- notes on using libpcap on AIX
-doc/README.dag	- notes on using libpcap to capture on Endace DAG devices
-doc/README.hpux	- notes on using libpcap on HP-UX
-doc/README.linux.md - notes on using libpcap on Linux
-doc/README.macos	- notes on using libpcap on macOS
-doc/README.septel   - notes on using libpcap to capture on Intel/Septel devices
-doc/README.sita	- notes on using libpcap to capture on SITA devices
-doc/README.tru64	- notes on using libpcap on Digital/Tru64 UNIX
-doc/README.Win32	- notes on using libpcap on Win32 systems (with Npcap)
-VERSION		- version of this release
-acconfig.h	- support for post-2.13 autoconf
-aclocal.m4	- autoconf macros
-arcnet.h	- ARCNET definitions
-atmuni31.h	- ATM Q.2931 definitions
-bpf_dump.c	- BPF program printing routines
-bpf_filter.c	- BPF filtering routines
-bpf_image.c	- BPF disassembly routine
-config.guess	- autoconf support
-config.h.in	- autoconf input
-config.sub	- autoconf support
-configure	- configure script (run this first)
-configure.ac	- configure script source
-dlpisubs.c	- DLPI-related functions for pcap-dlpi.c and pcap-libdlpi.c
-dlpisubs.h	- DLPI-related function declarations
-etherent.c	- /etc/ethers support routines
-ethertype.h	- Ethernet protocol types and names definitions
-fad-getad.c	- pcap_findalldevs() for systems with getifaddrs()
-fad-gifc.c	- pcap_findalldevs() for systems with only SIOCGIFLIST
-fad-glifc.c	- pcap_findalldevs() for systems with SIOCGLIFCONF
-filtertest.c	- test program for BPF compiler
-findalldevstest.c - test program for pcap_findalldevs()
-gencode.c	- BPF code generation routines
-gencode.h	- BPF code generation definitions
-grammar.y	- filter string grammar
-ieee80211.h	- 802.11 definitions
-install-sh	- BSD style install script
-lbl/os-*.h	- OS-dependent defines and prototypes
-llc.h		- 802.2 LLC SAP definitions
-missing/*	- replacements for missing library functions
-mkdep		- construct Makefile dependency list
-msdos/*		- drivers for MS-DOS capture support
-nametoaddr.c	- hostname to address routines
-nlpid.h		- OSI network layer protocol identifier definitions
-net		- symlink to bpf/net
-optimize.c	- BPF optimization routines
-pcap/bluetooth.h - public definition of DLT_BLUETOOTH_HCI_H4_WITH_PHDR header
-pcap/bpf.h	- BPF definitions
-pcap/namedb.h	- public libpcap name database definitions
-pcap/pcap.h	- public libpcap definitions
-pcap/sll.h	- public definition of DLT_LINUX_SLL header
-pcap/usb.h	- public definition of DLT_USB header
-pcap-bpf.c	- BSD Packet Filter support
-pcap-bpf.h	- header for backwards compatibility
-pcap-bt-linux.c	- Bluetooth capture support for Linux
-pcap-bt-linux.h	- Bluetooth capture support for Linux
-pcap-dag.c	- Endace DAG device capture support
-pcap-dag.h	- Endace DAG device capture support
-pcap-dlpi.c	- Data Link Provider Interface support
-pcap-dos.c	- MS-DOS capture support
-pcap-dos.h	- headers for MS-DOS capture support
-pcap-enet.c	- enet support
-pcap-int.h	- internal libpcap definitions
-pcap-libdlpi.c	- Data Link Provider Interface support for systems with libdlpi
-pcap-linux.c	- Linux packet socket support
-pcap-namedb.h	- header for backwards compatibility
-pcap-nit.c	- SunOS Network Interface Tap support
-pcap-nit.h	- SunOS Network Interface Tap definitions
-pcap-npf.c	- WinPcap capture support
-pcap-null.c	- dummy monitor support (allows offline use of libpcap)
-pcap-pf.c	- Ultrix and Digital/Tru64 UNIX Packet Filter support
-pcap-pf.h	- Ultrix and Digital/Tru64 UNIX Packet Filter definitions
-pcap-septel.c   - Intel/Septel device capture support
-pcap-septel.h   - Intel/Septel device capture support
-pcap-sita.c	- SITA device capture support
-pcap-sita.h	- SITA device capture support
-pcap-sita.html	- SITA device capture documentation
-pcap-stdinc.h	- includes and #defines for compiling on Win32 systems
-pcap-snit.c	- SunOS 4.x STREAMS-based Network Interface Tap support
-pcap-snoop.c	- IRIX Snoop network monitoring support
-pcap-usb-linux.c - USB capture support for Linux
-pcap-usb-linux.h - USB capture support for Linux
-pcap.3pcap	- manual entry for the library
-pcap.c		- pcap utility routines
-pcap.h		- header for backwards compatibility
-pcap_*.3pcap	- manual entries for library functions
-pcap-filter.4	- manual entry for filter syntax
-pcap-linktype.4	- manual entry for link-layer header types
-ppp.h		- Point to Point Protocol definitions
-savefile.c	- offline support
-scanner.l	- filter string scanner
-sunatmpos.h	- definitions for SunATM capturing
-Win32		- headers and routines for building on Win32 systems
+	CHANGES		    - description of differences between releases
+	ChmodBPF/*	    - macOS startup item to set ownership and permissions on /dev/bpf*
+	CMakeLists.txt	    - CMake file
+	CONTRIBUTING.md	    - guidelines for contributing
+	CREDITS		    - people that have helped libpcap along
+	INSTALL.md	    - this file
+	LICENSE		    - the license under which tcpdump is distributed
+	Makefile.in	    - compilation rules (input to the configure script)
+	README.md	    - description of distribution
+	doc/README.aix	    - notes on using libpcap on AIX
+	doc/README.dag	    - notes on using libpcap to capture on Endace DAG devices
+	doc/README.hpux	    - notes on using libpcap on HP-UX
+	doc/README.linux.md - notes on using libpcap on Linux
+	doc/README.macos    - notes on using libpcap on macOS
+	doc/README.septel   - notes on using libpcap to capture on Intel/Septel devices
+	doc/README.sita	    - notes on using libpcap to capture on SITA devices
+	doc/README.tru64    - notes on using libpcap on Digital/Tru64 UNIX
+	doc/README.Win32.md - notes on using libpcap on Win32 systems (with Npcap)
+	VERSION		    - version of this release
+	acconfig.h	    - support for post-2.13 autoconf
+	aclocal.m4	    - autoconf macros
+	arcnet.h	    - ARCNET definitions
+	atmuni31.h	    - ATM Q.2931 definitions
+	bpf_dump.c	    - BPF program printing routines
+	bpf_filter.c	    - BPF filtering routines
+	bpf_image.c	    - BPF disassembly routine
+	config.guess	    - autoconf support
+	config.h.in	    - autoconf input
+	config.sub	    - autoconf support
+	configure	    - configure script (run this first)
+	configure.ac	    - configure script source
+	dlpisubs.c	    - DLPI-related functions for pcap-dlpi.c and pcap-libdlpi.c
+	dlpisubs.h	    - DLPI-related function declarations
+	etherent.c	    - /etc/ethers support routines
+	ethertype.h	    - Ethernet protocol types and names definitions
+	fad-getad.c	    - pcap_findalldevs() for systems with getifaddrs()
+	fad-gifc.c	    - pcap_findalldevs() for systems with only SIOCGIFLIST
+	fad-glifc.c	    - pcap_findalldevs() for systems with SIOCGLIFCONF
+	filtertest.c	    - test program for BPF compiler
+	findalldevstest.c   - test program for pcap_findalldevs()
+	gencode.c	    - BPF code generation routines
+	gencode.h	    - BPF code generation definitions
+	grammar.y	    - filter string grammar
+	ieee80211.h	    - 802.11 definitions
+	install-sh	    - BSD style install script
+	lbl/os-*.h	    - OS-dependent defines and prototypes
+	llc.h		    - 802.2 LLC SAP definitions
+	missing/*	    - replacements for missing library functions
+	mkdep		    - construct Makefile dependency list
+	msdos/*		    - drivers for MS-DOS capture support
+	nametoaddr.c	    - hostname to address routines
+	nlpid.h		    - OSI network layer protocol identifier definitions
+	net		    - symlink to bpf/net
+	optimize.c	    - BPF optimization routines
+	pcap/bluetooth.h    - public definition of DLT_BLUETOOTH_HCI_H4_WITH_PHDR header
+	pcap/bpf.h	    - BPF definitions
+	pcap/namedb.h	    - public libpcap name database definitions
+	pcap/pcap.h	    - public libpcap definitions
+	pcap/sll.h	    - public definitions of DLT_LINUX_SLL and DLT_LINUX_SLL2 headers
+	pcap/usb.h	    - public definition of DLT_USB header
+	pcap-bpf.c	    - BSD Packet Filter support
+	pcap-bpf.h	    - header for backwards compatibility
+	pcap-bt-linux.c	    - Bluetooth capture support for Linux
+	pcap-bt-linux.h	    - Bluetooth capture support for Linux
+	pcap-dag.c	    - Endace DAG device capture support
+	pcap-dag.h	    - Endace DAG device capture support
+	pcap-dlpi.c	    - Data Link Provider Interface support
+	pcap-dos.c	    - MS-DOS capture support
+	pcap-dos.h	    - headers for MS-DOS capture support
+	pcap-enet.c	    - enet support
+	pcap-int.h	    - internal libpcap definitions
+	pcap-libdlpi.c	    - Data Link Provider Interface support for systems with libdlpi
+	pcap-linux.c	    - Linux packet socket support
+	pcap-namedb.h	    - header for backwards compatibility
+	pcap-nit.c	    - SunOS Network Interface Tap support
+	pcap-nit.h	    - SunOS Network Interface Tap definitions
+	pcap-npf.c	    - Npcap capture support
+	pcap-null.c	    - dummy monitor support (allows offline use of libpcap)
+	pcap-pf.c	    - Ultrix and Digital/Tru64 UNIX Packet Filter support
+	pcap-pf.h	    - Ultrix and Digital/Tru64 UNIX Packet Filter definitions
+	pcap-septel.c       - Intel/Septel device capture support
+	pcap-septel.h       - Intel/Septel device capture support
+	pcap-sita.c	    - SITA device capture support
+	pcap-sita.h	    - SITA device capture support
+	pcap-sita.html	    - SITA device capture documentation
+	pcap-stdinc.h	    - includes and #defines for compiling on Win32 systems
+	pcap-snit.c	    - SunOS 4.x STREAMS-based Network Interface Tap support
+	pcap-snoop.c	    - IRIX Snoop network monitoring support
+	pcap-usb-linux.c    - USB capture support for Linux
+	pcap-usb-linux.h    - USB capture support for Linux
+	pcap.3pcap	    - manual entry for the library
+	pcap.c		    - pcap utility routines
+	pcap.h		    - header for backwards compatibility
+	pcap_*.3pcap	    - manual entries for library functions
+	pcap-filter.4	    - manual entry for filter syntax
+	pcap-linktype.4	    - manual entry for link-layer header types
+	ppp.h		    - Point to Point Protocol definitions
+	savefile.c	    - offline support
+	scanner.l	    - filter string scanner
+	sunatmpos.h	    - definitions for SunATM capturing
+	Win32		    - headers and routines for building on Win32 systems
diff --git a/METADATA b/METADATA
index e62c7cb..2f80bb8 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://github.com/the-tcpdump-group/libpcap/archive/libpcap-1.9.1.tar.gz"
+    value: "https://github.com/the-tcpdump-group/libpcap/archive/libpcap-1.10.0.tar.gz"
   }
-  version: "libpcap-1.9.1"
+  version: "libpcap-1.10.0"
   license_type: RESTRICTED
   last_upgrade_date {
-    year: 2020
-    month: 4
-    day: 24
+    year: 2021
+    month: 1
+    day: 5
   }
 }
diff --git a/Makefile.in b/Makefile.in
index 5a6b165..d8b8507 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -38,6 +38,7 @@
 
 # VPATH
 srcdir = @srcdir@
+top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 
 #
@@ -70,6 +71,7 @@
 
 # Standard CFLAGS for building members of a shared library
 FULL_CFLAGS = $(CCOPT) @V_LIB_CCOPT_FAT@ $(SHLIB_CCOPT) $(INCLS) $(DEFS) $(CFLAGS)
+CXXFLAGS = $(CCOPT) @V_LIB_CCOPT_FAT@ $(SHLIB_CCOPT) $(INCLS) $(DEFS) $(CFLAGS)
 
 INSTALL = @INSTALL@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -86,21 +88,29 @@
 	@rm -f $@
 	$(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c
 
-PSRC =	pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ @NETFILTER_SRC@ @DBUS_SRC@ @NETMAP_SRC@ @RDMA_SRC@
-FSRC =  @V_FINDALLDEVS@
-SSRC =  @SSRC@
-CSRC =	pcap.c gencode.c optimize.c nametoaddr.c etherent.c \
-	fmtutils.c \
-	savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \
-	bpf_image.c bpf_filter.c bpf_dump.c
-GENSRC = scanner.c grammar.c
+PLATFORM_C_SRC =	@PLATFORM_C_SRC@
+PLATFORM_CXX_SRC =	@PLATFORM_CXX_SRC@
+MODULE_C_SRC =		@MODULE_C_SRC@
+REMOTE_C_SRC =		@REMOTE_C_SRC@
+COMMON_C_SRC =	pcap.c gencode.c optimize.c nametoaddr.c etherent.c \
+		fmtutils.c \
+		savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \
+		bpf_image.c bpf_filter.c bpf_dump.c
+GENERATED_C_SRC = scanner.c grammar.c
 LIBOBJS = @LIBOBJS@
 
-SRC =	$(PSRC) $(FSRC) $(CSRC) $(SSRC) $(GENSRC)
+SRC =	$(PLATFORM_C_SRC) $(PLATFORM_CXX_SRC) \
+	$(MODULE_C_SRC) $(REMOTE_C_SRC) $(COMMON_C_SRC) \
+	$(GENERATED_C_SRC)
 
 # We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot
-# hack the extra indirection
-OBJ =	$(PSRC:.c=.o) $(FSRC:.c=.o) $(CSRC:.c=.o) $(SSRC:.c=.o) $(GENSRC:.c=.o) $(LIBOBJS)
+# hack the extra indirection, and we have to handle PLATFORM_CXX_SRC
+# differently from the defines for C source
+OBJ =	$(PLATFORM_C_SRC:.c=.o) $(PLATFORM_CXX_SRC:.cpp=.o) \
+	$(MODULE_C_SRC:.c=.o) $(REMOTE_C_SRC:.c=.o) $(COMMON_C_SRC:.c=.o) \
+	$(GENERATED_C_SRC:.c=.o) \
+	$(LIBOBJS)
+
 PUBHDR = \
 	pcap.h \
 	pcap-bpf.h \
@@ -154,7 +164,7 @@
 	$(SRC) $(HDR)
 
 CLEANFILES = $(OBJ) libpcap.a libpcap.so.`cat $(srcdir)/VERSION` \
-	$(PROG)-`cat $(srcdir)/VERSION`.tar.gz $(GENSRC) $(GENHDR) \
+	$(PROG)-`cat $(srcdir)/VERSION`.tar.gz $(GENERATED_C_SRC) $(GENHDR) \
 	lex.yy.c pcap-config libpcap.pc
 
 MAN1 = pcap-config.1
@@ -193,6 +203,7 @@
 	pcap_get_required_select_timeout.3pcap \
 	pcap_get_selectable_fd.3pcap \
 	pcap_geterr.3pcap \
+	pcap_init.3pcap \
 	pcap_inject.3pcap \
 	pcap_is_swapped.3pcap \
 	pcap_lib_version.3pcap \
@@ -246,10 +257,13 @@
 	TODO \
 	VERSION \
 	aclocal.m4 \
+	charconv.c \
+	charconv.h \
 	chmod_bpf \
 	cmake_uninstall.cmake.in \
 	cmakeconfig.h.in \
 	cmake/Modules/FindDAG.cmake \
+	cmake/Modules/Finddpdk.cmake \
 	cmake/Modules/FindFseeko.cmake \
 	cmake/Modules/FindLFS.cmake \
 	cmake/Modules/FindPacket.cmake \
@@ -266,7 +280,7 @@
 	fad-getad.c \
 	fad-gifc.c \
 	fad-glifc.c \
-	grammar.y \
+	grammar.y.in \
 	install-sh \
 	lbl/os-aix4.h \
 	lbl/os-aix7.h \
@@ -280,12 +294,10 @@
 	missing/asprintf.c \
 	missing/getopt.c \
 	missing/getopt.h \
-	missing/snprintf.c \
 	missing/strlcat.c \
 	missing/strlcpy.c \
 	missing/strtok_r.c \
 	missing/win_asprintf.c \
-	missing/win_snprintf.c \
 	mkdep \
 	msdos/bin2c.c \
 	msdos/makefile \
@@ -298,6 +310,8 @@
 	msdos/readme.dos \
 	nomkdep \
 	org.tcpdump.chmod_bpf.plist \
+	pcap-airpcap.c \
+	pcap-airpcap.h \
 	pcap-bpf.c \
 	pcap-bt-linux.c \
 	pcap-bt-linux.h \
@@ -312,7 +326,10 @@
 	pcap-dlpi.c \
 	pcap-dos.c \
 	pcap-dos.h \
+	pcap-dpdk.c \
+	pcap-dpdk.h \
 	pcap-enet.c \
+	pcap-haiku.cpp \
 	pcap-int.h \
 	pcap-libdlpi.c \
 	pcap-linux.c \
@@ -367,6 +384,8 @@
 	rpcapd/win32-svc.h \
 	sockutils.c \
 	sockutils.h \
+	sslutils.c \
+	sslutils.h \
 	scanner.l \
 	testprogs/CMakeLists.txt \
 	testprogs/Makefile.in \
@@ -374,12 +393,23 @@
 	testprogs/capturetest.c \
 	testprogs/filtertest.c \
 	testprogs/findalldevstest.c \
+	testprogs/findalldevstest-perf.c \
+	testprogs/fuzz/CMakeLists.txt \
+	testprogs/fuzz/fuzz_both.c \
+	testprogs/fuzz/fuzz_both.options \
+	testprogs/fuzz/fuzz_filter.c \
+	testprogs/fuzz/fuzz_filter.options \
+	testprogs/fuzz/fuzz_pcap.c \
+	testprogs/fuzz/fuzz_pcap.options \
+	testprogs/fuzz/onefile.c \
 	testprogs/opentest.c \
 	testprogs/reactivatetest.c \
 	testprogs/selpolltest.c \
 	testprogs/threadsignaltest.c \
 	testprogs/unix.h \
 	testprogs/valgrindtest.c \
+	testprogs/visopts.py \
+	testprogs/writecaptest.c \
 	tests/shb-option-too-long.pcapng \
 	Win32/Prj/wpcap.sln \
 	Win32/Prj/wpcap.vcxproj \
@@ -480,7 +510,26 @@
 scanner.o: scanner.c grammar.h
 	$(CC) $(FULL_CFLAGS) -c scanner.c
 
-grammar.c: $(srcdir)/grammar.y
+#
+# Generate the grammar.y file.
+#
+# Some Makes, e.g. AIX Make and Solaris Make, can't handle "--file=$@.tmp:$<";
+# for example, the Solaris 9 make man page says
+#
+#	Because make assigns $< and $* as it would for implicit rules
+#	(according to the suffixes list and the directory contents),
+#	they may be unreliable when used within explicit target entries.
+#
+# and this is an explicit target entry.
+#
+# Therefore, instead of using $<, we explicitly put in $(srcdir)/libpcap.pc.in.
+#
+grammar.y: $(srcdir)/grammar.y.in ./config.status
+	@rm -f $@ $@.tmp
+	./config.status --file=$@.tmp:$(srcdir)/grammar.y.in
+	mv $@.tmp $@
+
+grammar.c: grammar.y
 	$(YACC) -p pcap_ -o grammar.c -d $<
 grammar.h: grammar.c
 ## Recover from the removal of $@
@@ -528,7 +577,6 @@
 	@rm -f $@ $@.tmp
 	./config.status --file=$@.tmp:$(srcdir)/libpcap.pc.in
 	mv $@.tmp $@
-	chmod a+x $@
 
 #
 # Generate the pcap-config script.  See above.
@@ -695,6 +743,7 @@
 	for i in $(MAN3PCAP); do \
 		rm -f $(DESTDIR)$(mandir)/man3/$$i; done
 	rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description.3pcap
+	rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description_or_dlt.3pcap
 	rm -f $(DESTDIR)$(mandir)/man3/pcap_dump_fopen.3pcap
 	rm -f $(DESTDIR)$(mandir)/man3/pcap_freealldevs.3pcap
 	rm -f $(DESTDIR)$(mandir)/man3/pcap_perror.3pcap
@@ -745,7 +794,7 @@
 	cd testprogs; $(MAKE) clean
 
 distclean: clean
-	rm -f Makefile config.cache config.log config.status \
+	rm -f Makefile grammar.y config.cache config.log config.status \
 	    config.h gnuc.h net os-proto.h libpcap.pc \
 	    pcap-config stamp-h stamp-h.in
 	rm -f $(MAN3PCAP_EXPAND:.in=) $(MANFILE:.in=) $(MANMISC:.in=)
@@ -760,15 +809,23 @@
 	ctags -wtd $(TAGFILES)
 
 releasetar:
-	@cwd=`pwd` ; dir=`basename $$cwd` ; name=$(PROG)-`cat VERSION` ; \
+	@autoreconf -f; \
+	name=$(PROG)-`cat VERSION` ; \
 	   mkdir $$name; \
-	   tar -c --exclude='*~' -f - $(CSRC) $(HDR) $(MAN1) $(MAN3PCAP_EXPAND) \
-	      $(MAN3PCAP_NOEXPAND) $(MANFILE) $(MANMISC) $(EXTRA_DIST) | \
+	   tar -c --exclude='*~' -f - $(COMMON_C_SRC) $(HDR) $(MAN1) \
+	      $(MAN3PCAP_EXPAND) $(MAN3PCAP_NOEXPAND) $(MANFILE) \
+	      $(MANMISC) $(EXTRA_DIST) | \
 	      (cd $$name; tar xf -); \
 	   tar -c -z -f $$name.tar.gz $$name; \
 	   rm -rf $$name
 
-depend:	$(GENSRC) $(GENHDR)
-	$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
+rc1 rc2 rc3 rc4 rc5:
+	@VER=`cat $(srcdir)/VERSION`; \
+	sed -i "s/$$VER/$${VER}$@/" VERSION ; \
+	make releasetar; \
+	git checkout VERSION
+
+depend:	$(GENERATED_C_SRC) $(GENHDR)
+	$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
 	cd rpcapd; $(MAKE) depend
 	cd testprogs; $(MAKE) depend
diff --git a/README.md b/README.md
index 78cc3c4..1e3a245 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,31 @@
-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 file
-[CONTRIBUTING](CONTRIBUTING.md) in the libpcap source tree root.
-
-The directory doc/ has README files about specific operating systems and
-options.
-
 LIBPCAP 1.x.y
-Now maintained by "The Tcpdump Group"
-https://www.tcpdump.org
+=============
 
-Anonymous Git is available via:
-        https://github.com/the-tcpdump-group/libpcap.git
+[![Build Status](https://travis-ci.org/the-tcpdump-group/tcpdump.svg?branch=master)](https://travis-ci.org/the-tcpdump-group/libpcap)
+
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/the-tcpdump-group/tcpdump?branch=master&svg=true)](https://ci.appveyor.com/project/guyharris/libpcap)
+
+Now maintained by "The Tcpdump Group"
+
+  https://www.tcpdump.org
 
 formerly from 	Lawrence Berkeley National Laboratory
 		Network Research Group <libpcap@ee.lbl.gov>
 		ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z
 
+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 file
+[CONTRIBUTING.md](CONTRIBUTING.md) in the libpcap source tree root.
+
+The 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
@@ -39,19 +47,15 @@
 User-level Packet Capture''.  A compressed PostScript version can be
 found at
 
-	ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z
-
-or
-
-	https://www.tcpdump.org/papers/bpf-usenix93.ps.Z
+  https://www.tcpdump.org/papers/bpf-usenix93.ps.Z
 
 and a gzipped version can be found at
 
-	https://www.tcpdump.org/papers/bpf-usenix93.ps.gz
+  https://www.tcpdump.org/papers/bpf-usenix93.ps.gz
 
 A PDF version can be found at
 
-	https://www.tcpdump.org/papers/bpf-usenix93.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.
@@ -68,7 +72,7 @@
 utilizes).  Also, you can add BPF filter support to Ultrix using the
 kernel source and/or object patches available in:
 
-	https://www.tcpdump.org/other/bpfext42.tar.Z
+  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
@@ -87,7 +91,3 @@
 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.
-
-Current versions can be found at https://www.tcpdump.org.
-
- - The TCPdump group
diff --git a/VERSION b/VERSION
index 9ab8337..81c871d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.9.1
+1.10.0
diff --git a/Win32/Prj/wpcap.vcxproj.filters b/Win32/Prj/wpcap.vcxproj.filters
index 6e06ccb..879bb05 100644
--- a/Win32/Prj/wpcap.vcxproj.filters
+++ b/Win32/Prj/wpcap.vcxproj.filters
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project ToolsVersion="4.0" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
     <ClCompile Include="..\..\bpf_dump.c">
       <Filter>Source Files</Filter>
diff --git a/aclocal.m4 b/aclocal.m4
index aa91e84..786423b 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -271,7 +271,7 @@
 dnl set, and don't add the flag to the first argument if the compile
 dnl fails; this is for warning options cause problems that can't be
 dnl worked around.  If a third argument is supplied, a fourth argument
-dnl should also be supplied; it's a message desribing what the test
+dnl should also be supplied; it's a message describing what the test
 dnl program is checking.
 dnl
 AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT,
@@ -425,14 +425,14 @@
 		if AC_RUN_LOG([eval "$CC $ac_lbl_dependency_flag conftest.c >/dev/null 2>&1"]); then
 			AC_MSG_RESULT([yes, with $ac_lbl_dependency_flag])
 			DEPENDENCY_CFLAG="$ac_lbl_dependency_flag"
-			MKDEP='${srcdir}/mkdep'
+			MKDEP='${top_srcdir}/mkdep'
 		else
 			AC_MSG_RESULT([no])
 			#
 			# We can't run mkdep, so have "make depend" do
 			# nothing.
 			#
-			MKDEP='${srcdir}/nomkdep'
+			MKDEP='${top_srcdir}/nomkdep'
 		fi
 		rm -rf conftest*
 	else
@@ -441,7 +441,7 @@
 		# We can't run mkdep, so have "make depend" do
 		# nothing.
 		#
-		MKDEP='${srcdir}/nomkdep'
+		MKDEP='${top_srcdir}/nomkdep'
 	fi
 	AC_SUBST(DEPENDENCY_CFLAG)
 	AC_SUBST(MKDEP)
@@ -484,8 +484,8 @@
 	    aix*)
 		    ;;
 
-	    freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|midipix*)
-	    	    #
+	    freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|haiku*|midipix*)
+		    #
 		    # Platforms where the linker is the GNU linker
 		    # or accepts command-line arguments like
 		    # those the GNU linker accepts.
@@ -514,7 +514,7 @@
 
 	    hpux*)
 		    V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic"
-	    	    #
+		    #
 		    # XXX - this assumes GCC is using the HP linker,
 		    # rather than the GNU linker, and that the "+h"
 		    # option is used on all HP-UX platforms, both .sl
@@ -522,7 +522,7 @@
 		    #
 		    V_SONAME_OPT="-Wl,+h,"
 		    #
-		    # By default, directories specifed with -L
+		    # By default, directories specified with -L
 		    # are added to the run-time search path, so
 		    # we don't add them in pcap-config.
 		    #
@@ -583,14 +583,14 @@
 		    V_SHLIB_OPT="-b"
 		    V_SONAME_OPT="+h "
 		    #
-		    # By default, directories specifed with -L
+		    # By default, directories specified with -L
 		    # are added to the run-time search path, so
 		    # we don't add them in pcap-config.
 		    #
 		    ;;
 
 	    osf*)
-	    	    #
+		    #
 		    # Presumed to be DEC OSF/1, Digital UNIX, or
 		    # Tru64 UNIX.
 		    #
@@ -753,106 +753,6 @@
     ])
 
 dnl
-dnl Checks to see if unaligned memory accesses fail
-dnl
-dnl usage:
-dnl
-dnl	AC_LBL_UNALIGNED_ACCESS
-dnl
-dnl results:
-dnl
-dnl	LBL_ALIGN (DEFINED)
-dnl
-AC_DEFUN(AC_LBL_UNALIGNED_ACCESS,
-    [AC_MSG_CHECKING(if unaligned accesses fail)
-    AC_CACHE_VAL(ac_cv_lbl_unaligned_fail,
-	[case "$host_cpu" in
-
-	#
-	# These are CPU types where:
-	#
-	#	the CPU faults on an unaligned access, but at least some
-	#	OSes that support that CPU catch the fault and simulate
-	#	the unaligned access (e.g., Alpha/{Digital,Tru64} UNIX) -
-	#	the simulation is slow, so we don't want to use it;
-	#
-	#	the CPU, I infer (from the old
-	#
-	# XXX: should also check that they don't do weird things (like on arm)
-	#
-	#	comment) doesn't fault on unaligned accesses, but doesn't
-	#	do a normal unaligned fetch, either (e.g., presumably, ARM);
-	#
-	#	for whatever reason, the test program doesn't work
-	#	(this has been claimed to be the case for several of those
-	#	CPUs - I don't know what the problem is; the problem
-	#	was reported as "the test program dumps core" for SuperH,
-	#	but that's what the test program is *supposed* to do -
-	#	it dumps core before it writes anything, so the test
-	#	for an empty output file should find an empty output
-	#	file and conclude that unaligned accesses don't work).
-	#
-	# This run-time test won't work if you're cross-compiling, so
-	# in order to support cross-compiling for a particular CPU,
-	# we have to wire in the list of CPU types anyway, as far as
-	# I know, so perhaps we should just have a set of CPUs on
-	# which we know it doesn't work, a set of CPUs on which we
-	# know it does work, and have the script just fail on other
-	# cpu types and update it when such a failure occurs.
-	#
-	alpha*|arm*|bfin*|hp*|mips*|sh*|sparc*|ia64|nv1)
-		ac_cv_lbl_unaligned_fail=yes
-		;;
-
-	*)
-		cat >conftest.c <<EOF
-#		include <sys/types.h>
-#		include <sys/wait.h>
-#		include <stdio.h>
-		unsigned char a[[5]] = { 1, 2, 3, 4, 5 };
-		main() {
-		unsigned int i;
-		pid_t pid;
-		int status;
-		/* avoid "core dumped" message */
-		pid = fork();
-		if (pid <  0)
-			exit(2);
-		if (pid > 0) {
-			/* parent */
-			pid = waitpid(pid, &status, 0);
-			if (pid < 0)
-				exit(3);
-			exit(!WIFEXITED(status));
-		}
-		/* child */
-		i = *(unsigned int *)&a[[1]];
-		printf("%d\n", i);
-		exit(0);
-		}
-EOF
-		${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \
-		    conftest.c $LIBS >/dev/null 2>&1
-		if test ! -x conftest ; then
-			dnl failed to compile for some reason
-			ac_cv_lbl_unaligned_fail=yes
-		else
-			./conftest >conftest.out
-			if test ! -s conftest.out ; then
-				ac_cv_lbl_unaligned_fail=yes
-			else
-				ac_cv_lbl_unaligned_fail=no
-			fi
-		fi
-		rm -f -r conftest* core core.conftest
-		;;
-	esac])
-    AC_MSG_RESULT($ac_cv_lbl_unaligned_fail)
-    if test $ac_cv_lbl_unaligned_fail = yes ; then
-	    AC_DEFINE(LBL_ALIGN,1,[if unaligned access fails])
-    fi])
-
-dnl
 dnl If the file .devel exists:
 dnl	Add some warning flags if the compiler supports them
 dnl	If an os prototype include exists, symlink os-proto.h to it
@@ -881,12 +781,13 @@
 		    AC_LBL_CHECK_COMPILER_OPT($1, -W)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wall)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wcomma)
-		    AC_LBL_CHECK_COMPILER_OPT($1, -Wdeclaration-after-statement)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wdocumentation)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wformat-nonliteral)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-noreturn)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-prototypes)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-variable-declarations)
+		    AC_LBL_CHECK_COMPILER_OPT($1, -Wpointer-arith)
+		    AC_LBL_CHECK_COMPILER_OPT($1, -Wpointer-sign)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wshadow)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wsign-compare)
 		    AC_LBL_CHECK_COMPILER_OPT($1, -Wstrict-prototypes)
@@ -930,6 +831,7 @@
 }
 		      ],
 		      [generates warnings from ntohs()])
+		    AC_LBL_CHECK_COMPILER_OPT($1, -Wshorten-64-to-32)
 	    fi
 	    AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT()
 	    #
@@ -1056,10 +958,19 @@
 	    LIBS="-lsocket -lnsl $LIBS"
 	],
 	[
-	    #
-	    # We didn't find it.
-	    #
-	    AC_MSG_ERROR([getaddrinfo is required, but wasn't found])
+		AC_CHECK_LIB(network, getaddrinfo,
+		[
+		    #
+		    # OK, we found it in libnetwork on Haiku.
+		    #
+		    LIBS="-lnetwork $LIBS"
+		],
+		[
+		    #
+		    # We didn't find it.
+		    #
+		    AC_MSG_ERROR([getaddrinfo is required, but wasn't found])
+		])
 	], -lnsl)
 
 	#
@@ -1077,3 +988,281 @@
     # DLPI needs putmsg under HPUX so test for -lstr while we're at it
     AC_SEARCH_LIBS(putmsg, str)
 ])
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+dnl pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
+dnl serial 11 (pkg-config-0.29)
+dnl
+dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a
+dnl configuration script generated by Autoconf, you may include it under
+dnl the same distribution terms that you use for the rest of that
+dnl program.
+
+dnl PKG_PREREQ(MIN-VERSION)
+dnl -----------------------
+dnl Since: 0.29
+dnl
+dnl Verify that the version of the pkg-config macros are at least
+dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
+dnl installed version of pkg-config, this checks the developer's version
+dnl of pkg.m4 when generating configure.
+dnl
+dnl To ensure that this macro is defined, also add:
+dnl m4_ifndef([PKG_PREREQ],
+dnl     [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
+dnl
+dnl See the "Since" comment for each macro you use to see what version
+dnl of the macros you require.
+m4_defun([PKG_PREREQ],
+[m4_define([PKG_MACROS_VERSION], [0.29])
+m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
+    [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
+])dnl PKG_PREREQ
+
+dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
+dnl ----------------------------------
+dnl Since: 0.16
+dnl
+dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
+dnl first found in the path. Checks that the version of pkg-config found
+dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
+dnl used since that's the first version where most current features of
+dnl pkg-config existed.
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=m4_default([$1], [0.9.0])
+	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		AC_MSG_RESULT([yes])
+	else
+		AC_MSG_RESULT([no])
+		PKG_CONFIG=""
+	fi
+fi[]dnl
+])dnl PKG_PROG_PKG_CONFIG
+
+dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------------------------------
+dnl Since: 0.18
+dnl
+dnl Check to see whether a particular set of modules exists. Similar to
+dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
+dnl
+dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+dnl only at the first occurrence in configure.ac, so if the first place
+dnl it's called might be skipped (such as if it is within an "if", you
+dnl have to call PKG_CHECK_EXISTS manually
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+  m4_default([$2], [:])
+m4_ifvaln([$3], [else
+  $3])dnl
+fi])
+
+dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+dnl ---------------------------------------------
+dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
+dnl pkg_failed based on the result.
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+    pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+    PKG_CHECK_EXISTS([$3],
+                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes ],
+		     [pkg_failed=yes])
+ else
+    pkg_failed=untried
+fi[]dnl
+])dnl _PKG_CONFIG
+
+dnl _PKG_SHORT_ERRORS_SUPPORTED
+dnl ---------------------------
+dnl Internal check to see if pkg-config supports short errors.
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi[]dnl
+])dnl _PKG_SHORT_ERRORS_SUPPORTED
+
+
+dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl --------------------------------------------------------------
+dnl Since: 0.4.0
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
+dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+   	AC_MSG_RESULT([no])
+        _PKG_SHORT_ERRORS_SUPPORTED
+        if test $_pkg_short_errors_supported = yes; then
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+        else
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+	m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+        ])
+elif test $pkg_failed = untried; then
+     	AC_MSG_RESULT([no])
+	m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <https://pkg-config.freedesktop.org/>.])[]dnl
+        ])
+else
+	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+        AC_MSG_RESULT([yes])
+	$3
+fi[]dnl
+])dnl PKG_CHECK_MODULES
+
+
+dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl ---------------------------------------------------------------------
+dnl Since: 0.29
+dnl
+dnl Checks for existence of MODULES and gathers its build flags with
+dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
+dnl and VARIABLE-PREFIX_LIBS from --libs.
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
+dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
+dnl configure.ac.
+AC_DEFUN([PKG_CHECK_MODULES_STATIC],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+_save_PKG_CONFIG=$PKG_CONFIG
+PKG_CONFIG="$PKG_CONFIG --static"
+PKG_CHECK_MODULES($@)
+PKG_CONFIG=$_save_PKG_CONFIG[]dnl
+])dnl PKG_CHECK_MODULES_STATIC
+
+
+dnl PKG_INSTALLDIR([DIRECTORY])
+dnl -------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable pkgconfigdir as the location where a module
+dnl should install pkg-config .pc files. By default the directory is
+dnl $libdir/pkgconfig, but the default can be changed by passing
+dnl DIRECTORY. The user can override through the --with-pkgconfigdir
+dnl parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+    [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_INSTALLDIR
+
+
+dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
+dnl --------------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable noarch_pkgconfigdir as the location where a
+dnl module should install arch-independent pkg-config .pc files. By
+dnl default the directory is $datadir/pkgconfig, but the default can be
+dnl changed by passing DIRECTORY. The user can override through the
+dnl --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+    [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_NOARCH_INSTALLDIR
+
+
+dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------
+dnl Since: 0.28
+dnl
+dnl Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])dnl PKG_CHECK_VAR
+
diff --git a/atmuni31.h b/atmuni31.h
index 0f85430..7d4f270 100644
--- a/atmuni31.h
+++ b/atmuni31.h
@@ -76,7 +76,7 @@
 #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 mesage length */
+#define MSG_LEN_POS     7	/* offset of message length */
 #define IE_BEGIN_POS    9	/* offset of first information element */
 
 /* format of signalling messages */
diff --git a/bpf_filter.c b/bpf_filter.c
index 33872ff..22d2558 100644
--- a/bpf_filter.c
+++ b/bpf_filter.c
@@ -44,6 +44,11 @@
 
 #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>
@@ -55,42 +60,6 @@
 
 #include <stdlib.h>
 
-#define int32 bpf_int32
-#define u_int32 bpf_u_int32
-
-#ifndef LBL_ALIGN
-/*
- * XXX - IA-64?  If not, this probably won't work on Win64 IA-64
- * systems, unless LBL_ALIGN is defined elsewhere for them.
- * XXX - SuperH?  If not, this probably won't work on WinCE SuperH
- * systems, unless LBL_ALIGN is defined elsewhere for them.
- */
-#if defined(sparc) || defined(__sparc__) || defined(mips) || \
-    defined(ibm032) || defined(__alpha) || defined(__hpux) || \
-    defined(__arm__)
-#define LBL_ALIGN
-#endif
-#endif
-
-#ifndef LBL_ALIGN
-#ifndef _WIN32
-#include <netinet/in.h>
-#endif
-
-#define EXTRACT_SHORT(p)	((u_short)ntohs(*(u_short *)p))
-#define EXTRACT_LONG(p)		(ntohl(*(u_int32 *)p))
-#else
-#define EXTRACT_SHORT(p)\
-	((u_short)\
-		((u_short)*((u_char *)p+0)<<8|\
-		 (u_short)*((u_char *)p+1)<<0))
-#define EXTRACT_LONG(p)\
-		((u_int32)*((u_char *)p+0)<<24|\
-		 (u_int32)*((u_char *)p+1)<<16|\
-		 (u_int32)*((u_char *)p+2)<<8|\
-		 (u_int32)*((u_char *)p+3)<<0)
-#endif
-
 #ifdef __linux__
 #include <linux/types.h>
 #include <linux/if_packet.h>
@@ -115,13 +84,19 @@
  *
  * Thanks to Ani Sinha <ani@arista.com> for providing initial implementation
  */
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
 u_int
-bpf_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+pcap_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
     u_int wirelen, u_int buflen, const struct 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 bpf_aux_data *aux_data _U_)
+#endif
 {
-	register u_int32 A, X;
+	register uint32_t A, X;
 	register bpf_u_int32 k;
-	u_int32 mem[BPF_MEMWORDS];
+	uint32_t mem[BPF_MEMWORDS];
 
 	if (pc == 0)
 		/*
@@ -160,6 +135,13 @@
 			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)
@@ -183,6 +165,7 @@
 				A = p[k];
 				break;
 			}
+DIAG_ON_DEFAULT_ONLY_SWITCH
 			continue;
 
 		case BPF_LD|BPF_W|BPF_LEN:
@@ -405,13 +388,12 @@
 }
 
 u_int
-bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
+pcap_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
     u_int buflen)
 {
-	return bpf_filter_with_aux_data(pc, p, wirelen, buflen, NULL);
+	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
@@ -424,7 +406,7 @@
  * Otherwise, a bogus program could easily crash the system.
  */
 int
-bpf_validate(const struct bpf_insn *f, int len)
+pcap_validate_filter(const struct bpf_insn *f, int len)
 {
 	u_int i, from;
 	const struct bpf_insn *p;
@@ -546,3 +528,19 @@
 	}
 	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
index ab41d1e..e48c76d 100644
--- a/bpf_image.c
+++ b/bpf_image.c
@@ -28,12 +28,104 @@
 #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)
 {
@@ -46,13 +138,13 @@
 
 	default:
 		op = "unimp";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "0x%x", p->code);
+		(void)snprintf(operand_buf, sizeof operand_buf, "0x%x", p->code);
 		operand = operand_buf;
 		break;
 
 	case BPF_RET|BPF_K:
 		op = "ret";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
 		operand = operand_buf;
 		break;
 
@@ -63,19 +155,19 @@
 
 	case BPF_LD|BPF_W|BPF_ABS:
 		op = "ld";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "[%d]", p->k);
+		bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
 		operand = operand_buf;
 		break;
 
 	case BPF_LD|BPF_H|BPF_ABS:
 		op = "ldh";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "[%d]", p->k);
+		bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
 		operand = operand_buf;
 		break;
 
 	case BPF_LD|BPF_B|BPF_ABS:
 		op = "ldb";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "[%d]", p->k);
+		bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
 		operand = operand_buf;
 		break;
 
@@ -86,91 +178,91 @@
 
 	case BPF_LD|BPF_W|BPF_IND:
 		op = "ld";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_LD|BPF_IMM:
 		op = "ld";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_LDX|BPF_IMM:
 		op = "ldx";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "4*([%d]&0xf)", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "4*([%d]&0xf)", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_LD|BPF_MEM:
 		op = "ld";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_LDX|BPF_MEM:
 		op = "ldx";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_ST:
 		op = "st";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_STX:
 		op = "stx";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_JMP|BPF_JA:
 		op = "ja";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "%d", n + 1 + p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
 		operand = operand_buf;
 		break;
 
@@ -246,61 +338,61 @@
 
 	case BPF_ALU|BPF_ADD|BPF_K:
 		op = "add";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_ALU|BPF_SUB|BPF_K:
 		op = "sub";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_ALU|BPF_MUL|BPF_K:
 		op = "mul";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_ALU|BPF_DIV|BPF_K:
 		op = "div";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_ALU|BPF_MOD|BPF_K:
 		op = "mod";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_ALU|BPF_AND|BPF_K:
 		op = "and";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+		(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)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
 		operand = operand_buf;
 		break;
 
 	case BPF_ALU|BPF_RSH|BPF_K:
 		op = "rsh";
-		(void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
 		operand = operand_buf;
 		break;
 
@@ -320,11 +412,11 @@
 		break;
 	}
 	if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) {
-		(void)pcap_snprintf(image, sizeof image,
+		(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)pcap_snprintf(image, sizeof image,
+		(void)snprintf(image, sizeof image,
 			      "(%03d) %-8s %s",
 			      n, op, operand);
 	}
diff --git a/charconv.c b/charconv.c
new file mode 100644
index 0000000..4ede572
--- /dev/null
+++ b/charconv.c
@@ -0,0 +1,216 @@
+/* -*- 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.
+ */
+
+#ifdef _WIN32
+#include <stdio.h>
+
+#include <pcap/pcap.h>	/* Needed for PCAP_ERRBUF_SIZE */
+
+#include "charconv.h"
+
+wchar_t *
+cp_to_utf_16le(UINT codepage, const char *cp_string, DWORD flags)
+{
+	int utf16le_len;
+	wchar_t *utf16le_string;
+
+	/*
+	 * Map from the specified code page to UTF-16LE.
+	 * First, find out how big a buffer we'll need.
+	 */
+	utf16le_len = MultiByteToWideChar(codepage, flags, cp_string, -1,
+	    NULL, 0);
+	if (utf16le_len == 0) {
+		/*
+		 * Error.  Fail with EINVAL.
+		 */
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/*
+	 * Now attempt to allocate a buffer for that.
+	 */
+	utf16le_string = malloc(utf16le_len * sizeof (wchar_t));
+	if (utf16le_string == NULL) {
+		/*
+		 * Not enough memory; assume errno has been
+		 * set, and fail.
+		 */
+		return (NULL);
+	}
+
+	/*
+	 * Now convert.
+	 */
+	utf16le_len = MultiByteToWideChar(codepage, flags, cp_string, -1,
+	    utf16le_string, utf16le_len);
+	if (utf16le_len == 0) {
+		/*
+		 * Error.  Fail with EINVAL.
+		 * XXX - should this ever happen, given that
+		 * we already ran the string through
+		 * MultiByteToWideChar() to find out how big
+		 * a buffer we needed?
+		 */
+		free(utf16le_string);
+		errno = EINVAL;
+		return (NULL);
+	}
+	return (utf16le_string);
+}
+
+char *
+utf_16le_to_cp(UINT codepage, const wchar_t *utf16le_string)
+{
+	int cp_len;
+	char *cp_string;
+
+	/*
+	 * Map from UTF-16LE to the specified code page.
+	 * First, find out how big a buffer we'll need.
+	 * We convert composite characters to precomposed characters,
+	 * as that's what Windows expects.
+	 */
+	cp_len = WideCharToMultiByte(codepage, WC_COMPOSITECHECK,
+	    utf16le_string, -1, NULL, 0, NULL, NULL);
+	if (cp_len == 0) {
+		/*
+		 * Error.  Fail with EINVAL.
+		 */
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/*
+	 * Now attempt to allocate a buffer for that.
+	 */
+	cp_string = malloc(cp_len * sizeof (char));
+	if (cp_string == NULL) {
+		/*
+		 * Not enough memory; assume errno has been
+		 * set, and fail.
+		 */
+		return (NULL);
+	}
+
+	/*
+	 * Now convert.
+	 */
+	cp_len = WideCharToMultiByte(codepage, WC_COMPOSITECHECK,
+	    utf16le_string, -1, cp_string, cp_len, NULL, NULL);
+	if (cp_len == 0) {
+		/*
+		 * Error.  Fail with EINVAL.
+		 * XXX - should this ever happen, given that
+		 * we already ran the string through
+		 * WideCharToMultiByte() to find out how big
+		 * a buffer we needed?
+		 */
+		free(cp_string);
+		errno = EINVAL;
+		return (NULL);
+	}
+	return (cp_string);
+}
+
+/*
+ * Convert an error message string from UTF-8 to the local code page, as
+ * best we can.
+ *
+ * The buffer is assumed to be PCAP_ERRBUF_SIZE bytes long; we truncate
+ * if it doesn't fit.
+ */
+void
+utf_8_to_acp_truncated(char *errbuf)
+{
+	wchar_t *utf_16_errbuf;
+	int retval;
+	DWORD err;
+
+	/*
+	 * Do this by converting to UTF-16LE and then to the local
+	 * code page.  That means we get to use Microsoft's
+	 * conversion routines, rather than having to understand
+	 * all the code pages ourselves, *and* that this routine
+	 * can convert in place.
+	 */
+
+	/*
+	 * Map from UTF-8 to UTF-16LE.
+	 * First, find out how big a buffer we'll need.
+	 * Convert any invalid characters to REPLACEMENT CHARACTER.
+	 */
+	utf_16_errbuf = cp_to_utf_16le(CP_UTF8, errbuf, 0);
+	if (utf_16_errbuf == NULL) {
+		/*
+		 * Error.  Give up.
+		 */
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "Can't convert error string to the local code page");
+		return;
+	}
+
+	/*
+	 * Now, convert that to the local code page.
+	 * Use the current thread's code page.  For unconvertable
+	 * characters, let it pick the "best fit" character.
+	 *
+	 * XXX - we'd like some way to do what utf_16le_to_utf_8_truncated()
+	 * does if the buffer isn't big enough, but we don't want to have
+	 * to handle all local code pages ourselves; doing so requires
+	 * knowledge of all those code pages, including knowledge of how
+	 * characters are formed in thoe code pages so that we can avoid
+	 * cutting a multi-byte character into pieces.
+	 *
+	 * Converting to an un-truncated string using Windows APIs, and
+	 * then copying to the buffer, still requires knowledge of how
+	 * characters are formed in the target code page.
+	 */
+	retval = WideCharToMultiByte(CP_THREAD_ACP, 0, utf_16_errbuf, -1,
+	    errbuf, PCAP_ERRBUF_SIZE, NULL, NULL);
+	if (retval == 0) {
+		err = GetLastError();
+		free(utf_16_errbuf);
+		if (err == ERROR_INSUFFICIENT_BUFFER)
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "The error string, in the local code page, didn't fit in the buffer");
+		else
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "Can't convert error string to the local code page");
+		return;
+	}
+	free(utf_16_errbuf);
+}
+#endif
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/cmake/Modules/FindAirPcap.cmake b/cmake/Modules/FindAirPcap.cmake
new file mode 100644
index 0000000..8198f70
--- /dev/null
+++ b/cmake/Modules/FindAirPcap.cmake
@@ -0,0 +1,69 @@
+#
+# FindAirPcap
+# ==========
+#
+# Find the AirPcap library and include files.
+#
+# This module defines the following variables:
+#
+# AIRPCAP_INCLUDE_DIR     - absolute path to the directory containing airpcap.h.
+#
+# AIRPCAP_LIBRARY         - relative or absolute path to the AirPcap library to
+#                          link with. An absolute path is will be used if the
+#                          AirPcap library is not located in the compiler's
+#                          default search path.
+
+# AIRPCAP_FOUND           - TRUE if the AirPcap library *and* header are found.
+#
+# Hints and Backward Compatibility
+# ================================
+#
+# To tell this module where to look, a user may set the environment variable
+# AirPcap_ROOT to point cmake to the *root* of a directory with include and
+# lib subdirectories for airpcap.dll (e.g Airpcap_Devpack).
+# Alternatively, AirPcap_ROOT may also be set from the CMake command
+# line or GUI (e.g cmake -DAirPcap_ROOT=C:\path\to\airpcap_sdk [...])
+#
+
+# The 64-bit airpcap.lib is located under /x64
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+  #
+  # For the WinPcap and Npcap SDKs, the Lib subdirectory of the top-level
+  # directory contains 32-bit libraries; the 64-bit libraries are in the
+  # Lib/x64 directory.
+  #
+  # The only way to *FORCE* CMake to look in the Lib/x64 directory
+  # without searching in the Lib directory first appears to be to set
+  # CMAKE_LIBRARY_ARCHITECTURE to "x64".
+  #
+  # In newer versions of CMake, CMAKE_LIBRARY_ARCHITECTURE is set according to
+  # the language, e.g., CMAKE_<LANG>_LIBRARY_ARCHITECTURE. So, set the new
+  # variable, CMAKE_C_LIBRARY_ARCHITECTURE, so that CMAKE_LIBRARY_ARCHITECTURE
+  # inherits the correct value.
+  #
+  set(CMAKE_C_LIBRARY_ARCHITECTURE "x64")
+  set(CMAKE_LIBRARY_ARCHITECTURE "x64")
+endif()
+
+# Find the header
+find_path(AIRPCAP_INCLUDE_DIR airpcap.h
+  PATH_SUFFIXES include
+)
+
+# Find the library
+find_library(AIRPCAP_LIBRARY
+  NAMES airpcap
+)
+
+# Set AIRPCAP_FOUND to TRUE if AIRPCAP_INCLUDE_DIR and AIRPCAP_LIBRARY are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(AIRPCAP
+  DEFAULT_MSG
+  AIRPCAP_INCLUDE_DIR
+  AIRPCAP_LIBRARY
+)
+
+mark_as_advanced(AIRPCAP_INCLUDE_DIR AIRPCAP_LIBRARY)
+
+set(AIRPCAP_INCLUDE_DIRS ${AIRPCAP_INCLUDE_DIR})
+set(AIRPCAP_LIBRARIES ${AIRPCAP_LIBRARY})
diff --git a/cmake/Modules/FindPacket.cmake b/cmake/Modules/FindPacket.cmake
index f114875..900c8e3 100644
--- a/cmake/Modules/FindPacket.cmake
+++ b/cmake/Modules/FindPacket.cmake
@@ -33,8 +33,7 @@
 # PACKET_LIBRARY         - relative or absolute path to the Packet library to
 #                          link with. An absolute path is will be used if the
 #                          Packet library is not located in the compiler's
-#                          default search path. See e.g. PACKET_DLL_DIR
-#                          variable below.
+#                          default search path.
 
 # PACKET_FOUND           - TRUE if the Packet library *and* header are found.
 #
@@ -42,10 +41,10 @@
 # ================================
 #
 # To tell this module where to look, a user may set the environment variable
-# PACKET_DLL_DIR to point cmake to the *root* of a directory with include and
-# lib subdirectories for packet.dll (e.g WpdPack/npcap-sdk).
-# Alternatively, PACKET_DLL_DIR may also be set from cmake command line or GUI
-# (e.g cmake -DPACKET_DLL_DIR=/path/to/packet [...])
+# Packet_ROOT to point cmake to the *root* of a directory with include and
+# lib subdirectories for packet.dll (e.g WpdPack or npcap-sdk).
+# Alternatively, Packet_ROOT may also be set from cmake command line or GUI
+# (e.g cmake -DPacket_ROOT=C:\path\to\packet [...])
 #
 
 # The 64-bit Packet.lib is located under /x64
@@ -59,19 +58,23 @@
   # without searching in the Lib directory first appears to be to set
   # CMAKE_LIBRARY_ARCHITECTURE to "x64".
   #
+  # In newer versions of CMake, CMAKE_LIBRARY_ARCHITECTURE is set according to
+  # the language, e.g., CMAKE_<LANG>_LIBRARY_ARCHITECTURE. So, set the new
+  # variable, CMAKE_C_LIBRARY_ARCHITECTURE, so that CMAKE_LIBRARY_ARCHITECTURE
+  # inherits the correct value.
+  #
+  set(CMAKE_C_LIBRARY_ARCHITECTURE "x64")
   set(CMAKE_LIBRARY_ARCHITECTURE "x64")
 endif()
 
 # Find the header
 find_path(PACKET_INCLUDE_DIR Packet32.h
-  HINTS "${PACKET_DLL_DIR}" ENV PACKET_DLL_DIR
   PATH_SUFFIXES include Include
 )
 
 # Find the library
 find_library(PACKET_LIBRARY
   NAMES Packet packet
-  HINTS "${PACKET_DLL_DIR}" ENV PACKET_DLL_DIR
 )
 
 # Set PACKET_FOUND to TRUE if PACKET_INCLUDE_DIR and PACKET_LIBRARY are TRUE.
diff --git a/cmake/Modules/Finddpdk.cmake b/cmake/Modules/Finddpdk.cmake
new file mode 100644
index 0000000..50eafd9
--- /dev/null
+++ b/cmake/Modules/Finddpdk.cmake
@@ -0,0 +1,123 @@
+# Try to find dpdk
+#
+# Once done, this will define
+#
+# dpdk_FOUND
+# dpdk_INCLUDE_DIRS
+# dpdk_LIBRARIES
+
+if(PKG_CONFIG_FOUND)
+  pkg_check_modules(dpdk QUIET libdpdk)
+endif()
+message(STATUS "Executing Finddpdk")
+if(NOT dpdk_INCLUDE_DIRS)
+  message(STATUS "Executing find_path")
+  find_path(dpdk_config_INCLUDE_DIR rte_config.h
+    HINTS
+      ENV DPDK_DIR
+    PATH_SUFFIXES
+      dpdk
+      include
+)
+  find_path(dpdk_common_INCLUDE_DIR rte_common.h
+    HINTS
+      ENC DPDK_DIR
+    PATH_SUFFIXES
+      dpdk
+      include
+)
+  set(dpdk_INCLUDE_DIRS "${dpdk_config_INCLUDE_DIR}")
+  if(NOT dpdk_config_INCLUDE_DIR EQUAL dpdk_common_INCLUDE_DIR)
+    list(APPEND dpdk_INCLUDE_DIRS "${dpdk_common_INCLUDE_DIR}")
+  endif()
+
+  set(components
+    bus_pci
+    cmdline
+    eal
+    ethdev
+    hash
+    kvargs
+    mbuf
+    mempool
+    mempool_ring
+    mempool_stack
+    pci
+    pmd_af_packet
+    pmd_bond
+    pmd_i40e
+    pmd_ixgbe
+    pmd_mlx5
+    pmd_ring
+    pmd_vmxnet3_uio
+    ring)
+
+  set(dpdk_LIBRARIES)
+
+  foreach(c ${components})
+    find_library(DPDK_rte_${c}_LIBRARY rte_${c}
+      HINTS
+        ENV DPDK_DIR
+        ${dpdk_LIBRARY_DIRS}
+      PATH_SUFFIXES lib)
+    if(DPDK_rte_${c}_LIBRARY)
+      set(dpdk_lib dpdk::${c})
+      if (NOT TARGET ${dpdk_lib})
+        add_library(${dpdk_lib} UNKNOWN IMPORTED)
+        set_target_properties(${dpdk_lib} PROPERTIES
+          INTERFACE_INCLUDE_DIRECTORIES "${dpdk_INCLUDE_DIRS}"
+          IMPORTED_LOCATION "${DPDK_rte_${c}_LIBRARY}")
+        if(c STREQUAL pmd_mlx5)
+          find_package(verbs QUIET)
+          if(verbs_FOUND)
+            target_link_libraries(${dpdk_lib} INTERFACE IBVerbs::verbs)
+          endif()
+        endif()
+      endif()
+      list(APPEND dpdk_LIBRARIES ${dpdk_lib})
+    endif()
+  endforeach()
+
+  #
+  # Where the heck did this list come from?  libdpdk on Ubuntu 20.04,
+  # for example, doesn't even *have* -ldpdk; that's why we go with
+  # pkg-config, in the hopes that it provides a correct set of flags
+  # for this tangled mess.
+  #
+  list(APPEND dpdk_LIBRARIES dpdk rt m numo dl)
+endif()
+
+mark_as_advanced(dpdk_INCLUDE_DIRS ${dpdk_LIBRARIES})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(dpdk DEFAULT_MSG
+  dpdk_INCLUDE_DIRS
+  dpdk_LIBRARIES)
+
+if(dpdk_FOUND)
+  if(NOT TARGET dpdk::cflags)
+     if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64")
+      set(rte_cflags "-march=core2")
+    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM")
+      set(rte_cflags "-march=armv7-a")
+    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64")
+      set(rte_cflags "-march=armv8-a+crc")
+    endif()
+    add_library(dpdk::cflags INTERFACE IMPORTED)
+    if (rte_cflags)
+      set_target_properties(dpdk::cflags PROPERTIES
+        INTERFACE_COMPILE_OPTIONS "${rte_cflags}")
+    endif()
+  endif()
+
+  if(NOT TARGET dpdk::dpdk)
+    add_library(dpdk::dpdk INTERFACE IMPORTED)
+    find_package(Threads QUIET)
+    list(APPEND dpdk_LIBRARIES
+      Threads::Threads
+      dpdk::cflags)
+    set_target_properties(dpdk::dpdk PROPERTIES
+      INTERFACE_LINK_LIBRARIES "${dpdk_LIBRARIES}"
+      INTERFACE_INCLUDE_DIRECTORIES "${dpdk_INCLUDE_DIRS}")
+  endif()
+endif()
diff --git a/cmakeconfig.h.in b/cmakeconfig.h.in
index 1639925..192209c 100644
--- a/cmakeconfig.h.in
+++ b/cmakeconfig.h.in
@@ -15,9 +15,15 @@
 /* define if we have the AIX getprotobyname_r() */
 #cmakedefine HAVE_AIX_GETPROTOBYNAME_R 1
 
+/* define if you have the AirPcap API */
+#cmakedefine HAVE_AIRPCAP_API 1
+
 /* Define to 1 if you have the `asprintf' function. */
 #cmakedefine HAVE_ASPRINTF 1
 
+/* Define to 1 if you have the <config/HaikuConfig.h> header file. */
+#cmakedefine HAVE_CONFIG_HAIKUCONFIG_H 1
+
 /* define if you have the DAG API */
 #cmakedefine HAVE_DAG_API 1
 
@@ -69,45 +75,21 @@
 /* if libnl exists */
 #cmakedefine HAVE_LIBNL 1
 
-/* if libnl exists and is version 2.x */
-#cmakedefine HAVE_LIBNL_2_x 1
-
-/* if libnl exists and is version 3.x */
-#cmakedefine HAVE_LIBNL_3_x 1
-
-/* libnl has NLE_FAILURE */
-#cmakedefine HAVE_LIBNL_NLE 1
-
-/* libnl has new-style socket api */
-#cmakedefine HAVE_LIBNL_SOCKETS 1
-
-/* Define to 1 if you have the <limits.h> header file. */
-#cmakedefine HAVE_LIMITS_H 1
-
 /* Define to 1 if you have the <linux/compiler.h> header file. */
 #cmakedefine HAVE_LINUX_COMPILER_H 1
 
-/* Define to 1 if you have the <linux/ethtool.h> header file. */
-#cmakedefine HAVE_LINUX_ETHTOOL_H 1
-
 /* define if we have the Linux getnetbyname_r() */
 #cmakedefine HAVE_LINUX_GETNETBYNAME_R 1
 
 /* define if we have the Linux getprotobyname_r() */
 #cmakedefine HAVE_LINUX_GETPROTOBYNAME_R 1
 
-/* Define to 1 if you have the <linux/if_bonding.h> header file. */
-#cmakedefine HAVE_LINUX_IF_BONDING_H 1
-
 /* Define to 1 if you have the <linux/net_tstamp.h> header file. */
 #cmakedefine HAVE_LINUX_NET_TSTAMP_H 1
 
 /* Define to 1 if you have the <linux/socket.h> header file. */
 #cmakedefine HAVE_LINUX_SOCKET_H 1
 
-/* Define to 1 if you have the <linux/sockios.h> header file. */
-#cmakedefine HAVE_LINUX_SOCKIOS_H 1
-
 /* Define to 1 if you have the <linux/usbdevice_fs.h> header file. */
 #cmakedefine HAVE_LINUX_USBDEVICE_FS_H 1
 
@@ -141,6 +123,9 @@
 /* Define to 1 if you have the <net/raw.h> header file. */
 #cmakedefine HAVE_NET_RAW_H 1
 
+/* Use OpenSSL */
+#cmakedefine HAVE_OPENSSL 1
+
 /* if there's an os_proto.h for this platform, to use additional prototypes */
 #cmakedefine HAVE_OS_PROTO_H 1
 
@@ -186,9 +171,6 @@
 /* Define to 1 if you have the `strerror' function. */
 #cmakedefine HAVE_STRERROR 1
 
-/* Define to 1 if you have the `strerror_s' function. */
-#cmakedefine HAVE_STRERROR_S 1
-
 /* Define to 1 if you have the <strings.h> header file. */
 #cmakedefine HAVE_STRINGS_H 1
 
@@ -216,6 +198,9 @@
 /* Define to 1 if `msg_flags' is a member of `struct msghdr'. */
 #cmakedefine HAVE_STRUCT_MSGHDR_MSG_FLAGS 1
 
+/* Define to 1 if the system has the type `struct rte_ether_addr'. */
+#cmakedefine HAVE_STRUCT_RTE_ETHER_ADDR 1
+
 /* Define to 1 if `hci_channel' is a member of `struct sockaddr_hci'. */
 #cmakedefine HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL 1
 
@@ -228,9 +213,6 @@
 /* Define to 1 if `tp_vlan_tci' is a member of `struct tpacket_auxdata'. */
 #cmakedefine HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI 1
 
-/* Define to 1 if the system has the type `struct tpacket_stats'. */
-#cmakedefine HAVE_STRUCT_TPACKET_STATS 1
-
 /* Define to 1 if `bRequestType' is a member of `struct
    usbdevfs_ctrltransfer'. */
 #cmakedefine HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE 1
@@ -272,7 +254,13 @@
 #cmakedefine HAVE_VSNPRINTF 1
 
 /* Define to 1 if you have the `vsyslog' function. */
-#undef HAVE_VSYSLOG
+#cmakedefine HAVE_VSYSLOG 1
+
+/* Define to 1 if you have the `_wcserror_s' function. */
+#cmakedefine HAVE__WCSERROR_S 1
+
+/* Define to 1 if you have the `PacketGetTimestampModes' function. */
+#cmakedefine HAVE_PACKET_GET_TIMESTAMP_MODES 1
 
 /* Define to 1 if you have the `PacketIsLoopbackAdapter' function. */
 #cmakedefine HAVE_PACKET_IS_LOOPBACK_ADAPTER 1
@@ -280,9 +268,6 @@
 /* IPv6 */
 #cmakedefine INET6 1
 
-/* if unaligned access fails */
-#cmakedefine LBL_ALIGN 1
-
 /* path for device for USB sniffing */
 #cmakedefine LINUX_USB_MON_DEV "@LINUX_USB_MON_DEV@"
 
@@ -301,7 +286,7 @@
 /* Define to the address where bug reports for this package should be sent. */
 #cmakedefine PACKAGE_BUGREPORT 1
 
-/* Define to the DLL-preferred version string of of this package. */
+/* Define to the DLL-preferred version string of this package. */
 #cmakedefine PACKAGE_VERSION_DLL @PACKAGE_VERSION_DLL@
 
 /* Define to the full name of this package. */
@@ -328,24 +313,21 @@
 /* support D-Bus sniffing */
 #cmakedefine PCAP_SUPPORT_DBUS 1
 
+/* target host supports DPDK */
+#cmakedefine PCAP_SUPPORT_DPDK 1
+
+/* target host supports Linux usbmon for USB sniffing */
+#cmakedefine PCAP_SUPPORT_LINUX_USBMON 1
+
 /* target host supports netfilter sniffing */
 #cmakedefine PCAP_SUPPORT_NETFILTER 1
 
 /* target host supports netmap */
 #cmakedefine PCAP_SUPPORT_NETMAP 1
 
-/* use packet ring capture support on Linux if available */
-#cmakedefine PCAP_SUPPORT_PACKET_RING 1
-
 /* target host supports RDMA sniffing */
 #cmakedefine PCAP_SUPPORT_RDMASNIFF 1
 
-/* target host supports USB sniffing */
-#cmakedefine PCAP_SUPPORT_USB 1
-
-/* include ACN support */
-#cmakedefine SITA 1
-
 /* Define to 1 if you have the ANSI C header files. */
 #cmakedefine STDC_HEADERS 1
 
diff --git a/config.guess b/config.guess
index 2b79f6d..7f74817 100755
--- a/config.guess
+++ b/config.guess
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2018 Free Software Foundation, Inc.
+#   Copyright 1992-2020 Free Software Foundation, Inc.
 
-timestamp='2018-07-06'
+timestamp='2020-12-22'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -27,12 +27,12 @@
 # Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
 #
 # You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
 #
 # Please send patches to <config-patches@gnu.org>.
 
 
-me=`echo "$0" | sed -e 's,.*/,,'`
+me=$(echo "$0" | sed -e 's,.*/,,')
 
 usage="\
 Usage: $0 [OPTION]
@@ -50,7 +50,7 @@
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2018 Free Software Foundation, Inc.
+Copyright 1992-2020 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -84,8 +84,6 @@
   exit 1
 fi
 
-trap 'exit 1' 1 2 15
-
 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a
 # compiler to aid in system detection is discouraged as it requires
 # temporary files to be created and, as you can see below, it is a
@@ -96,66 +94,82 @@
 
 # Portable tmp directory creation inspired by the Autoconf team.
 
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp 2>/dev/null) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
- ,,)    echo "int x;" > "$dummy.c" ;
-	for c in cc gcc c89 c99 ; do
-	  if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
-	     CC_FOR_BUILD="$c"; break ;
-	  fi ;
-	done ;
-	if test x"$CC_FOR_BUILD" = x ; then
-	  CC_FOR_BUILD=no_compiler_found ;
-	fi
-	;;
- ,,*)   CC_FOR_BUILD=$CC ;;
- ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
+tmp=
+# shellcheck disable=SC2172
+trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
+
+set_cc_for_build() {
+    # prevent multiple calls if $tmp is already set
+    test "$tmp" && return 0
+    : "${TMPDIR=/tmp}"
+    # shellcheck disable=SC2039
+    { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } ||
+	{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
+	{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+	{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
+    dummy=$tmp/dummy
+    case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+	,,)    echo "int x;" > "$dummy.c"
+	       for driver in cc gcc c89 c99 ; do
+		   if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+		       CC_FOR_BUILD="$driver"
+		       break
+		   fi
+	       done
+	       if test x"$CC_FOR_BUILD" = x ; then
+		   CC_FOR_BUILD=no_compiler_found
+	       fi
+	       ;;
+	,,*)   CC_FOR_BUILD=$CC ;;
+	,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+    esac
+}
 
 # This is needed to find uname on a Pyramid OSx when run in the BSD universe.
 # (ghazi@noc.rutgers.edu 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+if test -f /.attbin/uname ; then
 	PATH=$PATH:/.attbin ; export PATH
 fi
 
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown
+UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown
+UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown
+UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown
 
 case "$UNAME_SYSTEM" in
 Linux|GNU|GNU/*)
-	# If the system lacks a compiler, then just pick glibc.
-	# We could probably try harder.
-	LIBC=gnu
+	LIBC=unknown
 
-	eval "$set_cc_for_build"
+	set_cc_for_build
 	cat <<-EOF > "$dummy.c"
 	#include <features.h>
 	#if defined(__UCLIBC__)
 	LIBC=uclibc
 	#elif defined(__dietlibc__)
 	LIBC=dietlibc
-	#else
+	#elif defined(__GLIBC__)
 	LIBC=gnu
+	#else
+	#include <stdarg.h>
+	/* First heuristic to detect musl libc.  */
+	#ifdef __DEFINED_va_list
+	LIBC=musl
+	#endif
 	#endif
 	EOF
-	eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+	eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')"
 
-	# If ldd exists, use it to detect musl libc.
-	if command -v ldd >/dev/null && \
-		ldd --version 2>&1 | grep -q ^musl
-	then
-	    LIBC=musl
+	# Second heuristic to detect musl libc.
+	if [ "$LIBC" = unknown ] &&
+	   command -v ldd >/dev/null &&
+	   ldd --version 2>&1 | grep -q ^musl; then
+		LIBC=musl
+	fi
+
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	if [ "$LIBC" = unknown ]; then
+		LIBC=gnu
 	fi
 	;;
 esac
@@ -175,19 +189,20 @@
 	# Note: NetBSD doesn't particularly care about the vendor
 	# portion of the name.  We always set it to "unknown".
 	sysctl="sysctl -n hw.machine_arch"
-	UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+	UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \
 	    "/sbin/$sysctl" 2>/dev/null || \
 	    "/usr/sbin/$sysctl" 2>/dev/null || \
-	    echo unknown)`
+	    echo unknown))
 	case "$UNAME_MACHINE_ARCH" in
+	    aarch64eb) machine=aarch64_be-unknown ;;
 	    armeb) machine=armeb-unknown ;;
 	    arm*) machine=arm-unknown ;;
 	    sh3el) machine=shl-unknown ;;
 	    sh3eb) machine=sh-unknown ;;
 	    sh5el) machine=sh5le-unknown ;;
 	    earmv*)
-		arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
-		endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+		arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,')
+		endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p')
 		machine="${arch}${endian}"-unknown
 		;;
 	    *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
@@ -199,7 +214,7 @@
 		os=netbsdelf
 		;;
 	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
-		eval "$set_cc_for_build"
+		set_cc_for_build
 		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
 			| grep -q __ELF__
 		then
@@ -218,7 +233,7 @@
 	case "$UNAME_MACHINE_ARCH" in
 	    earm*)
 		expr='s/^earmv[0-9]/-eabi/;s/eb$//'
-		abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+		abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr")
 		;;
 	esac
 	# The OS release
@@ -231,7 +246,7 @@
 		release='-gnu'
 		;;
 	    *)
-		release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
+		release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2)
 		;;
 	esac
 	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
@@ -240,15 +255,15 @@
 	echo "$machine-${os}${release}${abi-}"
 	exit ;;
     *:Bitrig:*:*)
-	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//')
 	echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
 	exit ;;
     *:OpenBSD:*:*)
-	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//')
 	echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
 	exit ;;
     *:LibertyBSD:*:*)
-	UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+	UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//')
 	echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
 	exit ;;
     *:MidnightBSD:*:*)
@@ -260,6 +275,9 @@
     *:SolidBSD:*:*)
 	echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
 	exit ;;
+    *:OS108:*:*)
+	echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE"
+	exit ;;
     macppc:MirBSD:*:*)
 	echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
 	exit ;;
@@ -269,26 +287,29 @@
     *:Sortix:*:*)
 	echo "$UNAME_MACHINE"-unknown-sortix
 	exit ;;
+    *:Twizzler:*:*)
+	echo "$UNAME_MACHINE"-unknown-twizzler
+	exit ;;
     *:Redox:*:*)
 	echo "$UNAME_MACHINE"-unknown-redox
 	exit ;;
     mips:OSF1:*.*)
-        echo mips-dec-osf1
-        exit ;;
+	echo mips-dec-osf1
+	exit ;;
     alpha:OSF1:*:*)
 	case $UNAME_RELEASE in
 	*4.0)
-		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}')
 		;;
 	*5.*)
-		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}')
 		;;
 	esac
 	# According to Compaq, /usr/sbin/psrinfo has been available on
 	# OSF/1 and Tru64 systems produced since 1995.  I hope that
 	# covers most systems running today.  This code pipes the CPU
 	# types through head -n 1, so we only detect the type of CPU 0.
-	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1)
 	case "$ALPHA_CPU_TYPE" in
 	    "EV4 (21064)")
 		UNAME_MACHINE=alpha ;;
@@ -326,7 +347,7 @@
 	# A Tn.n version is a released field test version.
 	# A Xn.n version is an unreleased experimental baselevel.
 	# 1.2 uses "1.2" for uname -r.
-	echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
+	echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)"
 	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
 	exitcode=$?
 	trap '' 0
@@ -360,7 +381,7 @@
 	exit ;;
     Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
 	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
-	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+	if test "$( (/bin/universe) 2>/dev/null)" = att ; then
 		echo pyramid-pyramid-sysv3
 	else
 		echo pyramid-pyramid-bsd
@@ -373,28 +394,28 @@
 	echo sparc-icl-nx6
 	exit ;;
     DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
-	case `/usr/bin/uname -p` in
+	case $(/usr/bin/uname -p) in
 	    sparc) echo sparc-icl-nx7; exit ;;
 	esac ;;
     s390x:SunOS:*:*)
-	echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+	echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
 	exit ;;
     sun4H:SunOS:5.*:*)
-	echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+	echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
 	exit ;;
     sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
-	echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+	echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
 	exit ;;
     i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
 	echo i386-pc-auroraux"$UNAME_RELEASE"
 	exit ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
-	eval "$set_cc_for_build"
+	set_cc_for_build
 	SUN_ARCH=i386
 	# If there is a compiler, see if it is configured for 64-bit objects.
 	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
 	# This test works for both compilers.
-	if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+	if test "$CC_FOR_BUILD" != no_compiler_found; then
 	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
 		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
 		grep IS_64BIT_ARCH >/dev/null
@@ -402,30 +423,30 @@
 		SUN_ARCH=x86_64
 	    fi
 	fi
-	echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+	echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
 	exit ;;
     sun4*:SunOS:6*:*)
 	# According to config.sub, this is the proper way to canonicalize
 	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
 	# it's likely to be more like Solaris than SunOS4.
-	echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+	echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
 	exit ;;
     sun4*:SunOS:*:*)
-	case "`/usr/bin/arch -k`" in
+	case "$(/usr/bin/arch -k)" in
 	    Series*|S4*)
-		UNAME_RELEASE=`uname -v`
+		UNAME_RELEASE=$(uname -v)
 		;;
 	esac
 	# Japanese Language versions have a version number like `4.1.3-JL'.
-	echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
+	echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')"
 	exit ;;
     sun3*:SunOS:*:*)
 	echo m68k-sun-sunos"$UNAME_RELEASE"
 	exit ;;
     sun*:*:4.2BSD:*)
-	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null)
 	test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
-	case "`/bin/arch`" in
+	case "$(/bin/arch)" in
 	    sun3)
 		echo m68k-sun-sunos"$UNAME_RELEASE"
 		;;
@@ -482,7 +503,7 @@
 	echo clipper-intergraph-clix"$UNAME_RELEASE"
 	exit ;;
     mips:*:*:UMIPS | mips:*:*:RISCos)
-	eval "$set_cc_for_build"
+	set_cc_for_build
 	sed 's/^	//' << EOF > "$dummy.c"
 #ifdef __cplusplus
 #include <stdio.h>  /* for printf() prototype */
@@ -505,8 +526,8 @@
 	}
 EOF
 	$CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
-	  dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
-	  SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
+	  dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') &&
+	  SYSTEM_NAME=$("$dummy" "$dummyarg") &&
 	    { echo "$SYSTEM_NAME"; exit; }
 	echo mips-mips-riscos"$UNAME_RELEASE"
 	exit ;;
@@ -533,11 +554,11 @@
 	exit ;;
     AViiON:dgux:*:*)
 	# DG/UX returns AViiON for all architectures
-	UNAME_PROCESSOR=`/usr/bin/uname -p`
-	if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+	UNAME_PROCESSOR=$(/usr/bin/uname -p)
+	if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
 	then
-	    if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
-	       [ "$TARGET_BINARY_INTERFACE"x = x ]
+	    if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
+	       test "$TARGET_BINARY_INTERFACE"x = x
 	    then
 		echo m88k-dg-dgux"$UNAME_RELEASE"
 	    else
@@ -561,17 +582,17 @@
 	echo m68k-tektronix-bsd
 	exit ;;
     *:IRIX*:*:*)
-	echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
+	echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')"
 	exit ;;
     ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
 	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
-	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+	exit ;;               # Note that: echo "'$(uname -s)'" gives 'AIX '
     i*86:AIX:*:*)
 	echo i386-ibm-aix
 	exit ;;
     ia64:AIX:*:*)
-	if [ -x /usr/bin/oslevel ] ; then
-		IBM_REV=`/usr/bin/oslevel`
+	if test -x /usr/bin/oslevel ; then
+		IBM_REV=$(/usr/bin/oslevel)
 	else
 		IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
 	fi
@@ -579,7 +600,7 @@
 	exit ;;
     *:AIX:2:3)
 	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
-		eval "$set_cc_for_build"
+		set_cc_for_build
 		sed 's/^		//' << EOF > "$dummy.c"
 		#include <sys/systemcfg.h>
 
@@ -591,7 +612,7 @@
 			exit(0);
 			}
 EOF
-		if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
+		if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy")
 		then
 			echo "$SYSTEM_NAME"
 		else
@@ -604,15 +625,15 @@
 	fi
 	exit ;;
     *:AIX:*:[4567])
-	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }')
 	if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
 		IBM_ARCH=rs6000
 	else
 		IBM_ARCH=powerpc
 	fi
-	if [ -x /usr/bin/lslpp ] ; then
-		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
-			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+	if test -x /usr/bin/lslpp ; then
+		IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc |
+			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/)
 	else
 		IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
 	fi
@@ -640,14 +661,14 @@
 	echo m68k-hp-bsd4.4
 	exit ;;
     9000/[34678]??:HP-UX:*:*)
-	HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+	HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
 	case "$UNAME_MACHINE" in
 	    9000/31?)            HP_ARCH=m68000 ;;
 	    9000/[34]??)         HP_ARCH=m68k ;;
 	    9000/[678][0-9][0-9])
-		if [ -x /usr/bin/getconf ]; then
-		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
-		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		if test -x /usr/bin/getconf; then
+		    sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null)
+		    sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null)
 		    case "$sc_cpu_version" in
 		      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
 		      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
@@ -659,8 +680,8 @@
 			esac ;;
 		    esac
 		fi
-		if [ "$HP_ARCH" = "" ]; then
-		    eval "$set_cc_for_build"
+		if test "$HP_ARCH" = ""; then
+		    set_cc_for_build
 		    sed 's/^		//' << EOF > "$dummy.c"
 
 		#define _HPUX_SOURCE
@@ -694,13 +715,13 @@
 		    exit (0);
 		}
 EOF
-		    (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
+		    (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy")
 		    test -z "$HP_ARCH" && HP_ARCH=hppa
 		fi ;;
 	esac
-	if [ "$HP_ARCH" = hppa2.0w ]
+	if test "$HP_ARCH" = hppa2.0w
 	then
-	    eval "$set_cc_for_build"
+	    set_cc_for_build
 
 	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
 	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
@@ -722,11 +743,11 @@
 	echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
 	exit ;;
     ia64:HP-UX:*:*)
-	HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+	HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
 	echo ia64-hp-hpux"$HPUX_REV"
 	exit ;;
     3050*:HI-UX:*:*)
-	eval "$set_cc_for_build"
+	set_cc_for_build
 	sed 's/^	//' << EOF > "$dummy.c"
 	#include <unistd.h>
 	int
@@ -752,7 +773,7 @@
 	  exit (0);
 	}
 EOF
-	$CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
+	$CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") &&
 		{ echo "$SYSTEM_NAME"; exit; }
 	echo unknown-hitachi-hiuxwe2
 	exit ;;
@@ -772,7 +793,7 @@
 	echo hppa1.0-hp-osf
 	exit ;;
     i*86:OSF1:*:*)
-	if [ -x /usr/sbin/sysversion ] ; then
+	if test -x /usr/sbin/sysversion ; then
 	    echo "$UNAME_MACHINE"-unknown-osf1mk
 	else
 	    echo "$UNAME_MACHINE"-unknown-osf1
@@ -821,14 +842,14 @@
 	echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
-	FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
-	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
-	FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+	FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)
+	FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
+	FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/')
 	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
 	exit ;;
     5000:UNIX_System_V:4.*:*)
-	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
-	FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+	FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
+	FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/')
 	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
 	exit ;;
     i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -840,15 +861,26 @@
     *:BSD/OS:*:*)
 	echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
 	exit ;;
+    arm:FreeBSD:*:*)
+	UNAME_PROCESSOR=$(uname -p)
+	set_cc_for_build
+	if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_PCS_VFP
+	then
+	    echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi
+	else
+	    echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf
+	fi
+	exit ;;
     *:FreeBSD:*:*)
-	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	UNAME_PROCESSOR=$(/usr/bin/uname -p)
 	case "$UNAME_PROCESSOR" in
 	    amd64)
 		UNAME_PROCESSOR=x86_64 ;;
 	    i386)
 		UNAME_PROCESSOR=i586 ;;
 	esac
-	echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+	echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
 	exit ;;
     i*:CYGWIN*:*)
 	echo "$UNAME_MACHINE"-pc-cygwin
@@ -881,18 +913,18 @@
 	echo "$UNAME_MACHINE"-pc-uwin
 	exit ;;
     amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
-	echo x86_64-unknown-cygwin
+	echo x86_64-pc-cygwin
 	exit ;;
     prep*:SunOS:5.*:*)
-	echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+	echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
 	exit ;;
     *:GNU:*:*)
 	# the GNU system
-	echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
+	echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')"
 	exit ;;
     *:GNU/*:*:*)
 	# other systems with GNU libc and userland
-	echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
+	echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC"
 	exit ;;
     *:Minix:*:*)
 	echo "$UNAME_MACHINE"-unknown-minix
@@ -905,7 +937,7 @@
 	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     alpha:Linux:*:*)
-	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in
 	  EV5)   UNAME_MACHINE=alphaev5 ;;
 	  EV56)  UNAME_MACHINE=alphaev56 ;;
 	  PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -922,7 +954,7 @@
 	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     arm*:Linux:*:*)
-	eval "$set_cc_for_build"
+	set_cc_for_build
 	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
 	    | grep -q __ARM_EABI__
 	then
@@ -964,6 +996,9 @@
     k1om:Linux:*:*)
 	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
+    loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
     m32r*:Linux:*:*)
 	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
@@ -971,23 +1006,51 @@
 	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     mips:Linux:*:* | mips64:Linux:*:*)
-	eval "$set_cc_for_build"
+	set_cc_for_build
+	IS_GLIBC=0
+	test x"${LIBC}" = xgnu && IS_GLIBC=1
 	sed 's/^	//' << EOF > "$dummy.c"
 	#undef CPU
-	#undef ${UNAME_MACHINE}
-	#undef ${UNAME_MACHINE}el
+	#undef mips
+	#undef mipsel
+	#undef mips64
+	#undef mips64el
+	#if ${IS_GLIBC} && defined(_ABI64)
+	LIBCABI=gnuabi64
+	#else
+	#if ${IS_GLIBC} && defined(_ABIN32)
+	LIBCABI=gnuabin32
+	#else
+	LIBCABI=${LIBC}
+	#endif
+	#endif
+
+	#if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+	CPU=mipsisa64r6
+	#else
+	#if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+	CPU=mipsisa32r6
+	#else
+	#if defined(__mips64)
+	CPU=mips64
+	#else
+	CPU=mips
+	#endif
+	#endif
+	#endif
+
 	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-	CPU=${UNAME_MACHINE}el
+	MIPS_ENDIAN=el
 	#else
 	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-	CPU=${UNAME_MACHINE}
+	MIPS_ENDIAN=
 	#else
-	CPU=
+	MIPS_ENDIAN=
 	#endif
 	#endif
 EOF
-	eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`"
-	test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; }
+	eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')"
+	test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
 	;;
     mips64el:Linux:*:*)
 	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
@@ -1006,7 +1069,7 @@
 	exit ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
 	# Look for CPU level
-	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in
 	  PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
 	  PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
 	  *)    echo hppa-unknown-linux-"$LIBC" ;;
@@ -1046,7 +1109,17 @@
 	echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
 	exit ;;
     x86_64:Linux:*:*)
-	echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+	set_cc_for_build
+	LIBCABI=$LIBC
+	if test "$CC_FOR_BUILD" != no_compiler_found; then
+	    if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
+		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_X32 >/dev/null
+	    then
+		LIBCABI="$LIBC"x32
+	    fi
+	fi
+	echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI"
 	exit ;;
     xtensa*:Linux:*:*)
 	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
@@ -1086,7 +1159,7 @@
 	echo "$UNAME_MACHINE"-pc-msdosdjgpp
 	exit ;;
     i*86:*:4.*:*)
-	UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
+	UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//')
 	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
 		echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
 	else
@@ -1095,19 +1168,19 @@
 	exit ;;
     i*86:*:5:[678]*)
 	# UnixWare 7.x, OpenUNIX and OpenServer 6.
-	case `/bin/uname -X | grep "^Machine"` in
+	case $(/bin/uname -X | grep "^Machine") in
 	    *486*)	     UNAME_MACHINE=i486 ;;
 	    *Pentium)	     UNAME_MACHINE=i586 ;;
 	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
 	esac
-	echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}"
+	echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
 	exit ;;
     i*86:*:3.2:*)
 	if test -f /usr/options/cb.name; then
-		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		UNAME_REL=$(sed -n 's/.*Version //p' </usr/options/cb.name)
 		echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
 	elif /bin/uname -X 2>/dev/null >/dev/null ; then
-		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //'))
 		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
 		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
 			&& UNAME_MACHINE=i586
@@ -1157,7 +1230,7 @@
     3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
 	OS_REL=''
 	test -r /etc/.relid \
-	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	&& OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
 	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
 	  && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
 	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1168,7 +1241,7 @@
     NCR*:*:4.2:* | MPRAS*:*:4.2:*)
 	OS_REL='.3'
 	test -r /etc/.relid \
-	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	    && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
 	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
 	    && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
 	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1201,7 +1274,7 @@
 	exit ;;
     *:SINIX-*:*:*)
 	if uname -p 2>/dev/null >/dev/null ; then
-		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		UNAME_MACHINE=$( (uname -p) 2>/dev/null)
 		echo "$UNAME_MACHINE"-sni-sysv4
 	else
 		echo ns32k-sni-sysv
@@ -1235,7 +1308,7 @@
 	echo mips-sony-newsos6
 	exit ;;
     R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
-	if [ -d /usr/nec ]; then
+	if test -d /usr/nec; then
 		echo mips-nec-sysv"$UNAME_RELEASE"
 	else
 		echo mips-unknown-sysv"$UNAME_RELEASE"
@@ -1283,44 +1356,48 @@
     *:Rhapsody:*:*)
 	echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
 	exit ;;
+    arm64:Darwin:*:*)
+	echo aarch64-apple-darwin"$UNAME_RELEASE"
+	exit ;;
     *:Darwin:*:*)
-	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
-	eval "$set_cc_for_build"
-	if test "$UNAME_PROCESSOR" = unknown ; then
-	    UNAME_PROCESSOR=powerpc
+	UNAME_PROCESSOR=$(uname -p)
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	if command -v xcode-select > /dev/null 2> /dev/null && \
+		! xcode-select --print-path > /dev/null 2> /dev/null ; then
+	    # Avoid executing cc if there is no toolchain installed as
+	    # cc will be a stub that puts up a graphical alert
+	    # prompting the user to install developer tools.
+	    CC_FOR_BUILD=no_compiler_found
+	else
+	    set_cc_for_build
 	fi
-	if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then
-	    if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
-		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-		       (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
-		       grep IS_64BIT_ARCH >/dev/null
-		then
-		    case $UNAME_PROCESSOR in
-			i386) UNAME_PROCESSOR=x86_64 ;;
-			powerpc) UNAME_PROCESSOR=powerpc64 ;;
-		    esac
-		fi
-		# On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
-		if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
-		       (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
-		       grep IS_PPC >/dev/null
-		then
-		    UNAME_PROCESSOR=powerpc
-		fi
+	if test "$CC_FOR_BUILD" != no_compiler_found; then
+	    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		   (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		   grep IS_64BIT_ARCH >/dev/null
+	    then
+		case $UNAME_PROCESSOR in
+		    i386) UNAME_PROCESSOR=x86_64 ;;
+		    powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		esac
+	    fi
+	    # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+	    if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+		   (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		   grep IS_PPC >/dev/null
+	    then
+		UNAME_PROCESSOR=powerpc
 	    fi
 	elif test "$UNAME_PROCESSOR" = i386 ; then
-	    # Avoid executing cc on OS X 10.9, as it ships with a stub
-	    # that puts up a graphical alert prompting to install
-	    # developer tools.  Any system running Mac OS X 10.7 or
-	    # later (Darwin 11 and later) is required to have a 64-bit
-	    # processor. This is not true of the ARM version of Darwin
-	    # that Apple uses in portable devices.
-	    UNAME_PROCESSOR=x86_64
+	    # uname -m returns i386 or x86_64
+	    UNAME_PROCESSOR=$UNAME_MACHINE
 	fi
 	echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
 	exit ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
-	UNAME_PROCESSOR=`uname -p`
+	UNAME_PROCESSOR=$(uname -p)
 	if test "$UNAME_PROCESSOR" = x86; then
 		UNAME_PROCESSOR=i386
 		UNAME_MACHINE=pc
@@ -1358,6 +1435,7 @@
 	# "uname -m" is not consistent, so use $cputype instead. 386
 	# is converted to i386 for consistency with other x86
 	# operating systems.
+	# shellcheck disable=SC2154
 	if test "$cputype" = 386; then
 	    UNAME_MACHINE=i386
 	else
@@ -1387,10 +1465,10 @@
 	echo mips-sei-seiux"$UNAME_RELEASE"
 	exit ;;
     *:DragonFly:*:*)
-	echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+	echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
 	exit ;;
     *:*VMS:*:*)
-	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	UNAME_MACHINE=$( (uname -p) 2>/dev/null)
 	case "$UNAME_MACHINE" in
 	    A*) echo alpha-dec-vms ; exit ;;
 	    I*) echo ia64-dec-vms ; exit ;;
@@ -1400,7 +1478,7 @@
 	echo i386-pc-xenix
 	exit ;;
     i*86:skyos:*:*)
-	echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
+	echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')"
 	exit ;;
     i*86:rdos:*:*)
 	echo "$UNAME_MACHINE"-pc-rdos
@@ -1414,8 +1492,148 @@
     amd64:Isilon\ OneFS:*:*)
 	echo x86_64-unknown-onefs
 	exit ;;
+    *:Unleashed:*:*)
+	echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
+	exit ;;
 esac
 
+# No uname command or uname output not recognized.
+set_cc_for_build
+cat > "$dummy.c" <<EOF
+#ifdef _SEQUENT_
+#include <sys/types.h>
+#include <sys/utsname.h>
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#include <signal.h>
+#if defined(_SIZE_T_) || defined(SIGLOST)
+#include <sys/utsname.h>
+#endif
+#endif
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+  "4"
+#else
+  ""
+#endif
+  ); exit (0);
+#endif
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null);
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+  struct utsname un;
+
+  uname(&un);
+  if (strncmp(un.version, "V2", 2) == 0) {
+    printf ("i386-sequent-ptx2\n"); exit (0);
+  }
+  if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+    printf ("i386-sequent-ptx1\n"); exit (0);
+  }
+  printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+#include <sys/param.h>
+#if defined (BSD)
+#if BSD == 43
+  printf ("vax-dec-bsd4.3\n"); exit (0);
+#else
+#if BSD == 199006
+  printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#else
+  printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#endif
+#else
+  printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#else
+#if defined(_SIZE_T_) || defined(SIGLOST)
+  struct utsname un;
+  uname (&un);
+  printf ("vax-dec-ultrix%s\n", un.release); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#if defined(_SIZE_T_) || defined(SIGLOST)
+  struct utsname *un;
+  uname (&un);
+  printf ("mips-dec-ultrix%s\n", un.release); exit (0);
+#else
+  printf ("mips-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
+
 echo "$0: unable to guess system type" >&2
 
 case "$UNAME_MACHINE:$UNAME_SYSTEM" in
@@ -1435,9 +1653,15 @@
 operating system you are using. If your script is old, overwrite *all*
 copies of config.guess and config.sub with the latest versions from:
 
-  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+  https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
 and
-  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+  https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
+EOF
+
+year=$(echo $timestamp | sed 's,-.*,,')
+# shellcheck disable=SC2003
+if test "$(expr "$(date +%Y)" - "$year")" -lt 3 ; then
+   cat >&2 <<EOF
 
 If $0 has already been updated, send the following data and any
 information you think might be pertinent to config-patches@gnu.org to
@@ -1445,26 +1669,27 @@
 
 config.guess timestamp = $timestamp
 
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
+uname -m = $( (uname -m) 2>/dev/null || echo unknown)
+uname -r = $( (uname -r) 2>/dev/null || echo unknown)
+uname -s = $( (uname -s) 2>/dev/null || echo unknown)
+uname -v = $( (uname -v) 2>/dev/null || echo unknown)
 
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
-/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null)
+/bin/uname -X     = $( (/bin/uname -X) 2>/dev/null)
 
-hostinfo               = `(hostinfo) 2>/dev/null`
-/bin/universe          = `(/bin/universe) 2>/dev/null`
-/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
-/bin/arch              = `(/bin/arch) 2>/dev/null`
-/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+hostinfo               = $( (hostinfo) 2>/dev/null)
+/bin/universe          = $( (/bin/universe) 2>/dev/null)
+/usr/bin/arch -k       = $( (/usr/bin/arch -k) 2>/dev/null)
+/bin/arch              = $( (/bin/arch) 2>/dev/null)
+/usr/bin/oslevel       = $( (/usr/bin/oslevel) 2>/dev/null)
+/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null)
 
 UNAME_MACHINE = "$UNAME_MACHINE"
 UNAME_RELEASE = "$UNAME_RELEASE"
 UNAME_SYSTEM  = "$UNAME_SYSTEM"
 UNAME_VERSION = "$UNAME_VERSION"
 EOF
+fi
 
 exit 1
 
diff --git a/config.h.in b/config.h.in
index 94db7bb..00618ae 100644
--- a/config.h.in
+++ b/config.h.in
@@ -18,6 +18,9 @@
 /* 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
 
@@ -78,45 +81,21 @@
 /* if libnl exists */
 #undef HAVE_LIBNL
 
-/* if libnl exists and is version 2.x */
-#undef HAVE_LIBNL_2_x
-
-/* if libnl exists and is version 3.x */
-#undef HAVE_LIBNL_3_x
-
-/* libnl has NLE_FAILURE */
-#undef HAVE_LIBNL_NLE
-
-/* libnl has new-style socket api */
-#undef HAVE_LIBNL_SOCKETS
-
-/* Define to 1 if you have the <limits.h> header file. */
-#undef HAVE_LIMITS_H
-
 /* Define to 1 if you have the <linux/compiler.h> header file. */
 #undef HAVE_LINUX_COMPILER_H
 
-/* Define to 1 if you have the <linux/ethtool.h> header file. */
-#undef HAVE_LINUX_ETHTOOL_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/if_bonding.h> header file. */
-#undef HAVE_LINUX_IF_BONDING_H
-
 /* 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/sockios.h> header file. */
-#undef HAVE_LINUX_SOCKIOS_H
-
 /* Define to 1 if you have the <linux/usbdevice_fs.h> header file. */
 #undef HAVE_LINUX_USBDEVICE_FS_H
 
@@ -135,9 +114,18 @@
 /* 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
 
@@ -150,6 +138,9 @@
 /* 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
 
@@ -165,9 +156,6 @@
 /* define if you have the Myricom SNF API */
 #undef HAVE_SNF_API
 
-/* Define to 1 if you have the `snprintf' function. */
-#undef HAVE_SNPRINTF
-
 /* Define to 1 if the system has the type `socklen_t'. */
 #undef HAVE_SOCKLEN_T
 
@@ -189,9 +177,6 @@
 /* Define to 1 if you have the `strerror' function. */
 #undef HAVE_STRERROR
 
-/* Define to 1 if you have the `strerror_s' function. */
-#undef HAVE_STRERROR_S
-
 /* Define to 1 if you have the <strings.h> header file. */
 #undef HAVE_STRINGS_H
 
@@ -219,6 +204,9 @@
 /* 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
 
@@ -231,9 +219,6 @@
 /* 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 the system has the type `struct tpacket_stats'. */
-#undef HAVE_STRUCT_TPACKET_STATS
-
 /* Define to 1 if `bRequestType' is a member of `struct
    usbdevfs_ctrltransfer'. */
 #undef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
@@ -271,18 +256,15 @@
 /* Define to 1 if you have the `vasprintf' function. */
 #undef HAVE_VASPRINTF
 
-/* Define to 1 if you have the `vsnprintf' function. */
-#undef HAVE_VSNPRINTF
-
 /* 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
+
 /* IPv6 */
 #undef INET6
 
-/* if unaligned access fails */
-#undef LBL_ALIGN
-
 /* path for device for USB sniffing */
 #undef LINUX_USB_MON_DEV
 
@@ -325,24 +307,21 @@
 /* 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
 
-/* use packet ring capture support on Linux if available */
-#undef PCAP_SUPPORT_PACKET_RING
-
 /* target host supports RDMA sniffing */
 #undef PCAP_SUPPORT_RDMASNIFF
 
-/* target host supports USB sniffing */
-#undef PCAP_SUPPORT_USB
-
-/* include ACN support */
-#undef SITA
-
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
diff --git a/config.sub b/config.sub
index c95acc6..90bb8ae 100755
--- a/config.sub
+++ b/config.sub
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2018 Free Software Foundation, Inc.
+#   Copyright 1992-2020 Free Software Foundation, Inc.
 
-timestamp='2018-07-03'
+timestamp='2020-12-22'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@
 # Otherwise, we print the canonical config type on stdout and succeed.
 
 # You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
 
 # This file is supposed to be the same for all GNU packages
 # and recognize all the CPU types, system types and aliases
@@ -50,7 +50,7 @@
 #	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
 # It is wrong to echo any other type of specification.
 
-me=`echo "$0" | sed -e 's,.*/,,'`
+me=$(echo "$0" | sed -e 's,.*/,,')
 
 usage="\
 Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
@@ -67,7 +67,7 @@
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2018 Free Software Foundation, Inc.
+Copyright 1992-2020 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -89,7 +89,7 @@
     - )	# Use stdin as input.
        break ;;
     -* )
-       echo "$me: invalid option $1$help"
+       echo "$me: invalid option $1$help" >&2
        exit 1 ;;
 
     *local*)
@@ -111,7 +111,8 @@
 esac
 
 # Split fields of configuration type
-IFS="-" read -r field1 field2 field3 field4 <<EOF
+# shellcheck disable=SC2162
+IFS="-" read field1 field2 field3 field4 <<EOF
 $1
 EOF
 
@@ -123,55 +124,64 @@
 		;;
 	*-*-*-*)
 		basic_machine=$field1-$field2
-		os=$field3-$field4
+		basic_os=$field3-$field4
 		;;
 	*-*-*)
 		# Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
 		# parts
 		maybe_os=$field2-$field3
 		case $maybe_os in
-			nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \
-			| linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \
+			nto-qnx* | linux-* | uclinux-uclibc* \
 			| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
 			| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
 			| storm-chaos* | os2-emx* | rtmk-nova*)
 				basic_machine=$field1
-				os=$maybe_os
+				basic_os=$maybe_os
 				;;
 			android-linux)
 				basic_machine=$field1-unknown
-				os=linux-android
+				basic_os=linux-android
 				;;
 			*)
 				basic_machine=$field1-$field2
-				os=$field3
+				basic_os=$field3
 				;;
 		esac
 		;;
 	*-*)
-		# Second component is usually, but not always the OS
-		case $field2 in
-			# Prevent following clause from handling this valid os
-			sun*os*)
-				basic_machine=$field1
-				os=$field2
+		# A lone config we happen to match not fitting any pattern
+		case $field1-$field2 in
+			decstation-3100)
+				basic_machine=mips-dec
+				basic_os=
 				;;
-			# Manufacturers
-			dec* | mips* | sequent* | encore* | pc532* | sgi* | sony* \
-			| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
-			| unicom* | ibm* | next | hp | isi* | apollo | altos* \
-			| convergent* | ncr* | news | 32* | 3600* | 3100* | hitachi* \
-			| c[123]* | convex* | sun | crds | omron* | dg | ultra | tti* \
-			| harris | dolphin | highlevel | gould | cbm | ns | masscomp \
-			| apple | axis | knuth | cray | microblaze* \
-			| sim | cisco | oki | wec | wrs | winbond)
-				basic_machine=$field1-$field2
-				os=
-				;;
-			*)
-				basic_machine=$field1
-				os=$field2
-				;;
+			*-*)
+				# Second component is usually, but not always the OS
+				case $field2 in
+					# Prevent following clause from handling this valid os
+					sun*os*)
+						basic_machine=$field1
+						basic_os=$field2
+						;;
+					# Manufacturers
+					dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
+					| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
+					| unicom* | ibm* | next | hp | isi* | apollo | altos* \
+					| convergent* | ncr* | news | 32* | 3600* | 3100* \
+					| hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
+					| ultra | tti* | harris | dolphin | highlevel | gould \
+					| cbm | ns | masscomp | apple | axis | knuth | cray \
+					| microblaze* | sim | cisco \
+					| oki | wec | wrs | winbond)
+						basic_machine=$field1-$field2
+						basic_os=
+						;;
+					*)
+						basic_machine=$field1
+						basic_os=$field2
+						;;
+				esac
+			;;
 		esac
 		;;
 	*)
@@ -180,1105 +190,1089 @@
 		case $field1 in
 			386bsd)
 				basic_machine=i386-pc
-				os=bsd
+				basic_os=bsd
 				;;
 			a29khif)
 				basic_machine=a29k-amd
-				os=udi
+				basic_os=udi
 				;;
 			adobe68k)
 				basic_machine=m68010-adobe
-				os=scout
+				basic_os=scout
+				;;
+			alliant)
+				basic_machine=fx80-alliant
+				basic_os=
+				;;
+			altos | altos3068)
+				basic_machine=m68k-altos
+				basic_os=
 				;;
 			am29k)
 				basic_machine=a29k-none
-				os=bsd
+				basic_os=bsd
 				;;
 			amdahl)
 				basic_machine=580-amdahl
-				os=sysv
+				basic_os=sysv
+				;;
+			amiga)
+				basic_machine=m68k-unknown
+				basic_os=
 				;;
 			amigaos | amigados)
 				basic_machine=m68k-unknown
-				os=amigaos
+				basic_os=amigaos
 				;;
 			amigaunix | amix)
 				basic_machine=m68k-unknown
-				os=sysv4
+				basic_os=sysv4
 				;;
 			apollo68)
 				basic_machine=m68k-apollo
-				os=sysv
+				basic_os=sysv
 				;;
 			apollo68bsd)
 				basic_machine=m68k-apollo
-				os=bsd
+				basic_os=bsd
 				;;
 			aros)
 				basic_machine=i386-pc
-				os=aros
+				basic_os=aros
 				;;
 			aux)
 				basic_machine=m68k-apple
-				os=aux
+				basic_os=aux
 				;;
 			balance)
 				basic_machine=ns32k-sequent
-				os=dynix
+				basic_os=dynix
 				;;
 			blackfin)
 				basic_machine=bfin-unknown
-				os=linux
+				basic_os=linux
 				;;
 			cegcc)
 				basic_machine=arm-unknown
-				os=cegcc
+				basic_os=cegcc
+				;;
+			convex-c1)
+				basic_machine=c1-convex
+				basic_os=bsd
+				;;
+			convex-c2)
+				basic_machine=c2-convex
+				basic_os=bsd
+				;;
+			convex-c32)
+				basic_machine=c32-convex
+				basic_os=bsd
+				;;
+			convex-c34)
+				basic_machine=c34-convex
+				basic_os=bsd
+				;;
+			convex-c38)
+				basic_machine=c38-convex
+				basic_os=bsd
 				;;
 			cray)
 				basic_machine=j90-cray
-				os=unicos
+				basic_os=unicos
 				;;
-			craynv)
-				basic_machine=craynv-cray
-				os=unicosmp
+			crds | unos)
+				basic_machine=m68k-crds
+				basic_os=
+				;;
+			da30)
+				basic_machine=m68k-da30
+				basic_os=
+				;;
+			decstation | pmax | pmin | dec3100 | decstatn)
+				basic_machine=mips-dec
+				basic_os=
 				;;
 			delta88)
 				basic_machine=m88k-motorola
-				os=sysv3
+				basic_os=sysv3
 				;;
 			dicos)
 				basic_machine=i686-pc
-				os=dicos
+				basic_os=dicos
 				;;
 			djgpp)
 				basic_machine=i586-pc
-				os=msdosdjgpp
+				basic_os=msdosdjgpp
 				;;
 			ebmon29k)
 				basic_machine=a29k-amd
-				os=ebmon
+				basic_os=ebmon
 				;;
 			es1800 | OSE68k | ose68k | ose | OSE)
 				basic_machine=m68k-ericsson
-				os=ose
+				basic_os=ose
 				;;
 			gmicro)
 				basic_machine=tron-gmicro
-				os=sysv
+				basic_os=sysv
 				;;
 			go32)
 				basic_machine=i386-pc
-				os=go32
+				basic_os=go32
 				;;
 			h8300hms)
 				basic_machine=h8300-hitachi
-				os=hms
+				basic_os=hms
 				;;
 			h8300xray)
 				basic_machine=h8300-hitachi
-				os=xray
+				basic_os=xray
 				;;
 			h8500hms)
 				basic_machine=h8500-hitachi
-				os=hms
+				basic_os=hms
 				;;
 			harris)
 				basic_machine=m88k-harris
-				os=sysv3
+				basic_os=sysv3
+				;;
+			hp300 | hp300hpux)
+				basic_machine=m68k-hp
+				basic_os=hpux
 				;;
 			hp300bsd)
 				basic_machine=m68k-hp
-				os=bsd
-				;;
-			hp300hpux)
-				basic_machine=m68k-hp
-				os=hpux
+				basic_os=bsd
 				;;
 			hppaosf)
 				basic_machine=hppa1.1-hp
-				os=osf
+				basic_os=osf
 				;;
 			hppro)
 				basic_machine=hppa1.1-hp
-				os=proelf
+				basic_os=proelf
 				;;
 			i386mach)
 				basic_machine=i386-mach
-				os=mach
-				;;
-			vsta)
-				basic_machine=i386-unknown
-				os=vsta
+				basic_os=mach
 				;;
 			isi68 | isi)
 				basic_machine=m68k-isi
-				os=sysv
+				basic_os=sysv
 				;;
 			m68knommu)
 				basic_machine=m68k-unknown
-				os=linux
+				basic_os=linux
 				;;
 			magnum | m3230)
 				basic_machine=mips-mips
-				os=sysv
+				basic_os=sysv
 				;;
 			merlin)
 				basic_machine=ns32k-utek
-				os=sysv
+				basic_os=sysv
 				;;
 			mingw64)
 				basic_machine=x86_64-pc
-				os=mingw64
+				basic_os=mingw64
 				;;
 			mingw32)
 				basic_machine=i686-pc
-				os=mingw32
+				basic_os=mingw32
 				;;
 			mingw32ce)
 				basic_machine=arm-unknown
-				os=mingw32ce
+				basic_os=mingw32ce
 				;;
 			monitor)
 				basic_machine=m68k-rom68k
-				os=coff
+				basic_os=coff
 				;;
 			morphos)
 				basic_machine=powerpc-unknown
-				os=morphos
+				basic_os=morphos
 				;;
 			moxiebox)
 				basic_machine=moxie-unknown
-				os=moxiebox
+				basic_os=moxiebox
 				;;
 			msdos)
 				basic_machine=i386-pc
-				os=msdos
+				basic_os=msdos
 				;;
 			msys)
 				basic_machine=i686-pc
-				os=msys
+				basic_os=msys
 				;;
 			mvs)
 				basic_machine=i370-ibm
-				os=mvs
+				basic_os=mvs
 				;;
 			nacl)
 				basic_machine=le32-unknown
-				os=nacl
+				basic_os=nacl
 				;;
 			ncr3000)
 				basic_machine=i486-ncr
-				os=sysv4
+				basic_os=sysv4
 				;;
 			netbsd386)
-				basic_machine=i386-unknown
-				os=netbsd
+				basic_machine=i386-pc
+				basic_os=netbsd
 				;;
 			netwinder)
 				basic_machine=armv4l-rebel
-				os=linux
+				basic_os=linux
 				;;
 			news | news700 | news800 | news900)
 				basic_machine=m68k-sony
-				os=newsos
+				basic_os=newsos
 				;;
 			news1000)
 				basic_machine=m68030-sony
-				os=newsos
+				basic_os=newsos
 				;;
 			necv70)
 				basic_machine=v70-nec
-				os=sysv
+				basic_os=sysv
 				;;
 			nh3000)
 				basic_machine=m68k-harris
-				os=cxux
+				basic_os=cxux
 				;;
 			nh[45]000)
 				basic_machine=m88k-harris
-				os=cxux
+				basic_os=cxux
 				;;
 			nindy960)
 				basic_machine=i960-intel
-				os=nindy
+				basic_os=nindy
 				;;
 			mon960)
 				basic_machine=i960-intel
-				os=mon960
+				basic_os=mon960
 				;;
 			nonstopux)
 				basic_machine=mips-compaq
-				os=nonstopux
+				basic_os=nonstopux
 				;;
 			os400)
 				basic_machine=powerpc-ibm
-				os=os400
+				basic_os=os400
 				;;
 			OSE68000 | ose68000)
 				basic_machine=m68000-ericsson
-				os=ose
+				basic_os=ose
 				;;
 			os68k)
 				basic_machine=m68k-none
-				os=os68k
+				basic_os=os68k
 				;;
 			paragon)
 				basic_machine=i860-intel
-				os=osf
+				basic_os=osf
 				;;
 			parisc)
 				basic_machine=hppa-unknown
-				os=linux
+				basic_os=linux
+				;;
+			psp)
+				basic_machine=mipsallegrexel-sony
+				basic_os=psp
 				;;
 			pw32)
 				basic_machine=i586-unknown
-				os=pw32
+				basic_os=pw32
 				;;
 			rdos | rdos64)
 				basic_machine=x86_64-pc
-				os=rdos
+				basic_os=rdos
 				;;
 			rdos32)
 				basic_machine=i386-pc
-				os=rdos
+				basic_os=rdos
 				;;
 			rom68k)
 				basic_machine=m68k-rom68k
-				os=coff
+				basic_os=coff
 				;;
 			sa29200)
 				basic_machine=a29k-amd
-				os=udi
+				basic_os=udi
 				;;
 			sei)
 				basic_machine=mips-sei
-				os=seiux
+				basic_os=seiux
+				;;
+			sequent)
+				basic_machine=i386-sequent
+				basic_os=
 				;;
 			sps7)
 				basic_machine=m68k-bull
-				os=sysv2
+				basic_os=sysv2
+				;;
+			st2000)
+				basic_machine=m68k-tandem
+				basic_os=
 				;;
 			stratus)
 				basic_machine=i860-stratus
-				os=sysv4
+				basic_os=sysv4
+				;;
+			sun2)
+				basic_machine=m68000-sun
+				basic_os=
 				;;
 			sun2os3)
 				basic_machine=m68000-sun
-				os=sunos3
+				basic_os=sunos3
 				;;
 			sun2os4)
 				basic_machine=m68000-sun
-				os=sunos4
+				basic_os=sunos4
+				;;
+			sun3)
+				basic_machine=m68k-sun
+				basic_os=
 				;;
 			sun3os3)
 				basic_machine=m68k-sun
-				os=sunos3
+				basic_os=sunos3
 				;;
 			sun3os4)
 				basic_machine=m68k-sun
-				os=sunos4
+				basic_os=sunos4
+				;;
+			sun4)
+				basic_machine=sparc-sun
+				basic_os=
 				;;
 			sun4os3)
 				basic_machine=sparc-sun
-				os=sunos3
+				basic_os=sunos3
 				;;
 			sun4os4)
 				basic_machine=sparc-sun
-				os=sunos4
+				basic_os=sunos4
 				;;
 			sun4sol2)
 				basic_machine=sparc-sun
-				os=solaris2
+				basic_os=solaris2
+				;;
+			sun386 | sun386i | roadrunner)
+				basic_machine=i386-sun
+				basic_os=
 				;;
 			sv1)
 				basic_machine=sv1-cray
-				os=unicos
+				basic_os=unicos
 				;;
 			symmetry)
 				basic_machine=i386-sequent
-				os=dynix
+				basic_os=dynix
 				;;
 			t3e)
 				basic_machine=alphaev5-cray
-				os=unicos
+				basic_os=unicos
 				;;
 			t90)
 				basic_machine=t90-cray
-				os=unicos
+				basic_os=unicos
 				;;
 			toad1)
 				basic_machine=pdp10-xkl
-				os=tops20
+				basic_os=tops20
 				;;
 			tpf)
 				basic_machine=s390x-ibm
-				os=tpf
+				basic_os=tpf
 				;;
 			udi29k)
 				basic_machine=a29k-amd
-				os=udi
+				basic_os=udi
 				;;
 			ultra3)
 				basic_machine=a29k-nyu
-				os=sym1
+				basic_os=sym1
 				;;
 			v810 | necv810)
 				basic_machine=v810-nec
-				os=none
+				basic_os=none
 				;;
 			vaxv)
 				basic_machine=vax-dec
-				os=sysv
+				basic_os=sysv
 				;;
 			vms)
 				basic_machine=vax-dec
-				os=vms
+				basic_os=vms
+				;;
+			vsta)
+				basic_machine=i386-pc
+				basic_os=vsta
 				;;
 			vxworks960)
 				basic_machine=i960-wrs
-				os=vxworks
+				basic_os=vxworks
 				;;
 			vxworks68)
 				basic_machine=m68k-wrs
-				os=vxworks
+				basic_os=vxworks
 				;;
 			vxworks29k)
 				basic_machine=a29k-wrs
-				os=vxworks
+				basic_os=vxworks
 				;;
 			xbox)
 				basic_machine=i686-pc
-				os=mingw32
+				basic_os=mingw32
 				;;
 			ymp)
 				basic_machine=ymp-cray
-				os=unicos
+				basic_os=unicos
 				;;
 			*)
 				basic_machine=$1
-				os=
+				basic_os=
 				;;
 		esac
 		;;
 esac
 
-# Decode aliases for certain CPU-COMPANY combinations.
+# Decode 1-component or ad-hoc basic machines
 case $basic_machine in
-	# Recognize the basic CPU types without company name.
-	# Some are omitted here because they have special meanings below.
-	1750a | 580 \
-	| a29k \
-	| aarch64 | aarch64_be \
-	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
-	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
-	| am33_2.0 \
-	| arc | arceb \
-	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv6m | armv[78][arm] \
-	| avr | avr32 \
-	| ba \
-	| be32 | be64 \
-	| bfin \
-	| c4x | c8051 | clipper | csky \
-	| d10v | d30v | dlx | dsp16xx \
-	| e2k | epiphany \
-	| fido | fr30 | frv | ft32 \
-	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
-	| hexagon \
-	| i370 | i860 | i960 | ia16 | ia64 \
-	| ip2k | iq2000 \
-	| k1om \
-	| le32 | le64 \
-	| lm32 \
-	| m32c | m32r | m32rle | m68000 | m68k | m88k \
-	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
-	| mips | mipsbe | mipseb | mipsel | mipsle \
-	| mips16 \
-	| mips64 | mips64el \
-	| mips64octeon | mips64octeonel \
-	| mips64orion | mips64orionel \
-	| mips64r5900 | mips64r5900el \
-	| mips64vr | mips64vrel \
-	| mips64vr4100 | mips64vr4100el \
-	| mips64vr4300 | mips64vr4300el \
-	| mips64vr5000 | mips64vr5000el \
-	| mips64vr5900 | mips64vr5900el \
-	| mipsisa32 | mipsisa32el \
-	| mipsisa32r2 | mipsisa32r2el \
-	| mipsisa32r6 | mipsisa32r6el \
-	| mipsisa64 | mipsisa64el \
-	| mipsisa64r2 | mipsisa64r2el \
-	| mipsisa64r6 | mipsisa64r6el \
-	| mipsisa64sb1 | mipsisa64sb1el \
-	| mipsisa64sr71k | mipsisa64sr71kel \
-	| mipsr5900 | mipsr5900el \
-	| mipstx39 | mipstx39el \
-	| mn10200 | mn10300 \
-	| moxie \
-	| mt \
-	| msp430 \
-	| nds32 | nds32le | nds32be \
-	| nfp \
-	| nios | nios2 | nios2eb | nios2el \
-	| ns16k | ns32k \
-	| open8 | or1k | or1knd | or32 \
-	| pdp10 | pj | pjl \
-	| powerpc | powerpc64 | powerpc64le | powerpcle \
-	| pru \
-	| pyramid \
-	| riscv | riscv32 | riscv64 \
-	| rl78 | rx \
-	| score \
-	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
-	| sh64 | sh64le \
-	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
-	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
-	| spu \
-	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
-	| ubicom32 \
-	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
-	| visium \
-	| wasm32 \
-	| x86 | xc16x | xstormy16 | xtensa \
-	| z8k | z80)
-		basic_machine=$basic_machine-unknown
+	# Here we handle the default manufacturer of certain CPU types.  It is in
+	# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		cpu=hppa1.1
+		vendor=winbond
 		;;
-	c54x)
-		basic_machine=tic54x-unknown
+	op50n)
+		cpu=hppa1.1
+		vendor=oki
 		;;
-	c55x)
-		basic_machine=tic55x-unknown
+	op60c)
+		cpu=hppa1.1
+		vendor=oki
 		;;
-	c6x)
-		basic_machine=tic6x-unknown
+	ibm*)
+		cpu=i370
+		vendor=ibm
 		;;
-	leon|leon[3-9])
-		basic_machine=sparc-$basic_machine
+	orion105)
+		cpu=clipper
+		vendor=highlevel
 		;;
-	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
-		basic_machine=$basic_machine-unknown
-		os=${os:-none}
+	mac | mpw | mac-mpw)
+		cpu=m68k
+		vendor=apple
 		;;
-	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65)
-		;;
-	m9s12z | m68hcs12z | hcs12z | s12z)
-		basic_machine=s12z-unknown
-		os=${os:-none}
-		;;
-	ms1)
-		basic_machine=mt-unknown
-		;;
-	strongarm | thumb | xscale)
-		basic_machine=arm-unknown
-		;;
-	xgate)
-		basic_machine=$basic_machine-unknown
-		os=${os:-none}
-		;;
-	xscaleeb)
-		basic_machine=armeb-unknown
+	pmac | pmac-mpw)
+		cpu=powerpc
+		vendor=apple
 		;;
 
-	xscaleel)
-		basic_machine=armel-unknown
-		;;
-
-	# We use `pc' rather than `unknown'
-	# because (1) that's what they normally are, and
-	# (2) the word "unknown" tends to confuse beginning users.
-	i*86 | x86_64)
-	  basic_machine=$basic_machine-pc
-	  ;;
-	# Recognize the basic CPU types with company name.
-	580-* \
-	| a29k-* \
-	| aarch64-* | aarch64_be-* \
-	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
-	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
-	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
-	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
-	| avr-* | avr32-* \
-	| ba-* \
-	| be32-* | be64-* \
-	| bfin-* | bs2000-* \
-	| c[123]* | c30-* | [cjt]90-* | c4x-* \
-	| c8051-* | clipper-* | craynv-* | csky-* | cydra-* \
-	| d10v-* | d30v-* | dlx-* \
-	| e2k-* | elxsi-* \
-	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
-	| h8300-* | h8500-* \
-	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
-	| hexagon-* \
-	| i*86-* | i860-* | i960-* | ia16-* | ia64-* \
-	| ip2k-* | iq2000-* \
-	| k1om-* \
-	| le32-* | le64-* \
-	| lm32-* \
-	| m32c-* | m32r-* | m32rle-* \
-	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
-	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
-	| microblaze-* | microblazeel-* \
-	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
-	| mips16-* \
-	| mips64-* | mips64el-* \
-	| mips64octeon-* | mips64octeonel-* \
-	| mips64orion-* | mips64orionel-* \
-	| mips64r5900-* | mips64r5900el-* \
-	| mips64vr-* | mips64vrel-* \
-	| mips64vr4100-* | mips64vr4100el-* \
-	| mips64vr4300-* | mips64vr4300el-* \
-	| mips64vr5000-* | mips64vr5000el-* \
-	| mips64vr5900-* | mips64vr5900el-* \
-	| mipsisa32-* | mipsisa32el-* \
-	| mipsisa32r2-* | mipsisa32r2el-* \
-	| mipsisa32r6-* | mipsisa32r6el-* \
-	| mipsisa64-* | mipsisa64el-* \
-	| mipsisa64r2-* | mipsisa64r2el-* \
-	| mipsisa64r6-* | mipsisa64r6el-* \
-	| mipsisa64sb1-* | mipsisa64sb1el-* \
-	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
-	| mipsr5900-* | mipsr5900el-* \
-	| mipstx39-* | mipstx39el-* \
-	| mmix-* \
-	| mt-* \
-	| msp430-* \
-	| nds32-* | nds32le-* | nds32be-* \
-	| nfp-* \
-	| nios-* | nios2-* | nios2eb-* | nios2el-* \
-	| none-* | np1-* | ns16k-* | ns32k-* \
-	| open8-* \
-	| or1k*-* \
-	| orion-* \
-	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
-	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
-	| pru-* \
-	| pyramid-* \
-	| riscv-* | riscv32-* | riscv64-* \
-	| rl78-* | romp-* | rs6000-* | rx-* \
-	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
-	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
-	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
-	| sparclite-* \
-	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
-	| tahoe-* \
-	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
-	| tile*-* \
-	| tron-* \
-	| ubicom32-* \
-	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
-	| vax-* \
-	| visium-* \
-	| wasm32-* \
-	| we32k-* \
-	| x86-* | x86_64-* | xc16x-* | xps100-* \
-	| xstormy16-* | xtensa*-* \
-	| ymp-* \
-	| z8k-* | z80-*)
-		;;
-	# Recognize the basic CPU types without company name, with glob match.
-	xtensa*)
-		basic_machine=$basic_machine-unknown
-		;;
 	# Recognize the various machine names and aliases which stand
 	# for a CPU type and a company and sometimes even an OS.
 	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
-		basic_machine=m68000-att
+		cpu=m68000
+		vendor=att
 		;;
 	3b*)
-		basic_machine=we32k-att
-		;;
-	abacus)
-		basic_machine=abacus-unknown
-		;;
-	alliant | fx80)
-		basic_machine=fx80-alliant
-		;;
-	altos | altos3068)
-		basic_machine=m68k-altos
-		;;
-	amd64)
-		basic_machine=x86_64-pc
-		;;
-	amd64-*)
-		basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	amiga | amiga-*)
-		basic_machine=m68k-unknown
-		;;
-	asmjs)
-		basic_machine=asmjs-unknown
-		;;
-	blackfin-*)
-		basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		os=linux
+		cpu=we32k
+		vendor=att
 		;;
 	bluegene*)
-		basic_machine=powerpc-ibm
-		os=cnk
-		;;
-	c54x-*)
-		basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	c55x-*)
-		basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	c6x-*)
-		basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	c90)
-		basic_machine=c90-cray
-		os=${os:-unicos}
-		;;
-	convex-c1)
-		basic_machine=c1-convex
-		os=bsd
-		;;
-	convex-c2)
-		basic_machine=c2-convex
-		os=bsd
-		;;
-	convex-c32)
-		basic_machine=c32-convex
-		os=bsd
-		;;
-	convex-c34)
-		basic_machine=c34-convex
-		os=bsd
-		;;
-	convex-c38)
-		basic_machine=c38-convex
-		os=bsd
-		;;
-	cr16 | cr16-*)
-		basic_machine=cr16-unknown
-		os=${os:-elf}
-		;;
-	crds | unos)
-		basic_machine=m68k-crds
-		;;
-	crisv32 | crisv32-* | etraxfs*)
-		basic_machine=crisv32-axis
-		;;
-	cris | cris-* | etrax*)
-		basic_machine=cris-axis
-		;;
-	crx)
-		basic_machine=crx-unknown
-		os=${os:-elf}
-		;;
-	da30 | da30-*)
-		basic_machine=m68k-da30
-		;;
-	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
-		basic_machine=mips-dec
+		cpu=powerpc
+		vendor=ibm
+		basic_os=cnk
 		;;
 	decsystem10* | dec10*)
-		basic_machine=pdp10-dec
-		os=tops10
+		cpu=pdp10
+		vendor=dec
+		basic_os=tops10
 		;;
 	decsystem20* | dec20*)
-		basic_machine=pdp10-dec
-		os=tops20
+		cpu=pdp10
+		vendor=dec
+		basic_os=tops20
 		;;
 	delta | 3300 | motorola-3300 | motorola-delta \
 	      | 3300-motorola | delta-motorola)
-		basic_machine=m68k-motorola
-		;;
-	dpx20 | dpx20-*)
-		basic_machine=rs6000-bull
-		os=${os:-bosx}
+		cpu=m68k
+		vendor=motorola
 		;;
 	dpx2*)
-		basic_machine=m68k-bull
-		os=sysv3
-		;;
-	e500v[12])
-		basic_machine=powerpc-unknown
-		os=$os"spe"
-		;;
-	e500v[12]-*)
-		basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		os=$os"spe"
+		cpu=m68k
+		vendor=bull
+		basic_os=sysv3
 		;;
 	encore | umax | mmax)
-		basic_machine=ns32k-encore
+		cpu=ns32k
+		vendor=encore
 		;;
 	elxsi)
-		basic_machine=elxsi-elxsi
-		os=${os:-bsd}
+		cpu=elxsi
+		vendor=elxsi
+		basic_os=${basic_os:-bsd}
 		;;
 	fx2800)
-		basic_machine=i860-alliant
+		cpu=i860
+		vendor=alliant
 		;;
 	genix)
-		basic_machine=ns32k-ns
+		cpu=ns32k
+		vendor=ns
 		;;
 	h3050r* | hiux*)
-		basic_machine=hppa1.1-hitachi
-		os=hiuxwe2
-		;;
-	hp300-*)
-		basic_machine=m68k-hp
+		cpu=hppa1.1
+		vendor=hitachi
+		basic_os=hiuxwe2
 		;;
 	hp3k9[0-9][0-9] | hp9[0-9][0-9])
-		basic_machine=hppa1.0-hp
+		cpu=hppa1.0
+		vendor=hp
 		;;
 	hp9k2[0-9][0-9] | hp9k31[0-9])
-		basic_machine=m68000-hp
+		cpu=m68000
+		vendor=hp
 		;;
 	hp9k3[2-9][0-9])
-		basic_machine=m68k-hp
+		cpu=m68k
+		vendor=hp
 		;;
 	hp9k6[0-9][0-9] | hp6[0-9][0-9])
-		basic_machine=hppa1.0-hp
+		cpu=hppa1.0
+		vendor=hp
 		;;
 	hp9k7[0-79][0-9] | hp7[0-79][0-9])
-		basic_machine=hppa1.1-hp
+		cpu=hppa1.1
+		vendor=hp
 		;;
 	hp9k78[0-9] | hp78[0-9])
 		# FIXME: really hppa2.0-hp
-		basic_machine=hppa1.1-hp
+		cpu=hppa1.1
+		vendor=hp
 		;;
 	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
 		# FIXME: really hppa2.0-hp
-		basic_machine=hppa1.1-hp
+		cpu=hppa1.1
+		vendor=hp
 		;;
 	hp9k8[0-9][13679] | hp8[0-9][13679])
-		basic_machine=hppa1.1-hp
+		cpu=hppa1.1
+		vendor=hp
 		;;
 	hp9k8[0-9][0-9] | hp8[0-9][0-9])
-		basic_machine=hppa1.0-hp
-		;;
-	i370-ibm* | ibm*)
-		basic_machine=i370-ibm
+		cpu=hppa1.0
+		vendor=hp
 		;;
 	i*86v32)
-		basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
-		os=sysv32
+		cpu=$(echo "$1" | sed -e 's/86.*/86/')
+		vendor=pc
+		basic_os=sysv32
 		;;
 	i*86v4*)
-		basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
-		os=sysv4
+		cpu=$(echo "$1" | sed -e 's/86.*/86/')
+		vendor=pc
+		basic_os=sysv4
 		;;
 	i*86v)
-		basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
-		os=sysv
+		cpu=$(echo "$1" | sed -e 's/86.*/86/')
+		vendor=pc
+		basic_os=sysv
 		;;
 	i*86sol2)
-		basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
-		os=solaris2
+		cpu=$(echo "$1" | sed -e 's/86.*/86/')
+		vendor=pc
+		basic_os=solaris2
 		;;
 	j90 | j90-cray)
-		basic_machine=j90-cray
-		os=${os:-unicos}
+		cpu=j90
+		vendor=cray
+		basic_os=${basic_os:-unicos}
 		;;
 	iris | iris4d)
-		basic_machine=mips-sgi
-		case $os in
+		cpu=mips
+		vendor=sgi
+		case $basic_os in
 		    irix*)
 			;;
 		    *)
-			os=irix4
+			basic_os=irix4
 			;;
 		esac
 		;;
-	leon-*|leon[3-9]-*)
-		basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'`
-		;;
-	m68knommu-*)
-		basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		os=linux
-		;;
-	microblaze*)
-		basic_machine=microblaze-xilinx
-		;;
 	miniframe)
-		basic_machine=m68000-convergent
+		cpu=m68000
+		vendor=convergent
 		;;
 	*mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
-		basic_machine=m68k-atari
-		os=mint
-		;;
-	mips3*-*)
-		basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`
-		;;
-	mips3*)
-		basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown
-		;;
-	ms1-*)
-		basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'`
+		cpu=m68k
+		vendor=atari
+		basic_os=mint
 		;;
 	news-3600 | risc-news)
-		basic_machine=mips-sony
-		os=newsos
+		cpu=mips
+		vendor=sony
+		basic_os=newsos
 		;;
 	next | m*-next)
-		basic_machine=m68k-next
-		case $os in
-		    nextstep* )
+		cpu=m68k
+		vendor=next
+		case $basic_os in
+		    openstep*)
+		        ;;
+		    nextstep*)
 			;;
 		    ns2*)
-		      os=nextstep2
+		      basic_os=nextstep2
 			;;
 		    *)
-		      os=nextstep3
+		      basic_os=nextstep3
 			;;
 		esac
 		;;
 	np1)
-		basic_machine=np1-gould
-		;;
-	neo-tandem)
-		basic_machine=neo-tandem
-		;;
-	nse-tandem)
-		basic_machine=nse-tandem
-		;;
-	nsr-tandem)
-		basic_machine=nsr-tandem
-		;;
-	nsv-tandem)
-		basic_machine=nsv-tandem
-		;;
-	nsx-tandem)
-		basic_machine=nsx-tandem
+		cpu=np1
+		vendor=gould
 		;;
 	op50n-* | op60c-*)
-		basic_machine=hppa1.1-oki
-		os=proelf
-		;;
-	openrisc | openrisc-*)
-		basic_machine=or32-unknown
+		cpu=hppa1.1
+		vendor=oki
+		basic_os=proelf
 		;;
 	pa-hitachi)
-		basic_machine=hppa1.1-hitachi
-		os=hiuxwe2
-		;;
-	parisc-*)
-		basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		os=linux
+		cpu=hppa1.1
+		vendor=hitachi
+		basic_os=hiuxwe2
 		;;
 	pbd)
-		basic_machine=sparc-tti
+		cpu=sparc
+		vendor=tti
 		;;
 	pbb)
-		basic_machine=m68k-tti
+		cpu=m68k
+		vendor=tti
 		;;
-	pc532 | pc532-*)
-		basic_machine=ns32k-pc532
-		;;
-	pc98)
-		basic_machine=i386-pc
-		;;
-	pc98-*)
-		basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	pentium | p5 | k5 | k6 | nexgen | viac3)
-		basic_machine=i586-pc
-		;;
-	pentiumpro | p6 | 6x86 | athlon | athlon_*)
-		basic_machine=i686-pc
-		;;
-	pentiumii | pentium2 | pentiumiii | pentium3)
-		basic_machine=i686-pc
-		;;
-	pentium4)
-		basic_machine=i786-pc
-		;;
-	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
-		basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	pentiumpro-* | p6-* | 6x86-* | athlon-*)
-		basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
-		basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	pentium4-*)
-		basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+	pc532)
+		cpu=ns32k
+		vendor=pc532
 		;;
 	pn)
-		basic_machine=pn-gould
+		cpu=pn
+		vendor=gould
 		;;
-	power)	basic_machine=power-ibm
-		;;
-	ppc | ppcbe)	basic_machine=powerpc-unknown
-		;;
-	ppc-* | ppcbe-*)
-		basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	ppcle | powerpclittle)
-		basic_machine=powerpcle-unknown
-		;;
-	ppcle-* | powerpclittle-*)
-		basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	ppc64)	basic_machine=powerpc64-unknown
-		;;
-	ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	ppc64le | powerpc64little)
-		basic_machine=powerpc64le-unknown
-		;;
-	ppc64le-* | powerpc64little-*)
-		basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+	power)
+		cpu=power
+		vendor=ibm
 		;;
 	ps2)
-		basic_machine=i386-ibm
+		cpu=i386
+		vendor=ibm
 		;;
 	rm[46]00)
-		basic_machine=mips-siemens
+		cpu=mips
+		vendor=siemens
 		;;
 	rtpc | rtpc-*)
-		basic_machine=romp-ibm
-		;;
-	s390 | s390-*)
-		basic_machine=s390-ibm
-		;;
-	s390x | s390x-*)
-		basic_machine=s390x-ibm
-		;;
-	sb1)
-		basic_machine=mipsisa64sb1-unknown
-		;;
-	sb1el)
-		basic_machine=mipsisa64sb1el-unknown
+		cpu=romp
+		vendor=ibm
 		;;
 	sde)
-		basic_machine=mipsisa32-sde
-		os=${os:-elf}
-		;;
-	sequent)
-		basic_machine=i386-sequent
-		;;
-	sh5el)
-		basic_machine=sh5le-unknown
+		cpu=mipsisa32
+		vendor=sde
+		basic_os=${basic_os:-elf}
 		;;
 	simso-wrs)
-		basic_machine=sparclite-wrs
-		os=vxworks
-		;;
-	spur)
-		basic_machine=spur-unknown
-		;;
-	st2000)
-		basic_machine=m68k-tandem
-		;;
-	strongarm-* | thumb-*)
-		basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-		;;
-	sun2)
-		basic_machine=m68000-sun
-		;;
-	sun3 | sun3-*)
-		basic_machine=m68k-sun
-		;;
-	sun4)
-		basic_machine=sparc-sun
-		;;
-	sun386 | sun386i | roadrunner)
-		basic_machine=i386-sun
-		;;
-	tile*)
-		basic_machine=$basic_machine-unknown
-		os=linux-gnu
-		;;
-	tx39)
-		basic_machine=mipstx39-unknown
-		;;
-	tx39el)
-		basic_machine=mipstx39el-unknown
+		cpu=sparclite
+		vendor=wrs
+		basic_os=vxworks
 		;;
 	tower | tower-32)
-		basic_machine=m68k-ncr
+		cpu=m68k
+		vendor=ncr
 		;;
 	vpp*|vx|vx-*)
-		basic_machine=f301-fujitsu
+		cpu=f301
+		vendor=fujitsu
 		;;
-	w65*)
-		basic_machine=w65-wdc
-		os=none
+	w65)
+		cpu=w65
+		vendor=wdc
 		;;
 	w89k-*)
-		basic_machine=hppa1.1-winbond
-		os=proelf
-		;;
-	x64)
-		basic_machine=x86_64-pc
-		;;
-	xps | xps100)
-		basic_machine=xps100-honeywell
-		;;
-	xscale-* | xscalee[bl]-*)
-		basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'`
+		cpu=hppa1.1
+		vendor=winbond
+		basic_os=proelf
 		;;
 	none)
-		basic_machine=none-none
-		os=${os:-none}
+		cpu=none
+		vendor=none
+		;;
+	leon|leon[3-9])
+		cpu=sparc
+		vendor=$basic_machine
+		;;
+	leon-*|leon[3-9]-*)
+		cpu=sparc
+		vendor=$(echo "$basic_machine" | sed 's/-.*//')
 		;;
 
-# Here we handle the default manufacturer of certain CPU types.  It is in
-# some cases the only manufacturer, in others, it is the most popular.
-	w89k)
-		basic_machine=hppa1.1-winbond
+	*-*)
+		# shellcheck disable=SC2162
+		IFS="-" read cpu vendor <<EOF
+$basic_machine
+EOF
 		;;
-	op50n)
-		basic_machine=hppa1.1-oki
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+		cpu=$basic_machine
+		vendor=pc
 		;;
-	op60c)
-		basic_machine=hppa1.1-oki
+	# These rules are duplicated from below for sake of the special case above;
+	# i.e. things that normalized to x86 arches should also default to "pc"
+	pc98)
+		cpu=i386
+		vendor=pc
 		;;
-	romp)
-		basic_machine=romp-ibm
+	x64 | amd64)
+		cpu=x86_64
+		vendor=pc
 		;;
-	mmix)
-		basic_machine=mmix-knuth
-		;;
-	rs6000)
-		basic_machine=rs6000-ibm
-		;;
-	vax)
-		basic_machine=vax-dec
-		;;
-	pdp11)
-		basic_machine=pdp11-dec
-		;;
-	we32k)
-		basic_machine=we32k-att
-		;;
-	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
-		basic_machine=sh-unknown
-		;;
-	cydra)
-		basic_machine=cydra-cydrome
-		;;
-	orion)
-		basic_machine=orion-highlevel
-		;;
-	orion105)
-		basic_machine=clipper-highlevel
-		;;
-	mac | mpw | mac-mpw)
-		basic_machine=m68k-apple
-		;;
-	pmac | pmac-mpw)
-		basic_machine=powerpc-apple
-		;;
-	*-unknown)
-		# Make sure to match an already-canonicalized machine name.
-		;;
+	# Recognize the basic CPU types without company name.
 	*)
-		echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
-		exit 1
+		cpu=$basic_machine
+		vendor=unknown
+		;;
+esac
+
+unset -v basic_machine
+
+# Decode basic machines in the full and proper CPU-Company form.
+case $cpu-$vendor in
+	# Here we handle the default manufacturer of certain CPU types in canonical form. It is in
+	# some cases the only manufacturer, in others, it is the most popular.
+	craynv-unknown)
+		vendor=cray
+		basic_os=${basic_os:-unicosmp}
+		;;
+	c90-unknown | c90-cray)
+		vendor=cray
+		basic_os=${Basic_os:-unicos}
+		;;
+	fx80-unknown)
+		vendor=alliant
+		;;
+	romp-unknown)
+		vendor=ibm
+		;;
+	mmix-unknown)
+		vendor=knuth
+		;;
+	microblaze-unknown | microblazeel-unknown)
+		vendor=xilinx
+		;;
+	rs6000-unknown)
+		vendor=ibm
+		;;
+	vax-unknown)
+		vendor=dec
+		;;
+	pdp11-unknown)
+		vendor=dec
+		;;
+	we32k-unknown)
+		vendor=att
+		;;
+	cydra-unknown)
+		vendor=cydrome
+		;;
+	i370-ibm*)
+		vendor=ibm
+		;;
+	orion-unknown)
+		vendor=highlevel
+		;;
+	xps-unknown | xps100-unknown)
+		cpu=xps100
+		vendor=honeywell
+		;;
+
+	# Here we normalize CPU types with a missing or matching vendor
+	dpx20-unknown | dpx20-bull)
+		cpu=rs6000
+		vendor=bull
+		basic_os=${basic_os:-bosx}
+		;;
+
+	# Here we normalize CPU types irrespective of the vendor
+	amd64-*)
+		cpu=x86_64
+		;;
+	blackfin-*)
+		cpu=bfin
+		basic_os=linux
+		;;
+	c54x-*)
+		cpu=tic54x
+		;;
+	c55x-*)
+		cpu=tic55x
+		;;
+	c6x-*)
+		cpu=tic6x
+		;;
+	e500v[12]-*)
+		cpu=powerpc
+		basic_os=${basic_os}"spe"
+		;;
+	mips3*-*)
+		cpu=mips64
+		;;
+	ms1-*)
+		cpu=mt
+		;;
+	m68knommu-*)
+		cpu=m68k
+		basic_os=linux
+		;;
+	m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
+		cpu=s12z
+		;;
+	openrisc-*)
+		cpu=or32
+		;;
+	parisc-*)
+		cpu=hppa
+		basic_os=linux
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		cpu=i586
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+		cpu=i686
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		cpu=i686
+		;;
+	pentium4-*)
+		cpu=i786
+		;;
+	pc98-*)
+		cpu=i386
+		;;
+	ppc-* | ppcbe-*)
+		cpu=powerpc
+		;;
+	ppcle-* | powerpclittle-*)
+		cpu=powerpcle
+		;;
+	ppc64-*)
+		cpu=powerpc64
+		;;
+	ppc64le-* | powerpc64little-*)
+		cpu=powerpc64le
+		;;
+	sb1-*)
+		cpu=mipsisa64sb1
+		;;
+	sb1el-*)
+		cpu=mipsisa64sb1el
+		;;
+	sh5e[lb]-*)
+		cpu=$(echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/')
+		;;
+	spur-*)
+		cpu=spur
+		;;
+	strongarm-* | thumb-*)
+		cpu=arm
+		;;
+	tx39-*)
+		cpu=mipstx39
+		;;
+	tx39el-*)
+		cpu=mipstx39el
+		;;
+	x64-*)
+		cpu=x86_64
+		;;
+	xscale-* | xscalee[bl]-*)
+		cpu=$(echo "$cpu" | sed 's/^xscale/arm/')
+		;;
+	arm64-*)
+		cpu=aarch64
+		;;
+
+	# Recognize the canonical CPU Types that limit and/or modify the
+	# company names they are paired with.
+	cr16-*)
+		basic_os=${basic_os:-elf}
+		;;
+	crisv32-* | etraxfs*-*)
+		cpu=crisv32
+		vendor=axis
+		;;
+	cris-* | etrax*-*)
+		cpu=cris
+		vendor=axis
+		;;
+	crx-*)
+		basic_os=${basic_os:-elf}
+		;;
+	neo-tandem)
+		cpu=neo
+		vendor=tandem
+		;;
+	nse-tandem)
+		cpu=nse
+		vendor=tandem
+		;;
+	nsr-tandem)
+		cpu=nsr
+		vendor=tandem
+		;;
+	nsv-tandem)
+		cpu=nsv
+		vendor=tandem
+		;;
+	nsx-tandem)
+		cpu=nsx
+		vendor=tandem
+		;;
+	mipsallegrexel-sony)
+		cpu=mipsallegrexel
+		vendor=sony
+		;;
+	tile*-*)
+		basic_os=${basic_os:-linux-gnu}
+		;;
+
+	*)
+		# Recognize the canonical CPU types that are allowed with any
+		# company name.
+		case $cpu in
+			1750a | 580 \
+			| a29k \
+			| aarch64 | aarch64_be \
+			| abacus \
+			| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
+			| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
+			| alphapca5[67] | alpha64pca5[67] \
+			| am33_2.0 \
+			| amdgcn \
+			| arc | arceb \
+			| arm | arm[lb]e | arme[lb] | armv* \
+			| avr | avr32 \
+			| asmjs \
+			| ba \
+			| be32 | be64 \
+			| bfin | bpf | bs2000 \
+			| c[123]* | c30 | [cjt]90 | c4x \
+			| c8051 | clipper | craynv | csky | cydra \
+			| d10v | d30v | dlx | dsp16xx \
+			| e2k | elxsi | epiphany \
+			| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+			| h8300 | h8500 \
+			| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+			| hexagon \
+			| i370 | i*86 | i860 | i960 | ia16 | ia64 \
+			| ip2k | iq2000 \
+			| k1om \
+			| le32 | le64 \
+			| lm32 \
+			| loongarch32 | loongarch64 | loongarchx32 \
+			| m32c | m32r | m32rle \
+			| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
+			| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
+			| m88110 | m88k | maxq | mb | mcore | mep | metag \
+			| microblaze | microblazeel \
+			| mips | mipsbe | mipseb | mipsel | mipsle \
+			| mips16 \
+			| mips64 | mips64eb | mips64el \
+			| mips64octeon | mips64octeonel \
+			| mips64orion | mips64orionel \
+			| mips64r5900 | mips64r5900el \
+			| mips64vr | mips64vrel \
+			| mips64vr4100 | mips64vr4100el \
+			| mips64vr4300 | mips64vr4300el \
+			| mips64vr5000 | mips64vr5000el \
+			| mips64vr5900 | mips64vr5900el \
+			| mipsisa32 | mipsisa32el \
+			| mipsisa32r2 | mipsisa32r2el \
+			| mipsisa32r6 | mipsisa32r6el \
+			| mipsisa64 | mipsisa64el \
+			| mipsisa64r2 | mipsisa64r2el \
+			| mipsisa64r6 | mipsisa64r6el \
+			| mipsisa64sb1 | mipsisa64sb1el \
+			| mipsisa64sr71k | mipsisa64sr71kel \
+			| mipsr5900 | mipsr5900el \
+			| mipstx39 | mipstx39el \
+			| mmix \
+			| mn10200 | mn10300 \
+			| moxie \
+			| mt \
+			| msp430 \
+			| nds32 | nds32le | nds32be \
+			| nfp \
+			| nios | nios2 | nios2eb | nios2el \
+			| none | np1 | ns16k | ns32k | nvptx \
+			| open8 \
+			| or1k* \
+			| or32 \
+			| orion \
+			| picochip \
+			| pdp10 | pdp11 | pj | pjl | pn | power \
+			| powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+			| pru \
+			| pyramid \
+			| riscv | riscv32 | riscv64 \
+			| rl78 | romp | rs6000 | rx \
+			| s390 | s390x \
+			| score \
+			| sh | shl \
+			| sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
+			| sh[1234]e[lb] |  sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
+			| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+			| sparclite \
+			| sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+			| spu \
+			| tahoe \
+			| thumbv7* \
+			| tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+			| tron \
+			| ubicom32 \
+			| v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+			| vax \
+			| visium \
+			| w65 \
+			| wasm32 | wasm64 \
+			| we32k \
+			| x86 | x86_64 | xc16x | xgate | xps100 \
+			| xstormy16 | xtensa* \
+			| ymp \
+			| z8k | z80)
+				;;
+
+			*)
+				echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+				exit 1
+				;;
+		esac
 		;;
 esac
 
 # Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
-	*-digital*)
-		basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'`
+case $vendor in
+	digital*)
+		vendor=dec
 		;;
-	*-commodore*)
-		basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'`
+	commodore*)
+		vendor=cbm
 		;;
 	*)
 		;;
@@ -1286,8 +1280,47 @@
 
 # Decode manufacturer-specific aliases for certain operating systems.
 
-if [ x$os != x ]
+if test x$basic_os != x
 then
+
+# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
+# set os.
+case $basic_os in
+	gnu/linux*)
+		kernel=linux
+		os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|')
+		;;
+	os2-emx)
+		kernel=os2
+		os=$(echo $basic_os | sed -e 's|os2-emx|emx|')
+		;;
+	nto-qnx*)
+		kernel=nto
+		os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|')
+		;;
+	*-*)
+		# shellcheck disable=SC2162
+		IFS="-" read kernel os <<EOF
+$basic_os
+EOF
+		;;
+	# Default OS when just kernel was specified
+	nto*)
+		kernel=nto
+		os=$(echo $basic_os | sed -e 's|nto|qnx|')
+		;;
+	linux*)
+		kernel=linux
+		os=$(echo $basic_os | sed -e 's|linux|gnu|')
+		;;
+	*)
+		kernel=
+		os=$basic_os
+		;;
+esac
+
+# Now, normalize the OS (knowing we just have one component, it's not a kernel,
+# etc.)
 case $os in
 	# First match some system type aliases that might get confused
 	# with valid system types.
@@ -1299,7 +1332,7 @@
 		os=cnk
 		;;
 	solaris1 | solaris1.*)
-		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		os=$(echo $os | sed -e 's|solaris1|sunos4|')
 		;;
 	solaris)
 		os=solaris2
@@ -1307,9 +1340,6 @@
 	unixware*)
 		os=sysv4.2uw
 		;;
-	gnu/linux*)
-		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
-		;;
 	# es1800 is here to avoid being matched by es* (a different OS)
 	es1800*)
 		os=ose
@@ -1331,12 +1361,9 @@
 		os=sco3.2v4
 		;;
 	sco3.2.[4-9]*)
-		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		os=$(echo $os | sed -e 's/sco3.2./sco3.2v/')
 		;;
-	sco3.2v[4-9]* | sco5v6*)
-		# Don't forget version if it is 3.2v4 or newer.
-		;;
-	scout)
+	sco*v* | scout)
 		# Don't match below
 		;;
 	sco*)
@@ -1345,78 +1372,26 @@
 	psos*)
 		os=psos
 		;;
-	# Now accept the basic system types.
-	# The portable systems comes first.
-	# Each alternative MUST end in a * to match a version number.
-	# sysv* is not here because it comes later, after sysvr4.
-	gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
-	     | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\
-	     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
-	     | sym* | kopensolaris* | plan9* \
-	     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
-	     | aos* | aros* | cloudabi* | sortix* \
-	     | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
-	     | clix* | riscos* | uniplus* | iris* | rtu* | xenix* \
-	     | knetbsd* | mirbsd* | netbsd* \
-	     | bitrig* | openbsd* | solidbsd* | libertybsd* \
-	     | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \
-	     | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
-	     | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
-	     | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \
-	     | chorusrdb* | cegcc* | glidix* \
-	     | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
-	     | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \
-	     | linux-newlib* | linux-musl* | linux-uclibc* \
-	     | uxpv* | beos* | mpeix* | udk* | moxiebox* \
-	     | interix* | uwin* | mks* | rhapsody* | darwin* \
-	     | openstep* | oskit* | conix* | pw32* | nonstopux* \
-	     | storm-chaos* | tops10* | tenex* | tops20* | its* \
-	     | os2* | vos* | palmos* | uclinux* | nucleus* \
-	     | morphos* | superux* | rtmk* | windiss* \
-	     | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
-	     | skyos* | haiku* | rdos* | toppers* | drops* | es* \
-	     | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
-	     | midnightbsd*)
-	# Remember, each alternative MUST END IN *, to match a version number.
-		;;
 	qnx*)
-		case $basic_machine in
-		    x86-* | i*86-*)
-			;;
-		    *)
-			os=nto-$os
-			;;
-		esac
+		os=qnx
 		;;
 	hiux*)
 		os=hiuxwe2
 		;;
-	nto-qnx*)
-		;;
-	nto*)
-		os=`echo $os | sed -e 's|nto|nto-qnx|'`
-		;;
-	sim | xray | os68k* | v88r* \
-	    | windows* | osx | abug | netware* | os9* \
-	    | macos* | mpw* | magic* | mmixware* | mon960* | lnews*)
-		;;
-	linux-dietlibc)
-		os=linux-dietlibc
-		;;
-	linux*)
-		os=`echo $os | sed -e 's|linux|linux-gnu|'`
-		;;
 	lynx*178)
 		os=lynxos178
 		;;
 	lynx*5)
 		os=lynxos5
 		;;
+	lynxos*)
+		# don't get caught up in next wildcard
+		;;
 	lynx*)
 		os=lynxos
 		;;
-	mac*)
-		os=`echo "$os" | sed -e 's|mac|macos|'`
+	mac[0-9]*)
+		os=$(echo "$os" | sed -e 's|mac|macos|')
 		;;
 	opened*)
 		os=openedition
@@ -1425,10 +1400,10 @@
 		os=os400
 		;;
 	sunos5*)
-		os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+		os=$(echo "$os" | sed -e 's|sunos5|solaris2|')
 		;;
 	sunos6*)
-		os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+		os=$(echo "$os" | sed -e 's|sunos6|solaris3|')
 		;;
 	wince*)
 		os=wince
@@ -1460,12 +1435,9 @@
 	ns2)
 		os=nextstep2
 		;;
-	nsk*)
-		os=nsk
-		;;
 	# Preserve the version number of sinix5.
 	sinix5.*)
-		os=`echo $os | sed -e 's|sinix|sysv|'`
+		os=$(echo $os | sed -e 's|sinix|sysv|')
 		;;
 	sinix*)
 		os=sysv4
@@ -1488,18 +1460,12 @@
 	sysvr4)
 		os=sysv4
 		;;
-	# This must come after sysvr4.
-	sysv*)
-		;;
 	ose*)
 		os=ose
 		;;
 	*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
 		os=mint
 		;;
-	zvmoe)
-		os=zvmoe
-		;;
 	dicos*)
 		os=dicos
 		;;
@@ -1507,7 +1473,7 @@
 		# Until real need of OS specific support for
 		# particular features comes up, bare metal
 		# configurations are quite functional.
-		case $basic_machine in
+		case $cpu in
 		    arm*)
 			os=eabi
 			;;
@@ -1516,19 +1482,11 @@
 			;;
 		esac
 		;;
-	nacl*)
-		;;
-	ios)
-		;;
-	none)
-		;;
-	*-eabi)
-		;;
 	*)
-		echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
-		exit 1
+		# No normalization, but not necessarily accepted, that comes below.
 		;;
 esac
+
 else
 
 # Here we handle the default operating systems that come with various machines.
@@ -1541,7 +1499,8 @@
 # will signal an error saying that MANUFACTURER isn't an operating
 # system, and we'll never get to this point.
 
-case $basic_machine in
+kernel=
+case $cpu-$vendor in
 	score-*)
 		os=elf
 		;;
@@ -1552,7 +1511,8 @@
 		os=riscix1.2
 		;;
 	arm*-rebel)
-		os=linux
+		kernel=linux
+		os=gnu
 		;;
 	arm*-semi)
 		os=aout
@@ -1718,86 +1678,173 @@
 		os=none
 		;;
 esac
+
 fi
 
-# Here we handle the case where we know the os, and the CPU type, but not the
-# manufacturer.  We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
-	*-unknown)
-		case $os in
-			riscix*)
-				vendor=acorn
-				;;
-			sunos*)
-				vendor=sun
-				;;
-			cnk*|-aix*)
-				vendor=ibm
-				;;
-			beos*)
-				vendor=be
-				;;
-			hpux*)
-				vendor=hp
-				;;
-			mpeix*)
-				vendor=hp
-				;;
-			hiux*)
-				vendor=hitachi
-				;;
-			unos*)
-				vendor=crds
-				;;
-			dgux*)
-				vendor=dg
-				;;
-			luna*)
-				vendor=omron
-				;;
-			genix*)
-				vendor=ns
-				;;
-			clix*)
-				vendor=intergraph
-				;;
-			mvs* | opened*)
-				vendor=ibm
-				;;
-			os400*)
-				vendor=ibm
-				;;
-			ptx*)
-				vendor=sequent
-				;;
-			tpf*)
-				vendor=ibm
-				;;
-			vxsim* | vxworks* | windiss*)
-				vendor=wrs
-				;;
-			aux*)
-				vendor=apple
-				;;
-			hms*)
-				vendor=hitachi
-				;;
-			mpw* | macos*)
-				vendor=apple
-				;;
-			*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
-				vendor=atari
-				;;
-			vos*)
-				vendor=stratus
-				;;
-		esac
-		basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"`
+# Now, validate our (potentially fixed-up) OS.
+case $os in
+	# Sometimes we do "kernel-abi", so those need to count as OSes.
+	musl* | newlib* | uclibc*)
+		;;
+	# Likewise for "kernel-libc"
+	eabi | eabihf | gnueabi | gnueabihf)
+		;;
+	# Now accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST end in a * to match a version number.
+	gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
+	     | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
+	     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+	     | sym* |  plan9* | psp* | sim* | xray* | os68k* | v88r* \
+	     | hiux* | abug | nacl* | netware* | windows* \
+	     | os9* | macos* | osx* | ios* \
+	     | mpw* | magic* | mmixware* | mon960* | lnews* \
+	     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+	     | aos* | aros* | cloudabi* | sortix* | twizzler* \
+	     | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
+	     | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
+	     | mirbsd* | netbsd* | dicos* | openedition* | ose* \
+	     | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \
+	     | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
+	     | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
+	     | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+	     | udi* | lites* | ieee* | go32* | aux* | hcos* \
+	     | chorusrdb* | cegcc* | glidix* \
+	     | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+	     | midipix* | mingw32* | mingw64* | mint* \
+	     | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+	     | interix* | uwin* | mks* | rhapsody* | darwin* \
+	     | openstep* | oskit* | conix* | pw32* | nonstopux* \
+	     | storm-chaos* | tops10* | tenex* | tops20* | its* \
+	     | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
+	     | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
+	     | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
+	     | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+	     | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+	     | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
+	     | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
+		;;
+	# This one is extra strict with allowed versions
+	sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		;;
+	none)
+		;;
+	*)
+		echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
+		exit 1
 		;;
 esac
 
-echo "$basic_machine-$os"
+# As a final step for OS-related things, validate the OS-kernel combination
+# (given a valid OS), if there is a kernel.
+case $kernel-$os in
+	linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
+		;;
+	uclinux-uclibc* )
+		;;
+	-dietlibc* | -newlib* | -musl* | -uclibc* )
+		# These are just libc implementations, not actual OSes, and thus
+		# require a kernel.
+		echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
+		exit 1
+		;;
+	kfreebsd*-gnu* | kopensolaris*-gnu*)
+		;;
+	nto-qnx*)
+		;;
+	os2-emx)
+		;;
+	*-eabi* | *-gnueabi*)
+		;;
+	-*)
+		# Blank kernel with real OS is always fine.
+		;;
+	*-*)
+		echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+		exit 1
+		;;
+esac
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+case $vendor in
+	unknown)
+		case $cpu-$os in
+			*-riscix*)
+				vendor=acorn
+				;;
+			*-sunos*)
+				vendor=sun
+				;;
+			*-cnk* | *-aix*)
+				vendor=ibm
+				;;
+			*-beos*)
+				vendor=be
+				;;
+			*-hpux*)
+				vendor=hp
+				;;
+			*-mpeix*)
+				vendor=hp
+				;;
+			*-hiux*)
+				vendor=hitachi
+				;;
+			*-unos*)
+				vendor=crds
+				;;
+			*-dgux*)
+				vendor=dg
+				;;
+			*-luna*)
+				vendor=omron
+				;;
+			*-genix*)
+				vendor=ns
+				;;
+			*-clix*)
+				vendor=intergraph
+				;;
+			*-mvs* | *-opened*)
+				vendor=ibm
+				;;
+			*-os400*)
+				vendor=ibm
+				;;
+			s390-* | s390x-*)
+				vendor=ibm
+				;;
+			*-ptx*)
+				vendor=sequent
+				;;
+			*-tpf*)
+				vendor=ibm
+				;;
+			*-vxsim* | *-vxworks* | *-windiss*)
+				vendor=wrs
+				;;
+			*-aux*)
+				vendor=apple
+				;;
+			*-hms*)
+				vendor=hitachi
+				;;
+			*-mpw* | *-macos*)
+				vendor=apple
+				;;
+			*-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)
+				vendor=atari
+				;;
+			*-vos*)
+				vendor=stratus
+				;;
+		esac
+		;;
+esac
+
+echo "$cpu-$vendor-${kernel:+$kernel-}$os"
 exit
 
 # Local variables:
diff --git a/configure b/configure
index fa15fc7..fd57219 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for pcap 1.9.1.
+# Generated by GNU Autoconf 2.69 for pcap 1.10.0.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -577,8 +577,8 @@
 # Identity of this package.
 PACKAGE_NAME='pcap'
 PACKAGE_TARNAME='pcap'
-PACKAGE_VERSION='1.9.1'
-PACKAGE_STRING='pcap 1.9.1'
+PACKAGE_VERSION='1.10.0'
+PACKAGE_STRING='pcap 1.10.0'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -623,20 +623,13 @@
 INSTALL_DATA
 INSTALL_SCRIPT
 INSTALL_PROGRAM
-RDMA_SRC
 PCAP_SUPPORT_RDMASNIFF
-DBUS_SRC
 PCAP_SUPPORT_DBUS
-PKGCONFIG
-BT_MONITOR_SRC
-BT_SRC
 PCAP_SUPPORT_BT
-NETMAP_SRC
+PCAP_SUPPORT_DPDK
 PCAP_SUPPORT_NETMAP
-NETFILTER_SRC
 PCAP_SUPPORT_NETFILTER
-USB_SRC
-PCAP_SUPPORT_USB
+PCAP_SUPPORT_LINUX_USBMON
 EXTRA_NETWORK_LIBS
 RPCAPD_LIBS
 INSTALL_RPCAPD
@@ -647,7 +640,10 @@
 MAN_FILE_FORMATS
 MAN_DEVICES
 DYEXT
-SSRC
+REMOTE_C_SRC
+MODULE_C_SRC
+PLATFORM_CXX_SRC
+PLATFORM_C_SRC
 ADDLARCHIVEOBJS
 ADDLOBJS
 V_YACC
@@ -656,10 +652,8 @@
 V_SHLIB_OPT
 V_SHLIB_CMD
 V_SHLIB_CCOPT
-V_PCAP
 V_LEX
 V_INCLS
-V_FINDALLDEVS
 V_DEFS
 V_PROG_LDFLAGS_FAT
 V_PROG_CCOPT_FAT
@@ -671,17 +665,21 @@
 LN_S
 AR
 RANLIB
+REENTRANT_PARSER
 YFLAGS
 YACC
 LEXLIB
 LEX_OUTPUT_ROOT
 LEX
-PCAP_SUPPORT_PACKET_RING
+PKGCONFIG
 VALGRINDTEST_SRC
 LIBOBJS
 EGREP
 GREP
 CPP
+ac_ct_CXX
+CXXFLAGS
+CXX
 OBJEXT
 EXEEXT
 ac_ct_CC
@@ -747,10 +745,8 @@
 with_gcc
 enable_largefile
 enable_protochain
-with_sita
 with_pcap
 with_libnl
-enable_packet_ring
 enable_ipv6
 with_dag
 with_dag_includes
@@ -767,6 +763,7 @@
 enable_shared
 enable_usb
 enable_netmap
+with_dpdk
 enable_bluetooth
 enable_dbus
 enable_rdma
@@ -779,6 +776,9 @@
 LDFLAGS
 LIBS
 CPPFLAGS
+CXX
+CXXFLAGS
+CCC
 CPP
 YACC
 YFLAGS'
@@ -1332,7 +1332,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures pcap 1.9.1 to adapt to many kinds of systems.
+\`configure' configures pcap 1.10.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1399,7 +1399,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of pcap 1.9.1:";;
+     short | recursive ) echo "Configuration of pcap 1.10.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1409,7 +1409,6 @@
   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
   --disable-largefile     omit support for large files
   --disable-protochain    disable \"protochain\" insn
-  --enable-packet-ring    enable packet ring support on Linux [default=yes]
   --enable-ipv6           build IPv6-capable version [default=yes]
   --enable-remote         enable remote packet capture [default=no]
   --disable-remote        disable remote packet capture
@@ -1418,8 +1417,8 @@
   --disable-universal     don't build universal on macOS
   --enable-shared         build shared libraries [default=yes, if support
                           available]
-  --enable-usb            enable USB capture support [default=yes, if support
-                          available]
+  --enable-usb            enable Linux usbmon USB capture support
+                          [default=yes, if support available]
   --enable-netmap         enable netmap support [default=yes, if support
                           available]
   --enable-bluetooth      enable Bluetooth support [default=yes, if support
@@ -1433,7 +1432,6 @@
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --without-gcc           don't use gcc
-  --with-sita             include SITA support
   --with-pcap=TYPE        use packet capture TYPE
   --without-libnl         disable libnl support [default=yes, on Linux, if
                           present]
@@ -1454,6 +1452,8 @@
   --with-turbocap[=DIR]   include Riverbed TurboCap support (located in
                           directory DIR, if supplied). [default=yes, if
                           present]
+  --with-dpdk[=DIR]       include DPDK support (located in directory DIR, if
+                          supplied). [default=yes, if present]
 
 Some influential environment variables:
   CC          C compiler command
@@ -1463,6 +1463,8 @@
   LIBS        libraries to pass to the linker, e.g. -l<library>
   CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
   CPP         C preprocessor
   YACC        The `Yet Another Compiler Compiler' implementation to use.
               Defaults to the first program found out of: `bison -y', `byacc',
@@ -1537,7 +1539,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-pcap configure 1.9.1
+pcap configure 1.10.0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1589,6 +1591,44 @@
 
 } # ac_fn_c_try_compile
 
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
 # ac_fn_c_try_link LINENO
 # -----------------------
 # Try to link conftest.$ac_ext, and return whether this succeeded.
@@ -2059,7 +2099,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by pcap $as_me 1.9.1, which was
+It was created by pcap $as_me 1.10.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2624,8 +2664,9 @@
     fi
 
 #
-# Try to enable as many C99 features as we can.
-# At minimum, we want C++/C99-style // comments.
+# We require C99 or later.
+# Try to get it, which may involve adding compiler flags;
+# if that fails, give up.
 #
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -3594,9 +3635,273 @@
 
 
 if test "$ac_cv_prog_cc_c99" = "no"; then
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: The C compiler does not support C99; there may be compiler errors" >&5
-$as_echo "$as_me: WARNING: The C compiler does not support C99; there may be compiler errors" >&2;}
+	as_fn_error $? "The C compiler does not support C99" "$LINENO" 5
 fi
+case "$host_os" in
+haiku*)
+	#
+	# Haiku's platform file is in C++.
+	#
+	ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+else
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+	;;
+esac
+
 
 
 
@@ -4018,8 +4323,8 @@
 	    aix*)
 		    ;;
 
-	    freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|midipix*)
-	    	    #
+	    freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|haiku*|midipix*)
+		    #
 		    # Platforms where the linker is the GNU linker
 		    # or accepts command-line arguments like
 		    # those the GNU linker accepts.
@@ -4048,7 +4353,7 @@
 
 	    hpux*)
 		    V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic"
-	    	    #
+		    #
 		    # XXX - this assumes GCC is using the HP linker,
 		    # rather than the GNU linker, and that the "+h"
 		    # option is used on all HP-UX platforms, both .sl
@@ -4056,7 +4361,7 @@
 		    #
 		    V_SONAME_OPT="-Wl,+h,"
 		    #
-		    # By default, directories specifed with -L
+		    # By default, directories specified with -L
 		    # are added to the run-time search path, so
 		    # we don't add them in pcap-config.
 		    #
@@ -4117,14 +4422,14 @@
 		    V_SHLIB_OPT="-b"
 		    V_SONAME_OPT="+h "
 		    #
-		    # By default, directories specifed with -L
+		    # By default, directories specified with -L
 		    # are added to the run-time search path, so
 		    # we don't add them in pcap-config.
 		    #
 		    ;;
 
 	    osf*)
-	    	    #
+		    #
 		    # Presumed to be DEC OSF/1, Digital UNIX, or
 		    # Tru64 UNIX.
 		    #
@@ -4876,7 +5181,7 @@
 done
 
 
-for ac_header in sys/ioccom.h sys/sockio.h limits.h
+for ac_header in sys/ioccom.h sys/sockio.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -4952,24 +5257,11 @@
 fi
 
 case "$host_os" in
-linux*|uclinux*)
-	for ac_header in linux/sockios.h linux/if_bonding.h
-do :
-  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "
-#include <sys/socket.h>
-#include <linux/if.h>
-
-"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
+haiku*)
+	#
+	# Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them.
+	#
+	CFLAGS="$CFLAGS -D_BSD_SOURCE"
 	;;
 esac
 
@@ -5079,14 +5371,14 @@
 else
 
 	#
-	# We don't have strerror_r; do we have strerror_s?
+	# We don't have strerror_r; do we have _wcserror_s?
 	#
-	for ac_func in strerror_s
+	for ac_func in _wcserror_s
 do :
-  ac_fn_c_check_func "$LINENO" "strerror_s" "ac_cv_func_strerror_s"
-if test "x$ac_cv_func_strerror_s" = xyes; then :
+  ac_fn_c_check_func "$LINENO" "_wcserror_s" "ac_cv_func__wcserror_s"
+if test "x$ac_cv_func__wcserror_s" = xyes; then :
   cat >>confdefs.h <<_ACEOF
-#define HAVE_STRERROR_S 1
+#define HAVE__WCSERROR_S 1
 _ACEOF
 
 fi
@@ -5112,41 +5404,22 @@
 
 
 #
-# Either:
+# Make sure we have vsnprintf() and snprintf(); we require them.
 #
-#	we have snprintf() and vsnprintf(), and have asprintf() and
-#	vasprintf();
-#
-#	we have snprintf() and vsnprintf(), but don't have asprintf()
-#	or vasprintf();
-#
-#	we have neither snprintf() nor vsnprintf(), and don't have
-#	asprintf() or vasprintf(), either.
-#
-# We assume that if we have asprintf() we have vasprintf(), as well
-# as snprintf() and vsnprintf(), and that if we have snprintf() we
-# have vsnprintf().
-#
-# For the first case, we don't need any replacement routines.
-# For the second case, we need replacement asprintf()/vasprintf()
-# routines.
-# For the third case, we need replacement snprintf()/vsnprintf() and
-# asprintf()/vasprintf() routines.
-#
-needsnprintf=no
-for ac_func in vsnprintf snprintf
-do :
-  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf"
+if test "x$ac_cv_func_vsnprintf" = xyes; then :
 
 else
-  needsnprintf=yes
+  as_fn_error $? "vsnprintf() is required but wasn't found" "$LINENO" 5
 fi
-done
+
+ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf"
+if test "x$ac_cv_func_snprintf" = xyes; then :
+
+else
+  as_fn_error $? "snprintf() is required but wasn't found" "$LINENO" 5
+fi
+
 
 needasprintf=no
 for ac_func in vasprintf asprintf
@@ -5163,23 +5436,7 @@
 fi
 done
 
-if test $needsnprintf = yes; then
-	#
-	# We assume we have none of them; missing/snprintf.c supplies
-	# all of them.
-	#
-	case " $LIBOBJS " in
-  *" snprintf.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
- ;;
-esac
-
-elif test $needasprintf = yes; then
-	#
-	# We assume we have snprintf()/vsnprintf() but lack
-	# asprintf()/vasprintf(); missing/asprintf.c supplies
-	# the latter (using vsnprintf()).
-	#
+if test $needasprintf = yes; then
 	case " $LIBOBJS " in
   *" asprintf.$ac_objext "* ) ;;
   *) LIBOBJS="$LIBOBJS asprintf.$ac_objext"
@@ -5355,10 +5612,58 @@
 
 else
 
-	    #
-	    # We didn't find it.
-	    #
-	    as_fn_error $? "getaddrinfo is required, but wasn't found" "$LINENO" 5
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo in -lnetwork" >&5
+$as_echo_n "checking for getaddrinfo in -lnetwork... " >&6; }
+if ${ac_cv_lib_network_getaddrinfo+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnetwork  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getaddrinfo ();
+int
+main ()
+{
+return getaddrinfo ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_network_getaddrinfo=yes
+else
+  ac_cv_lib_network_getaddrinfo=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_getaddrinfo" >&5
+$as_echo "$ac_cv_lib_network_getaddrinfo" >&6; }
+if test "x$ac_cv_lib_network_getaddrinfo" = xyes; then :
+
+		    #
+		    # OK, we found it in libnetwork on Haiku.
+		    #
+		    LIBS="-lnetwork $LIBS"
+
+else
+
+		    #
+		    # We didn't find it.
+		    #
+		    as_fn_error $? "getaddrinfo is required, but wasn't found" "$LINENO" 5
+
+fi
+
 
 fi
 
@@ -6101,25 +6406,6 @@
 #
 VALGRINDTEST_SRC=
 
-#
-# SITA support is mutually exclusive with native capture support;
-# "--with-sita" selects SITA support.
-#
-
-# Check whether --with-sita was given.
-if test "${with_sita+set}" = set; then :
-  withval=$with_sita;
-	if test ! "x$withval" = "xno" ; then
-
-$as_echo "#define SITA 1" >>confdefs.h
-
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: Enabling SITA ACN support" >&5
-$as_echo "$as_me: Enabling SITA ACN support" >&6;}
-		V_PCAP=sita
-	fi
-
-else
-
 
 # Check whether --with-pcap was given.
 if test "${with_pcap+set}" = set; then :
@@ -6254,6 +6540,18 @@
 
 done
 
+	for ac_header in config/HaikuConfig.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "config/HaikuConfig.h" "ac_cv_header_config_HaikuConfig_h" "$ac_includes_default"
+if test "x$ac_cv_header_config_HaikuConfig_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_CONFIG_HAIKUCONFIG_H 1
+_ACEOF
+
+fi
+
+done
+
 
 	if test "$ac_cv_lbl_bpf_h_defines_biocsetif" = yes; then
 		#
@@ -6279,11 +6577,6 @@
 		# No prizes for guessing this one.
 		#
 		V_PCAP=linux
-
-		#
-		# XXX - this won't work with older kernels that have
-		# SOCK_PACKET sockets but not PF_PACKET sockets.
-		#
 		VALGRINDTEST_SRC=valgrindtest.c
 	elif test "$ac_cv_header_net_pfilt_h" = yes; then
 	        #
@@ -6315,6 +6608,11 @@
 		# DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others.
 		#
 		V_PCAP=dlpi
+	elif test "$ac_cv_header_config_HaikuConfig_h" = yes; then
+		#
+		# Haiku.
+		#
+		V_PCAP=haiku
 	else
 		#
 		# Nothing we support.
@@ -6333,16 +6631,53 @@
 
 
 #
-# Do capture-mechanism-dependent tests.
+# Do we have pkg-config?
+#
+# Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PKGCONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$PKGCONFIG"; then
+  ac_cv_prog_PKGCONFIG="$PKGCONFIG" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_PKGCONFIG="pkg-config"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_prog_PKGCONFIG" && ac_cv_prog_PKGCONFIG="no"
+fi
+fi
+PKGCONFIG=$ac_cv_prog_PKGCONFIG
+if test -n "$PKGCONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5
+$as_echo "$PKGCONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+#
+# Handle each capture type.
 #
 case "$V_PCAP" in
 dlpi)
 	#
-	# Needed for common functions used by pcap-[dlpi,libdlpi].c
-	#
- 	SSRC="dlpisubs.c"
-
-	#
 	# Checks for some header files.
 	#
 	for ac_header in sys/bufmod.h sys/dlpi_ext.h
@@ -6370,7 +6705,7 @@
 	# Also, due to the bug above applications that link to libpcap with
 	# libdlpi will have to add "-L/lib" option to "configure".
 	#
-	saved_ldflags=$LDFLAGS
+	save_LDFLAGS="$LDFLAGS"
 	LDFLAGS="$LIBS -L/lib"
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlpi_walk in -ldlpi" >&5
 $as_echo_n "checking for dlpi_walk in -ldlpi... " >&6; }
@@ -6413,14 +6748,28 @@
 			LIBS="-ldlpi $LIBS"
 			V_PCAP=libdlpi
 
+			#
+			# Capture module plus common code needed for
+			# common functions used by pcap-[dlpi,libdlpi].c
+			#
+			PLATFORM_C_SRC="pcap-libdlpi.c dlpisubs.c"
+
 $as_echo "#define HAVE_LIBDLPI 1" >>confdefs.h
 
 
 else
-  V_PCAP=dlpi
+
+			V_PCAP=dlpi
+
+			#
+			# Capture module plus common code needed for
+			# common functions used by pcap-[dlpi,libdlpi].c
+			#
+			PLATFORM_C_SRC="pcap-dlpi.c dlpisubs.c"
+
 fi
 
-	LDFLAGS=$saved_ldflags
+	LDFLAGS="$save_LDFLAGS"
 
 	#
 	# Checks whether <sys/dlpi.h> is usable, to catch weird SCO
@@ -6482,8 +6831,44 @@
 
 	;;
 
+enet)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-enet.c"
+	;;
+
+haiku)
+	#
+	# Capture module
+	#
+ 	PLATFORM_CXX_SRC="pcap-haiku.cpp"
+
+	#
+	# Just for the sake of it.
+	#
+	for ac_header in net/if.h net/if_dl.h net/if_types.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+	;;
+
 linux)
 	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-linux.c"
+
+	#
 	# Do we have the wireless extensions?
 	#
 	for ac_header in linux/wireless.h
@@ -6506,6 +6891,12 @@
 
 	#
 	# Do we have libnl?
+	# We only want version 3.  Version 2 was, apparently,
+	# short-lived, and version 1 is source and binary
+	# incompatible with version 3, and it appears that,
+	# these days, everybody's using version 3.  We're
+	# not supporting older versions of the Linux kernel;
+	# let's drop support for older versions of libnl, too.
 	#
 
 # Check whether --with-libnl was given.
@@ -6517,27 +6908,51 @@
 
 
 	if test x$with_libnl != xno ; then
-		have_any_nl="no"
+		if test "x$PKGCONFIG" != "xno"; then
+			#
+			# We have pkg-config; see if we have libnl-genl-3.0
+			# as a package.
+			#
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnl-genl-3.0 with pkg-config" >&5
+$as_echo_n "checking for libnl-genl-3.0 with pkg-config... " >&6; }
+			if "$PKGCONFIG" libnl-genl-3.0; then
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
+$as_echo "found" >&6; }
+				pkg_config_found_libnl=yes
+				libnl_genl_cflags=`"$PKGCONFIG" --cflags libnl-genl-3.0`
+				V_INCLS="$V_INCLS ${libnl_genl_cflags}"
+				libnl_genl_libs=`"$PKGCONFIG" --libs libnl-genl-3.0`
+				LIBS="${libnl_genl_libs} $LIBS"
 
-                incdir=-I/usr/include/libnl3
-                libnldir=
-                case "$with_libnl" in
+$as_echo "#define HAVE_LIBNL 1" >>confdefs.h
 
-                yes|if_available)
-                  ;;
+			else
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+			fi
+		fi
 
-                *)
-                  if test -d $withval; then
-                    libnldir=-L${withval}/lib/.libs
-                    incdir=-I${withval}/include
-                  fi
-                  ;;
-                esac
+		if test x$pkg_config_found_libnl != xyes; then
+			#
+			# OK, either we don't have pkg-config or there
+			# wasn't a .pc file for it; Check for it directly.
+			#
+			case "$with_libnl" in
 
-		#
-		# Try libnl 3.x first.
-		#
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl-3" >&5
+			yes|if_available)
+				incdir=-I/usr/include/libnl3
+				libnldir=
+				;;
+
+			*)
+				if test -d $withval; then
+					libnldir=-L${withval}/lib
+					incdir=-I${withval}/include
+				fi
+				;;
+			esac
+
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl-3" >&5
 $as_echo_n "checking for nl_socket_alloc in -lnl-3... " >&6; }
 if ${ac_cv_lib_nl_3_nl_socket_alloc+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -6575,195 +6990,31 @@
 $as_echo "$ac_cv_lib_nl_3_nl_socket_alloc" >&6; }
 if test "x$ac_cv_lib_nl_3_nl_socket_alloc" = xyes; then :
 
-			#
-			# Yes, we have libnl 3.x.
-			#
-			LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS"
+				#
+				# Yes, we have libnl 3.x.
+				#
+				LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS"
 
 $as_echo "#define HAVE_LIBNL 1" >>confdefs.h
 
+				V_INCLS="$V_INCLS ${incdir}"
 
-$as_echo "#define HAVE_LIBNL_3_x 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_NLE 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_SOCKETS 1" >>confdefs.h
-
-			V_INCLS="$V_INCLS ${incdir}"
-			have_any_nl="yes"
-
-fi
-
-
-		if test x$have_any_nl = xno ; then
-			#
-			# Try libnl 2.x
-			#
-			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl" >&5
-$as_echo_n "checking for nl_socket_alloc in -lnl... " >&6; }
-if ${ac_cv_lib_nl_nl_socket_alloc+:} false; then :
-  $as_echo_n "(cached) " >&6
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lnl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char nl_socket_alloc ();
-int
-main ()
-{
-return nl_socket_alloc ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_nl_nl_socket_alloc=yes
-else
-  ac_cv_lib_nl_nl_socket_alloc=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_nl_socket_alloc" >&5
-$as_echo "$ac_cv_lib_nl_nl_socket_alloc" >&6; }
-if test "x$ac_cv_lib_nl_nl_socket_alloc" = xyes; then :
 
 				#
-				# Yes, we have libnl 2.x.
+				# No, we don't have libnl at all.
+				# Fail if the user explicitly requested
+				# it.
 				#
-				LIBS="${libnldir} -lnl-genl -lnl $LIBS"
-
-$as_echo "#define HAVE_LIBNL 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_2_x 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_NLE 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_SOCKETS 1" >>confdefs.h
-
-				have_any_nl="yes"
+				if test x$with_libnl = xyes ; then
+					as_fn_error $? "libnl support requested but libnl not found" "$LINENO" 5
+				fi
 
 fi
 
 		fi
-
-		if test x$have_any_nl = xno ; then
-			#
-			# No, we don't; do we have libnl 1.x?
-			#
-			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_handle_alloc in -lnl" >&5
-$as_echo_n "checking for nl_handle_alloc in -lnl... " >&6; }
-if ${ac_cv_lib_nl_nl_handle_alloc+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lnl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char nl_handle_alloc ();
-int
-main ()
-{
-return nl_handle_alloc ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_nl_nl_handle_alloc=yes
-else
-  ac_cv_lib_nl_nl_handle_alloc=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_nl_handle_alloc" >&5
-$as_echo "$ac_cv_lib_nl_nl_handle_alloc" >&6; }
-if test "x$ac_cv_lib_nl_nl_handle_alloc" = xyes; then :
-
-				#
-				# Yes.
-				#
-				LIBS="${libnldir} -lnl $LIBS"
-
-$as_echo "#define HAVE_LIBNL 1" >>confdefs.h
-
-				have_any_nl="yes"
-
-fi
-
-		fi
-
-		if test x$have_any_nl = xno ; then
-			#
-			# No, we don't have libnl at all.
-			#
-			if test x$with_libnl = xyes ; then
-				as_fn_error $? "libnl support requested but libnl not found" "$LINENO" 5
-			fi
-		fi
 	fi
 
-	for ac_header in linux/ethtool.h
-do :
-  ac_fn_c_check_header_compile "$LINENO" "linux/ethtool.h" "ac_cv_header_linux_ethtool_h" "
-$ac_includes_default
-#include <linux/types.h>
-
-"
-if test "x$ac_cv_header_linux_ethtool_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LINUX_ETHTOOL_H 1
-_ACEOF
-
-fi
-
-done
-
-
-	#
-	# Check to see if struct tpacket_stats is defined in
-	# <linux/if_packet.h>.  If so, then pcap-linux.c can use this
-	# to report proper statistics.
-	#
-	# -Scott Barron
-	#
-	ac_fn_c_check_type "$LINENO" "struct tpacket_stats" "ac_cv_type_struct_tpacket_stats" "
-		#include <linux/if_packet.h>
-
-"
-if test "x$ac_cv_type_struct_tpacket_stats" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_TPACKET_STATS 1
-_ACEOF
-
-
-fi
-
-
 	#
 	# Check to see if the tpacket_auxdata struct has a tp_vlan_tci member.
 	#
@@ -6790,6 +7041,11 @@
 
 bpf)
 	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-bpf.c"
+
+	#
 	# Check whether we have the *BSD-style ioctls.
 	#
 	for ac_header in net/if_media.h
@@ -6828,12 +7084,44 @@
 
 	;;
 
+pf)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-pf.c"
+	;;
+
+snit)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-snit.c"
+	;;
+
+snoop)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-snoop.c"
+	;;
+
 dag)
 	#
 	# --with-pcap=dag is the only way to get here, and it means
 	# "DAG support but nothing else"
 	#
 	V_DEFS="$V_DEFS -DDAG_ONLY"
+	PLATFORM_C_SRC="pcap-dag.c"
+	xxx_only=yes
+	;;
+
+dpdk)
+	#
+	# --with-pcap=dpdk is the only way to get here, and it means
+	# "DPDK support but nothing else"
+	#
+	V_DEFS="$V_DEFS -DDPDK_ONLY"
+	PLATFORM_C_SRC="pcap-dpdk.c"
 	xxx_only=yes
 	;;
 
@@ -6843,6 +7131,7 @@
 	# "Septel support but nothing else"
 	#
 	V_DEFS="$V_DEFS -DSEPTEL_ONLY"
+	PLATFORM_C_SRC="pcap-septel.c"
 	xxx_only=yes
 	;;
 
@@ -6852,10 +7141,15 @@
 	# "SNF support but nothing else"
 	#
 	V_DEFS="$V_DEFS -DSNF_ONLY"
+	PLATFORM_C_SRC="pcap-snf.c"
 	xxx_only=yes
 	;;
 
 null)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-null.c"
 	;;
 
 *)
@@ -6879,7 +7173,7 @@
 		    # We have the header, so we use "getifaddrs()" to
 		    # get the list of interfaces.
 		    #
-		    V_FINDALLDEVS=fad-getad.c
+		    PLATFORM_C_SRC="$PLATFORM_C_SRC fad-getad.c"
 
 else
 
@@ -6948,18 +7242,15 @@
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_have_siocglifconf" >&5
 $as_echo "$ac_cv_lbl_have_siocglifconf" >&6; }
 		if test $ac_cv_lbl_have_siocglifconf = yes ; then
-			V_FINDALLDEVS=fad-glifc.c
+			PLATFORM_C_SRC="$PLATFORM_C_SRC fad-glifc.c"
 		else
-			V_FINDALLDEVS=fad-gifc.c
+			PLATFORM_C_SRC="$PLATFORM_C_SRC fad-gifc.c"
 		fi
 
 fi
 
 fi
 
-fi
-
-
 case "$host_os" in
 linux*)
 	for ac_header in linux/net_tstamp.h
@@ -6981,21 +7272,6 @@
 	;;
 esac
 
-# Check whether --enable-packet-ring was given.
-if test "${enable_packet_ring+set}" = set; then :
-  enableval=$enable_packet_ring;
-else
-  enable_packet_ring=yes
-fi
-
-
-if test "x$enable_packet_ring" != "xno" ; then
-
-$as_echo "#define PCAP_SUPPORT_PACKET_RING 1" >>confdefs.h
-
-
-fi
-
 #
 # Check for socklen_t.
 #
@@ -7105,10 +7381,17 @@
 
 	if test -z "$dag_lib_dir"; then
 		dag_lib_dir="$dag_root/lib"
+		#
+		# Handle multiarch systems.
+		#
+		if test -d "$dag_lib_dir/$host"
+		then
+			dag_lib_dir="$dag_lib_dir/$host"
+		fi
 	fi
 
-	V_INCLS="$V_INCLS -I$dag_include_dir"
-
+	save_CFLAGS="$CFLAGS"
+	CFLAGS="$CFLAGS -I$dag_include_dir"
 	for ac_header in dagapi.h
 do :
   ac_fn_c_check_header_mongrel "$LINENO" "dagapi.h" "ac_cv_header_dagapi_h" "$ac_includes_default"
@@ -7124,14 +7407,16 @@
 
 	if test "$ac_cv_header_dagapi_h" = yes; then
 
+		V_INCLS="$V_INCLS -I$dag_include_dir"
+
 		if test $V_PCAP != dag ; then
-			 SSRC="$SSRC pcap-dag.c"
+			 MODULE_C_SRC="$MODULE_C_SRC pcap-dag.c"
 		fi
 
 		# Check for various DAG API functions.
 		# Don't need to save and restore LIBS to prevent -ldag being
 		# included if there's a found-action (arg 3).
-		saved_ldflags=$LDFLAGS
+		save_LDFLAGS="$LDFLAGS"
 		LDFLAGS="-L$dag_lib_dir"
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_attach_stream in -ldag" >&5
 $as_echo_n "checking for dag_attach_stream in -ldag... " >&6; }
@@ -7309,7 +7594,7 @@
 fi
 
 
-		LDFLAGS=$saved_ldflags
+		LDFLAGS="$save_LDFLAGS"
 
 		#
 		# We assume that if we have libdag we have libdagconf,
@@ -7388,10 +7673,11 @@
 		fi
 
 		if test "$want_dag" = yes; then
-	        	# User wanted DAG support but we couldn't find it.
+			# User wanted DAG support but we couldn't find it.
 			as_fn_error $? "DAG support requested with --with-dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support" "$LINENO" 5
 		fi
 	fi
+	CFLAGS="$save_CFLAGS"
 fi
 
 
@@ -7457,7 +7743,7 @@
 		ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o"
 
 		if test "$V_PCAP" != septel ; then
-			 SSRC="$SSRC pcap-septel.c"
+			 MODULE_C_SRC="$MODULE_C_SRC pcap-septel.c"
 		fi
 
 
@@ -7474,7 +7760,7 @@
 		fi
 
 		if test "$want_septel" = yes; then
-	        	# User wanted Septel support but we couldn't find it.
+			# User wanted Septel support but we couldn't find it.
 			as_fn_error $? "Septel support requested with --with-septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support" "$LINENO" 5
 		fi
 	fi
@@ -7558,11 +7844,18 @@
 
 	if test -z "$snf_lib_dir"; then
 		snf_lib_dir="$snf_root/lib"
+		#
+		# Handle multiarch systems.
+		#
+		if test -d "$snf_lib_dir/$host"
+		then
+			snf_lib_dir="$snf_lib_dir/$host"
+		fi
 	fi
 
 	if test -f "$snf_include_dir/snf.h"; then
 		# We found a header; make sure we can link with the library
-		saved_ldflags=$LDFLAGS
+		save_LDFLAGS="$LDFLAGS"
 		LDFLAGS="$LDFLAGS -L$snf_lib_dir"
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for snf_init in -lsnf" >&5
 $as_echo_n "checking for snf_init in -lsnf... " >&6; }
@@ -7604,7 +7897,7 @@
   ac_cv_lbl_snf_api="yes"
 fi
 
-		LDFLAGS="$saved_ldflags"
+		LDFLAGS="$save_LDFLAGS"
 		if test "$ac_cv_lbl_snf_api" = no; then
 			as_fn_error $? "SNF API cannot correctly be linked; check config.log" "$LINENO" 5
 		fi
@@ -7619,7 +7912,7 @@
 		LDFLAGS="$LDFLAGS -L$snf_lib_dir"
 
 		if test "$V_PCAP" != snf ; then
-			SSRC="$SSRC pcap-snf.c"
+			MODULE_C_SRC="$MODULE_C_SRC pcap-snf.c"
 		fi
 
 
@@ -7717,7 +8010,7 @@
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
 
-		SSRC="$SSRC pcap-tc.c"
+		MODULE_C_SRC="$MODULE_C_SRC pcap-tc.c"
 		V_INCLS="$V_INCLS $TURBOCAP_CFLAGS"
 		LIBS="$LIBS $TURBOCAP_LIBS -lTcApi -lpthread -lstdc++"
 
@@ -7729,7 +8022,7 @@
 $as_echo "no" >&6; }
 
 		if test "$want_turbocap" = yes; then
-	        	# User wanted Turbo support but we couldn't find it.
+			# User wanted Turbo support but we couldn't find it.
 			as_fn_error $? "TurboCap support requested with --with-turbocap, but the TurboCap headers weren't found: make sure the TurboCap support is installed or don't request TurboCap support" "$LINENO" 5
 		fi
 	fi
@@ -7869,10 +8162,142 @@
 fi
 
 
+	#
+	# Optionally, we may want to support SSL.
+	# Check for OpenSSL/libressl.
+	#
+	# First, try looking for it as a regular system library.
+	# Make sure we can find SSL_library_init() using the
+	# standard headers, just in case we're running a version
+	# of macOS that ships with the OpenSSL library but not
+	# the OpenSSL headers, and have also installed another
+	# version of OpenSSL with headers.
+	#
+	save_LIBS="$LIBS"
+	LIBS="-lssl -lcrypto"
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have a system OpenSSL/libressl that we can use" >&5
+$as_echo_n "checking whether we have a system OpenSSL/libressl that we can use... " >&6; }
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <openssl/ssl.h>
+
+int
+main ()
+{
+
+SSL_library_init();
+return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+		HAVE_OPENSSL=yes
+		OPENSSL_LIBS="-lssl -lcrypto"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	LIBS="$save_LIBS"
+
+	#
+	# If we didn't find it, check for it with pkg-config.
+	#
+	if test "x$HAVE_OPENSSL" != "xyes"; then
+		if test "x$PKGCONFIG" != "xno"; then
+			#
+			# We have pkg-config; see if we have OpenSSL/
+			# libressl installed as a package.
+			#
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL/libressl with pkg-config" >&5
+$as_echo_n "checking for OpenSSL/libressl with pkg-config... " >&6; }
+			if "$PKGCONFIG" openssl; then
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
+$as_echo "found" >&6; }
+				HAVE_OPENSSL=yes
+				OPENSSL_CFLAGS=`"$PKGCONFIG" --cflags openssl`
+				OPENSSL_LIBS=`"$PKGCONFIG" --libs openssl`
+			else
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+			fi
+		fi
+	fi
+
+	#
+	# If we didn't find it, check for it under /usr/local/opt/openssl;
+	# that's where Homebrew puts it on macOS.  Feel free to add other
+	# -L directories as necessary; the "system library" check should
+	# also handle "add-on library under /usr/local", so that shouldn't
+	# be necessary here.
+	#
+	if test "x$HAVE_OPENSSL" != "xyes"; then
+		save_CFLAGS="$CFLAGS"
+		save_LIBS="$LIBS"
+		CFLAGS="$CFLAGS -L/usr/local/opt/openssl/include"
+		LIBS="$LIBS -L/usr/local/opt/openssl/lib -lssl -lcrypto"
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have OpenSSL/libressl in /usr/local/opt that we can use" >&5
+$as_echo_n "checking whether we have OpenSSL/libressl in /usr/local/opt that we can use... " >&6; }
+		cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <openssl/ssl.h>
+
+int
+main ()
+{
+
+SSL_library_init();
+return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+			HAVE_OPENSSL=yes
+			OPENSSL_CFLAGS="-I/usr/local/opt/openssl/include"
+			OPENSSL_LIBS="-L/usr/local/opt/openssl/lib -lssl -lcrypto"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+		CFLAGS="$save_CFLAGS"
+		LIBS="$save_LIBS"
+	fi
+
+	#
+	# OK, did we find it?
+	#
+	if test "x$HAVE_OPENSSL" = "xyes"; then
+
+$as_echo "#define HAVE_OPENSSL 1" >>confdefs.h
+
+		CFLAGS="$CFLAGS $OPENSSL_CFLAGS"
+		LIBS="$LIBS $OPENSSL_LIBS"
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: OpenSSL not found" >&5
+$as_echo "$as_me: OpenSSL not found" >&6;}
+	fi
+
 
 $as_echo "#define ENABLE_REMOTE /**/" >>confdefs.h
 
-	SSRC="$SSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c"
+	REMOTE_C_SRC="$REMOTE_C_SRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
 	BUILD_RPCAPD=build-rpcapd
 	INSTALL_RPCAPD=install-rpcapd
 	;;
@@ -8146,28 +8571,59 @@
 test -n "$YACC" || YACC="yacc"
 
 
-#
-# Make sure it supports the -p flag and supports processing our
-# grammar.y.
-#
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for capable yacc/bison" >&5
-$as_echo_n "checking for capable yacc/bison... " >&6; }
+case "$YACC" in
+
+*yacc)
+	#
+	# Make sure this is Berkeley YACC, not AT&T YACC; the latter
+	# doesn't support reentrant parsers.  Run it with "-V";
+	# that succeeds and reports the version number with
+	# Berkeley YACC, but will (probably) fail with various
+	# vendor flavors of AT&T YACC.
+	#
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for capable yacc" >&5
+$as_echo_n "checking for capable yacc... " >&6; }
 if ${tcpdump_cv_capable_yacc+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if $YACC -p pcap_ -o /dev/null $srcdir/grammar.y >/dev/null 2>&1; then
-	    tcpdump_cv_capable_yacc=yes
-	else
-	    tcpdump_cv_capable_yacc=insufficient
-	fi
+  if $YACC -V >/dev/null 2>&1; then
+		tcpdump_cv_capable_yacc=yes
+	    else
+		tcpdump_cv_capable_yacc=insufficient
+	    fi
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcpdump_cv_capable_yacc" >&5
 $as_echo "$tcpdump_cv_capable_yacc" >&6; }
-if test $tcpdump_cv_capable_yacc = insufficient ; then
-	as_fn_error $? "$YACC is insufficient to compile libpcap.
+	if test $tcpdump_cv_capable_yacc = insufficient ; then
+	    as_fn_error $? "$YACC is insufficient to compile libpcap.
  libpcap requires Bison, a newer version of Berkeley YACC with support
  for reentrant parsers, or another YACC compatible with them." "$LINENO" 5
-fi
+	fi
+
+	#
+	# Berkeley YACC doesn't support "%define api.pure", so use
+	# "%pure-parser".
+	#
+	REENTRANT_PARSER="%pure-parser"
+	;;
+
+*)
+	#
+	# Bison prior to 2.4(.1) doesn't support "%define api.pure", so use
+	# "%pure-parser".
+	#
+	bison_major_version=`$YACC -V | sed -n 's/.* \([1-9][0-9]*\)\.[1-9][0-9.]*/\1/p'`
+	bison_minor_version=`$YACC -V | sed -n 's/.* [1-9][0-9]*\.\([1-9][0-9]*\).*/\1/p'`
+	if test "$bison_major_version" -lt 2 -o \
+	    \( "$bison_major_version" -eq 2 -a "$bison_major_version" -lt 4 \)
+	then
+		REENTRANT_PARSER="%pure-parser"
+	else
+		REENTRANT_PARSER="%define api.pure"
+	fi
+	;;
+esac
+
 
 #
 # Do various checks for various OSes and versions of those OSes.
@@ -8363,12 +8819,24 @@
   return 0;
 }
 _ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"; then :
 
 				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-				V_LIB_CCOPT_FAT="-arch x86_64 -arch i386"
-				V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386"
+				V_LIB_CCOPT_FAT="-arch x86_64"
+				V_LIB_LDFLAGS_FAT="-arch x86_64"
+
+				#
+				# OpenSSL installation on macOS seems
+				# to install only the libs for 64-bit
+				# x86 - at least that's what Brew does:
+				# only configure 32-bit builds if we
+				# don't have OpenSSL.
+				#
+				if test "$HAVE_OPENSSL" != yes; then
+					V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386"
+					V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386"
+				fi
 
 else
 
@@ -8400,7 +8868,8 @@
 				esac
 
 fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 			CFLAGS="$save_CFLAGS"
 			;;
 		esac
@@ -8473,7 +8942,7 @@
 	MAN_MISC_INFO=5
 	;;
 
-linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|midipix*)
+linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|haiku*|midipix*)
 	DYEXT="so"
 
 	#
@@ -9064,88 +9533,6 @@
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdeclaration-after-statement option" >&5
-$as_echo_n "checking whether the compiler supports the -Wdeclaration-after-statement option... " >&6; }
-	save_CFLAGS="$CFLAGS"
-	if expr "x-Wdeclaration-after-statement" : "x-W.*" >/dev/null
-	then
-	    CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wdeclaration-after-statement"
-	elif expr "x-Wdeclaration-after-statement" : "x-f.*" >/dev/null
-	then
-	    CFLAGS="$CFLAGS -Werror -Wdeclaration-after-statement"
-	elif expr "x-Wdeclaration-after-statement" : "x-m.*" >/dev/null
-	then
-	    CFLAGS="$CFLAGS -Werror -Wdeclaration-after-statement"
-	else
-	    CFLAGS="$CFLAGS -Wdeclaration-after-statement"
-	fi
-	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-return 0
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-		can_add_to_cflags=yes
-		#
-		# The compile supports this; do we have some C code for
-		# which the warning should *not* appear?
-		# We test the fourth argument because the third argument
-		# could contain quotes, breaking the test.
-		#
-		if test "x" != "x"
-		then
-		    CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
-		    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wdeclaration-after-statement " >&5
-$as_echo_n "checking whether -Wdeclaration-after-statement ... " >&6; }
-		    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-			#
-			# Not a problem.
-			#
-			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-else
-
-			#
-			# A problem.
-			#
-			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-			can_add_to_cflags=no
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-		fi
-		CFLAGS="$save_CFLAGS"
-		if test x"$can_add_to_cflags" = "xyes"
-		then
-		    V_CCOPT="$V_CCOPT -Wdeclaration-after-statement"
-		fi
-
-else
-
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-		CFLAGS="$save_CFLAGS"
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdocumentation option" >&5
 $as_echo_n "checking whether the compiler supports the -Wdocumentation option... " >&6; }
 	save_CFLAGS="$CFLAGS"
@@ -9556,6 +9943,170 @@
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wpointer-arith option" >&5
+$as_echo_n "checking whether the compiler supports the -Wpointer-arith option... " >&6; }
+	save_CFLAGS="$CFLAGS"
+	if expr "x-Wpointer-arith" : "x-W.*" >/dev/null
+	then
+	    CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wpointer-arith"
+	elif expr "x-Wpointer-arith" : "x-f.*" >/dev/null
+	then
+	    CFLAGS="$CFLAGS -Werror -Wpointer-arith"
+	elif expr "x-Wpointer-arith" : "x-m.*" >/dev/null
+	then
+	    CFLAGS="$CFLAGS -Werror -Wpointer-arith"
+	else
+	    CFLAGS="$CFLAGS -Wpointer-arith"
+	fi
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+return 0
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+		can_add_to_cflags=yes
+		#
+		# The compile supports this; do we have some C code for
+		# which the warning should *not* appear?
+		# We test the fourth argument because the third argument
+		# could contain quotes, breaking the test.
+		#
+		if test "x" != "x"
+		then
+		    CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
+		    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wpointer-arith " >&5
+$as_echo_n "checking whether -Wpointer-arith ... " >&6; }
+		    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+			#
+			# Not a problem.
+			#
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+			#
+			# A problem.
+			#
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+			can_add_to_cflags=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+		fi
+		CFLAGS="$save_CFLAGS"
+		if test x"$can_add_to_cflags" = "xyes"
+		then
+		    V_CCOPT="$V_CCOPT -Wpointer-arith"
+		fi
+
+else
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		CFLAGS="$save_CFLAGS"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wpointer-sign option" >&5
+$as_echo_n "checking whether the compiler supports the -Wpointer-sign option... " >&6; }
+	save_CFLAGS="$CFLAGS"
+	if expr "x-Wpointer-sign" : "x-W.*" >/dev/null
+	then
+	    CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wpointer-sign"
+	elif expr "x-Wpointer-sign" : "x-f.*" >/dev/null
+	then
+	    CFLAGS="$CFLAGS -Werror -Wpointer-sign"
+	elif expr "x-Wpointer-sign" : "x-m.*" >/dev/null
+	then
+	    CFLAGS="$CFLAGS -Werror -Wpointer-sign"
+	else
+	    CFLAGS="$CFLAGS -Wpointer-sign"
+	fi
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+return 0
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+		can_add_to_cflags=yes
+		#
+		# The compile supports this; do we have some C code for
+		# which the warning should *not* appear?
+		# We test the fourth argument because the third argument
+		# could contain quotes, breaking the test.
+		#
+		if test "x" != "x"
+		then
+		    CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
+		    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wpointer-sign " >&5
+$as_echo_n "checking whether -Wpointer-sign ... " >&6; }
+		    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+			#
+			# Not a problem.
+			#
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+			#
+			# A problem.
+			#
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+			can_add_to_cflags=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+		fi
+		CFLAGS="$save_CFLAGS"
+		if test x"$can_add_to_cflags" = "xyes"
+		then
+		    V_CCOPT="$V_CCOPT -Wpointer-sign"
+		fi
+
+else
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		CFLAGS="$save_CFLAGS"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wshadow option" >&5
 $as_echo_n "checking whether the compiler supports the -Wshadow option... " >&6; }
 	save_CFLAGS="$CFLAGS"
@@ -10081,6 +10632,88 @@
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wshorten-64-to-32 option" >&5
+$as_echo_n "checking whether the compiler supports the -Wshorten-64-to-32 option... " >&6; }
+	save_CFLAGS="$CFLAGS"
+	if expr "x-Wshorten-64-to-32" : "x-W.*" >/dev/null
+	then
+	    CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wshorten-64-to-32"
+	elif expr "x-Wshorten-64-to-32" : "x-f.*" >/dev/null
+	then
+	    CFLAGS="$CFLAGS -Werror -Wshorten-64-to-32"
+	elif expr "x-Wshorten-64-to-32" : "x-m.*" >/dev/null
+	then
+	    CFLAGS="$CFLAGS -Werror -Wshorten-64-to-32"
+	else
+	    CFLAGS="$CFLAGS -Wshorten-64-to-32"
+	fi
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+return 0
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+		can_add_to_cflags=yes
+		#
+		# The compile supports this; do we have some C code for
+		# which the warning should *not* appear?
+		# We test the fourth argument because the third argument
+		# could contain quotes, breaking the test.
+		#
+		if test "x" != "x"
+		then
+		    CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
+		    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wshorten-64-to-32 " >&5
+$as_echo_n "checking whether -Wshorten-64-to-32 ... " >&6; }
+		    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+			#
+			# Not a problem.
+			#
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+			#
+			# A problem.
+			#
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+			can_add_to_cflags=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+		fi
+		CFLAGS="$save_CFLAGS"
+		if test x"$can_add_to_cflags" = "xyes"
+		then
+		    V_CCOPT="$V_CCOPT -Wshorten-64-to-32"
+		fi
+
+else
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		CFLAGS="$save_CFLAGS"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
 	    fi
 
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports generating dependencies" >&5
@@ -10161,7 +10794,7 @@
 			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, with $ac_lbl_dependency_flag" >&5
 $as_echo "yes, with $ac_lbl_dependency_flag" >&6; }
 			DEPENDENCY_CFLAG="$ac_lbl_dependency_flag"
-			MKDEP='${srcdir}/mkdep'
+			MKDEP='${top_srcdir}/mkdep'
 		else
 			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
@@ -10169,7 +10802,7 @@
 			# We can't run mkdep, so have "make depend" do
 			# nothing.
 			#
-			MKDEP='${srcdir}/nomkdep'
+			MKDEP='${top_srcdir}/nomkdep'
 		fi
 		rm -rf conftest*
 	else
@@ -10179,7 +10812,7 @@
 		# We can't run mkdep, so have "make depend" do
 		# nothing.
 		#
-		MKDEP='${srcdir}/nomkdep'
+		MKDEP='${top_srcdir}/nomkdep'
 	fi
 
 
@@ -10268,100 +10901,6 @@
 fi
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if unaligned accesses fail" >&5
-$as_echo_n "checking if unaligned accesses fail... " >&6; }
-    if ${ac_cv_lbl_unaligned_fail+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case "$host_cpu" in
-
-	#
-	# These are CPU types where:
-	#
-	#	the CPU faults on an unaligned access, but at least some
-	#	OSes that support that CPU catch the fault and simulate
-	#	the unaligned access (e.g., Alpha/{Digital,Tru64} UNIX) -
-	#	the simulation is slow, so we don't want to use it;
-	#
-	#	the CPU, I infer (from the old
-	#
-	# XXX: should also check that they don't do weird things (like on arm)
-	#
-	#	comment) doesn't fault on unaligned accesses, but doesn't
-	#	do a normal unaligned fetch, either (e.g., presumably, ARM);
-	#
-	#	for whatever reason, the test program doesn't work
-	#	(this has been claimed to be the case for several of those
-	#	CPUs - I don't know what the problem is; the problem
-	#	was reported as "the test program dumps core" for SuperH,
-	#	but that's what the test program is *supposed* to do -
-	#	it dumps core before it writes anything, so the test
-	#	for an empty output file should find an empty output
-	#	file and conclude that unaligned accesses don't work).
-	#
-	# This run-time test won't work if you're cross-compiling, so
-	# in order to support cross-compiling for a particular CPU,
-	# we have to wire in the list of CPU types anyway, as far as
-	# I know, so perhaps we should just have a set of CPUs on
-	# which we know it doesn't work, a set of CPUs on which we
-	# know it does work, and have the script just fail on other
-	# cpu types and update it when such a failure occurs.
-	#
-	alpha*|arm*|bfin*|hp*|mips*|sh*|sparc*|ia64|nv1)
-		ac_cv_lbl_unaligned_fail=yes
-		;;
-
-	*)
-		cat >conftest.c <<EOF
-#		include <sys/types.h>
-#		include <sys/wait.h>
-#		include <stdio.h>
-		unsigned char a[5] = { 1, 2, 3, 4, 5 };
-		main() {
-		unsigned int i;
-		pid_t pid;
-		int status;
-		/* avoid "core dumped" message */
-		pid = fork();
-		if (pid <  0)
-			exit(2);
-		if (pid > 0) {
-			/* parent */
-			pid = waitpid(pid, &status, 0);
-			if (pid < 0)
-				exit(3);
-			exit(!WIFEXITED(status));
-		}
-		/* child */
-		i = *(unsigned int *)&a[1];
-		printf("%d\n", i);
-		exit(0);
-		}
-EOF
-		${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \
-		    conftest.c $LIBS >/dev/null 2>&1
-		if test ! -x conftest ; then
-						ac_cv_lbl_unaligned_fail=yes
-		else
-			./conftest >conftest.out
-			if test ! -s conftest.out ; then
-				ac_cv_lbl_unaligned_fail=yes
-			else
-				ac_cv_lbl_unaligned_fail=no
-			fi
-		fi
-		rm -f -r conftest* core core.conftest
-		;;
-	esac
-fi
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_unaligned_fail" >&5
-$as_echo "$ac_cv_lbl_unaligned_fail" >&6; }
-    if test $ac_cv_lbl_unaligned_fail = yes ; then
-
-$as_echo "#define LBL_ALIGN 1" >>confdefs.h
-
-    fi
 
 
 
@@ -10393,6 +10932,9 @@
 
 
 
+#
+# Various Linux-specific mechanisms.
+#
 # Check whether --enable-usb was given.
 if test "${enable_usb+set}" = set; then :
   enableval=$enable_usb;
@@ -10401,39 +10943,38 @@
 fi
 
 
-if test "xxx_only" = yes; then
-	# User requested something-else-only pcap, so they don't
-	# want USB support.
-	enable_usb=no
-fi
+#
+# If somebody requested an XXX-only pcap, that doesn't include
+# additional mechanisms.
+#
+if test "xxx_only" != yes; then
+  case "$host_os" in
+  linux*)
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux usbmon USB sniffing support" >&5
+$as_echo_n "checking for Linux usbmon USB sniffing support... " >&6; }
+    if test "x$enable_usb" != "xno" ; then
 
-if test "x$enable_usb" != "xno" ; then
-      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for USB sniffing support" >&5
-$as_echo_n "checking for USB sniffing support... " >&6; }
-   case "$host_os" in
-   linux*)
+$as_echo "#define PCAP_SUPPORT_LINUX_USBMON 1" >>confdefs.h
 
-$as_echo "#define PCAP_SUPPORT_USB 1" >>confdefs.h
-
-	USB_SRC=pcap-usb-linux.c
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+      MODULE_C_SRC="$MODULE_C_SRC pcap-usb-linux.c"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-	ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null`
-	if test $? -ne 0 ; then
-	  ac_usb_dev_name="usbmon"
-	fi
+      ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null`
+      if test $? -ne 0 ; then
+        ac_usb_dev_name="usbmon"
+      fi
 
 cat >>confdefs.h <<_ACEOF
 #define LINUX_USB_MON_DEV "/dev/$ac_usb_dev_name"
 _ACEOF
 
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: Device for USB sniffing is /dev/$ac_usb_dev_name" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: Device for USB sniffing is /dev/$ac_usb_dev_name" >&5
 $as_echo "$as_me: Device for USB sniffing is /dev/$ac_usb_dev_name" >&6;}
-	#
-	# Do we have a version of <linux/compiler.h> available?
-	# If so, we might need it for <linux/usbdevice_fs.h>.
-	#
-	for ac_header in linux/compiler.h
+      #
+      # Do we have a version of <linux/compiler.h> available?
+      # If so, we might need it for <linux/usbdevice_fs.h>.
+      #
+      for ac_header in linux/compiler.h
 do :
   ac_fn_c_check_header_mongrel "$LINENO" "linux/compiler.h" "ac_cv_header_linux_compiler_h" "$ac_includes_default"
 if test "x$ac_cv_header_linux_compiler_h" = xyes; then :
@@ -10445,11 +10986,11 @@
 
 done
 
-	if test "$ac_cv_header_linux_compiler_h" = yes; then
-	  #
-	  # Yes - include it when testing for <linux/usbdevice_fs.h>.
-	  #
-	  for ac_header in linux/usbdevice_fs.h
+      if test "$ac_cv_header_linux_compiler_h" = yes; then
+        #
+        # Yes - include it when testing for <linux/usbdevice_fs.h>.
+        #
+        for ac_header in linux/usbdevice_fs.h
 do :
   ac_fn_c_check_header_compile "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "#include <linux/compiler.h>
 "
@@ -10462,8 +11003,8 @@
 
 done
 
-	else
-	  for ac_header in linux/usbdevice_fs.h
+      else
+        for ac_header in linux/usbdevice_fs.h
 do :
   ac_fn_c_check_header_mongrel "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "$ac_includes_default"
 if test "x$ac_cv_header_linux_usbdevice_fs_h" = xyes; then :
@@ -10475,20 +11016,20 @@
 
 done
 
-	fi
-	if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then
-	  #
-	  # OK, does it define bRequestType?  Older versions of the kernel
-	  # define fields with names like "requesttype, "request", and
-	  # "value", rather than "bRequestType", "bRequest", and
-	  # "wValue".
-	  #
-	  ac_fn_c_check_member "$LINENO" "struct usbdevfs_ctrltransfer" "bRequestType" "ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" "
-		  $ac_includes_default
-		  #ifdef HAVE_LINUX_COMPILER_H
-		  #include <linux/compiler.h>
-		  #endif
-		  #include <linux/usbdevice_fs.h>
+      fi
+      if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then
+        #
+        # OK, does it define bRequestType?  Older versions of the kernel
+        # define fields with names like "requesttype, "request", and
+        # "value", rather than "bRequestType", "bRequest", and
+        # "wValue".
+        #
+        ac_fn_c_check_member "$LINENO" "struct usbdevfs_ctrltransfer" "bRequestType" "ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" "
+            $ac_includes_default
+            #ifdef HAVE_LINUX_COMPILER_H
+            #include <linux/compiler.h>
+            #endif
+            #include <linux/usbdevice_fs.h>
 
 "
 if test "x$ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" = xyes; then :
@@ -10500,44 +11041,23 @@
 
 fi
 
-	fi
-	;;
-    freebsd*)
-	#
-	# This just uses BPF in FreeBSD 8.4 and later; we don't need
-	# to check for anything special for capturing.
-	#
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, in FreeBSD 8.4 and later" >&5
-$as_echo "yes, in FreeBSD 8.4 and later" >&6; }
-	;;
-
-    *)
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+      fi
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-	;;
-esac
-fi
+    fi
 
-
-
-if test "xxx_only" != yes; then
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the platform could support netfilter sniffing" >&5
-$as_echo_n "checking whether the platform could support netfilter sniffing... " >&6; }
-	case "$host_os" in
-	linux*)
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-		#
-		# Life's too short to deal with trying to get this to compile
-		# if you don't get the right types defined with
-		# __KERNEL_STRICT_NAMES getting defined by some other include.
-		#
-		# Check whether the includes Just Work.  If not, don't turn on
-		# netfilter support.
-		#
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can compile the netfilter support" >&5
+    #
+    # Life's too short to deal with trying to get this to compile
+    # if you don't get the right types defined with
+    # __KERNEL_STRICT_NAMES getting defined by some other include.
+    #
+    # Check whether the includes Just Work.  If not, don't turn on
+    # netfilter support.
+    #
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can compile the netfilter support" >&5
 $as_echo_n "checking whether we can compile the netfilter support... " >&6; }
-		if ${ac_cv_netfilter_can_compile+:} false; then :
+    if ${ac_cv_netfilter_can_compile+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -10569,20 +11089,16 @@
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
 
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_netfilter_can_compile" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_netfilter_can_compile" >&5
 $as_echo "$ac_cv_netfilter_can_compile" >&6; }
-		if test $ac_cv_netfilter_can_compile = yes ; then
+    if test $ac_cv_netfilter_can_compile = yes ; then
 
 $as_echo "#define PCAP_SUPPORT_NETFILTER 1" >>confdefs.h
 
-		  NETFILTER_SRC=pcap-netfilter-linux.c
-		fi
-		;;
-	*)
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-		;;
-	esac
+      MODULE_C_SRC="$MODULE_C_SRC pcap-netfilter-linux.c"
+    fi
+    ;;
+  esac
 fi
 
 
@@ -10635,10 +11151,294 @@
 
 $as_echo "#define PCAP_SUPPORT_NETMAP 1" >>confdefs.h
 
-	    NETMAP_SRC=pcap-netmap.c
+	    MODULE_C_SRC="$MODULE_C_SRC pcap-netmap.c"
 	fi
 
+fi
 
+# Check for DPDK support.
+
+# Check whether --with-dpdk was given.
+if test "${with_dpdk+set}" = set; then :
+  withval=$with_dpdk;
+	if test "$withval" = no
+	then
+		# User doesn't want DPDK support.
+		want_dpdk=no
+	elif test "$withval" = yes
+	then
+		# User wants DPDK support but hasn't specified a directory.
+		want_dpdk=yes
+	else
+		# User wants DPDK support and has specified a directory,
+		# so use the provided value.
+		want_dpdk=yes
+		dpdk_dir=$withval
+	fi
+
+else
+
+	if test "$V_PCAP" = dpdk; then
+		# User requested DPDK-only libpcap, so we'd better have
+		# the DPDK API.
+		want_dpdk=yes
+	elif test "xxx_only" = yes; then
+		# User requested something-else-only pcap, so they don't
+		# want DPDK support.
+		want_dpdk=no
+	else
+		#
+		# Use DPDK API if present, otherwise don't
+		#
+		want_dpdk=ifpresent
+	fi
+
+fi
+
+
+if test "$want_dpdk" != no; then
+	if test "x$PKGCONFIG" != "xno"
+	then
+		#
+		# We have pkg-config; see if we have DPDK installed
+		# as a package.
+		#
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DPDK with pkg-config" >&5
+$as_echo_n "checking for DPDK with pkg-config... " >&6; }
+		if "$PKGCONFIG" libdpdk
+		then
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
+$as_echo "found" >&6; }
+			found_dpdk_with_pkg_config=yes
+			DPDK_CFLAGS=`"$PKGCONFIG" --cflags libdpdk`
+			DPDK_LDFLAGS=`"$PKGCONFIG" --libs libdpdk`
+		else
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+		fi
+	fi
+
+	#
+	# If we didn't find it with pkg-config, try checking for
+	# it manually.
+	#
+	if test "x$found_dpdk_with_pkg_config" != "xyes"
+	then
+		if test -z "$dpdk_dir"; then
+			#
+			# The user didn't specify a directory containing
+			# the DPDK headers and libraries.  If we find
+			# a /usr/local/include/dpdk directory, assume
+			# it's /usr/local, otherwise assume it's /usr.
+			#
+			if test -d "/usr/local/include/dpdk"; then
+				dpdk_dir="/usr/local"
+			else
+				dpdk_dir="/usr"
+			fi
+		fi
+		#
+		# The convention appears to be that 1) there's a "dpdk"
+		# subdirectory of the include directory, containing DPDK
+		# headers (at least in the installation on Ubuntu with
+		# the system DPDK packages) and 2) includes of DPDK
+		# headers don't use "dpdk/{header}" (at least from the
+		# way the DPDK documentation is written).
+		#
+		# So we add "/dpdk" to the include directory, and always
+		# add that to the list of include directories to search.
+		#
+		dpdk_inc_dir="$dpdk_dir/include/dpdk"
+		dpdk_inc_flags="-I$dpdk_inc_dir"
+		dpdk_lib_dir="$dpdk_dir/lib"
+		#
+		# Handle multiarch systems.
+		#
+		# Step 1: run the C compiler with the -dumpmachine option;
+		# if it succeeds, the output would be the multiarch directory
+		# name if your system has multiarch directories.
+		#
+		multiarch_dir=`$CC -dumpmachine 2>/dev/null`
+		if test ! -z "$multiarch_dir"
+		then
+			#
+			# OK, we have a multiarch directory.
+			#
+			# Now deal with includes.  On Ubuntu 20.04, for
+			# example, we have /usr/include/dpdk *and*
+			# /usr/include/$multiarch_dir/dpdk, and must
+			# search both.
+			#
+			if test -d "$dpdk_dir/include/$multiarch_dir/dpdk"
+			then
+				dpdk_inc_flags="-I$dpdk_dir/include/$multiarch_dir/dpdk $dpdk_inc_flags"
+			fi
+
+			#
+			# Now deal with libraries.
+			#
+			if test -d "$dpdk_lib_dir/$multiarch_dir"
+			then
+				dpdk_lib_dir="$dpdk_lib_dir/$multiarch_dir"
+			fi
+		fi
+		DPDK_MACHINE_CFLAGS="-march=native"
+		DPDK_CFLAGS="$DPDK_MACHINE_CFLAGS $dpdk_inc_flags"
+		DPDK_LDFLAGS="-L$dpdk_lib_dir -ldpdk -lrt -lm -lnuma -ldl -pthread"
+	fi
+
+	save_CFLAGS="$CFLAGS"
+	save_LIBS="$LIBS"
+	save_LDFLAGS="$LDFLAGS"
+	CFLAGS="$CFLAGS $DPDK_CFLAGS"
+	LIBS="$LIBS $DPDK_LDFLAGS"
+	LDFLAGS="$LDFLAGS $DPDK_LDFLAGS"
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can compile the DPDK support" >&5
+$as_echo_n "checking whether we can compile the DPDK support... " >&6; }
+	if ${ac_cv_dpdk_can_compile+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+$ac_includes_default
+#include <rte_common.h>
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_dpdk_can_compile=yes
+else
+  ac_cv_dpdk_can_compile=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dpdk_can_compile" >&5
+$as_echo "$ac_cv_dpdk_can_compile" >&6; }
+
+	#
+	# We include rte_bus.h, and older versions of DPDK
+	# didn't have it, so check for it.
+	#
+	if test "$ac_cv_dpdk_can_compile" = yes; then
+		#
+		# This runs the preprocessor, so make sure it
+		# looks in the DPDK directories.  Instead of
+		# including dpdk/XXX.h, we include just XXX.h
+		# and assume DPDK_CFLAGS is the directory
+		# containing the DPDK headers (that's how
+		# pkg-config sets it, at least on Ubuntu),
+		# so just looking under /usr/include won't
+		# find it.
+		#
+		save_CPPFLAGS="$CPPFLAGS"
+		CPPFLAGS="$CPPFLAGS $DPDK_CFLAGS"
+		ac_fn_c_check_header_mongrel "$LINENO" "rte_bus.h" "ac_cv_header_rte_bus_h" "$ac_includes_default"
+if test "x$ac_cv_header_rte_bus_h" = xyes; then :
+
+fi
+
+
+		CPPFLAGS="$save_CPPFLAGS"
+	fi
+
+	#
+	# We call rte_eth_dev_count_avail(), and older versions
+	# of DPDK didn't have it, so check for it.
+	#
+	if test "$ac_cv_header_rte_bus_h" = yes; then
+		ac_fn_c_check_func "$LINENO" "rte_eth_dev_count_avail" "ac_cv_func_rte_eth_dev_count_avail"
+if test "x$ac_cv_func_rte_eth_dev_count_avail" = xyes; then :
+
+fi
+
+	fi
+
+	CFLAGS="$save_CFLAGS"
+	LIBS="$save_LIBS"
+	LDFLAGS="$save_LDFLAGS"
+
+	if test "$ac_cv_func_rte_eth_dev_count_avail" = yes; then
+		CFLAGS="$CFLAGS $DPDK_CFLAGS"
+		LIBS="$LIBS $DPDK_LDFLAGS"
+		LDFLAGS="$LDFLAGS $DPDK_LDFLAGS"
+		V_INCLS="$V_INCLS $DPDK_CFLAGS"
+
+$as_echo "#define PCAP_SUPPORT_DPDK 1" >>confdefs.h
+
+		if test $V_PCAP != dpdk ; then
+			MODULE_C_SRC="$MODULE_C_SRC pcap-dpdk.c"
+		fi
+
+		#
+		# Check whether the rte_ether.h file defines
+		# struct ether_addr or struct rte_ether_addr.
+		#
+		# ("API compatibility?  That's for losers!")
+		#
+		ac_fn_c_check_type "$LINENO" "struct rte_ether_addr" "ac_cv_type_struct_rte_ether_addr" "
+			#include <rte_ether.h>
+
+"
+if test "x$ac_cv_type_struct_rte_ether_addr" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_RTE_ETHER_ADDR 1
+_ACEOF
+
+
+fi
+
+	else
+		if test "$V_PCAP" = dpdk; then
+			# User requested DPDK-only capture support, but
+			# we couldn't the DPDK API support at all, or we
+			# found it but it wasn't a sufficiently recent
+			# version.
+			if test "$ac_cv_dpdk_can_compile" != yes; then
+				#
+				# Couldn't even find the headers.
+				#
+				as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but the DPDK headers weren't found at $dpdk_inc_dir: make sure the DPDK support is installed, specify a different path or paths if necessary, or don't request DPDK support" "$LINENO" 5
+			else
+				#
+				# Found the headers, but we couldn't find
+				# rte_bus.h or rte_eth_dev_count_avail(),
+				# we don't have a sufficiently recent
+				# version of DPDK.
+				#
+				as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but we require DPDK 18.x or later; install a newer version of DPDK, or don't request DPDK support" "$LINENO" 5
+			fi
+		fi
+
+		if test "$want_dpdk" = yes; then
+			# User requested DPDK-only capture support, but
+			# we couldn't the DPDK API support at all, or we
+			# found it but it wasn't a sufficiently recent
+			# version.
+			if test "$ac_cv_dpdk_can_compile" != yes; then
+				#
+				# Couldn't even find the headers.
+				#
+				as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but the DPDK headers weren't found at $dpdk_inc_dir: make sure the DPDK support is installed, specify a different path or paths if necessary, or don't request DPDK support" "$LINENO" 5
+			else
+				#
+				# Found the headers, but we couldn't find
+				# rte_bus.h or rte_eth_dev_count_avail(),
+				# we don't have a sufficiently recent
+				# version of DPDK.
+				#
+				as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but we require DPDK 18.x or later: install a newer version of DPDK, or don't request DPDK support" "$LINENO" 5
+			fi
+		fi
+	fi
 fi
 
 
@@ -10669,7 +11469,7 @@
 
 $as_echo "#define PCAP_SUPPORT_BT 1" >>confdefs.h
 
-			BT_SRC=pcap-bt-linux.c
+			MODULE_C_SRC="$MODULE_C_SRC pcap-bt-linux.c"
 			{ $as_echo "$as_me:${as_lineno-$LINENO}: Bluetooth sniffing is supported" >&5
 $as_echo "$as_me: Bluetooth sniffing is supported" >&6;}
 			ac_lbl_bluetooth_available=yes
@@ -10721,7 +11521,7 @@
 
 $as_echo "#define PCAP_SUPPORT_BT_MONITOR /**/" >>confdefs.h
 
-					    BT_MONITOR_SRC=pcap-bt-monitor-linux.c
+					    MODULE_C_SRC="$MODULE_C_SRC pcap-bt-monitor-linux.c"
 
 else
 
@@ -10763,8 +11563,6 @@
 		;;
 	esac
 
-
-
 fi
 
 # Check whether --enable-dbus was given.
@@ -10814,44 +11612,6 @@
 fi
 
 if test "x$enable_dbus" != "xno"; then
-	# Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_PKGCONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$PKGCONFIG"; then
-  ac_cv_prog_PKGCONFIG="$PKGCONFIG" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_PKGCONFIG="pkg-config"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  test -z "$ac_cv_prog_PKGCONFIG" && ac_cv_prog_PKGCONFIG="no"
-fi
-fi
-PKGCONFIG=$ac_cv_prog_PKGCONFIG
-if test -n "$PKGCONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5
-$as_echo "$PKGCONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
 	if test "x$PKGCONFIG" != "xno"; then
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for D-Bus" >&5
 $as_echo_n "checking for D-Bus... " >&6; }
@@ -10889,7 +11649,7 @@
 
 $as_echo "#define PCAP_SUPPORT_DBUS 1" >>confdefs.h
 
-				DBUS_SRC=pcap-dbus.c
+				MODULE_C_SRC="$MODULE_C_SRC pcap-dbus.c"
 				V_INCLS="$V_INCLS $DBUS_CFLAGS"
 
 else
@@ -10914,7 +11674,6 @@
 		fi
 	fi
 
-
 fi
 
 # Check whether --enable-rdma was given.
@@ -11009,7 +11768,7 @@
 
 $as_echo "#define PCAP_SUPPORT_RDMASNIFF /**/" >>confdefs.h
 
-					RDMA_SRC=pcap-rdmasniff.c
+					MODULE_C_SRC="$MODULE_C_SRC pcap-rdmasniff.c"
 					LIBS="-libverbs $LIBS"
 
 else
@@ -11029,7 +11788,6 @@
 fi
 
 
-
 fi
 
 # Find a good install program.  We prefer a C program (faster),
@@ -11131,7 +11889,7 @@
 
 ac_config_commands="$ac_config_commands default-1"
 
-ac_config_files="$ac_config_files Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_immediate_mode.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap rpcapd/Makefile rpcapd/rpcapd.manadmin rpcapd/rpcapd-config.manfile testprogs/Makefile"
+ac_config_files="$ac_config_files Makefile grammar.y pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_immediate_mode.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap rpcapd/Makefile rpcapd/rpcapd.manadmin rpcapd/rpcapd-config.manfile testprogs/Makefile"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -11639,7 +12397,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by pcap $as_me 1.9.1, which was
+This file was extended by pcap $as_me 1.10.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -11705,7 +12463,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-pcap config.status 1.9.1
+pcap config.status 1.10.0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -11835,6 +12593,7 @@
     "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
     "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "grammar.y") CONFIG_FILES="$CONFIG_FILES grammar.y" ;;
     "pcap-filter.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-filter.manmisc" ;;
     "pcap-linktype.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-linktype.manmisc" ;;
     "pcap-tstamp.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-tstamp.manmisc" ;;
diff --git a/configure.ac b/configure.ac
index eba2723..2ad28bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,7 +8,7 @@
 #
 # See
 #
-#	http://ftp.gnu.org/gnu/config/README
+#	https://ftp.gnu.org/gnu/config/README
 #
 # for the URLs to use to fetch new versions of config.guess and
 # config.sub.
@@ -24,13 +24,23 @@
 
 AC_LBL_C_INIT_BEFORE_CC(V_CCOPT, V_INCLS)
 #
-# Try to enable as many C99 features as we can.
-# At minimum, we want C++/C99-style // comments.
+# We require C99 or later.
+# Try to get it, which may involve adding compiler flags;
+# if that fails, give up.
 #
 AC_PROG_CC_C99
 if test "$ac_cv_prog_cc_c99" = "no"; then
-	AC_MSG_WARN([The C compiler does not support C99; there may be compiler errors])
+	AC_MSG_ERROR([The C compiler does not support C99])
 fi
+case "$host_os" in
+haiku*)
+	#
+	# Haiku's platform file is in C++.
+	#
+	AC_PROG_CXX
+	;;
+esac
+
 AC_LBL_C_INIT(V_CCOPT, V_INCLS)
 AC_LBL_SHLIBS_INIT
 AC_LBL_C_INLINE
@@ -50,7 +60,7 @@
 dnl and set "HAVE_SYS_IOCCOM_H" if we have it, otherwise
 dnl "AC_LBL_FIXINCLUDES" wouldn't work on some platforms such as Solaris.
 dnl
-AC_CHECK_HEADERS(sys/ioccom.h sys/sockio.h limits.h)
+AC_CHECK_HEADERS(sys/ioccom.h sys/sockio.h)
 AC_CHECK_HEADERS(netpacket/packet.h)
 AC_CHECK_HEADERS(net/pfvar.h, , , [#include <sys/types.h>
 #include <sys/socket.h>
@@ -75,12 +85,11 @@
 fi
 
 case "$host_os" in
-linux*|uclinux*)
-	AC_CHECK_HEADERS(linux/sockios.h linux/if_bonding.h,,,
-	[
-#include <sys/socket.h>
-#include <linux/if.h>
-	])
+haiku*)
+	#
+	# Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them.
+	#
+	CFLAGS="$CFLAGS -D_BSD_SOURCE"
 	;;
 esac
 
@@ -124,9 +133,9 @@
     ],
     [
 	#
-	# We don't have strerror_r; do we have strerror_s?
+	# We don't have strerror_r; do we have _wcserror_s?
 	#
-	AC_CHECK_FUNCS(strerror_s)
+	AC_CHECK_FUNCS(_wcserror_s)
     ])
 
 #
@@ -135,45 +144,17 @@
 AC_CHECK_FUNCS(vsyslog)
 
 #
-# Either:
+# Make sure we have vsnprintf() and snprintf(); we require them.
 #
-#	we have snprintf() and vsnprintf(), and have asprintf() and
-#	vasprintf();
-#
-#	we have snprintf() and vsnprintf(), but don't have asprintf()
-#	or vasprintf();
-#
-#	we have neither snprintf() nor vsnprintf(), and don't have
-#	asprintf() or vasprintf(), either.
-#
-# We assume that if we have asprintf() we have vasprintf(), as well
-# as snprintf() and vsnprintf(), and that if we have snprintf() we
-# have vsnprintf().
-#
-# For the first case, we don't need any replacement routines.
-# For the second case, we need replacement asprintf()/vasprintf()
-# routines.
-# For the third case, we need replacement snprintf()/vsnprintf() and
-# asprintf()/vasprintf() routines.
-#
-needsnprintf=no
-AC_CHECK_FUNCS(vsnprintf snprintf,,
-	[needsnprintf=yes])
+AC_CHECK_FUNC(vsnprintf,,
+    AC_MSG_ERROR([vsnprintf() is required but wasn't found]))
+AC_CHECK_FUNC(snprintf,,
+    AC_MSG_ERROR([snprintf() is required but wasn't found]))
+
 needasprintf=no
 AC_CHECK_FUNCS(vasprintf asprintf,,
 	[needasprintf=yes])
-if test $needsnprintf = yes; then
-	#
-	# We assume we have none of them; missing/snprintf.c supplies
-	# all of them.
-	#
-	AC_LIBOBJ([snprintf])
-elif test $needasprintf = yes; then
-	#
-	# We assume we have snprintf()/vsnprintf() but lack
-	# asprintf()/vasprintf(); missing/asprintf.c supplies
-	# the latter (using vsnprintf()).
-	#
+if test $needasprintf = yes; then
 	AC_LIBOBJ([asprintf])
 fi
 
@@ -609,20 +590,6 @@
 #
 VALGRINDTEST_SRC=
 
-#
-# SITA support is mutually exclusive with native capture support;
-# "--with-sita" selects SITA support.
-#
-AC_ARG_WITH(sita,
-AC_HELP_STRING([--with-sita],[include SITA support]),
-[
-	if test ! "x$withval" = "xno" ; then
-		AC_DEFINE(SITA,1,[include ACN support])
-		AC_MSG_NOTICE(Enabling SITA ACN support)
-		V_PCAP=sita
-	fi
-],
-[
 AC_ARG_WITH(pcap,
 AC_HELP_STRING([--with-pcap=TYPE],[use packet capture TYPE]))
 if test ! -z "$with_pcap" ; then
@@ -688,6 +655,7 @@
 	AC_CHECK_HEADERS(net/pfilt.h net/enet.h)
 	AC_CHECK_HEADERS(net/nit.h sys/net/nit.h)
 	AC_CHECK_HEADERS(linux/socket.h net/raw.h sys/dlpi.h)
+	AC_CHECK_HEADERS(config/HaikuConfig.h)
 
 	if test "$ac_cv_lbl_bpf_h_defines_biocsetif" = yes; then
 		#
@@ -713,11 +681,6 @@
 		# No prizes for guessing this one.
 		#
 		V_PCAP=linux
-
-		#
-		# XXX - this won't work with older kernels that have
-		# SOCK_PACKET sockets but not PF_PACKET sockets.
-		#
 		VALGRINDTEST_SRC=valgrindtest.c
 	elif test "$ac_cv_header_net_pfilt_h" = yes; then
 	        #
@@ -749,6 +712,11 @@
 		# DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others.
 		#
 		V_PCAP=dlpi
+	elif test "$ac_cv_header_config_HaikuConfig_h" = yes; then
+		#
+		# Haiku.
+		#
+		V_PCAP=haiku
 	else
 		#
 		# Nothing we support.
@@ -763,16 +731,16 @@
 AC_SUBST(VALGRINDTEST_SRC)
 
 #
-# Do capture-mechanism-dependent tests.
+# Do we have pkg-config?
+#
+AC_CHECK_PROG([PKGCONFIG], [pkg-config], [pkg-config], [no])
+
+#
+# Handle each capture type.
 #
 case "$V_PCAP" in
 dlpi)
 	#
-	# Needed for common functions used by pcap-[dlpi,libdlpi].c
-	#
- 	SSRC="dlpisubs.c"
-
-	#
 	# Checks for some header files.
 	#
 	AC_CHECK_HEADERS(sys/bufmod.h sys/dlpi_ext.h)
@@ -788,16 +756,30 @@
 	# Also, due to the bug above applications that link to libpcap with
 	# libdlpi will have to add "-L/lib" option to "configure".
 	#
-	saved_ldflags=$LDFLAGS
+	save_LDFLAGS="$LDFLAGS"
 	LDFLAGS="$LIBS -L/lib"
 	AC_CHECK_LIB(dlpi, dlpi_walk,
 		[
 			LIBS="-ldlpi $LIBS"
 			V_PCAP=libdlpi
+
+			#
+			# Capture module plus common code needed for
+			# common functions used by pcap-[dlpi,libdlpi].c
+			#
+			PLATFORM_C_SRC="pcap-libdlpi.c dlpisubs.c"
 			AC_DEFINE(HAVE_LIBDLPI,1,[if libdlpi exists])
 		],
-		V_PCAP=dlpi)
-	LDFLAGS=$saved_ldflags
+		[
+			V_PCAP=dlpi
+
+			#
+			# Capture module plus common code needed for
+			# common functions used by pcap-[dlpi,libdlpi].c
+			#
+			PLATFORM_C_SRC="pcap-dlpi.c dlpisubs.c"
+		])
+	LDFLAGS="$save_LDFLAGS"
 
 	#
 	# Checks whether <sys/dlpi.h> is usable, to catch weird SCO
@@ -832,8 +814,32 @@
 	    ])
 	;;
 
+enet)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-enet.c"
+	;;
+
+haiku)
+	#
+	# Capture module
+	#
+ 	PLATFORM_CXX_SRC="pcap-haiku.cpp"
+
+	#
+	# Just for the sake of it.
+	#
+	AC_CHECK_HEADERS(net/if.h net/if_dl.h net/if_types.h)
+	;;
+
 linux)
 	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-linux.c"
+
+	#
 	# Do we have the wireless extensions?
 	#
 	AC_CHECK_HEADERS(linux/wireless.h, [], [],
@@ -845,107 +851,78 @@
 
 	#
 	# Do we have libnl?
+	# We only want version 3.  Version 2 was, apparently,
+	# short-lived, and version 1 is source and binary
+	# incompatible with version 3, and it appears that,
+	# these days, everybody's using version 3.  We're
+	# not supporting older versions of the Linux kernel;
+	# let's drop support for older versions of libnl, too.
 	#
 	AC_ARG_WITH(libnl,
 	AC_HELP_STRING([--without-libnl],[disable libnl support @<:@default=yes, on Linux, if present@:>@]),
 		with_libnl=$withval,with_libnl=if_available)
 
 	if test x$with_libnl != xno ; then
-		have_any_nl="no"
-
-                incdir=-I/usr/include/libnl3
-                libnldir=
-                case "$with_libnl" in
-
-                yes|if_available)
-                  ;;
-
-                *)
-                  if test -d $withval; then
-                    libnldir=-L${withval}/lib/.libs
-                    incdir=-I${withval}/include
-                  fi
-                  ;;
-                esac
-
-		#
-		# Try libnl 3.x first.
-		#
-		AC_CHECK_LIB(nl-3, nl_socket_alloc,
-		[
+		if test "x$PKGCONFIG" != "xno"; then
 			#
-			# Yes, we have libnl 3.x.
+			# We have pkg-config; see if we have libnl-genl-3.0
+			# as a package.
 			#
-			LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS"
-			AC_DEFINE(HAVE_LIBNL,1,[if libnl exists])
-			AC_DEFINE(HAVE_LIBNL_3_x,1,[if libnl exists and is version 3.x])
-			AC_DEFINE(HAVE_LIBNL_NLE,1,[libnl has NLE_FAILURE])
-			AC_DEFINE(HAVE_LIBNL_SOCKETS,1,[libnl has new-style socket api])
-			V_INCLS="$V_INCLS ${incdir}"
-			have_any_nl="yes"
-		],[], ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 )
-
-		if test x$have_any_nl = xno ; then
-			#
-			# Try libnl 2.x
-			#
-			AC_CHECK_LIB(nl, nl_socket_alloc,
-			[
-				#
-				# Yes, we have libnl 2.x.
-				#
-				LIBS="${libnldir} -lnl-genl -lnl $LIBS"
+			AC_MSG_CHECKING([for libnl-genl-3.0 with pkg-config])
+			if "$PKGCONFIG" libnl-genl-3.0; then
+				AC_MSG_RESULT([found])
+				pkg_config_found_libnl=yes
+				libnl_genl_cflags=`"$PKGCONFIG" --cflags libnl-genl-3.0`
+				V_INCLS="$V_INCLS ${libnl_genl_cflags}"
+				libnl_genl_libs=`"$PKGCONFIG" --libs libnl-genl-3.0`
+				LIBS="${libnl_genl_libs} $LIBS"
 				AC_DEFINE(HAVE_LIBNL,1,[if libnl exists])
-				AC_DEFINE(HAVE_LIBNL_2_x,1,[if libnl exists and is version 2.x])
-				AC_DEFINE(HAVE_LIBNL_NLE,1,[libnl has NLE_FAILURE])
-				AC_DEFINE(HAVE_LIBNL_SOCKETS,1,[libnl has new-style socket api])
-				have_any_nl="yes"
-			])
-		fi
-
-		if test x$have_any_nl = xno ; then
-			#
-			# No, we don't; do we have libnl 1.x?
-			#
-			AC_CHECK_LIB(nl, nl_handle_alloc,
-			[
-				#
-				# Yes.
-				#
-				LIBS="${libnldir} -lnl $LIBS"
-				AC_DEFINE(HAVE_LIBNL,1,[if libnl exists])
-				have_any_nl="yes"
-			])
-		fi
-
-		if test x$have_any_nl = xno ; then
-			#
-			# No, we don't have libnl at all.
-			#
-			if test x$with_libnl = xyes ; then
-				AC_MSG_ERROR([libnl support requested but libnl not found])
+			else
+				AC_MSG_RESULT([not found])
 			fi
 		fi
+
+		if test x$pkg_config_found_libnl != xyes; then
+			#
+			# OK, either we don't have pkg-config or there
+			# wasn't a .pc file for it; Check for it directly.
+			#
+			case "$with_libnl" in
+
+			yes|if_available)
+				incdir=-I/usr/include/libnl3
+				libnldir=
+				;;
+
+			*)
+				if test -d $withval; then
+					libnldir=-L${withval}/lib
+					incdir=-I${withval}/include
+				fi
+				;;
+			esac
+
+			AC_CHECK_LIB(nl-3, nl_socket_alloc,
+			[
+				#
+				# Yes, we have libnl 3.x.
+				#
+				LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS"
+				AC_DEFINE(HAVE_LIBNL,1,[if libnl exists])
+				V_INCLS="$V_INCLS ${incdir}"
+			],[
+				#
+				# No, we don't have libnl at all.
+				# Fail if the user explicitly requested
+				# it.
+				#
+				if test x$with_libnl = xyes ; then
+					AC_MSG_ERROR([libnl support requested but libnl not found])
+				fi
+			], ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 )
+		fi
 	fi
 
-	AC_CHECK_HEADERS(linux/ethtool.h,,,
-	    [
-AC_INCLUDES_DEFAULT
-#include <linux/types.h>
-	    ])
-
-	#
-	# Check to see if struct tpacket_stats is defined in
-	# <linux/if_packet.h>.  If so, then pcap-linux.c can use this
-	# to report proper statistics.
-	#
-	# -Scott Barron
-	#
-	AC_CHECK_TYPES(struct tpacket_stats,,,
-	    [
-		#include <linux/if_packet.h>
-	    ])
-
 	#
 	# Check to see if the tpacket_auxdata struct has a tp_vlan_tci member.
 	#
@@ -963,6 +940,11 @@
 
 bpf)
 	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-bpf.c"
+
+	#
 	# Check whether we have the *BSD-style ioctls.
 	#
 	AC_CHECK_HEADERS(net/if_media.h)
@@ -981,12 +963,44 @@
 	    ])
 	;;
 
+pf)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-pf.c"
+	;;
+
+snit)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-snit.c"
+	;;
+
+snoop)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-snoop.c"
+	;;
+
 dag)
 	#
 	# --with-pcap=dag is the only way to get here, and it means
 	# "DAG support but nothing else"
 	#
 	V_DEFS="$V_DEFS -DDAG_ONLY"
+	PLATFORM_C_SRC="pcap-dag.c"
+	xxx_only=yes
+	;;
+
+dpdk)
+	#
+	# --with-pcap=dpdk is the only way to get here, and it means
+	# "DPDK support but nothing else"
+	#
+	V_DEFS="$V_DEFS -DDPDK_ONLY"
+	PLATFORM_C_SRC="pcap-dpdk.c"
 	xxx_only=yes
 	;;
 
@@ -996,6 +1010,7 @@
 	# "Septel support but nothing else"
 	#
 	V_DEFS="$V_DEFS -DSEPTEL_ONLY"
+	PLATFORM_C_SRC="pcap-septel.c"
 	xxx_only=yes
 	;;
 
@@ -1005,10 +1020,15 @@
 	# "SNF support but nothing else"
 	#
 	V_DEFS="$V_DEFS -DSNF_ONLY"
+	PLATFORM_C_SRC="pcap-snf.c"
 	xxx_only=yes
 	;;
 
 null)
+	#
+	# Capture module
+	#
+ 	PLATFORM_C_SRC="pcap-null.c"
 	;;
 
 *)
@@ -1033,7 +1053,7 @@
 		    # We have the header, so we use "getifaddrs()" to
 		    # get the list of interfaces.
 		    #
-		    V_FINDALLDEVS=fad-getad.c
+		    PLATFORM_C_SRC="$PLATFORM_C_SRC fad-getad.c"
 		],[
 		    #
 		    # We don't have the header - give up.
@@ -1077,13 +1097,12 @@
 			ac_cv_lbl_have_siocglifconf=no))
 		AC_MSG_RESULT($ac_cv_lbl_have_siocglifconf)
 		if test $ac_cv_lbl_have_siocglifconf = yes ; then
-			V_FINDALLDEVS=fad-glifc.c
+			PLATFORM_C_SRC="$PLATFORM_C_SRC fad-glifc.c"
 		else
-			V_FINDALLDEVS=fad-gifc.c
+			PLATFORM_C_SRC="$PLATFORM_C_SRC fad-gifc.c"
 		fi
 	])
 fi
-])
 
 dnl check for hardware timestamp support
 case "$host_os" in
@@ -1095,15 +1114,6 @@
 	;;
 esac
 
-AC_ARG_ENABLE([packet-ring],
-[AC_HELP_STRING([--enable-packet-ring],[enable packet ring support on Linux @<:@default=yes@:>@])],
-,enable_packet_ring=yes)
-
-if test "x$enable_packet_ring" != "xno" ; then
-	AC_DEFINE(PCAP_SUPPORT_PACKET_RING, 1, [use packet ring capture support on Linux if available])
-	AC_SUBST(PCAP_SUPPORT_PACKET_RING)
-fi
-
 #
 # Check for socklen_t.
 #
@@ -1188,22 +1198,31 @@
 
 	if test -z "$dag_lib_dir"; then
 		dag_lib_dir="$dag_root/lib"
+		#
+		# Handle multiarch systems.
+		#
+		if test -d "$dag_lib_dir/$host"
+		then
+			dag_lib_dir="$dag_lib_dir/$host"
+		fi
 	fi
 
-	V_INCLS="$V_INCLS -I$dag_include_dir"
-
+	save_CFLAGS="$CFLAGS"
+	CFLAGS="$CFLAGS -I$dag_include_dir"
 	AC_CHECK_HEADERS([dagapi.h])
 
 	if test "$ac_cv_header_dagapi_h" = yes; then
 
+		V_INCLS="$V_INCLS -I$dag_include_dir"
+
 		if test $V_PCAP != dag ; then
-			 SSRC="$SSRC pcap-dag.c"
+			 MODULE_C_SRC="$MODULE_C_SRC pcap-dag.c"
 		fi
 
 		# Check for various DAG API functions.
 		# Don't need to save and restore LIBS to prevent -ldag being
 		# included if there's a found-action (arg 3).
-		saved_ldflags=$LDFLAGS
+		save_LDFLAGS="$LDFLAGS"
 		LDFLAGS="-L$dag_lib_dir"
 		AC_CHECK_LIB([dag], [dag_attach_stream],
 		    [],
@@ -1214,7 +1233,7 @@
 		AC_CHECK_LIB([dag],[dag_get_stream_erf_types], [
 			AC_DEFINE(HAVE_DAG_GET_STREAM_ERF_TYPES, 1, [define if you have dag_get_stream_erf_types()])])
 
-		LDFLAGS=$saved_ldflags
+		LDFLAGS="$save_LDFLAGS"
 
 		#
 		# We assume that if we have libdag we have libdagconf,
@@ -1246,10 +1265,11 @@
 		fi
 
 		if test "$want_dag" = yes; then
-	        	# User wanted DAG support but we couldn't find it.
+			# User wanted DAG support but we couldn't find it.
 			AC_MSG_ERROR([DAG support requested with --with-dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support])
 		fi
 	fi
+	CFLAGS="$save_CFLAGS"
 fi
 
 AC_ARG_WITH(septel,
@@ -1308,7 +1328,7 @@
 		ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o"
 
 		if test "$V_PCAP" != septel ; then
-			 SSRC="$SSRC pcap-septel.c"
+			 MODULE_C_SRC="$MODULE_C_SRC pcap-septel.c"
 		fi
 
 		AC_DEFINE(HAVE_SEPTEL_API, 1, [define if you have the Septel API])
@@ -1322,7 +1342,7 @@
 		fi
 
 		if test "$want_septel" = yes; then
-	        	# User wanted Septel support but we couldn't find it.
+			# User wanted Septel support but we couldn't find it.
 			AC_MSG_ERROR([Septel support requested with --with-septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support])
 		fi
 	fi
@@ -1394,14 +1414,21 @@
 
 	if test -z "$snf_lib_dir"; then
 		snf_lib_dir="$snf_root/lib"
+		#
+		# Handle multiarch systems.
+		#
+		if test -d "$snf_lib_dir/$host"
+		then
+			snf_lib_dir="$snf_lib_dir/$host"
+		fi
 	fi
 
 	if test -f "$snf_include_dir/snf.h"; then
 		# We found a header; make sure we can link with the library
-		saved_ldflags=$LDFLAGS
+		save_LDFLAGS="$LDFLAGS"
 		LDFLAGS="$LDFLAGS -L$snf_lib_dir"
 		AC_CHECK_LIB([snf], [snf_init], [ac_cv_lbl_snf_api="yes"])
-		LDFLAGS="$saved_ldflags"
+		LDFLAGS="$save_LDFLAGS"
 		if test "$ac_cv_lbl_snf_api" = no; then
 			AC_MSG_ERROR(SNF API cannot correctly be linked; check config.log)
 		fi
@@ -1415,7 +1442,7 @@
 		LDFLAGS="$LDFLAGS -L$snf_lib_dir"
 
 		if test "$V_PCAP" != snf ; then
-			SSRC="$SSRC pcap-snf.c"
+			MODULE_C_SRC="$MODULE_C_SRC pcap-snf.c"
 		fi
 
 		AC_DEFINE(HAVE_SNF_API, 1, [define if you have the Myricom SNF API])
@@ -1492,7 +1519,7 @@
 	if test $ac_cv_lbl_turbocap_api = yes; then
 		AC_MSG_RESULT(yes)
 
-		SSRC="$SSRC pcap-tc.c"
+		MODULE_C_SRC="$MODULE_C_SRC pcap-tc.c"
 		V_INCLS="$V_INCLS $TURBOCAP_CFLAGS"
 		LIBS="$LIBS $TURBOCAP_LIBS -lTcApi -lpthread -lstdc++"
 
@@ -1501,7 +1528,7 @@
 		AC_MSG_RESULT(no)
 
 		if test "$want_turbocap" = yes; then
-	        	# User wanted Turbo support but we couldn't find it.
+			# User wanted Turbo support but we couldn't find it.
 			AC_MSG_ERROR([TurboCap support requested with --with-turbocap, but the TurboCap headers weren't found: make sure the TurboCap support is installed or don't request TurboCap support])
 		fi
 	fi
@@ -1567,9 +1594,103 @@
 		#include <sys/socket.h>
 	    ])
 
+	#
+	# Optionally, we may want to support SSL.
+	# Check for OpenSSL/libressl.
+	#
+	# First, try looking for it as a regular system library.
+	# Make sure we can find SSL_library_init() using the
+	# standard headers, just in case we're running a version
+	# of macOS that ships with the OpenSSL library but not
+	# the OpenSSL headers, and have also installed another
+	# version of OpenSSL with headers.
+	#
+	save_LIBS="$LIBS"
+	LIBS="-lssl -lcrypto"
+	AC_MSG_CHECKING(whether we have a system OpenSSL/libressl that we can use)
+	AC_TRY_LINK(
+	    [
+#include <openssl/ssl.h>
+	    ],
+	    [
+SSL_library_init();
+return 0;
+	    ],
+	    [
+		AC_MSG_RESULT(yes)
+		HAVE_OPENSSL=yes
+		OPENSSL_LIBS="-lssl -lcrypto"
+	    ],
+	    AC_MSG_RESULT(no))
+	LIBS="$save_LIBS"
+
+	#
+	# If we didn't find it, check for it with pkg-config.
+	#
+	if test "x$HAVE_OPENSSL" != "xyes"; then
+		if test "x$PKGCONFIG" != "xno"; then
+			#
+			# We have pkg-config; see if we have OpenSSL/
+			# libressl installed as a package.
+			#
+			AC_MSG_CHECKING([for OpenSSL/libressl with pkg-config])
+			if "$PKGCONFIG" openssl; then
+				AC_MSG_RESULT([found])
+				HAVE_OPENSSL=yes
+				OPENSSL_CFLAGS=`"$PKGCONFIG" --cflags openssl`
+				OPENSSL_LIBS=`"$PKGCONFIG" --libs openssl`
+			else
+				AC_MSG_RESULT([not found])
+			fi
+		fi
+	fi
+
+	#
+	# If we didn't find it, check for it under /usr/local/opt/openssl;
+	# that's where Homebrew puts it on macOS.  Feel free to add other
+	# -L directories as necessary; the "system library" check should
+	# also handle "add-on library under /usr/local", so that shouldn't
+	# be necessary here.
+	#
+	if test "x$HAVE_OPENSSL" != "xyes"; then
+		save_CFLAGS="$CFLAGS"
+		save_LIBS="$LIBS"
+		CFLAGS="$CFLAGS -L/usr/local/opt/openssl/include"
+		LIBS="$LIBS -L/usr/local/opt/openssl/lib -lssl -lcrypto"
+		AC_MSG_CHECKING(whether we have OpenSSL/libressl in /usr/local/opt that we can use)
+		AC_TRY_LINK(
+		    [
+#include <openssl/ssl.h>
+		    ],
+		    [
+SSL_library_init();
+return 0;
+		    ],
+		    [
+			AC_MSG_RESULT(yes)
+			HAVE_OPENSSL=yes
+			OPENSSL_CFLAGS="-I/usr/local/opt/openssl/include"
+			OPENSSL_LIBS="-L/usr/local/opt/openssl/lib -lssl -lcrypto"
+		    ],
+		    AC_MSG_RESULT(no))
+		CFLAGS="$save_CFLAGS"
+		LIBS="$save_LIBS"
+	fi
+
+	#
+	# OK, did we find it?
+	#
+	if test "x$HAVE_OPENSSL" = "xyes"; then
+		AC_DEFINE([HAVE_OPENSSL], [1], [Use OpenSSL])
+		CFLAGS="$CFLAGS $OPENSSL_CFLAGS"
+		LIBS="$LIBS $OPENSSL_LIBS"
+	else
+		AC_MSG_NOTICE(OpenSSL not found)
+	fi
+
 	AC_DEFINE(ENABLE_REMOTE,,
 	    [Define to 1 if remote packet capture is to be supported])
-	SSRC="$SSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c"
+	REMOTE_C_SRC="$REMOTE_C_SRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
 	BUILD_RPCAPD=build-rpcapd
 	INSTALL_RPCAPD=install-rpcapd
 	;;
@@ -1621,21 +1742,52 @@
 #
 AC_PROG_YACC
 
-#
-# Make sure it supports the -p flag and supports processing our
-# grammar.y.
-#
-AC_CACHE_CHECK([for capable yacc/bison], tcpdump_cv_capable_yacc,
-	if $YACC -p pcap_ -o /dev/null $srcdir/grammar.y >/dev/null 2>&1; then
-	    tcpdump_cv_capable_yacc=yes
-	else
-	    tcpdump_cv_capable_yacc=insufficient
-	fi)
-if test $tcpdump_cv_capable_yacc = insufficient ; then
-	AC_MSG_ERROR([$YACC is insufficient to compile libpcap.
+case "$YACC" in
+
+*yacc)
+	#
+	# Make sure this is Berkeley YACC, not AT&T YACC; the latter
+	# doesn't support reentrant parsers.  Run it with "-V";
+	# that succeeds and reports the version number with
+	# Berkeley YACC, but will (probably) fail with various
+	# vendor flavors of AT&T YACC.
+	#
+	AC_CACHE_CHECK([for capable yacc], tcpdump_cv_capable_yacc,
+	    if $YACC -V >/dev/null 2>&1; then
+		tcpdump_cv_capable_yacc=yes
+	    else
+		tcpdump_cv_capable_yacc=insufficient
+	    fi)
+	if test $tcpdump_cv_capable_yacc = insufficient ; then
+	    AC_MSG_ERROR([$YACC is insufficient to compile libpcap.
  libpcap requires Bison, a newer version of Berkeley YACC with support
  for reentrant parsers, or another YACC compatible with them.])
-fi
+	fi
+
+	#
+	# Berkeley YACC doesn't support "%define api.pure", so use
+	# "%pure-parser".
+	#
+	REENTRANT_PARSER="%pure-parser"
+	;;
+
+*)
+	#
+	# Bison prior to 2.4(.1) doesn't support "%define api.pure", so use
+	# "%pure-parser".
+	#
+	bison_major_version=`$YACC -V | sed -n 's/.* \(@<:@1-9@:>@@<:@0-9@:>@*\)\.@<:@1-9@:>@@<:@0-9.@:>@*/\1/p'`
+	bison_minor_version=`$YACC -V | sed -n 's/.* @<:@1-9@:>@@<:@0-9@:>@*\.\(@<:@1-9@:>@@<:@0-9@:>@*\).*/\1/p'`
+	if test "$bison_major_version" -lt 2 -o \
+	    \( "$bison_major_version" -eq 2 -a "$bison_major_version" -lt 4 \)
+	then
+		REENTRANT_PARSER="%pure-parser"
+	else
+		REENTRANT_PARSER="%define api.pure"
+	fi
+	;;
+esac
+AC_SUBST(REENTRANT_PARSER)
 
 #
 # Do various checks for various OSes and versions of those OSes.
@@ -1813,13 +1965,25 @@
 			AC_MSG_CHECKING(whether building for 32-bit x86 is supported)
 			save_CFLAGS="$CFLAGS"
 			CFLAGS="$CFLAGS -arch i386"
-			AC_TRY_COMPILE(
+			AC_TRY_LINK(
 			    [],
 			    [return 0;],
 			    [
 				AC_MSG_RESULT(yes)
-				V_LIB_CCOPT_FAT="-arch x86_64 -arch i386"
-				V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386"
+				V_LIB_CCOPT_FAT="-arch x86_64"
+				V_LIB_LDFLAGS_FAT="-arch x86_64"
+
+				#
+				# OpenSSL installation on macOS seems
+				# to install only the libs for 64-bit
+				# x86 - at least that's what Brew does:
+				# only configure 32-bit builds if we
+				# don't have OpenSSL.
+				#
+				if test "$HAVE_OPENSSL" != yes; then
+					V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386"
+					V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386"
+				fi
 			    ],
 			    [
 				AC_MSG_RESULT(no)
@@ -1920,7 +2084,7 @@
 	MAN_MISC_INFO=5
 	;;
 
-linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|midipix*)
+linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|haiku*|midipix*)
 	DYEXT="so"
 
 	#
@@ -2040,18 +2204,14 @@
 	#include <sys/dlpi_ext.h>
     ])
 
-AC_LBL_UNALIGNED_ACCESS
-
 AC_SUBST(V_CCOPT)
 AC_SUBST(V_LIB_CCOPT_FAT)
 AC_SUBST(V_LIB_LDFLAGS_FAT)
 AC_SUBST(V_PROG_CCOPT_FAT)
 AC_SUBST(V_PROG_LDFLAGS_FAT)
 AC_SUBST(V_DEFS)
-AC_SUBST(V_FINDALLDEVS)
 AC_SUBST(V_INCLS)
 AC_SUBST(V_LEX)
-AC_SUBST(V_PCAP)
 AC_SUBST(V_SHLIB_CCOPT)
 AC_SUBST(V_SHLIB_CMD)
 AC_SUBST(V_SHLIB_OPT)
@@ -2060,7 +2220,10 @@
 AC_SUBST(V_YACC)
 AC_SUBST(ADDLOBJS)
 AC_SUBST(ADDLARCHIVEOBJS)
-AC_SUBST(SSRC)
+AC_SUBST(PLATFORM_C_SRC)
+AC_SUBST(PLATFORM_CXX_SRC)
+AC_SUBST(MODULE_C_SRC)
+AC_SUBST(REMOTE_C_SRC)
 AC_SUBST(DYEXT)
 AC_SUBST(MAN_DEVICES)
 AC_SUBST(MAN_FILE_FORMATS)
@@ -2072,94 +2235,77 @@
 AC_SUBST(RPCAPD_LIBS)
 AC_SUBST(EXTRA_NETWORK_LIBS)
 
+#
+# Various Linux-specific mechanisms.
+#
 AC_ARG_ENABLE([usb],
-[AC_HELP_STRING([--enable-usb],[enable USB capture support @<:@default=yes, if support available@:>@])],
+[AC_HELP_STRING([--enable-usb],[enable Linux usbmon USB capture support @<:@default=yes, if support available@:>@])],
     [],
     [enable_usb=yes])
 
-if test "xxx_only" = yes; then
-	# User requested something-else-only pcap, so they don't
-	# want USB support.
-	enable_usb=no
-fi
-
-if test "x$enable_usb" != "xno" ; then
-   dnl check for USB sniffing support
-   AC_MSG_CHECKING(for USB sniffing support)
-   case "$host_os" in
-   linux*)
-	AC_DEFINE(PCAP_SUPPORT_USB, 1, [target host supports USB sniffing])
-	USB_SRC=pcap-usb-linux.c
-	AC_MSG_RESULT(yes)
-	ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null`
-	if test $? -ne 0 ; then
-	  ac_usb_dev_name="usbmon"
-	fi
-	AC_DEFINE_UNQUOTED(LINUX_USB_MON_DEV, "/dev/$ac_usb_dev_name", [path for device for USB sniffing])
-	AC_MSG_NOTICE(Device for USB sniffing is /dev/$ac_usb_dev_name)
-	#
-	# Do we have a version of <linux/compiler.h> available?
-	# If so, we might need it for <linux/usbdevice_fs.h>.
-	#
-	AC_CHECK_HEADERS(linux/compiler.h)
-	if test "$ac_cv_header_linux_compiler_h" = yes; then
-	  #
-	  # Yes - include it when testing for <linux/usbdevice_fs.h>.
-	  #
-	  AC_CHECK_HEADERS(linux/usbdevice_fs.h,,,[#include <linux/compiler.h>])
-	else
-	  AC_CHECK_HEADERS(linux/usbdevice_fs.h)
-	fi
-	if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then
-	  #
-	  # OK, does it define bRequestType?  Older versions of the kernel
-	  # define fields with names like "requesttype, "request", and
-	  # "value", rather than "bRequestType", "bRequest", and
-	  # "wValue".
-	  #
-	  AC_CHECK_MEMBERS([struct usbdevfs_ctrltransfer.bRequestType],,,
-	      [
-		  AC_INCLUDES_DEFAULT
-		  #ifdef HAVE_LINUX_COMPILER_H
-		  #include <linux/compiler.h>
-		  #endif
-		  #include <linux/usbdevice_fs.h>
-	      ])
-	fi
-	;;
-    freebsd*)
-	#
-	# This just uses BPF in FreeBSD 8.4 and later; we don't need
-	# to check for anything special for capturing.
-	#
-	AC_MSG_RESULT([yes, in FreeBSD 8.4 and later])
-	;;
-
-    *)
-	AC_MSG_RESULT(no)
-	;;
-esac
-fi
-AC_SUBST(PCAP_SUPPORT_USB)
-AC_SUBST(USB_SRC)
-
-dnl check for netfilter sniffing support
+#
+# If somebody requested an XXX-only pcap, that doesn't include
+# additional mechanisms.
+#
 if test "xxx_only" != yes; then
-	AC_MSG_CHECKING(whether the platform could support netfilter sniffing)
-	case "$host_os" in
-	linux*)
-		AC_MSG_RESULT(yes)
-		#
-		# Life's too short to deal with trying to get this to compile
-		# if you don't get the right types defined with
-		# __KERNEL_STRICT_NAMES getting defined by some other include.
-		#
-		# Check whether the includes Just Work.  If not, don't turn on
-		# netfilter support.
-		#
-		AC_MSG_CHECKING(whether we can compile the netfilter support)
-		AC_CACHE_VAL(ac_cv_netfilter_can_compile,
-		  AC_TRY_COMPILE([
+  case "$host_os" in
+  linux*)
+    dnl check for USB sniffing support
+    AC_MSG_CHECKING(for Linux usbmon USB sniffing support)
+    if test "x$enable_usb" != "xno" ; then
+      AC_DEFINE(PCAP_SUPPORT_LINUX_USBMON, 1, [target host supports Linux usbmon for USB sniffing])
+      MODULE_C_SRC="$MODULE_C_SRC pcap-usb-linux.c"
+      AC_MSG_RESULT(yes)
+      ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null`
+      if test $? -ne 0 ; then
+        ac_usb_dev_name="usbmon"
+      fi
+      AC_DEFINE_UNQUOTED(LINUX_USB_MON_DEV, "/dev/$ac_usb_dev_name", [path for device for USB sniffing])
+      AC_MSG_NOTICE(Device for USB sniffing is /dev/$ac_usb_dev_name)
+      #
+      # Do we have a version of <linux/compiler.h> available?
+      # If so, we might need it for <linux/usbdevice_fs.h>.
+      #
+      AC_CHECK_HEADERS(linux/compiler.h)
+      if test "$ac_cv_header_linux_compiler_h" = yes; then
+        #
+        # Yes - include it when testing for <linux/usbdevice_fs.h>.
+        #
+        AC_CHECK_HEADERS(linux/usbdevice_fs.h,,,[#include <linux/compiler.h>])
+      else
+        AC_CHECK_HEADERS(linux/usbdevice_fs.h)
+      fi
+      if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then
+        #
+        # OK, does it define bRequestType?  Older versions of the kernel
+        # define fields with names like "requesttype, "request", and
+        # "value", rather than "bRequestType", "bRequest", and
+        # "wValue".
+        #
+        AC_CHECK_MEMBERS([struct usbdevfs_ctrltransfer.bRequestType],,,
+          [
+            AC_INCLUDES_DEFAULT
+            #ifdef HAVE_LINUX_COMPILER_H
+            #include <linux/compiler.h>
+            #endif
+            #include <linux/usbdevice_fs.h>
+          ])
+      fi
+    else
+      AC_MSG_RESULT(no)
+    fi
+
+    #
+    # Life's too short to deal with trying to get this to compile
+    # if you don't get the right types defined with
+    # __KERNEL_STRICT_NAMES getting defined by some other include.
+    #
+    # Check whether the includes Just Work.  If not, don't turn on
+    # netfilter support.
+    #
+    AC_MSG_CHECKING(whether we can compile the netfilter support)
+    AC_CACHE_VAL(ac_cv_netfilter_can_compile,
+      AC_TRY_COMPILE([
 AC_INCLUDES_DEFAULT
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -2170,23 +2316,20 @@
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_log.h>
 #include <linux/netfilter/nfnetlink_queue.h>],
-		    [],
-		    ac_cv_netfilter_can_compile=yes,
-		    ac_cv_netfilter_can_compile=no))
-		AC_MSG_RESULT($ac_cv_netfilter_can_compile)
-		if test $ac_cv_netfilter_can_compile = yes ; then
-		  AC_DEFINE(PCAP_SUPPORT_NETFILTER, 1,
-		    [target host supports netfilter sniffing])
-		  NETFILTER_SRC=pcap-netfilter-linux.c
-		fi
-		;;
-	*)
-		AC_MSG_RESULT(no)
-		;;
-	esac
+        [],
+        ac_cv_netfilter_can_compile=yes,
+        ac_cv_netfilter_can_compile=no))
+    AC_MSG_RESULT($ac_cv_netfilter_can_compile)
+    if test $ac_cv_netfilter_can_compile = yes ; then
+      AC_DEFINE(PCAP_SUPPORT_NETFILTER, 1,
+        [target host supports netfilter sniffing])
+      MODULE_C_SRC="$MODULE_C_SRC pcap-netfilter-linux.c"
+    fi
+    ;;
+  esac
 fi
+AC_SUBST(PCAP_SUPPORT_LINUX_USBMON)
 AC_SUBST(PCAP_SUPPORT_NETFILTER)
-AC_SUBST(NETFILTER_SRC)
 
 AC_ARG_ENABLE([netmap],
 [AC_HELP_STRING([--enable-netmap],[enable netmap support @<:@default=yes, if support available@:>@])],
@@ -2213,12 +2356,249 @@
 	if test $ac_cv_net_netmap_user_can_compile = yes ; then
 	  AC_DEFINE(PCAP_SUPPORT_NETMAP, 1,
 	    [target host supports netmap])
-	    NETMAP_SRC=pcap-netmap.c
+	    MODULE_C_SRC="$MODULE_C_SRC pcap-netmap.c"
 	fi
 	AC_SUBST(PCAP_SUPPORT_NETMAP)
-	AC_SUBST(NETMAP_SRC)
 fi
 
+# Check for DPDK support.
+AC_ARG_WITH([dpdk],
+AC_HELP_STRING([--with-dpdk@<:@=DIR@:>@],[include DPDK support (located in directory DIR, if supplied).  @<:@default=yes, if present@:>@]),
+[
+	if test "$withval" = no
+	then
+		# User doesn't want DPDK support.
+		want_dpdk=no
+	elif test "$withval" = yes
+	then
+		# User wants DPDK support but hasn't specified a directory.
+		want_dpdk=yes
+	else
+		# User wants DPDK support and has specified a directory,
+		# so use the provided value.
+		want_dpdk=yes
+		dpdk_dir=$withval
+	fi
+],[
+	if test "$V_PCAP" = dpdk; then
+		# User requested DPDK-only libpcap, so we'd better have
+		# the DPDK API.
+		want_dpdk=yes
+	elif test "xxx_only" = yes; then
+		# User requested something-else-only pcap, so they don't
+		# want DPDK support.
+		want_dpdk=no
+	else
+		#
+		# Use DPDK API if present, otherwise don't
+		#
+		want_dpdk=ifpresent
+	fi
+])
+
+if test "$want_dpdk" != no; then
+	if test "x$PKGCONFIG" != "xno"
+	then
+		#
+		# We have pkg-config; see if we have DPDK installed
+		# as a package.
+		#
+		AC_MSG_CHECKING([for DPDK with pkg-config])
+		if "$PKGCONFIG" libdpdk
+		then
+			AC_MSG_RESULT([found])
+			found_dpdk_with_pkg_config=yes
+			DPDK_CFLAGS=`"$PKGCONFIG" --cflags libdpdk`
+			DPDK_LDFLAGS=`"$PKGCONFIG" --libs libdpdk`
+		else
+			AC_MSG_RESULT([not found])
+		fi
+	fi
+
+	#
+	# If we didn't find it with pkg-config, try checking for
+	# it manually.
+	#
+	if test "x$found_dpdk_with_pkg_config" != "xyes"
+	then
+		if test -z "$dpdk_dir"; then
+			#
+			# The user didn't specify a directory containing
+			# the DPDK headers and libraries.  If we find
+			# a /usr/local/include/dpdk directory, assume
+			# it's /usr/local, otherwise assume it's /usr.
+			#
+			if test -d "/usr/local/include/dpdk"; then
+				dpdk_dir="/usr/local"
+			else
+				dpdk_dir="/usr"
+			fi
+		fi
+		#
+		# The convention appears to be that 1) there's a "dpdk"
+		# subdirectory of the include directory, containing DPDK
+		# headers (at least in the installation on Ubuntu with
+		# the system DPDK packages) and 2) includes of DPDK
+		# headers don't use "dpdk/{header}" (at least from the
+		# way the DPDK documentation is written).
+		#
+		# So we add "/dpdk" to the include directory, and always
+		# add that to the list of include directories to search.
+		#
+		dpdk_inc_dir="$dpdk_dir/include/dpdk"
+		dpdk_inc_flags="-I$dpdk_inc_dir"
+		dpdk_lib_dir="$dpdk_dir/lib"
+		#
+		# Handle multiarch systems.
+		#
+		# Step 1: run the C compiler with the -dumpmachine option;
+		# if it succeeds, the output would be the multiarch directory
+		# name if your system has multiarch directories.
+		#
+		multiarch_dir=`$CC -dumpmachine 2>/dev/null`
+		if test ! -z "$multiarch_dir"
+		then
+			#
+			# OK, we have a multiarch directory.
+			#
+			# Now deal with includes.  On Ubuntu 20.04, for
+			# example, we have /usr/include/dpdk *and*
+			# /usr/include/$multiarch_dir/dpdk, and must
+			# search both.
+			#
+			if test -d "$dpdk_dir/include/$multiarch_dir/dpdk"
+			then
+				dpdk_inc_flags="-I$dpdk_dir/include/$multiarch_dir/dpdk $dpdk_inc_flags"
+			fi
+
+			#
+			# Now deal with libraries.
+			#
+			if test -d "$dpdk_lib_dir/$multiarch_dir"
+			then
+				dpdk_lib_dir="$dpdk_lib_dir/$multiarch_dir"
+			fi
+		fi
+		DPDK_MACHINE_CFLAGS="-march=native"
+		DPDK_CFLAGS="$DPDK_MACHINE_CFLAGS $dpdk_inc_flags"
+		DPDK_LDFLAGS="-L$dpdk_lib_dir -ldpdk -lrt -lm -lnuma -ldl -pthread"
+	fi
+
+	save_CFLAGS="$CFLAGS"
+	save_LIBS="$LIBS"
+	save_LDFLAGS="$LDFLAGS"
+	CFLAGS="$CFLAGS $DPDK_CFLAGS"
+	LIBS="$LIBS $DPDK_LDFLAGS"
+	LDFLAGS="$LDFLAGS $DPDK_LDFLAGS"
+
+	AC_MSG_CHECKING(whether we can compile the DPDK support)
+	AC_CACHE_VAL(ac_cv_dpdk_can_compile,
+	AC_TRY_COMPILE([
+AC_INCLUDES_DEFAULT
+#include <rte_common.h>],
+	    [],
+	    ac_cv_dpdk_can_compile=yes,
+	    ac_cv_dpdk_can_compile=no))
+	AC_MSG_RESULT($ac_cv_dpdk_can_compile)
+
+	#
+	# We include rte_bus.h, and older versions of DPDK
+	# didn't have it, so check for it.
+	#
+	if test "$ac_cv_dpdk_can_compile" = yes; then
+		#
+		# This runs the preprocessor, so make sure it
+		# looks in the DPDK directories.  Instead of
+		# including dpdk/XXX.h, we include just XXX.h
+		# and assume DPDK_CFLAGS is the directory
+		# containing the DPDK headers (that's how
+		# pkg-config sets it, at least on Ubuntu),
+		# so just looking under /usr/include won't
+		# find it.
+		#
+		save_CPPFLAGS="$CPPFLAGS"
+		CPPFLAGS="$CPPFLAGS $DPDK_CFLAGS"
+		AC_CHECK_HEADER(rte_bus.h)
+		CPPFLAGS="$save_CPPFLAGS"
+	fi
+
+	#
+	# We call rte_eth_dev_count_avail(), and older versions
+	# of DPDK didn't have it, so check for it.
+	#
+	if test "$ac_cv_header_rte_bus_h" = yes; then
+		AC_CHECK_FUNC(rte_eth_dev_count_avail)
+	fi
+
+	CFLAGS="$save_CFLAGS"
+	LIBS="$save_LIBS"
+	LDFLAGS="$save_LDFLAGS"
+
+	if test "$ac_cv_func_rte_eth_dev_count_avail" = yes; then
+		CFLAGS="$CFLAGS $DPDK_CFLAGS"
+		LIBS="$LIBS $DPDK_LDFLAGS"
+		LDFLAGS="$LDFLAGS $DPDK_LDFLAGS"
+		V_INCLS="$V_INCLS $DPDK_CFLAGS"
+		AC_DEFINE(PCAP_SUPPORT_DPDK, 1, [target host supports DPDK])
+		if test $V_PCAP != dpdk ; then
+			MODULE_C_SRC="$MODULE_C_SRC pcap-dpdk.c"
+		fi
+
+		#
+		# Check whether the rte_ether.h file defines
+		# struct ether_addr or struct rte_ether_addr.
+		#
+		# ("API compatibility?  That's for losers!")
+		#
+		AC_CHECK_TYPES(struct rte_ether_addr,,,
+		    [
+			#include <rte_ether.h>
+		    ])
+	else
+		if test "$V_PCAP" = dpdk; then
+			# User requested DPDK-only capture support, but
+			# we couldn't the DPDK API support at all, or we
+			# found it but it wasn't a sufficiently recent
+			# version.
+			if test "$ac_cv_dpdk_can_compile" != yes; then
+				#
+				# Couldn't even find the headers.
+				#
+				AC_MSG_ERROR([DPDK support requested with --with-pcap=dpdk, but the DPDK headers weren't found at $dpdk_inc_dir: make sure the DPDK support is installed, specify a different path or paths if necessary, or don't request DPDK support])
+			else
+				#
+				# Found the headers, but we couldn't find
+				# rte_bus.h or rte_eth_dev_count_avail(),
+				# we don't have a sufficiently recent
+				# version of DPDK.
+				#
+				AC_MSG_ERROR([DPDK support requested with --with-pcap=dpdk, but we require DPDK 18.x or later; install a newer version of DPDK, or don't request DPDK support])
+			fi
+		fi
+
+		if test "$want_dpdk" = yes; then
+			# User requested DPDK-only capture support, but
+			# we couldn't the DPDK API support at all, or we
+			# found it but it wasn't a sufficiently recent
+			# version.
+			if test "$ac_cv_dpdk_can_compile" != yes; then
+				#
+				# Couldn't even find the headers.
+				#
+				AC_MSG_ERROR([DPDK support requested with --with-pcap=dpdk, but the DPDK headers weren't found at $dpdk_inc_dir: make sure the DPDK support is installed, specify a different path or paths if necessary, or don't request DPDK support])
+			else
+				#
+				# Found the headers, but we couldn't find
+				# rte_bus.h or rte_eth_dev_count_avail(),
+				# we don't have a sufficiently recent
+				# version of DPDK.
+				#
+				AC_MSG_ERROR([DPDK support requested with --with-pcap=dpdk, but we require DPDK 18.x or later: install a newer version of DPDK, or don't request DPDK support])
+			fi
+		fi
+	fi
+fi
+AC_SUBST(PCAP_SUPPORT_DPDK)
 
 AC_ARG_ENABLE([bluetooth],
 [AC_HELP_STRING([--enable-bluetooth],[enable Bluetooth support @<:@default=yes, if support available@:>@])],
@@ -2242,7 +2622,7 @@
 			# sniffing.
 			#
 			AC_DEFINE(PCAP_SUPPORT_BT, 1, [target host supports Bluetooth sniffing])
-			BT_SRC=pcap-bt-linux.c
+			MODULE_C_SRC="$MODULE_C_SRC pcap-bt-linux.c"
 			AC_MSG_NOTICE(Bluetooth sniffing is supported)
 			ac_lbl_bluetooth_available=yes
 
@@ -2269,7 +2649,7 @@
 					    AC_MSG_RESULT(yes)
 					    AC_DEFINE(PCAP_SUPPORT_BT_MONITOR,,
 					      [target host supports Bluetooth Monitor])
-					    BT_MONITOR_SRC=pcap-bt-monitor-linux.c
+					    MODULE_C_SRC="$MODULE_C_SRC pcap-bt-monitor-linux.c"
 					],
 					[
 					    AC_MSG_RESULT(no)
@@ -2301,8 +2681,6 @@
 		;;
 	esac
 	AC_SUBST(PCAP_SUPPORT_BT)
-	AC_SUBST(BT_SRC)
-	AC_SUBST(BT_MONITOR_SRC)
 fi
 
 AC_ARG_ENABLE([dbus],
@@ -2349,7 +2727,6 @@
 fi
 
 if test "x$enable_dbus" != "xno"; then
-	AC_CHECK_PROG([PKGCONFIG], [pkg-config], [pkg-config], [no])
 	if test "x$PKGCONFIG" != "xno"; then
 		AC_MSG_CHECKING([for D-Bus])
 		if "$PKGCONFIG" dbus-1; then
@@ -2372,7 +2749,7 @@
 			    [
 				AC_MSG_RESULT([yes])
 				AC_DEFINE(PCAP_SUPPORT_DBUS, 1, [support D-Bus sniffing])
-				DBUS_SRC=pcap-dbus.c
+				MODULE_C_SRC="$MODULE_C_SRC pcap-dbus.c"
 				V_INCLS="$V_INCLS $DBUS_CFLAGS"
 			    ],
 			    [
@@ -2391,7 +2768,6 @@
 		fi
 	fi
 	AC_SUBST(PCAP_SUPPORT_DBUS)
-	AC_SUBST(DBUS_SRC)
 fi
 
 AC_ARG_ENABLE([rdma],
@@ -2431,7 +2807,7 @@
 				[
 					AC_MSG_RESULT([yes])
 					AC_DEFINE(PCAP_SUPPORT_RDMASNIFF, , [target host supports RDMA sniffing])
-					RDMA_SRC=pcap-rdmasniff.c
+					MODULE_C_SRC="$MODULE_C_SRC pcap-rdmasniff.c"
 					LIBS="-libverbs $LIBS"
 				],
 				[
@@ -2441,7 +2817,6 @@
 		])
 	])
 	AC_SUBST(PCAP_SUPPORT_RDMASNIFF)
-	AC_SUBST(RDMA_SRC)
 fi
 
 AC_PROG_INSTALL
@@ -2453,7 +2828,7 @@
 	cat $srcdir/Makefile-devel-adds >> Makefile
 	make depend
 fi])
-AC_OUTPUT(Makefile pcap-filter.manmisc pcap-linktype.manmisc
+AC_OUTPUT(Makefile grammar.y pcap-filter.manmisc pcap-linktype.manmisc
 	pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap
 	pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap
 	pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap
diff --git a/diag-control.h b/diag-control.h
index cfc581b..47d31b9 100644
--- a/diag-control.h
+++ b/diag-control.h
@@ -48,7 +48,43 @@
 #endif
 
 /*
- * Suppress Flex warnings.
+ * 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)
   /*
@@ -64,7 +100,27 @@
     __pragma(warning(disable:4242)) \
     __pragma(warning(disable:4244)) \
     __pragma(warning(disable:4702))
-  #define DIAG_ON_FLEX  __pragma(warning(pop))
+  #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
@@ -79,11 +135,31 @@
     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.
@@ -97,6 +173,21 @@
     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
@@ -105,6 +196,10 @@
    */
   #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
@@ -127,92 +222,75 @@
   #if defined(_MSC_VER)
     /*
      * This is Microsoft Visual Studio; we can use
-     * __pragma(warning(disable:XXXX)) and __pragma(warning(push/pop)).
+     * __pragma(warning(disable:XXXX)).
      */
     #define DIAG_OFF_BISON_BYACC \
-      __pragma(warning(push)) \
       __pragma(warning(disable:4702))
-    #define DIAG_ON_BISON_BYACC  __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".
+     * ignored -Wxxx".
      */
     #define DIAG_OFF_BISON_BYACC \
-      PCAP_DO_PRAGMA(clang diagnostic push) \
       PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshadow") \
       PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
-    #define DIAG_ON_BISON_BYACC \
-      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).
+     * 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 push) \
       PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wshadow") \
       PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
-    #define DIAG_ON_BISON_BYACC \
-      PCAP_DO_PRAGMA(GCC diagnostic pop)
   #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
-    #define DIAG_ON_BISON_BYACC
   #endif
 #else
   /*
    * Bison.
    *
-   * The generated code may have functions with unreachable code, so
-   * suppress warnings about those.
+   * 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)) and __pragma(warning(push/pop)).
+     * __pragma(warning(disable:XXXX)).
      *
      * Suppress some /Wall warnings.
      */
     #define DIAG_OFF_BISON_BYACC \
-      __pragma(warning(push)) \
+      __pragma(warning(disable:4065)) \
       __pragma(warning(disable:4127)) \
       __pragma(warning(disable:4242)) \
       __pragma(warning(disable:4244)) \
       __pragma(warning(disable:4702))
-    #define DIAG_ON_BISON_BYACC  __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".
+     * ignored -Wxxx".
      */
     #define DIAG_OFF_BISON_BYACC \
-      PCAP_DO_PRAGMA(clang diagnostic push) \
       PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
-    #define DIAG_ON_BISON_BYACC \
-      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).
+     * 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 push) \
       PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
-    #define DIAG_ON_BISON_BYACC \
-      PCAP_DO_PRAGMA(GCC diagnostic pop)
   #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
-    #define DIAG_ON_BISON_BYACC
   #endif
 #endif
 
diff --git a/dlpisubs.c b/dlpisubs.c
index 5f6e41a..2ef0931 100644
--- a/dlpisubs.c
+++ b/dlpisubs.c
@@ -114,6 +114,20 @@
 }
 
 /*
+ * Does the processor for which we're compiling this support aligned loads?
+ */
+#if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
+    (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \
+    (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__))
+    /* Yes, it does. */
+#else
+    /* No, it doesn't. */
+    #define REQUIRE_ALIGNMENT
+#endif
+
+/*
  * Loop through the packets and call the callback for each packet.
  * Return the number of packets read.
  */
@@ -127,7 +141,7 @@
 	struct pcap_pkthdr pkthdr;
 #ifdef HAVE_SYS_BUFMOD_H
 	struct sb_hdr *sbp;
-#ifdef LBL_ALIGN
+#ifdef REQUIRE_ALIGNMENT
 	struct sb_hdr sbhdr;
 #endif
 #endif
@@ -157,7 +171,7 @@
 				return (n);
 			}
 		}
-#ifdef LBL_ALIGN
+#ifdef REQUIRE_ALIGNMENT
 		if ((long)bufp & 3) {
 			sbp = &sbhdr;
 			memcpy(sbp, bufp, sizeof(*sbp));
@@ -176,7 +190,7 @@
 		bufp += caplen;
 #endif
 		++pd->stat.ps_recv;
-		if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) {
+		if (pcap_filter(p->fcode.bf_insns, pk, origlen, caplen)) {
 #ifdef HAVE_SYS_BUFMOD_H
 			pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec;
 			pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec;
@@ -275,7 +289,7 @@
 		 * XXX - DL_IPNET devices default to "raw IP" rather than
 		 * "IPNET header"; see
 		 *
-		 *    http://seclists.org/tcpdump/2009/q1/202
+		 *    https://seclists.org/tcpdump/2009/q1/202
 		 *
 		 * We'd have to do DL_IOC_IPNET_INFO to enable getting
 		 * the IPNET header.
@@ -286,7 +300,7 @@
 #endif
 
 	default:
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype 0x%x",
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype 0x%x",
 		    mactype);
 		retv = -1;
 	}
diff --git a/doc/README.Win32.md b/doc/README.Win32.md
index 8de25c8..626f89b 100644
--- a/doc/README.Win32.md
+++ b/doc/README.Win32.md
@@ -1,3 +1,198 @@
-Win32 used to build with Visual Studio 6, but we now use cmake.
+Building libpcap on Windows with Visual Studio
+==============================================
 
-This file needs to be adopted by a windows expert developer.
+Unlike the UN*Xes on which libpcap can capture network traffic, Windows
+has no network traffic capture mechanism that libpcap can use.
+Therefore, libpcap requires a driver, and a library to access the
+driver, provided by the Npcap or WinPcap projects.
+
+Those projects include versions of libpcap built to use that driver and
+library; these instructions are for people who want to build libpcap
+source releases, or libpcap from the Git repository, as a replacement
+for the version provided with Npcap or WinPcap.
+
+Npcap and WinPcap SDK
+---------------------
+
+In order to build libpcap, you will need to download Npcap and its
+software development kit (SDK) or WinPcap and its software development
+kit.
+
+Npcap is currently being developed and maintained, and offers many
+additional capabilities that WinPcap does not.
+
+WinPcap is no longer being developed or maintained; it should be used
+only if there is some other requirement to use it rather than Npcap,
+such as a requirement to support versions of Windows earlier than
+Windows Vista, which is the earliest version supported by Npcap.
+
+Npcap and its SDK can be downloaded from its home page:
+
+  https://npcap.org
+
+The SDK is a ZIP archive; create a folder on your C: drive, e.g.
+C:\npcap-sdk, and put the contents of the ZIP archive into that folder.
+
+The WinPcap installer can be downloaded from
+
+  https://www.winpcap.org/install/default.htm
+
+and the WinPcap Developer's Kit can be downloaded from
+
+  https://www.winpcap.org/devel.htm
+
+Required build tools
+--------------------
+
+The Developer's Kit is a ZIP archive; it contains a folder named
+WpdPack, which you should place on your C: drive, e.g. C:\WpdPack.
+
+Building libpcap on Windows requires Visual Studio 2015 or later.  The
+Community Edition of Visual Studio can be downloaded at no cost from
+
+  https://visualstudio.microsoft.com
+
+Additional tools are also required.  Chocolatey is a package manager for
+Windows with which those tools, and other tools, can be installed; it
+can be downloaded from
+
+  https://chocolatey.org
+
+It is a command-line tool; a GUI tool, Chocolatey GUI, is provided as a
+Chocolatey package, which can be installed from the command line:
+
+	choco install chocolateygui
+
+For convenience, the "choco install" command can be run with the "-y"
+flag, forcing it to automatically answer all questions asked of the user
+with "yes":
+
+	choco install -y chocolateygui
+
+The required tools are:
+
+### CMake ###
+
+libpcap does not provide supported project files for Visual Studio
+(there are currently unsupported project files provided, but we do not
+guarantee that they will work or that we will continue to provide them).
+It does provide files for CMake, which is a cross-platform tool that
+runs on UN*Xes and on Windows and that can generate project files for
+UN*X Make, the Ninja build system, and Visual Studio, among other build
+systems.
+
+Visual Studio 2015 does not provide CMake; an installer can be
+downloaded from
+
+  https://cmake.org/download/
+
+When you run the installer, you should choose to add CMake to the system
+PATH for all users and to create the desktop icon.
+
+CMake can also be installed as the Chocolatey package "cmake":
+
+	choco install -y cmake
+
+Visual Studio 2017 and later provide CMake, so you will not need to
+install CMake if you have installed Visual Studio 2017 or later.  They
+include built-in support for CMake-based projects:
+
+  https://devblogs.microsoft.com/cppblog/cmake-support-in-visual-studio/
+
+For Visual Studio 2017, make sure "Visual C++ tools for CMake" is
+installed; for Visual Studio 2019, make sure "C++ CMake tools for
+Windows" is intalled.
+
+### winflexbison ###
+
+libpcap uses the Flex lexical-analyzer generator and the Bison or
+Berkeley YACC parser generators to generate the parser for filter
+expressions.  Windows versions of Flex and Bison can be downloaded from
+
+  https://sourceforge.net/projects/winflexbison/
+
+The downloaded file is a ZIP archive; create a folder on your C: drive,
+e.g. C:\Program Files\winflexbison, and put the contents of the ZIP
+archive into that folder.  Then add that folder to the system PATH
+environment variable.
+
+Git
+---
+
+An optional tool, required only if you will be building from a Git
+repository rather than from a release source tarball, is Git.  Git is
+provided as an optional installation component, "Git for Windows", with
+Visual Studio 2017 and later.
+
+Building from the Visual Studio GUI
+-----------------------------------
+
+### Visual Studio 2017 ###
+
+Open the folder containing the libpcap source with Open > Folder.
+Visual Studio will run CMake; however, you will need to indicate where
+the Npcap or WinPcap SDK is installed.
+
+To do this, go to Project > "Change CMake Settings" > pcap and:
+
+Choose which configuration type to build, if you don't want the default
+Debug build.
+
+In the CMakeSettings.json tab, change cmakeCommandArgs to include
+
+	-DPacket_ROOT={path-to-sdk}
+
+where {path-to-sdk} is the path of the directory containing the Npcap or
+WinPcap SDK.  Note that backslashes in the path must be specified as two
+backslashes.
+
+Save the configuration changes with File > "Save CMakeSettings.json" or
+with control-S.
+
+Visual Studio will then re-run CMake.  If that completes without errors,
+you can build with CMake > "Build All".
+
+### Visual Studio 2019 ###
+
+Open the folder containing the libpcap source with Open > Folder.
+Visual Studio will run CMake; however, you will need to indicate where
+the Npcap or WinPcap SDK is installed.
+
+To do this, go to Project > "CMake Settings for pcap" and:
+
+Choose which configuration type to build, if you don't want the default
+Debug build.
+
+Scroll down to "Cmake variables and cache", scroll through the list
+looking for the entry for Packet_ROOT, and either type in the path of
+the directory containing the Npcap or WinPcap SDK or use the "Browse..."
+button to browse for that directory.
+
+Save the configuration changes with File > "Save CMakeSettings.json" or
+with control-S.
+
+Visual Studio will then re-run CMake.  If that completes without errors,
+you can build with Build > "Build All".
+
+Building from the command line
+------------------------------
+
+Start the appropriate Native Tools command line prompt.
+
+Change to the directory into which you want to build libpcap, possibly
+after creating it first.  One choice is to create it as a subdirectory
+of the libpcap source directory.
+
+Run the command
+
+	cmake "-DPacket_ROOT={path-to-sdk}" {path-to-libpcap-source}
+
+where {path-to-sdk} is the path of the directory containing the Npcap or
+WinPcap SDK and {path-to-libpcap-source} is the pathname of the
+top-level source directory for libpcap.
+
+Run the command
+
+	msbuild/m pcap.sln
+
+to compile libpcap.
diff --git a/doc/README.aix b/doc/README.aix
index 92e513f..9e9a23d 100644
--- a/doc/README.aix
+++ b/doc/README.aix
@@ -27,7 +27,7 @@
     If you fix the problems yourself, please submit a patch by forking
     the branch at
 
-	https://github.com/the-tcpdump-group/libpcap/issues
+	https://github.com/the-tcpdump-group/libpcap/tree/master
 
     and issuing a pull request, so we can incorporate the fixes into the
     next release.
diff --git a/doc/README.capture-module b/doc/README.capture-module
new file mode 100644
index 0000000..e13eaf3
--- /dev/null
+++ b/doc/README.capture-module
@@ -0,0 +1,353 @@
+		    How to write a libpcap module
+
+WARNING: this document describes an unstable interface; future releases
+of libpcap may, and some probably will, change the interface in an
+incompatible fashion.  If you submit your module to the libpcap
+developers for inclusion in libpcap, not only does that make it more
+likely that it will be available in the libpcap provided by operating
+system vendors (such as Linux distributions), but it also means that we
+will attempt to update it to handle future changes to this interface.
+If we add new capabilities, we may have to ask you how to provide those
+additional capabilities if you're using an underlying mechanism for
+which we have neither the source code nor the documentation.
+
+NOTE: this document assumes familiarity with the entire libpcap API.
+
+TODO: more routines, more stuff that the activate routine has to do
+(such as setting the list of DLT_s), convert to Markdown?
+
+On Linux, *BSD, macOS, Solaris, AIX, HP-UX, IRIX, and Tru64 UNIX,
+Libpcap supports capturing on network interfaces as supported by the
+operating system networking stack, using the native packet capture
+mechanism provided by the OS.  On Windows, it supports it with the help
+of the driver and library supplied by WinPcap and Npcap.
+
+In addition, it also supports capturing on other types of devices, such
+as:
+
+	specialized capture cards, such as Endace DAG cards;
+
+	network adapters that provide special high-performance code
+	paths, such as CSPI Myricom adapters;
+
+	buses such as USB;
+
+	software communication channels such as D-Bus and Linux netlink;
+
+	etc..
+
+Support for those devices is provided by modules compiled into libpcap.
+
+If you want to add such a module, you would first have to check the list
+of link-layer header types supported by libpcap, to see if one of those
+would be sufficient for your device.  The current version of the list
+can be found at
+
+	https://www.tcpdump.org/linktypes.html
+
+If none of those would work for your device, please read
+doc/DLT_ALLOCATE_HOWTO.md and the introductory paragraphs on the Web
+page mentioned above, and then send a request for the new link-layer
+header type to tcpdump-workers@lists.tcpdump.org.
+
+Once you have a link-layer header type value or values that you can use,
+you can add new module.
+
+The module should be a C source file, with a name of the form
+pcap-{MOD}.c, where {MOD} is a name appropriate for your device; for
+example, the support for DAG cards is in pcap-dag.c, and the support for
+capturing USB traffic on Linux is pcap-usb-linux.c.
+
+Your module is assumed to support one or more named devices.  The names
+should be relatively short names, containing only lower-case
+alphanumeric characters, consisting of a prefix that ends with an
+alphabetic character and, if there can be more than one device instance,
+possibly followed by a numerical device ID, such as "mydevice" or
+"mydevice0"/"mydevice1"/....  If you have more than one type of device
+that you can support, you can have more than one prefix, each of which
+can be followed by a numerical device ID.
+
+The two exported functions that your module must provide are routines to
+provide a list of device instances and a program to initialize a
+created-but-not-activated pcap_t for an instance of one of your devices.
+
+The "list of device instances" routine takes, as arguments:
+
+	a pointer to a pcap_if_list_t;
+
+	a pointer to an error message buffer.
+
+The error message buffer may be assumed to be PCAP_ERRBUF_SIZE bytes
+large, but must not be assumed to be larger.  By convention, the routine
+typically has a name containing "findalldevs".
+
+The routine should attempt to determine what device instances are
+available and add them to the list pointed to by the first argument;
+this may be impossible for some modules, but, for those modules, it may
+be difficult to capture on the devices using Wirehshark (although it
+should be possible to capture on them using tcpdump, TShark, or other
+programs that take a device name on the command line), so we recommend
+that your routine provide the list of devices if possible.  If it
+cannot, it should just immediately return 0.
+
+The routine should add devices to the list by calling the add_dev()
+routine in libpcap, declared in the pcap-int.h header.  It takes, as
+arguments:
+
+	the pointer to the pcap_if_list_t passed as an argument to the
+	routine;
+
+	the device name, as described above;
+
+	a 32-bit word of flags, as provided by pcap_findalldevs();
+
+	a text description of the device, or NULL if there is no
+	description;
+
+	the error message buffer pointer provided to the routine.
+
+add_dev() will, if it succeeds, return a pointer to a pcap_if_t that was
+added to the list of devices.  If it fails, it will return NULL; in this
+case, the error message buffer has been filled in with an error string,
+and your routine must return -1 to indicate the error.
+
+If your routine succeeds, it must return 0.  If it fails, it must fill
+in the error message buffer with an error string and return -1.
+
+The "initialize the pcap_t" routine takes, as arguments:
+
+	a pointer to a device name;
+
+	a pointer to an error message buffer;
+
+	a pointer to an int.
+
+It returns a pointer to a pcap_t.
+
+Your module will probably need, for each pcap_t for an opened device, a
+private data structure to maintain its own information about the opened
+device.  These should be allocated per opened instance, not per device;
+if, for example, mydevice0 can be captured on by more than one program
+at the same time, there will be more than one pcap_t opened for
+mydevice0, and so there will be separate private data structures for
+each pcap_t.  If you need to maintain per-device, rather than per-opened
+instance information, you will have to maintain that yourself.
+
+The routine should first check the device to see whether it looks like a
+device that this module would handle; for example, it should begin with
+one of the device name prefixes for your module and, if your devices
+have instance numbers, be followed by a number.  If it is not one of
+those devices, you must set the integer pointed to by the third
+argument to 0, to indicate that this is *not* one of the devices for
+your module, and return NULL.
+
+If it *is* one of those devices, it should call pcap_create_common,
+passing to it the error message buffer as the first argument and the
+size of the per-opened instance data structure as the second argument.
+If it fails, it will return NULL; you must return NULL in this case.
+
+If it succeeds, the pcap_t pointed to by the return value has been
+partially initialized, but you will need to complete the process.  It
+has a "priv" member, which is a void * that points to the private data
+structure attached to it; that structure has been initialized to zeroes.
+
+What you need to set are some function pointers to your routines to
+handle certain operations:
+
+	activate_op
+		the routine called when pcap_activate() is done on the
+		pcap_t
+
+	can_set_rfmon_op
+		the routine called when pcap_can_set_rfmon() is done on
+		the pcap_t - if your device doesn't support 802.11
+		monitor mode, you can leave this as initialized by
+		pcap_create_common(), as that routine will return "no,
+		monitor mode isn't supported".
+
+Once you've set the activate_op and, if necessary, the can_set_rfmon_op,
+you must return the pcap_t * that was returned to you.
+
+Your activate routine takes, as an argument, a pointer to the pcap_t
+being activated, and returns an int.
+
+The perameters set for the device in the pcap_create() call, and after
+that call(), are mostly in the opt member of the pcap_t:
+
+	device
+		the name of the device
+
+	timeout
+		the buffering timeout, in milliseconds
+
+	buffer_size
+		the buffer size to use
+
+	promisc
+		1 if promiscuous mode is to be used, 0 otherwise
+
+	rfmon
+		1 if monitor mode is to be used, 0 otherwise
+
+	immediate
+		1 if the device should be in immediate mode, 0 otherwise
+
+	nonblock
+		1 if the device should be in non-blocking mode, 0
+		otherwise
+
+	tstamp_type
+		the type of time stamp to supply
+
+	tstamp_precision
+		the time stamp precision to supply
+
+The snapshot member of the pcap_t structure will contain the snapshot
+length to be used.
+
+Your routine should attempt to set up the device for capturing.  If it
+fails, it must return an error indication which is one of the PCAP_ERROR
+values.  For PCAP_ERROR, it must also set the errbuf member of the
+pcap_t to an error string.  For PCAP_ERROR_NO_SUCH_DEVICE and
+PCAP_ERROR_PERM_DENIED, it may set it to an error string providing
+additional information that may be useful for debugging, or may just
+leave it as a null string.
+
+If it succeeds, it must set certain function pointers in the pcap_t
+structure:
+
+	read_op
+		called whenever packets are to be read
+
+	inject_op
+		called whenever packets are to be injected
+
+	setfilter_op
+		called whenever pcap_setfilter() is called
+
+	setdirection_op
+		called whenever pcap_setdirection() is called
+
+	set_datalink_op
+		called whnever pcap_set_datalink() is called
+
+	getnonblock_op
+		called whenever pcap_getnonblock() is called
+
+	setnonblock_op
+		called whenever pcap_setnonblock() is called
+
+	stats_op
+		called whenever pcap_stats() is called
+
+	cleanup_op
+		called if the activate routine fails or pcap_close() is
+		called
+
+and must also set the linktype member to the DLT_ value for the device.
+
+On UN*Xes, if the device supports waiting for packets to arrive with
+select()/poll()/epoll()/kqueues etc., it should set the selectable_fd
+member of the structure to the descriptor you would use with those
+calls.  If it does not, then, if that's because the device polls for
+packets rather than receiving interrupts or other signals when packets
+arrive, it should have a struct timeval in the private data structure,
+set the value of that struct timeval to the poll timeout, and set the
+required_select_timeout member of the pcap_t to point to the struct
+timeval.
+
+The read_op routine is called when pcap_dispatch(), pcap_loop(),
+pcap_next(), or pcap_next_ex() is called.  It is passed the same
+arguments as pcap_dispatch() is called.
+
+The routine should first check if the break_loop member of the pcap_t is
+non-zero and, if so, set that member to zero and return
+PCAP_ERROR_BREAK.
+
+Then, if the pcap_t is in blocking mode (as opposed to non-blocking
+mode), and there are no packets immediately available to be passed to
+the callback, it should block waiting for packets to arrive, using the
+buffering timeout, first, and read packets from the device if necessary.
+
+Then it should loop through the available packets, calling the callback
+routine for each packet:
+
+	If the PACKET_COUNT_IS_UNLIMITED() macro evaluates to true when
+	passed the packet count argument, the loop should continue until
+	there are no more packets immediately available or the
+	break_loop member of the pcap_t is non-zero.  If the break_loop
+	member is fount to be non-zero, it should set that member to
+	zero and return PCAP_ERROR_BREAK.
+
+	If it doesn't evaluat to true, then the loop should also
+	terminate if the specified number of packets have been delivered
+	to the callback.
+
+Note that there is *NO* requirement that the packet header or data
+provided to the callback remain available, or valid, after the callback
+routine returns; if the callback needs to save the data for other code
+to use, it must make a copy of that data.  This means that the module is
+free to, for example, overwrite the buffer into which it read the
+packet, or release back to the kernel a packet in a memory-mapped
+buffer shared between the kernel and userland, after the callback
+returns.
+
+If an error occurs when reading packets from the device, it must set the
+errbuf member of the pcap_t to an error string and return PCAP_ERROR.
+
+If no error occurs, it must return the number of packets that were
+supplied to the callback routine.
+
+The inject routine is passed a pointer to the pcap_t, a buffer
+containing the contents of the packet to inject, and the number of bytes
+in the packet.  If the device doesn't support packet injection, the
+routine must set the errbuf member of the pcap_t to a message indicating
+that packet injection isn't supported and return PCAP_ERROR.  Otherwise,
+it should attempt to inject the packet; if the attempt fails, it must
+set the errbuf member of the pcap_t to an error message and return
+PCAP_ERROR.  Otherwise, it should return the number of bytes injected.
+
+The setfilter routine is passed a pointer to the pcap_t and a pointer
+to a struct bpf_program containing a BPF program to be used as a filter.
+If the mechanism used by your module can perform filtering with a BPF
+program, it would attempt to set that filter to the specified program.
+
+If that failed because the program was too large, or used BPF features
+not supported by that mechanism, the module should fall back on
+filtering in userland by saving a copy of the filter with a call to
+install_bpf_program(), setting a flag in the private data instructure
+indicating that filtering is being done by the module and, in the read
+routine's main loop, checking the flag and, if it's set, calling
+pcap_filter(), passing it the fcode.bf_insns member of the pcap_t, the
+raw packet data, the on-the-wire length of the packet, and the captured
+length of the packet, and only passing the packet to the callback
+routine, and counting it, if pcap_filter() returns a non-zero value.
+(If the flag is not set, all packets should be passed to the callback
+routine and counted, as the filtering is being done by the mechanism
+used by the module.)  If install_bpf_program() returns a negative value,
+the routine should return PCAP_ERROR.
+
+If the attempt to set the filter failed for any other reason, the
+routine must set the errbuf member of the pcap_t to an error message and
+return PCAP_ERROR.
+
+If the attempt to set the filter succeeded, or it failed because the
+mechanism used by the module rejected it and the call to
+install_bpf_program() succeeded, the routine should return 0.
+
+If the mechanism the module uses doesn't support filtering, the pointer
+to the setfilter routine can just be set to point to
+install_bpf_program; the module does not need a routine of its own to
+handle that.
+
+The setdirection routine is passed a pointer to the pcap_t and a
+pcap_direction_t indicating which packet directions should be accepted.
+If the module can't arrange to handle only incoming packets or only
+outgoing packets, it can set the pointer to the setdirection routine to
+NULL, and calls to pcap_setdirection() will fail with an error message
+indicating that setting the direction isn't supported.
+
+XXX describe set_datalink, including what the activate routine has to do
+XXX
+
+XXX describe the rest of the routines XXX
diff --git a/doc/README.dag b/doc/README.dag
index 7ea2504..13332c6 100644
--- a/doc/README.dag
+++ b/doc/README.dag
@@ -1,7 +1,7 @@
 
 The following instructions apply if you have a Linux or FreeBSD platform and
 want libpcap to support the DAG range of passive network monitoring cards from
-Endace (http://www.endace.com, see below for further contact details).
+Endace (https://www.endace.com, see below for further contact details).
 
 1) Install and build the DAG software distribution by following the
 instructions supplied with that package. Current Endace customers can download
@@ -117,6 +117,6 @@
 
 Please also visit our Web site at:
 
-        http://www.endace.com/
+        https://www.endace.com/
 
 For more information about Endace DAG cards contact <sales@endace.com>.
diff --git a/doc/README.hpux b/doc/README.hpux
index 65ecff9..b995eee 100644
--- a/doc/README.hpux
+++ b/doc/README.hpux
@@ -8,7 +8,7 @@
 able to see packets sent from the machine on which they're running.
 Some articles on groups.google.com discussing this are:
 
-	http://groups.google.com/groups?selm=82ld3v%2480i%241%40mamenchi.zrz.TU-Berlin.DE
+	https://groups.google.com/groups?selm=82ld3v%2480i%241%40mamenchi.zrz.TU-Berlin.DE
 
 which says:
 
@@ -69,7 +69,7 @@
 
 and
 
-	http://groups.google.com/groups?selm=38AA973E.96BE7DF7%40cc.uit.no
+	https://groups.google.com/groups?selm=38AA973E.96BE7DF7%40cc.uit.no
 
 which says:
 
@@ -118,7 +118,7 @@
 
 Another posting:
 
-	http://groups.google.com/groups?selm=7d6gvn%24b3%241%40ocean.cup.hp.com
+	https://groups.google.com/groups?selm=7d6gvn%24b3%241%40ocean.cup.hp.com
 
 indicates that you need to install the optional STREAMS product to do
 captures on HP-UX 9.x:
@@ -159,7 +159,7 @@
 	   of an interface
 	A: You need to get PHNE_20892,PHNE_20725 and PHCO_10947 (or
 	   newer, this is as of 4.4.00) and its dependencies.  Then you can
-	   enable the feature as descibed below:
+	   enable the feature as described below:
 
 	Patch Name: PHNE_20892
 	Patch Description: s700 10.20 PCI 100Base-T cumulative patch
diff --git a/doc/README.linux.md b/doc/README.linux.md
index ddca4fe..143dff6 100644
--- a/doc/README.linux.md
+++ b/doc/README.linux.md
@@ -1,73 +1,8 @@
-In order for libpcap to be able to capture packets on a Linux system,
-the "packet" protocol must be supported by your kernel.  If it is not,
-you may get error messages such as
+Currently, libpcap supports packet capturing on Linux 2.6.27 and later;
+earlier versions are not supported.
 
-	modprobe: can't locate module net-pf-17
-
-in "/var/adm/messages", or may get messages such as
-
-	socket: Address family not supported by protocol
-
-from applications using libpcap.
-
-You must configure the kernel with the CONFIG_PACKET option for this
-protocol; the following note is from the Linux "Configure.help" file for
-the 2.0[.x] kernel:
-
-	Packet socket
-	CONFIG_PACKET
-	  The Packet protocol is used by applications which communicate
-	  directly with network devices without an intermediate network
-	  protocol implemented in the kernel, e.g. tcpdump. If you want them
-	  to work, choose Y.
-
-	  This driver is also available as a module called af_packet.o ( =
-	  code which can be inserted in and removed from the running kernel
-	  whenever you want). If you want to compile it as a module, say M
-	  here and read Documentation/modules.txt; if you use modprobe or
-	  kmod, you may also want to add "alias net-pf-17 af_packet" to
-	  /etc/modules.conf.
-
-and the note for the 2.2[.x] kernel says:
-
-	Packet socket
-	CONFIG_PACKET
-	  The Packet protocol is used by applications which communicate
-	  directly with network devices without an intermediate network
-	  protocol implemented in the kernel, e.g. tcpdump. If you want them
-	  to work, choose Y. This driver is also available as a module called
-	  af_packet.o ( = code which can be inserted in and removed from the
-	  running kernel whenever you want). If you want to compile it as a
-	  module, say M here and read Documentation/modules.txt.  You will
-	  need to add 'alias net-pf-17 af_packet' to your /etc/conf.modules
-	  file for the module version to function automatically.  If unsure,
-	  say Y.
-
-In addition, there is an option that, in 2.2 and later kernels, will
-allow packet capture filters specified to programs such as tcpdump to be
-executed in the kernel, so that packets that don't pass the filter won't
-be copied from the kernel to the program, rather than having all packets
-copied to the program and libpcap doing the filtering in user mode.
-
-Copying packets from the kernel to the program consumes a significant
-amount of CPU, so filtering in the kernel can reduce the overhead of
-capturing packets if a filter has been specified that discards a
-significant number of packets.  (If no filter is specified, it makes no
-difference whether the filtering isn't performed in the kernel or isn't
-performed in user mode. :-))
-
-The option for this is the CONFIG_FILTER option; the "Configure.help"
-file says:
-
-	Socket filtering
-	CONFIG_FILTER
-	  The Linux Socket Filter is derived from the Berkeley Packet Filter.
-	  If you say Y here, user-space programs can attach a filter to any
-	  socket and thereby tell the kernel that it should allow or disallow
-	  certain types of data to get through the socket. Linux Socket
-	  Filtering works on all socket types except TCP for now. See the text
-	  file linux/Documentation/networking/filter.txt for more information.
-	  If unsure, say N.
+You must configure 2.26.x kernels with the CONFIG_PACKET_MMAP option for
+this protocol.  3.x and later kernels do not require that.
 
 Note that, by default, libpcap will, if libnl is present, build with it;
 it uses libnl to support monitor mode on mac80211 devices.  There is a
@@ -94,13 +29,6 @@
 Statistics reported by pcap are platform specific.  The statistics
 reported by pcap_stats on Linux are as follows:
 
-2.2.x
-=====
-ps_recv   Number of packets that were accepted by the pcap filter
-ps_drop   Always 0, this statistic is not gathered on this platform
-
-2.4.x and later
-=====
 ps_recv   Number of packets that were accepted by the pcap filter
 ps_drop   Number of packets that had passed filtering but were not
           passed on to pcap due to things like buffer shortage, etc.
diff --git a/doc/README.septel b/doc/README.septel
index fa2c0c9..203ec1a 100644
--- a/doc/README.septel
+++ b/doc/README.septel
@@ -1,6 +1,6 @@
 The following instructions apply if you have a Linux platform and want
 libpcap to support the Septel range of passive network monitoring cards
-from Intel (http://www.intel.com)
+from Intel (https://www.intel.com)
 
 1) Install and build the Septel software distribution by following the
 instructions supplied with that package.
diff --git a/doc/README.sita b/doc/README.sita
index 5a65822..37003f5 100644
--- a/doc/README.sita
+++ b/doc/README.sita
@@ -1,6 +1,13 @@
+NOTE: this is not currently supported; the configure script doesn't
+support --with-sita, and CMake doesn't support enabling SITA ACN
+support.  The code currently does not compile; it should really be
+implemented as an additional remote capture mechanism, using a URL,
+rather than as a separate version of libpcap that supports only the ACN
+product, but the infrastructure for that isn't yet available.
+
 The following instructions apply if you have a Linux platform and want
 libpcap to support the 'ACN' WAN/LAN router product from SITA
-(http://www.sita.aero)
+(https://www.sita.aero)
 
 This might also work on non-Linux Unix-compatible platforms, but that
 has not been tested.
@@ -12,7 +19,7 @@
 capture packets from a SITA ACN device (and potentially others).
 
 To enable its support you need to ensure that the distribution has
-a correct configure.ac file; that can be created if neccessay by
+a correct configure.ac file; that can be created if necessary by
 using the normal autoconf procedure of:
 
 aclocal
diff --git a/etherent.c b/etherent.c
index 5f49961..69da9a5 100644
--- a/etherent.c
+++ b/etherent.c
@@ -25,7 +25,6 @@
 
 #include <pcap-types.h>
 
-#include <ctype.h>
 #include <memory.h>
 #include <stdio.h>
 #include <string.h>
@@ -45,14 +44,18 @@
 static inline u_char
 xdtoi(u_char c)
 {
-	if (isdigit(c))
+	if (c >= '0' && c <= '9')
 		return (u_char)(c - '0');
-	else if (islower(c))
+	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)
 {
@@ -60,7 +63,7 @@
 
 	do {
 		c = getc(f);
-	} while (isspace(c) && c != '\n');
+	} while (c == ' ' || c == '\t' || c == '\r');
 
 	return c;
 }
@@ -97,7 +100,7 @@
 
 		/* If this is a comment, or first thing on line
 		   cannot be Ethernet address, skip the line. */
-		if (!isxdigit(c)) {
+		if (!PCAP_ISXDIGIT(c)) {
 			c = skip_line(fp);
 			if (c == EOF)
 				return (NULL);
@@ -110,7 +113,7 @@
 			c = getc(fp);
 			if (c == EOF)
 				return (NULL);
-			if (isxdigit(c)) {
+			if (PCAP_ISXDIGIT(c)) {
 				d <<= 4;
 				d |= xdtoi((u_char)c);
 				c = getc(fp);
@@ -126,7 +129,7 @@
 		}
 
 		/* Must be whitespace */
-		if (!isspace(c)) {
+		if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
 			c = skip_line(fp);
 			if (c == EOF)
 				return (NULL);
@@ -156,7 +159,8 @@
 			c = getc(fp);
 			if (c == EOF)
 				return (NULL);
-		} while (!isspace(c) && --namesize != 0);
+		} while (c != ' ' && c != '\t' && c != '\r' && c != '\n'
+		    && --namesize != 0);
 		*bp = '\0';
 
 		/* Eat trailing junk */
diff --git a/ethertype.h b/ethertype.h
index 51f6308..e34e07b 100644
--- a/ethertype.h
+++ b/ethertype.h
@@ -32,58 +32,58 @@
  */
 
 #ifndef ETHERTYPE_PUP
-#define	ETHERTYPE_PUP		0x0200	/* PUP protocol */
+#define ETHERTYPE_PUP		0x0200	/* PUP protocol */
 #endif
 #ifndef ETHERTYPE_IP
-#define	ETHERTYPE_IP		0x0800	/* IP protocol */
+#define ETHERTYPE_IP		0x0800	/* IP protocol */
 #endif
 #ifndef ETHERTYPE_ARP
 #define ETHERTYPE_ARP		0x0806	/* Addr. resolution protocol */
 #endif
-#ifndef ETHERTYPE_REVARP
-#define ETHERTYPE_REVARP	0x8035	/* reverse Addr. resolution protocol */
-#endif
 #ifndef ETHERTYPE_NS
 #define ETHERTYPE_NS		0x0600
 #endif
 #ifndef	ETHERTYPE_SPRITE
-#define	ETHERTYPE_SPRITE	0x0500
+#define ETHERTYPE_SPRITE	0x0500
 #endif
 #ifndef ETHERTYPE_TRAIL
 #define ETHERTYPE_TRAIL		0x1000
 #endif
 #ifndef	ETHERTYPE_MOPDL
-#define	ETHERTYPE_MOPDL		0x6001
+#define ETHERTYPE_MOPDL		0x6001
 #endif
 #ifndef	ETHERTYPE_MOPRC
-#define	ETHERTYPE_MOPRC		0x6002
+#define ETHERTYPE_MOPRC		0x6002
 #endif
 #ifndef	ETHERTYPE_DN
-#define	ETHERTYPE_DN		0x6003
+#define ETHERTYPE_DN		0x6003
 #endif
 #ifndef	ETHERTYPE_LAT
-#define	ETHERTYPE_LAT		0x6004
+#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
+#define ETHERTYPE_REVARP	0x8035	/* reverse Addr. resolution protocol */
 #endif
 #ifndef	ETHERTYPE_LANBRIDGE
-#define	ETHERTYPE_LANBRIDGE	0x8038
+#define ETHERTYPE_LANBRIDGE	0x8038
 #endif
 #ifndef	ETHERTYPE_DECDNS
-#define	ETHERTYPE_DECDNS	0x803c
+#define ETHERTYPE_DECDNS	0x803c
 #endif
 #ifndef	ETHERTYPE_DECDTS
-#define	ETHERTYPE_DECDTS	0x803e
+#define ETHERTYPE_DECDTS	0x803e
 #endif
 #ifndef	ETHERTYPE_VEXP
-#define	ETHERTYPE_VEXP		0x805b
+#define ETHERTYPE_VEXP		0x805b
 #endif
 #ifndef	ETHERTYPE_VPROD
-#define	ETHERTYPE_VPROD		0x805c
+#define ETHERTYPE_VPROD		0x805c
 #endif
 #ifndef ETHERTYPE_ATALK
 #define ETHERTYPE_ATALK		0x809b
@@ -101,10 +101,10 @@
 #define ETHERTYPE_IPV6		0x86dd
 #endif
 #ifndef ETHERTYPE_MPLS
-#define ETHERTYPE_MPLS          0x8847
+#define ETHERTYPE_MPLS		0x8847
 #endif
 #ifndef ETHERTYPE_MPLS_MULTI
-#define ETHERTYPE_MPLS_MULTI    0x8848
+#define ETHERTYPE_MPLS_MULTI	0x8848
 #endif
 #ifndef ETHERTYPE_PPPOED
 #define ETHERTYPE_PPPOED	0x8863
@@ -116,7 +116,7 @@
 #define ETHERTYPE_8021AD	0x88a8
 #endif
 #ifndef	ETHERTYPE_LOOPBACK
-#define	ETHERTYPE_LOOPBACK	0x9000
+#define ETHERTYPE_LOOPBACK	0x9000
 #endif
 #ifndef ETHERTYPE_8021QINQ
 #define ETHERTYPE_8021QINQ	0x9100
diff --git a/extract.h b/extract.h
index aa3ff99..e776a9e 100644
--- a/extract.h
+++ b/extract.h
@@ -25,15 +25,94 @@
 
 #include <pcap/pcap-inttypes.h>
 #include <pcap/compiler-tests.h>
+#include "portability.h"
 
 /*
- * Macros to extract possibly-unaligned big-endian integral values.
+ * 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.)
  */
-#ifdef LBL_ALIGN
+#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 doesn't natively handle unaligned loads.
+ * 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?
  */
-#if PCAP_IS_AT_LEAST_GNUC_VERSION(2,0) && \
+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__))
 /*
@@ -52,7 +131,7 @@
  *
  * 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 than the code to fetch the
+ * "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
@@ -93,45 +172,90 @@
 } __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;
 
-static inline uint16_t
-EXTRACT_16BITS(const void *p)
+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));
 }
 
-static inline uint32_t
-EXTRACT_32BITS(const void *p)
+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));
 }
 
-static inline uint64_t
-EXTRACT_64BITS(const void *p)
+UNALIGNED_OK static inline int32_t
+EXTRACT_BE_S_4(const void *p)
 {
-	return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 | \
+	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));
 }
 
-#else /* have to do it a byte at a time */
+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 isn't a GCC-compatible compiler, we don't have __attribute__,
+ * 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_16BITS(p) \
+#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_32BITS(p) \
+#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_64BITS(p) \
+#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) | \
@@ -140,47 +264,67 @@
 	            ((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \
 	            ((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \
 	            ((uint64_t)(*((const uint8_t *)(p) + 7)) << 0)))
-#endif /* must special-case unaligned accesses */
-#else /* LBL_ALIGN */
+#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)))
+
 /*
- * The processor natively handles unaligned loads, so we can just
- * cast the pointer and fetch through it.
+ * Extract an IPv4 address, which is in network byte order, and not
+ * necessarily aligned, and provide the result in host byte order.
  */
-static inline uint16_t
-EXTRACT_16BITS(const void *p)
-{
-	return ((uint16_t)ntohs(*(const uint16_t *)(p)));
-}
+#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 */
 
-static inline uint32_t
-EXTRACT_32BITS(const void *p)
-{
-	return ((uint32_t)ntohl(*(const uint32_t *)(p)));
-}
-
-static inline uint64_t
-EXTRACT_64BITS(const void *p)
-{
-	return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 | \
-		((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
-
-}
-
-#endif /* LBL_ALIGN */
-
-#define EXTRACT_24BITS(p) \
+/*
+ * 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_40BITS(p) \
+#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_48BITS(p) \
+#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) | \
@@ -188,7 +332,23 @@
 	            ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \
 	            ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0)))
 
-#define EXTRACT_56BITS(p) \
+#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) | \
@@ -197,24 +357,53 @@
 	            ((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_8BITS(p) (*(p))
-#define EXTRACT_LE_16BITS(p) \
+#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_32BITS(p) \
+#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_24BITS(p) \
+#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_64BITS(p) \
+#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) | \
@@ -223,3 +412,12 @@
 	            ((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
index 5236fbb..ba8f975 100644
--- a/fad-getad.c
+++ b/fad-getad.c
@@ -42,7 +42,6 @@
 
 #include <net/if.h>
 
-#include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -190,7 +189,7 @@
 			 * We have a ":"; is it followed by a number?
 			 */
 			q = p + 1;
-			while (isdigit((unsigned char)*q))
+			while (PCAP_ISDIGIT(*q))
 				q++;
 			if (*q == '\0') {
 				/*
diff --git a/fad-gifc.c b/fad-gifc.c
index 6b16127..8940876 100644
--- a/fad-gifc.c
+++ b/fad-gifc.c
@@ -49,19 +49,13 @@
 #include <net/if.h>
 #include <netinet/in.h>
 
-#include <ctype.h>
 #include <errno.h>
 #include <memory.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-
-#ifdef HAVE_LIMITS_H
 #include <limits.h>
-#else
-#define INT_MAX		2147483647
-#endif
 
 #include "pcap-int.h"
 
@@ -178,7 +172,7 @@
 		 * Don't let the buffer size get bigger than INT_MAX.
 		 */
 		if (buf_size > INT_MAX) {
-			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "interface information requires more than %u bytes",
 			    INT_MAX);
 			(void)close(fd);
@@ -399,7 +393,7 @@
 			 * We have a ":"; is it followed by a number?
 			 */
 			q = p + 1;
-			while (isdigit((unsigned char)*q))
+			while (PCAP_ISDIGIT(*q))
 				q++;
 			if (*q == '\0') {
 				/*
diff --git a/fad-glifc.c b/fad-glifc.c
index f22f56d..6b275eb 100644
--- a/fad-glifc.c
+++ b/fad-glifc.c
@@ -50,7 +50,6 @@
 #include <net/if.h>
 #include <netinet/in.h>
 
-#include <ctype.h>
 #include <errno.h>
 #include <memory.h>
 #include <stdio.h>
@@ -311,7 +310,7 @@
 			 * We have a ":"; is it followed by a number?
 			 */
 			q = p + 1;
-			while (isdigit((unsigned char)*q))
+			while (PCAP_ISDIGIT(*q))
 				q++;
 			if (*q == '\0') {
 				/*
diff --git a/fmtutils.c b/fmtutils.c
index 091e0d3..5c7ddad 100644
--- a/fmtutils.c
+++ b/fmtutils.c
@@ -47,12 +47,220 @@
 #include <string.h>
 #include <errno.h>
 
-#include <pcap/pcap.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.
@@ -67,7 +275,7 @@
 	size_t errbuflen_remaining;
 
 	va_start(ap, fmt);
-	pcap_vsnprintf(errbuf, errbuflen, fmt, ap);
+	vsnprintf(errbuf, errbuflen, fmt, ap);
 	va_end(ap);
 	msglen = strlen(errbuf);
 
@@ -84,24 +292,40 @@
 	*p++ = ':';
 	*p++ = ' ';
 	*p = '\0';
-	msglen += 2;
 	errbuflen_remaining -= 2;
 
 	/*
 	 * Now append the string for the error code.
 	 */
-#if defined(HAVE_STRERROR_S)
+#if defined(HAVE__WCSERROR_S)
 	/*
-	 * We have a Windows-style strerror_s().
+	 * We have a Windows-style _wcserror_s().
+	 * Generate a UTF-16LE error message.
 	 */
-	errno_t err = strerror_s(p, errbuflen_remaining, errnum);
+	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 strerror_s().
+		 * what the error returns from _wcserror_s().
 		 */
-		pcap_snprintf(p, errbuflen_remaining, "Error %d", errnum);
+		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
@@ -113,7 +337,7 @@
 	 */
 	char strerror_buf[PCAP_ERRBUF_SIZE];
 	char *errstring = strerror_r(errnum, strerror_buf, PCAP_ERRBUF_SIZE);
-	pcap_snprintf(p, errbuflen_remaining, "%s", errstring);
+	snprintf(p, errbuflen_remaining, "%s", errstring);
 #elif defined(HAVE_POSIX_STRERROR_R)
 	/*
 	 * We have a POSIX-style strerror_r(), which is guaranteed to fill
@@ -125,22 +349,22 @@
 		 * UNIX 03 says this isn't guaranteed to produce a
 		 * fallback error message.
 		 */
-		pcap_snprintf(p, errbuflen_remaining, "Unknown error: %d",
+		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.
 		 */
-		pcap_snprintf(p, errbuflen_remaining,
+		snprintf(p, errbuflen_remaining,
 		    "Message for error %d is too long", errnum);
 	}
 #else
 	/*
-	 * We have neither strerror_s() nor strerror_r(), so we're
+	 * We have neither _wcserror_s() nor strerror_r(), so we're
 	 * stuck with using pcap_strerror().
 	 */
-	pcap_snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum));
+	snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum));
 #endif
 }
 
@@ -158,10 +382,11 @@
 	char *p;
 	size_t errbuflen_remaining;
 	DWORD retval;
-	char win32_errbuf[PCAP_ERRBUF_SIZE+1];
+	wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE];
+	size_t utf_8_len;
 
 	va_start(ap, fmt);
-	pcap_vsnprintf(errbuf, errbuflen, fmt, ap);
+	vsnprintf(errbuf, errbuflen, fmt, ap);
 	va_end(ap);
 	msglen = strlen(errbuf);
 
@@ -197,18 +422,39 @@
 	 * get the message translated if it's in a language they don't
 	 * happen to understand.
 	 */
-	retval = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK,
+	retval = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK,
 	    NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-	    win32_errbuf, PCAP_ERRBUF_SIZE, NULL);
+	    utf_16_errbuf, PCAP_ERRBUF_SIZE, NULL);
 	if (retval == 0) {
 		/*
 		 * Failed.
 		 */
-		pcap_snprintf(p, errbuflen_remaining,
+		snprintf(p, errbuflen_remaining,
 		    "Couldn't get error message for error (%lu)", errnum);
 		return;
 	}
 
-	pcap_snprintf(p, errbuflen_remaining, "%s (%lu)", win32_errbuf, errnum);
+	/*
+	 * 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
index 838948b..ba0f66c 100644
--- a/fmtutils.h
+++ b/fmtutils.h
@@ -40,6 +40,8 @@
 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);
 
diff --git a/ftmacros.h b/ftmacros.h
index cd3daeb..3fafab8 100644
--- a/ftmacros.h
+++ b/ftmacros.h
@@ -83,14 +83,18 @@
    * least with HP's C compiler; hopefully doing so won't make it
    * *not* work with *un*-threaded code.
    */
-#elif defined(__linux__) || defined(linux) || defined(__linux)
+#else
   /*
    * Turn on _GNU_SOURCE to get everything GNU libc has to offer,
-   * including asprintf().
+   * 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
 
diff --git a/gencode.c b/gencode.c
index e3425cd..2978859 100644
--- a/gencode.c
+++ b/gencode.c
@@ -67,7 +67,7 @@
 #include "grammar.h"
 #include "scanner.h"
 
-#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER)
+#if defined(linux)
 #include <linux/types.h>
 #include <linux/if_packet.h>
 #include <linux/filter.h>
@@ -139,10 +139,6 @@
 
 #define ETHERMTU	1500
 
-#ifndef ETHERTYPE_TEB
-#define ETHERTYPE_TEB 0x6558
-#endif
-
 #ifndef IPPROTO_HOPOPTS
 #define IPPROTO_HOPOPTS 0
 #endif
@@ -248,6 +244,7 @@
 struct _compiler_state {
 	jmp_buf top_ctx;
 	pcap_t *bpf_pcap;
+	int error_set;
 
 	struct icode ic;
 
@@ -435,10 +432,22 @@
 {
 	va_list ap;
 
-	va_start(ap, fmt);
-	(void)pcap_vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
-	    fmt, ap);
-	va_end(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;
+	}
 }
 
 /*
@@ -454,7 +463,7 @@
 	va_list ap;
 
 	va_start(ap, fmt);
-	(void)pcap_vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
+	(void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
 	    fmt, ap);
 	va_end(ap);
 	longjmp(cstate->top_ctx, 1);
@@ -479,21 +488,21 @@
 static void backpatch(struct block *, struct block *);
 static void merge(struct block *, struct block *);
 static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    u_int, bpf_u_int32);
 static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    u_int, bpf_u_int32);
 static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    u_int, bpf_u_int32);
 static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    u_int, bpf_u_int32);
 static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32);
+    u_int, bpf_u_int32);
 static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int,
-    u_int, bpf_int32, bpf_u_int32);
+    u_int, bpf_u_int32, bpf_u_int32);
 static struct block *gen_bcmp(compiler_state_t *, enum e_offrel, u_int,
     u_int, const u_char *);
-static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, bpf_u_int32,
-    bpf_u_int32, bpf_u_int32, bpf_u_int32, int, bpf_int32);
+static struct block *gen_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,
@@ -502,9 +511,9 @@
 static struct block *gen_uncond(compiler_state_t *, int);
 static inline struct block *gen_true(compiler_state_t *);
 static inline struct block *gen_false(compiler_state_t *);
-static struct block *gen_ether_linktype(compiler_state_t *, int);
-static struct block *gen_ipnet_linktype(compiler_state_t *, int);
-static struct block *gen_linux_sll_linktype(compiler_state_t *, int);
+static struct block *gen_ether_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_ipnet_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_linux_sll_linktype(compiler_state_t *, bpf_u_int32);
 static struct slist *gen_load_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 *);
@@ -512,15 +521,15 @@
 static void insert_compute_vloffsets(compiler_state_t *, struct block *);
 static struct slist *gen_abs_offset_varpart(compiler_state_t *,
     bpf_abs_offset *);
-static int ethertype_to_ppptype(int);
-static struct block *gen_linktype(compiler_state_t *, int);
+static 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 *, int);
+static struct block *gen_llc_linktype(compiler_state_t *, bpf_u_int32);
 static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32,
-    int, int, u_int, u_int);
+    int, bpf_u_int32, u_int, u_int);
 #ifdef INET6
 static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *,
-    struct in6_addr *, int, int, u_int, u_int);
+    struct in6_addr *, int, 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);
@@ -529,7 +538,7 @@
 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 *, 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
@@ -541,23 +550,25 @@
     struct addrinfo *, int, int);
 #endif
 static struct block *gen_ipfrag(compiler_state_t *);
-static struct block *gen_portatom(compiler_state_t *, int, bpf_int32);
-static struct block *gen_portrangeatom(compiler_state_t *, int, bpf_int32,
-    bpf_int32);
-static struct block *gen_portatom6(compiler_state_t *, int, bpf_int32);
-static struct block *gen_portrangeatom6(compiler_state_t *, int, bpf_int32,
-    bpf_int32);
-struct block *gen_portop(compiler_state_t *, int, int, int);
-static struct block *gen_port(compiler_state_t *, int, int, int);
-struct block *gen_portrangeop(compiler_state_t *, int, int, int, int);
-static struct block *gen_portrange(compiler_state_t *, int, int, int, int);
-struct block *gen_portop6(compiler_state_t *, int, int, int);
-static struct block *gen_port6(compiler_state_t *, int, int, int);
-struct block *gen_portrangeop6(compiler_state_t *, int, int, int, int);
-static struct block *gen_portrange6(compiler_state_t *, int, int, int, int);
+static struct block *gen_portatom(compiler_state_t *, int, 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 *, int, int, int);
-static struct block *gen_proto(compiler_state_t *, int, int, 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);
@@ -567,7 +578,7 @@
 
 static struct block *gen_ppi_dlt_check(compiler_state_t *);
 static struct block *gen_atmfield_code_internal(compiler_state_t *, int,
-    bpf_int32, bpf_u_int32, 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);
 
@@ -721,7 +732,7 @@
 	 * link-layer type, so we can't use it.
 	 */
 	if (!p->activated) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "not-yet-activated pcap_t passed to pcap_compile");
 		return (-1);
 	}
@@ -762,13 +773,14 @@
 	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) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			 "snaplen of 0 rejects all packets");
 		rc = -1;
 		goto quit;
@@ -819,7 +831,7 @@
 		}
 		if (cstate.ic.root == NULL ||
 		    (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) {
-			(void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			(void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "expression rejects all packets");
 			rc = -1;
 			goto quit;
@@ -1013,42 +1025,42 @@
 
 static struct block *
 gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
 	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v);
 }
 
 static struct block *
 gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
 	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v);
 }
 
 static struct block *
 gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
 	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v);
 }
 
 static struct block *
 gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
 	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v);
 }
 
 static struct block *
 gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v)
+    u_int size, bpf_u_int32 v)
 {
 	return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v);
 }
 
 static struct block *
 gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
-    u_int size, bpf_int32 v, bpf_u_int32 mask)
+    u_int size, bpf_u_int32 v, bpf_u_int32 mask)
 {
 	return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v);
 }
@@ -1059,22 +1071,12 @@
 {
 	register struct block *b, *tmp;
 
-	/*
-	 * XXX - the actual *instructions* do unsigned comparisons on
-	 * most platforms, and the load instructions don't do sign
-	 * extension, so gen_cmp() should really take an unsigned
-	 * value argument.
-	 *
-	 * As the load instructons also don't do sign-extension, we
-	 * fetch the values from the byte array as unsigned.  We don't
-	 * want to use the signed versions of the extract calls.
-	 */
 	b = NULL;
 	while (size >= 4) {
 		register const u_char *p = &v[size - 4];
 
 		tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W,
-		    (bpf_int32)EXTRACT_32BITS(p));
+		    EXTRACT_BE_U_4(p));
 		if (b != NULL)
 			gen_and(b, tmp);
 		b = tmp;
@@ -1084,14 +1086,14 @@
 		register const u_char *p = &v[size - 2];
 
 		tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H,
-		    (bpf_int32)EXTRACT_16BITS(p));
+		    EXTRACT_BE_U_2(p));
 		if (b != NULL)
 			gen_and(b, tmp);
 		b = tmp;
 		size -= 2;
 	}
 	if (size > 0) {
-		tmp = gen_cmp(cstate, offrel, offset, BPF_B, (bpf_int32)v[0]);
+		tmp = gen_cmp(cstate, offrel, offset, BPF_B, v[0]);
 		if (b != NULL)
 			gen_and(b, tmp);
 		b = tmp;
@@ -1106,9 +1108,9 @@
  * should test the opposite of "jtype".
  */
 static struct block *
-gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, bpf_u_int32 offset,
-    bpf_u_int32 size, bpf_u_int32 mask, bpf_u_int32 jtype, int reverse,
-    bpf_int32 v)
+gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+    u_int size, bpf_u_int32 mask, int jtype, int reverse,
+    bpf_u_int32 v)
 {
 	struct slist *s, *s2;
 	struct block *b;
@@ -1956,11 +1958,11 @@
  * the appropriate test.
  */
 static struct block *
-gen_ether_linktype(compiler_state_t *cstate, int proto)
+gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
 	struct block *b0, *b1;
 
-	switch (proto) {
+	switch (ll_proto) {
 
 	case LLCSAP_ISONS:
 	case LLCSAP_IP:
@@ -1979,8 +1981,7 @@
 		 */
 		b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
 		gen_not(b0);
-		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)
-			     ((proto << 8) | proto));
+		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
 		gen_and(b0, b1);
 		return b1;
 
@@ -2017,8 +2018,8 @@
 		 * This generates code to check both for the
 		 * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3.
 		 */
-		b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
-		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF);
+		b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
+		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
 		gen_or(b0, b1);
 
 		/*
@@ -2048,7 +2049,7 @@
 		 * do that before checking for the other frame
 		 * types.
 		 */
-		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX);
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
 		gen_or(b0, b1);
 		return b1;
 
@@ -2078,9 +2079,9 @@
 		 * 0x000000 (encapsulated Ethernet) and a protocol
 		 * type of ETHERTYPE_AARP (Appletalk ARP).
 		 */
-		if (proto == ETHERTYPE_ATALK)
+		if (ll_proto == ETHERTYPE_ATALK)
 			b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
-		else	/* proto == ETHERTYPE_AARP */
+		else	/* ll_proto == ETHERTYPE_AARP */
 			b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
 		gen_and(b0, b1);
 
@@ -2089,13 +2090,13 @@
 		 * phase 1?); we just check for the Ethernet
 		 * protocol type.
 		 */
-		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
 
 		gen_or(b0, b1);
 		return b1;
 
 	default:
-		if (proto <= ETHERMTU) {
+		if (ll_proto <= ETHERMTU) {
 			/*
 			 * This is an LLC SAP value, so the frames
 			 * that match would be 802.2 frames.
@@ -2106,7 +2107,7 @@
 			 */
 			b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
 			gen_not(b0);
-			b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, (bpf_int32)proto);
+			b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, ll_proto);
 			gen_and(b0, b1);
 			return b1;
 		} else {
@@ -2115,18 +2116,17 @@
 			 * the length/type field with it (if
 			 * the frame is an 802.2 frame, the length
 			 * field will be <= ETHERMTU, and, as
-			 * "proto" is > ETHERMTU, this test
+			 * "ll_proto" is > ETHERMTU, this test
 			 * will fail and the frame won't match,
 			 * which is what we want).
 			 */
-			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
-			    (bpf_int32)proto);
+			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
 		}
 	}
 }
 
 static struct block *
-gen_loopback_linktype(compiler_state_t *cstate, int proto)
+gen_loopback_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
 	/*
 	 * For DLT_NULL, the link-layer header is a 32-bit word
@@ -2154,10 +2154,10 @@
 		 * code to compare against the result.
 		 */
 		if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped)
-			proto = SWAPLONG(proto);
-		proto = htonl(proto);
+			ll_proto = SWAPLONG(ll_proto);
+		ll_proto = htonl(ll_proto);
 	}
-	return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, (bpf_int32)proto));
+	return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, ll_proto));
 }
 
 /*
@@ -2165,17 +2165,16 @@
  * or IPv6 then we have an error.
  */
 static struct block *
-gen_ipnet_linktype(compiler_state_t *cstate, int proto)
+gen_ipnet_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
-	switch (proto) {
+	switch (ll_proto) {
 
 	case ETHERTYPE_IP:
-		return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET);
+		return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET);
 		/*NOTREACHED*/
 
 	case ETHERTYPE_IPV6:
-		return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-		    (bpf_int32)IPH_AF_INET6);
+		return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET6);
 		/*NOTREACHED*/
 
 	default:
@@ -2188,17 +2187,17 @@
 /*
  * Generate code to match a particular packet type.
  *
- * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * "ll_proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
  * value, if <= ETHERMTU.  We use that to determine whether to
  * match the type field or to check the type field for the special
  * LINUX_SLL_P_802_2 value and then do the appropriate test.
  */
 static struct block *
-gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
+gen_linux_sll_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
 	struct block *b0, *b1;
 
-	switch (proto) {
+	switch (ll_proto) {
 
 	case LLCSAP_ISONS:
 	case LLCSAP_IP:
@@ -2216,8 +2215,7 @@
 		 * (i.e., other SAP values)?
 		 */
 		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
-		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)
-			     ((proto << 8) | proto));
+		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
 		gen_and(b0, b1);
 		return b1;
 
@@ -2247,7 +2245,7 @@
 		 * then put a check for LINUX_SLL_P_802_2 frames
 		 * before it.
 		 */
-		b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
+		b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
 		b1 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX);
 		gen_or(b0, b1);
 		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
@@ -2265,7 +2263,7 @@
 		 * do that before checking for the other frame
 		 * types.
 		 */
-		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX);
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
 		gen_or(b0, b1);
 		return b1;
 
@@ -2294,9 +2292,9 @@
 		 * 0x000000 (encapsulated Ethernet) and a protocol
 		 * type of ETHERTYPE_AARP (Appletalk ARP).
 		 */
-		if (proto == ETHERTYPE_ATALK)
+		if (ll_proto == ETHERTYPE_ATALK)
 			b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
-		else	/* proto == ETHERTYPE_AARP */
+		else	/* ll_proto == ETHERTYPE_AARP */
 			b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
 		gen_and(b0, b1);
 
@@ -2305,13 +2303,13 @@
 		 * phase 1?); we just check for the Ethernet
 		 * protocol type.
 		 */
-		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+		b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
 
 		gen_or(b0, b1);
 		return b1;
 
 	default:
-		if (proto <= ETHERMTU) {
+		if (ll_proto <= ETHERMTU) {
 			/*
 			 * This is an LLC SAP value, so the frames
 			 * that match would be 802.2 frames.
@@ -2321,7 +2319,7 @@
 			 */
 			b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
 			b1 = gen_cmp(cstate, OR_LINKHDR, cstate->off_linkpl.constant_part, BPF_B,
-			     (bpf_int32)proto);
+			     ll_proto);
 			gen_and(b0, b1);
 			return b1;
 		} else {
@@ -2330,11 +2328,11 @@
 			 * the length/type field with it (if
 			 * the frame is an 802.2 frame, the length
 			 * field will be <= ETHERMTU, and, as
-			 * "proto" is > ETHERMTU, this test
+			 * "ll_proto" is > ETHERMTU, this test
 			 * will fail and the frame won't match,
 			 * which is what we want).
 			 */
-			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
 		}
 	}
 }
@@ -2848,7 +2846,7 @@
 		s2->s.k = 3;
 		sappend(s, s2);
 		s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_IMM);
-		s2->s.k = ~3;
+		s2->s.k = (bpf_u_int32)~3;
 		sappend(s, s2);
 		s2 = new_stmt(cstate, BPF_ST);
 		s2->s.k = cstate->off_linkpl.reg;
@@ -2929,7 +2927,7 @@
 	}
 
 	/*
-	 * If there there is no initialization yet and we need variable
+	 * If there is no initialization yet and we need variable
 	 * length offsets for VLAN, initialize them to zero
 	 */
 	if (s == NULL && cstate->is_vlan_vloffset) {
@@ -3035,33 +3033,33 @@
 /*
  * Map an Ethernet type to the equivalent PPP type.
  */
-static int
-ethertype_to_ppptype(int proto)
+static bpf_u_int32
+ethertype_to_ppptype(bpf_u_int32 ll_proto)
 {
-	switch (proto) {
+	switch (ll_proto) {
 
 	case ETHERTYPE_IP:
-		proto = PPP_IP;
+		ll_proto = PPP_IP;
 		break;
 
 	case ETHERTYPE_IPV6:
-		proto = PPP_IPV6;
+		ll_proto = PPP_IPV6;
 		break;
 
 	case ETHERTYPE_DN:
-		proto = PPP_DECNET;
+		ll_proto = PPP_DECNET;
 		break;
 
 	case ETHERTYPE_ATALK:
-		proto = PPP_APPLE;
+		ll_proto = PPP_APPLE;
 		break;
 
 	case ETHERTYPE_NS:
-		proto = PPP_NS;
+		ll_proto = PPP_NS;
 		break;
 
 	case LLCSAP_ISONS:
-		proto = PPP_OSI;
+		ll_proto = PPP_OSI;
 		break;
 
 	case LLCSAP_8021D:
@@ -3070,14 +3068,14 @@
 		 * over PPP are Spanning Tree Protocol
 		 * Bridging PDUs.
 		 */
-		proto = PPP_BRPDU;
+		ll_proto = PPP_BRPDU;
 		break;
 
 	case LLCSAP_IPX:
-		proto = PPP_IPX;
+		ll_proto = PPP_IPX;
 		break;
 	}
-	return (proto);
+	return (ll_proto);
 }
 
 /*
@@ -3133,29 +3131,14 @@
  * value, if <= ETHERMTU.
  */
 static struct block *
-gen_linktype(compiler_state_t *cstate, int proto)
+gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
 	struct block *b0, *b1, *b2;
 	const char *description;
 
 	/* are we checking MPLS-encapsulated packets? */
-	if (cstate->label_stack_depth > 0) {
-		switch (proto) {
-		case ETHERTYPE_IP:
-		case PPP_IP:
-			/* FIXME add other L3 proto IDs */
-			return gen_mpls_linktype(cstate, Q_IP);
-
-		case ETHERTYPE_IPV6:
-		case PPP_IPV6:
-			/* FIXME add other L3 proto IDs */
-			return gen_mpls_linktype(cstate, Q_IPV6);
-
-		default:
-			bpf_error(cstate, "unsupported protocol over mpls");
-			/*NOTREACHED*/
-		}
-	}
+	if (cstate->label_stack_depth > 0)
+		return gen_mpls_linktype(cstate, ll_proto);
 
 	switch (cstate->linktype) {
 
@@ -3169,21 +3152,21 @@
 		else
 			b0 = NULL;
 
-		b1 = gen_ether_linktype(cstate, proto);
+		b1 = gen_ether_linktype(cstate, ll_proto);
 		if (b0 != NULL)
 			gen_and(b0, b1);
 		return b1;
 		/*NOTREACHED*/
 
 	case DLT_C_HDLC:
-		switch (proto) {
+		switch (ll_proto) {
 
 		case LLCSAP_ISONS:
-			proto = (proto << 8 | LLCSAP_ISONS);
+			ll_proto = (ll_proto << 8 | LLCSAP_ISONS);
 			/* fall through */
 
 		default:
-			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
 			/*NOTREACHED*/
 		}
 
@@ -3200,7 +3183,7 @@
 		/*
 		 * Now check for the specified link-layer type.
 		 */
-		b1 = gen_llc_linktype(cstate, proto);
+		b1 = gen_llc_linktype(cstate, ll_proto);
 		gen_and(b0, b1);
 		return b1;
 		/*NOTREACHED*/
@@ -3209,20 +3192,20 @@
 		/*
 		 * XXX - check for LLC frames.
 		 */
-		return gen_llc_linktype(cstate, proto);
+		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, proto);
+		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, proto);
+		return gen_llc_linktype(cstate, ll_proto);
 		/*NOTREACHED*/
 
 	case DLT_SUNATM:
@@ -3234,13 +3217,13 @@
 		 * 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, proto);
+		b1 = gen_llc_linktype(cstate, ll_proto);
 		gen_and(b0, b1);
 		return b1;
 		/*NOTREACHED*/
 
 	case DLT_LINUX_SLL:
-		return gen_linux_sll_linktype(cstate, proto);
+		return gen_linux_sll_linktype(cstate, ll_proto);
 		/*NOTREACHED*/
 
 	case DLT_SLIP:
@@ -3253,7 +3236,7 @@
 		 * XXX - for IPv4, check for a version number of 4, and,
 		 * for IPv6, check for a version number of 6?
 		 */
-		switch (proto) {
+		switch (ll_proto) {
 
 		case ETHERTYPE_IP:
 			/* Check for a version number of 4. */
@@ -3272,7 +3255,7 @@
 		/*
 		 * Raw IPv4, so no type field.
 		 */
-		if (proto == ETHERTYPE_IP)
+		if (ll_proto == ETHERTYPE_IP)
 			return gen_true(cstate);	/* always true */
 
 		/* Checking for something other than IPv4; always false */
@@ -3283,7 +3266,7 @@
 		/*
 		 * Raw IPv6, so no type field.
 		 */
-		if (proto == ETHERTYPE_IPV6)
+		if (ll_proto == ETHERTYPE_IPV6)
 			return gen_true(cstate);	/* always true */
 
 		/* Checking for something other than IPv6; always false */
@@ -3298,8 +3281,8 @@
 		 * We use Ethernet protocol types inside libpcap;
 		 * map them to the corresponding PPP protocol types.
 		 */
-		proto = ethertype_to_ppptype(proto);
-		return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+		return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
+		    ethertype_to_ppptype(ll_proto));
 		/*NOTREACHED*/
 
 	case DLT_PPP_BSDOS:
@@ -3307,7 +3290,7 @@
 		 * We use Ethernet protocol types inside libpcap;
 		 * map them to the corresponding PPP protocol types.
 		 */
-		switch (proto) {
+		switch (ll_proto) {
 
 		case ETHERTYPE_IP:
 			/*
@@ -3322,16 +3305,15 @@
 			return b0;
 
 		default:
-			proto = ethertype_to_ppptype(proto);
 			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
-				(bpf_int32)proto);
+			    ethertype_to_ppptype(ll_proto));
 		}
 		/*NOTREACHED*/
 
 	case DLT_NULL:
 	case DLT_LOOP:
 	case DLT_ENC:
-		switch (proto) {
+		switch (ll_proto) {
 
 		case ETHERTYPE_IP:
 			return (gen_loopback_linktype(cstate, AF_INET));
@@ -3412,12 +3394,12 @@
 		 * af field is host byte order in contrast to the rest of
 		 * the packet.
 		 */
-		if (proto == ETHERTYPE_IP)
+		if (ll_proto == ETHERTYPE_IP)
 			return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
-			    BPF_B, (bpf_int32)AF_INET));
-		else if (proto == ETHERTYPE_IPV6)
+			    BPF_B, AF_INET));
+		else if (ll_proto == ETHERTYPE_IPV6)
 			return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
-			    BPF_B, (bpf_int32)AF_INET6));
+			    BPF_B, AF_INET6));
 		else
 			return gen_false(cstate);
 		/*NOTREACHED*/
@@ -3429,43 +3411,43 @@
 		 * XXX should we check for first fragment if the protocol
 		 * uses PHDS?
 		 */
-		switch (proto) {
+		switch (ll_proto) {
 
 		default:
 			return gen_false(cstate);
 
 		case ETHERTYPE_IPV6:
 			return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-				(bpf_int32)ARCTYPE_INET6));
+				ARCTYPE_INET6));
 
 		case ETHERTYPE_IP:
 			b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-				     (bpf_int32)ARCTYPE_IP);
+			    ARCTYPE_IP);
 			b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-				     (bpf_int32)ARCTYPE_IP_OLD);
+			    ARCTYPE_IP_OLD);
 			gen_or(b0, b1);
 			return (b1);
 
 		case ETHERTYPE_ARP:
 			b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-				     (bpf_int32)ARCTYPE_ARP);
+			    ARCTYPE_ARP);
 			b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-				     (bpf_int32)ARCTYPE_ARP_OLD);
+			    ARCTYPE_ARP_OLD);
 			gen_or(b0, b1);
 			return (b1);
 
 		case ETHERTYPE_REVARP:
 			return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-					(bpf_int32)ARCTYPE_REVARP));
+			    ARCTYPE_REVARP));
 
 		case ETHERTYPE_ATALK:
 			return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
-					(bpf_int32)ARCTYPE_ATALK));
+			    ARCTYPE_ATALK));
 		}
 		/*NOTREACHED*/
 
 	case DLT_LTALK:
-		switch (proto) {
+		switch (ll_proto) {
 		case ETHERTYPE_ATALK:
 			return gen_true(cstate);
 		default:
@@ -3478,7 +3460,7 @@
 		 * XXX - assumes a 2-byte Frame Relay header with
 		 * DLCI and flags.  What if the address is longer?
 		 */
-		switch (proto) {
+		switch (ll_proto) {
 
 		case ETHERTYPE_IP:
 			/*
@@ -3555,7 +3537,7 @@
 		return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000);
 
 	case DLT_IPNET:
-		return gen_ipnet_linktype(cstate, proto);
+		return gen_ipnet_linktype(cstate, ll_proto);
 
 	case DLT_LINUX_IRDA:
 		bpf_error(cstate, "IrDA link-layer type filtering not implemented");
@@ -3594,6 +3576,7 @@
 	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:
@@ -3632,7 +3615,7 @@
 			 * it's not, it needs to be handled specially
 			 * above.)
 			 */
-			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+			return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
 			/*NOTREACHED */
 		} else {
 			/*
@@ -3691,7 +3674,7 @@
 		 * Now check for the purported DSAP and SSAP not being
 		 * 0xFF, to rule out NetWare-over-802.3.
 		 */
-		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF);
+		b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
 		gen_not(b1);
 		gen_and(b0, b1);
 		return b1;
@@ -3903,12 +3886,12 @@
  * protocol ID in a SNAP header.
  */
 static struct block *
-gen_llc_linktype(compiler_state_t *cstate, int proto)
+gen_llc_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
 	/*
 	 * XXX - handle token-ring variable-length header.
 	 */
-	switch (proto) {
+	switch (ll_proto) {
 
 	case LLCSAP_IP:
 	case LLCSAP_ISONS:
@@ -3919,15 +3902,14 @@
 		 * DSAP, as we do for other SAP values?
 		 */
 		return gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_u_int32)
-			     ((proto << 8) | proto));
+			     ((ll_proto << 8) | ll_proto));
 
 	case LLCSAP_IPX:
 		/*
 		 * XXX - are there ever SNAP frames for IPX on
 		 * non-Ethernet 802.x networks?
 		 */
-		return gen_cmp(cstate, OR_LLC, 0, BPF_B,
-		    (bpf_int32)LLCSAP_IPX);
+		return gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
 
 	case ETHERTYPE_ATALK:
 		/*
@@ -3946,12 +3928,12 @@
 		 * XXX - we don't have to check for IPX 802.3
 		 * here, but should we check for the IPX Ethertype?
 		 */
-		if (proto <= ETHERMTU) {
+		if (ll_proto <= ETHERMTU) {
 			/*
 			 * This is an LLC SAP value, so check
 			 * the DSAP.
 			 */
-			return gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)proto);
+			return gen_cmp(cstate, OR_LLC, 0, BPF_B, ll_proto);
 		} else {
 			/*
 			 * This is an Ethernet type; we assume that it's
@@ -3966,20 +3948,20 @@
 			 * organization code of 0x000000 (encapsulated
 			 * Ethernet), we'd do
 			 *
-			 *	return gen_snap(cstate, 0x000000, proto);
+			 *	return gen_snap(cstate, 0x000000, ll_proto);
 			 *
 			 * here; for now, we don't, as per the above.
 			 * I don't know whether it's worth the extra CPU
 			 * time to do the right check or not.
 			 */
-			return gen_cmp(cstate, OR_LLC, 6, BPF_H, (bpf_int32)proto);
+			return gen_cmp(cstate, OR_LLC, 6, BPF_H, ll_proto);
 		}
 	}
 }
 
 static struct block *
 gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
-    int dir, int proto, u_int src_off, u_int dst_off)
+    int dir, bpf_u_int32 ll_proto, u_int src_off, u_int dst_off)
 {
 	struct block *b0, *b1;
 	u_int offset;
@@ -3995,15 +3977,15 @@
 		break;
 
 	case Q_AND:
-		b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off);
-		b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
+		b0 = gen_hostop(cstate, addr, mask, Q_SRC, 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, proto, src_off, dst_off);
-		b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
+		b0 = gen_hostop(cstate, addr, mask, Q_SRC, 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;
 
@@ -4035,8 +4017,8 @@
 		abort();
 		/*NOTREACHED*/
 	}
-	b0 = gen_linktype(cstate, proto);
-	b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, (bpf_int32)addr, mask);
+	b0 = gen_linktype(cstate, ll_proto);
+	b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, addr, mask);
 	gen_and(b0, b1);
 	return b1;
 }
@@ -4044,7 +4026,8 @@
 #ifdef INET6
 static struct block *
 gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
-    struct in6_addr *mask, int dir, int proto, u_int src_off, u_int dst_off)
+    struct in6_addr *mask, int dir, bpf_u_int32 ll_proto, u_int src_off,
+    u_int dst_off)
 {
 	struct block *b0, *b1;
 	u_int offset;
@@ -4061,15 +4044,15 @@
 		break;
 
 	case Q_AND:
-		b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off);
-		b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
+		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, proto, src_off, dst_off);
-		b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
+		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;
 
@@ -4111,7 +4094,7 @@
 	gen_and(b0, b1);
 	b0 = gen_mcmp(cstate, OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0]));
 	gen_and(b0, b1);
-	b0 = gen_linktype(cstate, proto);
+	b0 = gen_linktype(cstate, ll_proto);
 	gen_and(b0, b1);
 	return b1;
 }
@@ -4846,24 +4829,29 @@
 	b0 = gen_linktype(cstate, ETHERTYPE_DN);
 	/* Check for pad = 1, long header case */
 	tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H,
-	    (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF));
+	    (bpf_u_int32)ntohs(0x0681), (bpf_u_int32)ntohs(0x07FF));
 	b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh,
-	    BPF_H, (bpf_int32)ntohs((u_short)addr));
+	    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_int32)0x06, (bpf_int32)0x7);
-	b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+	tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (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_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF));
-	b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+	    (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_int32)0x02, (bpf_int32)0x7);
-	b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+	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);
 
@@ -4878,13 +4866,13 @@
  * field in the IP header.
  */
 static struct block *
-gen_mpls_linktype(compiler_state_t *cstate, int proto)
+gen_mpls_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
 {
 	struct block *b0, *b1;
 
-        switch (proto) {
+        switch (ll_proto) {
 
-        case Q_IP:
+        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 */
@@ -4892,7 +4880,7 @@
                 gen_and(b0, b1);
                 return b1;
 
-       case Q_IPV6:
+        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 */
@@ -4900,8 +4888,10 @@
                 gen_and(b0, b1);
                 return b1;
 
-       default:
-                abort();
+        default:
+               /* FIXME add other L3 proto IDs */
+               bpf_error(cstate, "unsupported protocol over mpls");
+               /*NOTREACHED*/
         }
 }
 
@@ -5583,46 +5573,46 @@
  * headers).
  */
 static struct block *
-gen_portatom(compiler_state_t *cstate, int off, bpf_int32 v)
+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_int32 v)
+gen_portatom6(compiler_state_t *cstate, int off, bpf_u_int32 v)
 {
 	return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v);
 }
 
-struct block *
-gen_portop(compiler_state_t *cstate, int port, int proto, int dir)
+static struct block *
+gen_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, (bpf_int32)proto);
+	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, (bpf_int32)port);
+		b1 = gen_portatom(cstate, 0, port);
 		break;
 
 	case Q_DST:
-		b1 = gen_portatom(cstate, 2, (bpf_int32)port);
+		b1 = gen_portatom(cstate, 2, port);
 		break;
 
 	case Q_AND:
-		tmp = gen_portatom(cstate, 0, (bpf_int32)port);
-		b1 = gen_portatom(cstate, 2, (bpf_int32)port);
+		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, (bpf_int32)port);
-		b1 = gen_portatom(cstate, 2, (bpf_int32)port);
+		tmp = gen_portatom(cstate, 0, port);
+		b1 = gen_portatom(cstate, 2, port);
 		gen_or(tmp, b1);
 		break;
 
@@ -5660,7 +5650,7 @@
 }
 
 static struct block *
-gen_port(compiler_state_t *cstate, int port, int ip_proto, int dir)
+gen_port(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
 {
 	struct block *b0, *b1, *tmp;
 
@@ -5687,7 +5677,7 @@
 	case IPPROTO_UDP:
 	case IPPROTO_TCP:
 	case IPPROTO_SCTP:
-		b1 = gen_portop(cstate, port, ip_proto, dir);
+		b1 = gen_portop(cstate, port, (u_int)ip_proto, dir);
 		break;
 
 	case PROTO_UNDEF:
@@ -5706,33 +5696,33 @@
 }
 
 struct block *
-gen_portop6(compiler_state_t *cstate, int port, int proto, int dir)
+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, (bpf_int32)proto);
+	b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
 
 	switch (dir) {
 	case Q_SRC:
-		b1 = gen_portatom6(cstate, 0, (bpf_int32)port);
+		b1 = gen_portatom6(cstate, 0, port);
 		break;
 
 	case Q_DST:
-		b1 = gen_portatom6(cstate, 2, (bpf_int32)port);
+		b1 = gen_portatom6(cstate, 2, port);
 		break;
 
 	case Q_AND:
-		tmp = gen_portatom6(cstate, 0, (bpf_int32)port);
-		b1 = gen_portatom6(cstate, 2, (bpf_int32)port);
+		tmp = gen_portatom6(cstate, 0, port);
+		b1 = gen_portatom6(cstate, 2, port);
 		gen_and(tmp, b1);
 		break;
 
 	case Q_DEFAULT:
 	case Q_OR:
-		tmp = gen_portatom6(cstate, 0, (bpf_int32)port);
-		b1 = gen_portatom6(cstate, 2, (bpf_int32)port);
+		tmp = gen_portatom6(cstate, 0, port);
+		b1 = gen_portatom6(cstate, 2, port);
 		gen_or(tmp, b1);
 		break;
 
@@ -5745,7 +5735,7 @@
 }
 
 static struct block *
-gen_port6(compiler_state_t *cstate, int port, int ip_proto, int dir)
+gen_port6(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
 {
 	struct block *b0, *b1, *tmp;
 
@@ -5756,7 +5746,7 @@
 	case IPPROTO_UDP:
 	case IPPROTO_TCP:
 	case IPPROTO_SCTP:
-		b1 = gen_portop6(cstate, port, ip_proto, dir);
+		b1 = gen_portop6(cstate, port, (u_int)ip_proto, dir);
 		break;
 
 	case PROTO_UNDEF:
@@ -5776,8 +5766,8 @@
 
 /* gen_portrange code */
 static struct block *
-gen_portrangeatom(compiler_state_t *cstate, int off, bpf_int32 v1,
-    bpf_int32 v2)
+gen_portrangeatom(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
+    bpf_u_int32 v2)
 {
 	struct block *b1, *b2;
 
@@ -5785,7 +5775,7 @@
 		/*
 		 * Reverse the order of the ports, so v1 is the lower one.
 		 */
-		bpf_int32 vtemp;
+		bpf_u_int32 vtemp;
 
 		vtemp = v1;
 		v1 = v2;
@@ -5800,36 +5790,36 @@
 	return b2;
 }
 
-struct block *
-gen_portrangeop(compiler_state_t *cstate, int port1, int port2, int proto,
-    int dir)
+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, (bpf_int32)proto);
+	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, (bpf_int32)port1, (bpf_int32)port2);
+		b1 = gen_portrangeatom(cstate, 0, port1, port2);
 		break;
 
 	case Q_DST:
-		b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+		b1 = gen_portrangeatom(cstate, 2, port1, port2);
 		break;
 
 	case Q_AND:
-		tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
-		b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+		tmp = gen_portrangeatom(cstate, 0, port1, port2);
+		b1 = gen_portrangeatom(cstate, 2, port1, port2);
 		gen_and(tmp, b1);
 		break;
 
 	case Q_DEFAULT:
 	case Q_OR:
-		tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
-		b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+		tmp = gen_portrangeatom(cstate, 0, port1, port2);
+		b1 = gen_portrangeatom(cstate, 2, port1, port2);
 		gen_or(tmp, b1);
 		break;
 
@@ -5867,7 +5857,7 @@
 }
 
 static struct block *
-gen_portrange(compiler_state_t *cstate, int port1, int port2, int ip_proto,
+gen_portrange(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
     int dir)
 {
 	struct block *b0, *b1, *tmp;
@@ -5879,7 +5869,8 @@
 	case IPPROTO_UDP:
 	case IPPROTO_TCP:
 	case IPPROTO_SCTP:
-		b1 = gen_portrangeop(cstate, port1, port2, ip_proto, dir);
+		b1 = gen_portrangeop(cstate, port1, port2, (bpf_u_int32)ip_proto,
+		    dir);
 		break;
 
 	case PROTO_UNDEF:
@@ -5898,8 +5889,8 @@
 }
 
 static struct block *
-gen_portrangeatom6(compiler_state_t *cstate, int off, bpf_int32 v1,
-    bpf_int32 v2)
+gen_portrangeatom6(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
+    bpf_u_int32 v2)
 {
 	struct block *b1, *b2;
 
@@ -5907,7 +5898,7 @@
 		/*
 		 * Reverse the order of the ports, so v1 is the lower one.
 		 */
-		bpf_int32 vtemp;
+		bpf_u_int32 vtemp;
 
 		vtemp = v1;
 		v1 = v2;
@@ -5922,35 +5913,35 @@
 	return b2;
 }
 
-struct block *
-gen_portrangeop6(compiler_state_t *cstate, int port1, int port2, int proto,
-    int dir)
+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, (bpf_int32)proto);
+	b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
 
 	switch (dir) {
 	case Q_SRC:
-		b1 = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
+		b1 = gen_portrangeatom6(cstate, 0, port1, port2);
 		break;
 
 	case Q_DST:
-		b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+		b1 = gen_portrangeatom6(cstate, 2, port1, port2);
 		break;
 
 	case Q_AND:
-		tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
-		b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+		tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+		b1 = gen_portrangeatom6(cstate, 2, port1, port2);
 		gen_and(tmp, b1);
 		break;
 
 	case Q_DEFAULT:
 	case Q_OR:
-		tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
-		b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+		tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+		b1 = gen_portrangeatom6(cstate, 2, port1, port2);
 		gen_or(tmp, b1);
 		break;
 
@@ -5963,7 +5954,7 @@
 }
 
 static struct block *
-gen_portrange6(compiler_state_t *cstate, int port1, int port2, int ip_proto,
+gen_portrange6(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
     int dir)
 {
 	struct block *b0, *b1, *tmp;
@@ -5975,7 +5966,8 @@
 	case IPPROTO_UDP:
 	case IPPROTO_TCP:
 	case IPPROTO_SCTP:
-		b1 = gen_portrangeop6(cstate, port1, port2, ip_proto, dir);
+		b1 = gen_portrangeop6(cstate, port1, port2, (bpf_u_int32)ip_proto,
+		    dir);
 		break;
 
 	case PROTO_UNDEF:
@@ -6045,10 +6037,10 @@
 #endif
 
 static struct block *
-gen_protochain(compiler_state_t *cstate, int v, int proto, int dir)
+gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
 {
 #ifdef NO_PROTOCHAIN
-	return gen_proto(cstate, v, proto, dir);
+	return gen_proto(cstate, v, proto);
 #else
 	struct block *b0, *b;
 	struct slist *s[100];
@@ -6065,8 +6057,8 @@
 	case Q_IPV6:
 		break;
 	case Q_DEFAULT:
-		b0 = gen_protochain(cstate, v, Q_IP, dir);
-		b = gen_protochain(cstate, v, Q_IPV6, dir);
+		b0 = gen_protochain(cstate, v, Q_IP);
+		b = gen_protochain(cstate, v, Q_IPV6);
 		gen_or(b0, b);
 		return b;
 	default:
@@ -6371,7 +6363,7 @@
  * against Q_IP and Q_IPV6.
  */
 static struct block *
-gen_proto(compiler_state_t *cstate, int v, int proto, int dir)
+gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir)
 {
 	struct block *b0, *b1;
 #ifndef CHASE_CHAIN
@@ -6409,7 +6401,7 @@
 		 */
 		b0 = gen_linktype(cstate, ETHERTYPE_IP);
 #ifndef CHASE_CHAIN
-		b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)v);
+		b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, v);
 #else
 		b1 = gen_protochain(cstate, v, Q_IP);
 #endif
@@ -6480,9 +6472,9 @@
 		 * header.
 		 */
 		b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT);
-		b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, (bpf_int32)v);
+		b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, v);
 		gen_and(b2, b1);
-		b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)v);
+		b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, v);
 		gen_or(b2, b1);
 #else
 		b1 = gen_protochain(cstate, v, Q_IPV6);
@@ -6499,7 +6491,7 @@
 		/*NOTREACHED*/
 
 	case Q_ESP:
-		bpf_error(cstate, "'ah proto' is bogus");
+		bpf_error(cstate, "'esp proto' is bogus");
 		/*NOTREACHED*/
 
 	case Q_PIM:
@@ -6546,13 +6538,13 @@
 			 */
 			b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS);
 			/* OSI in C-HDLC is stuffed with a fudge byte */
-			b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, (long)v);
+			b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, v);
 			gen_and(b0, b1);
 			return b1;
 
 		default:
 			b0 = gen_linktype(cstate, LLCSAP_ISONS);
-			b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, (long)v);
+			b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, v);
 			gen_and(b0, b1);
 			return b1;
 		}
@@ -6567,7 +6559,7 @@
 		 * 4 is the offset of the PDU type relative to the IS-IS
 		 * header.
 		 */
-		b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, (long)v);
+		b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, v);
 		gen_and(b0, b1);
 		return b1;
 
@@ -6928,7 +6920,7 @@
 	case Q_PROTOCHAIN:
 		real_proto = lookup_proto(cstate, name, proto);
 		if (real_proto >= 0)
-			return gen_protochain(cstate, real_proto, proto, dir);
+			return gen_protochain(cstate, real_proto, proto);
 		else
 			bpf_error(cstate, "unknown protocol: %s", name);
 
@@ -6942,7 +6934,7 @@
 
 struct block *
 gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2,
-    unsigned int masklen, struct qual q)
+    bpf_u_int32 masklen, struct qual q)
 {
 	register int nlen, mlen;
 	bpf_u_int32 n, m;
@@ -6955,11 +6947,15 @@
 		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)
@@ -7017,8 +7013,11 @@
 		vlen = __pcap_atodn(s, &v);
 		if (vlen == 0)
 			bpf_error(cstate, "malformed decnet address '%s'", s);
-	} else
+	} else {
 		vlen = __pcap_atoin(s, &v);
+		if (vlen < 0)
+			bpf_error(cstate, "invalid IPv4 address '%s'", s);
+	}
 
 	switch (q.addr) {
 
@@ -7062,8 +7061,8 @@
 
 	    {
 		struct block *b;
-		b = gen_port(cstate, (int)v, proto, dir);
-		gen_or(gen_port6(cstate, (int)v, proto, dir), b);
+		b = gen_port(cstate, v, proto, dir);
+		gen_or(gen_port6(cstate, v, proto, dir), b);
 		return b;
 	    }
 
@@ -7084,8 +7083,8 @@
 
 	    {
 		struct block *b;
-		b = gen_portrange(cstate, (int)v, (int)v, proto, dir);
-		gen_or(gen_portrange6(cstate, (int)v, (int)v, proto, dir), b);
+		b = gen_portrange(cstate, v, v, proto, dir);
+		gen_or(gen_portrange6(cstate, v, v, proto, dir), b);
 		return b;
 	    }
 
@@ -7094,10 +7093,10 @@
 		/*NOTREACHED*/
 
 	case Q_PROTO:
-		return gen_proto(cstate, (int)v, proto, dir);
+		return gen_proto(cstate, v, proto, dir);
 
 	case Q_PROTOCHAIN:
-		return gen_protochain(cstate, (int)v, proto, dir);
+		return gen_protochain(cstate, v, proto);
 
 	case Q_UNDEF:
 		syntax(cstate);
@@ -7113,7 +7112,7 @@
 #ifdef INET6
 struct block *
 gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
-    unsigned int masklen, struct qual q)
+    bpf_u_int32 masklen, struct qual q)
 {
 	struct addrinfo *res;
 	struct in6_addr *addr;
@@ -7139,10 +7138,10 @@
 		bpf_error(cstate, "%s resolved to multiple address", s1);
 	addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
 
-	if (sizeof(mask) * 8 < masklen)
-		bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask) * 8));
+	if (masklen > sizeof(mask.s6_addr) * 8)
+		bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask.s6_addr) * 8));
 	memset(&mask, 0, sizeof(mask));
-	memset(&mask, 0xff, masklen / 8);
+	memset(&mask.s6_addr, 0xff, masklen / 8);
 	if (masklen % 8) {
 		mask.s6_addr[masklen / 8] =
 			(0xff << (8 - masklen % 8)) & 0xff;
@@ -7271,8 +7270,10 @@
  * for "index".
  */
 static struct arth *
-gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int size)
+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);
@@ -7282,17 +7283,18 @@
 
 	default:
 		bpf_error(cstate, "data size must be 1, 2, or 4");
+		/*NOTREACHED*/
 
 	case 1:
-		size = BPF_B;
+		size_code = BPF_B;
 		break;
 
 	case 2:
-		size = BPF_H;
+		size_code = BPF_H;
 		break;
 
 	case 4:
-		size = BPF_W;
+		size_code = BPF_W;
 		break;
 	}
 	switch (proto) {
@@ -7319,7 +7321,7 @@
 		/*
 		 * Load the item at that offset.
 		 */
-		tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+		tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
 		sappend(s, tmp);
 		sappend(inst->s, s);
 		break;
@@ -7361,7 +7363,7 @@
 		 * variable-length; that header length is what we put
 		 * into the X register and then added to the index).
 		 */
-		tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+		tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
 		tmp->s.k = cstate->off_linkhdr.constant_part;
 		sappend(s, tmp);
 		sappend(inst->s, s);
@@ -7408,7 +7410,7 @@
 		 * payload, and the constant part of the offset of the
 		 * start of the link-layer payload.
 		 */
-		tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+		tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
 		tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
 		sappend(s, tmp);
 		sappend(inst->s, s);
@@ -7465,7 +7467,7 @@
 		sappend(s, xfer_to_a(cstate, inst));
 		sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
 		sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
-		sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size));
+		sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code));
 		tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
 		sappend(inst->s, s);
 
@@ -7527,7 +7529,7 @@
         * payload, and the constant part of the offset of the
         * start of the link-layer payload.
         */
-        tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+        tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
         tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 40;
 
         sappend(s, tmp);
@@ -7544,7 +7546,8 @@
 }
 
 struct arth *
-gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
+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
@@ -7640,7 +7643,7 @@
 }
 
 static struct arth *
-gen_loadi_internal(compiler_state_t *cstate, int val)
+gen_loadi_internal(compiler_state_t *cstate, bpf_u_int32 val)
 {
 	struct arth *a;
 	struct slist *s;
@@ -7661,7 +7664,7 @@
 }
 
 struct arth *
-gen_loadi(compiler_state_t *cstate, int val)
+gen_loadi(compiler_state_t *cstate, bpf_u_int32 val)
 {
 	/*
 	 * Catch errors reported by us and routines below us, and return NULL
@@ -7736,13 +7739,7 @@
 		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) {
-		/*
-		 * XXX - we need to make up our minds as to what integers
-		 * are signed and what integers are unsigned in BPF programs
-		 * and in our IR.
-		 */
-		if (a1->s->s.code == (BPF_LD|BPF_IMM) &&
-		    (a1->s->s.k < 0 || a1->s->s.k > 31))
+		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);
@@ -7863,7 +7860,7 @@
  * would generate code appropriate to the radio header in question.
  */
 struct block *
-gen_byteop(compiler_state_t *cstate, int op, int idx, int val)
+gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val)
 {
 	struct block *b;
 	struct slist *s;
@@ -7880,14 +7877,14 @@
 		abort();
 
 	case '=':
-		return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val);
+		return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
 
 	case '<':
-		b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val);
+		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, (bpf_int32)val);
+		b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
 		return b;
 
 	case '|':
@@ -7965,9 +7962,9 @@
 			bpf_error(cstate, "netmask not known, so 'ip broadcast' not supported");
 		b0 = gen_linktype(cstate, ETHERTYPE_IP);
 		hostmask = ~cstate->netmask;
-		b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, (bpf_int32)0, hostmask);
+		b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, 0, hostmask);
 		b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W,
-			      (bpf_int32)(~0 & hostmask), hostmask);
+			      ~0 & hostmask, hostmask);
 		gen_or(b1, b2);
 		gen_and(b0, b2);
 		return b2;
@@ -8164,13 +8161,13 @@
 
 	case Q_IP:
 		b0 = gen_linktype(cstate, ETHERTYPE_IP);
-		b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, (bpf_int32)224);
+		b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, 224);
 		gen_and(b0, b1);
 		return b1;
 
 	case Q_IPV6:
 		b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
-		b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, (bpf_int32)255);
+		b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, 255);
 		gen_and(b0, b1);
 		return b1;
 	}
@@ -8178,6 +8175,53 @@
 	/*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
@@ -8241,7 +8285,7 @@
 #ifdef HAVE_NET_PFVAR_H
 	case DLT_PFLOG:
 		b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
-		    (bpf_int32)((dir == 0) ? PF_IN : PF_OUT));
+		    ((dir == 0) ? PF_IN : PF_OUT));
 		break;
 #endif
 
@@ -8305,9 +8349,9 @@
 		 * with newer capture APIs, allowing it to be saved
 		 * in pcapng files.
 		 */
-#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER)
+#if defined(linux)
 		/*
-		 * This is Linux with PF_PACKET support.
+		 * 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.
@@ -8316,7 +8360,6 @@
 			/* 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));
-			b0 = NULL;
 			/*NOTREACHED*/
 		}
 		/* match outgoing packets */
@@ -8326,11 +8369,11 @@
 			/* to filter on inbound traffic, invert the match */
 			gen_not(b0);
 		}
-#else /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */
+#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) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */
+#endif /* defined(linux) */
 	}
 	return (b0);
 }
@@ -8414,7 +8457,7 @@
 	}
 
 	b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W,
-		 (bpf_int32)rnr);
+		 (bpf_u_int32)rnr);
 	return (b0);
 }
 
@@ -8437,7 +8480,7 @@
 	}
 
 	b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W,
-	    (bpf_int32)srnr);
+	    (bpf_u_int32)srnr);
 	return (b0);
 }
 
@@ -8460,7 +8503,7 @@
 	}
 
 	b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B,
-	    (bpf_int32)reason);
+	    (bpf_u_int32)reason);
 	return (b0);
 }
 
@@ -8483,7 +8526,7 @@
 	}
 
 	b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B,
-	    (bpf_int32)action);
+	    (bpf_u_int32)action);
 	return (b0);
 }
 #else /* !HAVE_NET_PFVAR_H */
@@ -8574,7 +8617,7 @@
 
 /* IEEE 802.11 wireless header */
 struct block *
-gen_p80211_type(compiler_state_t *cstate, int type, int mask)
+gen_p80211_type(compiler_state_t *cstate, bpf_u_int32 type, bpf_u_int32 mask)
 {
 	struct block *b0;
 
@@ -8591,8 +8634,7 @@
 	case DLT_PRISM_HEADER:
 	case DLT_IEEE802_11_RADIO_AVS:
 	case DLT_IEEE802_11_RADIO:
-		b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, (bpf_int32)type,
-		    (bpf_int32)mask);
+		b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, type, mask);
 		break;
 
 	default:
@@ -8604,7 +8646,7 @@
 }
 
 struct block *
-gen_p80211_fcdir(compiler_state_t *cstate, int fcdir)
+gen_p80211_fcdir(compiler_state_t *cstate, bpf_u_int32 fcdir)
 {
 	struct block *b0;
 
@@ -8628,8 +8670,8 @@
 		/*NOTREACHED*/
 	}
 
-	b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, (bpf_int32)fcdir,
-		(bpf_u_int32)IEEE80211_FC1_DIR_MASK);
+	b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, fcdir,
+	    IEEE80211_FC1_DIR_MASK);
 
 	return (b0);
 }
@@ -8746,7 +8788,7 @@
 		bpf_error(cstate, "VLAN tag %u greater than maximum %u",
 		    vlan_num, 0x0fff);
 	}
-	return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, (bpf_int32)vlan_num, 0x0fff);
+	return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, vlan_num, 0x0fff);
 }
 
 static struct block *
@@ -8776,7 +8818,8 @@
 #if defined(SKF_AD_VLAN_TAG_PRESENT)
 /* add v to variable part of off */
 static void
-gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off, int v, struct slist *s)
+gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off,
+    bpf_u_int32 v, struct slist *s)
 {
 	struct slist *s2;
 
@@ -8882,7 +8925,7 @@
 
 	/*
 	 * This is tricky. We need to insert the statements updating variable
-	 * parts of offsets before the the traditional TPID and VID tests so
+	 * parts of offsets before the traditional TPID and VID tests so
 	 * that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but
 	 * we do not want this update to affect those checks. That's why we
 	 * generate both test blocks first and insert the statements updating
@@ -9062,7 +9105,7 @@
 			    label_num, 0xFFFFF);
 		}
 		label_num = label_num << 12; /* label is shifted 12 bits on the wire */
-		b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, (bpf_int32)label_num,
+		b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, label_num,
 		    0xfffff000); /* only compare the first 20 bits */
 		gen_and(b0, b1);
 		b0 = b1;
@@ -9102,7 +9145,7 @@
 		return (NULL);
 
 	/* check for PPPoE discovery */
-	return gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOED);
+	return gen_linktype(cstate, ETHERTYPE_PPPOED);
 }
 
 struct block *
@@ -9120,7 +9163,7 @@
 	/*
 	 * Test against the PPPoE session link-layer type.
 	 */
-	b0 = gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOES);
+	b0 = gen_linktype(cstate, ETHERTYPE_PPPOES);
 
 	/* If a specific session is requested, check PPPoE session id */
 	if (has_sess_num) {
@@ -9128,8 +9171,7 @@
 			bpf_error(cstate, "PPPoE session number %u greater than maximum %u",
 			    sess_num, 0x0000ffff);
 		}
-		b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W,
-		    (bpf_int32)sess_num, 0x0000ffff);
+		b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, sess_num, 0x0000ffff);
 		gen_and(b0, b1);
 		b0 = b1;
 	}
@@ -9169,7 +9211,7 @@
  * specified. Parameterized to handle both IPv4 and IPv6. */
 static struct block *
 gen_geneve_check(compiler_state_t *cstate,
-    struct block *(*gen_portfn)(compiler_state_t *, int, int, int),
+    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;
@@ -9179,7 +9221,7 @@
 	/* Check that we are operating on version 0. Otherwise, we
 	 * can't decode the rest of the fields. The version is 2 bits
 	 * in the first byte of the Geneve header. */
-	b1 = gen_mcmp(cstate, offrel, 8, BPF_B, (bpf_int32)0, 0xc0);
+	b1 = gen_mcmp(cstate, offrel, 8, BPF_B, 0, 0xc0);
 	gen_and(b0, b1);
 	b0 = b1;
 
@@ -9189,8 +9231,7 @@
 			    vni, 0xffffff);
 		}
 		vni <<= 8; /* VNI is in the upper 3 bytes */
-		b1 = gen_mcmp(cstate, offrel, 12, BPF_W, (bpf_int32)vni,
-			      0xffffff00);
+		b1 = gen_mcmp(cstate, offrel, 12, BPF_W, vni, 0xffffff00);
 		gen_and(b0, b1);
 		b0 = b1;
 	}
@@ -9473,7 +9514,7 @@
 
 static struct block *
 gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield,
-    bpf_int32 jvalue, bpf_u_int32 jtype, int reverse)
+    bpf_u_int32 jvalue, int jtype, int reverse)
 {
 	struct block *b0;
 
@@ -9484,8 +9525,8 @@
 			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, 0xffffffff, jtype,
-		    reverse, jvalue);
+		b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B,
+		    0xffffffffU, jtype, reverse, jvalue);
 		break;
 
 	case A_VCI:
@@ -9493,22 +9534,22 @@
 			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, 0xffffffff, jtype,
-		    reverse, jvalue);
+		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, 0x0f, jtype,
-		    reverse, jvalue);
+		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,
-		    0xffffffff, jtype, reverse, jvalue);
+		    0xffffffffU, jtype, reverse, jvalue);
 		break;
 
 	case A_CALLREFTYPE:
@@ -9516,8 +9557,8 @@
 			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, 0xffffffff,
-		    jtype, reverse, jvalue);
+		b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B,
+		    0xffffffffU, jtype, reverse, jvalue);
 		break;
 
 	default:
@@ -9560,7 +9601,7 @@
 
 struct block *
 gen_atmfield_code(compiler_state_t *cstate, int atmfield,
-    bpf_int32 jvalue, bpf_u_int32 jtype, int reverse)
+    bpf_u_int32 jvalue, int jtype, int reverse)
 {
 	/*
 	 * Catch errors reported by us and routines below us, and return NULL
@@ -9700,7 +9741,8 @@
 		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
 			bpf_error(cstate, "'fisu' supported only on MTP2");
 		/* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
-		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JEQ, 0, 0);
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+		    0x3fU, BPF_JEQ, 0, 0U);
 		break;
 
 	case M_LSSU:
@@ -9708,8 +9750,10 @@
 		     (cstate->linktype != DLT_ERF) &&
 		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
 			bpf_error(cstate, "'lssu' supported only on MTP2");
-		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 1, 2);
-		b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 0, 0);
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+		    0x3fU, BPF_JGT, 1, 2U);
+		b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+		    0x3fU, BPF_JGT, 0, 0U);
 		gen_and(b1, b0);
 		break;
 
@@ -9718,7 +9762,8 @@
 		     (cstate->linktype != DLT_ERF) &&
 		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
 			bpf_error(cstate, "'msu' supported only on MTP2");
-		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 0, 2);
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+		    0x3fU, BPF_JGT, 0, 2U);
 		break;
 
 	case MH_FISU:
@@ -9727,7 +9772,8 @@
 		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
 			bpf_error(cstate, "'hfisu' supported only on MTP2_HSL");
 		/* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
-		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JEQ, 0, 0);
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+		    0xff80U, BPF_JEQ, 0, 0U);
 		break;
 
 	case MH_LSSU:
@@ -9735,8 +9781,10 @@
 		     (cstate->linktype != DLT_ERF) &&
 		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
 			bpf_error(cstate, "'hlssu' supported only on MTP2_HSL");
-		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 1, 0x0100);
-		b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0);
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+		    0xff80U, BPF_JGT, 1, 0x0100U);
+		b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+		    0xff80U, BPF_JGT, 0, 0U);
 		gen_and(b1, b0);
 		break;
 
@@ -9745,7 +9793,8 @@
 		     (cstate->linktype != DLT_ERF) &&
 		     (cstate->linktype != DLT_MTP2_WITH_PHDR) )
 			bpf_error(cstate, "'hmsu' supported only on MTP2_HSL");
-		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0x0100);
+		b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+		    0xff80U, BPF_JGT, 0, 0x0100U);
 		break;
 
 	default:
@@ -9761,7 +9810,7 @@
  */
 struct block *
 gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
-    bpf_u_int32 jvalue_arg, bpf_u_int32 jtype, int reverse)
+    bpf_u_int32 jvalue_arg, int jtype, int reverse)
 {
 	volatile bpf_u_int32 jvalue = jvalue_arg;
 	struct block *b0;
@@ -9795,8 +9844,8 @@
 		if(jvalue > 255)
 		        bpf_error(cstate, "sio value %u too big; max value = 255",
 		            jvalue);
-		b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffff,
-		    (u_int)jtype, reverse, (u_int)jvalue);
+		b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffffU,
+		    jtype, reverse, jvalue);
 		break;
 
 	case MH_OPC:
@@ -9819,8 +9868,8 @@
 		val3 = jvalue & 0x00000003;
 		val3 = val3 <<22;
 		jvalue = val1 + val2 + val3;
-		b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0f,
-		    (u_int)jtype, reverse, (u_int)jvalue);
+		b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0fU,
+		    jtype, reverse, jvalue);
 		break;
 
 	case MH_DPC:
@@ -9841,8 +9890,8 @@
 		val2 = jvalue & 0x00003f00;
 		val2 = val2 << 8;
 		jvalue = val1 + val2;
-		b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000,
-		    (u_int)jtype, reverse, (u_int)jvalue);
+		b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000U,
+		    jtype, reverse, jvalue);
 		break;
 
 	case MH_SLS:
@@ -9859,8 +9908,8 @@
 		/* the following instruction is made to convert jvalue
 		 * to the forme used to write sls in an ss7 message*/
 		jvalue = jvalue << 4;
-		b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0,
-		    (u_int)jtype,reverse, (u_int)jvalue);
+		b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0U,
+		    jtype, reverse, jvalue);
 		break;
 
 	default:
diff --git a/gencode.h b/gencode.h
index cc21e04..053e85f 100644
--- a/gencode.h
+++ b/gencode.h
@@ -200,11 +200,14 @@
 
 struct slist;
 
+/*
+ * A single statement, corresponding to an instruction in a block.
+ */
 struct stmt {
-	int code;
-	struct slist *jt;	/*only for relative jump in block*/
-	struct slist *jf;	/*only for relative jump in block*/
-	bpf_int32 k;
+	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 {
@@ -231,17 +234,27 @@
  */
 #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 {
-	int id;
-	int code;
+	u_int id;
+	int code;		/* opcode for branch corresponding to this edge */
 	uset edom;
-	struct block *succ;
-	struct block *pred;
+	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 {
-	int id;
+	u_int id;
 	struct slist *stmts;	/* side effect stmts */
 	struct stmt s;		/* branch stmt */
 	int mark;
@@ -250,18 +263,18 @@
 	int level;
 	int offset;
 	int sense;
-	struct edge et;
-	struct edge ef;
+	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;
+	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;
-	int val[N_ATOMS];
+	int oval;		/* value ID for value tested in branch stmt */
+	bpf_u_int32 val[N_ATOMS];
 };
 
 /*
@@ -286,8 +299,8 @@
 
 typedef struct _compiler_state compiler_state_t;
 
-struct arth *gen_loadi(compiler_state_t *, int);
-struct arth *gen_load(compiler_state_t *, int, struct arth *, int);
+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 *);
@@ -300,10 +313,10 @@
 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 *,
-    unsigned int, struct qual);
+    bpf_u_int32, struct qual);
 #ifdef INET6
 struct block *gen_mcode6(compiler_state_t *, const char *, const char *,
-    unsigned int, struct qual);
+    bpf_u_int32, struct qual);
 #endif
 struct block *gen_ncode(compiler_state_t *, const char *, bpf_u_int32,
     struct qual);
@@ -312,9 +325,10 @@
     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, 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 *);
@@ -332,14 +346,14 @@
 
 struct block *gen_geneve(compiler_state_t *, bpf_u_int32, int);
 
-struct block *gen_atmfield_code(compiler_state_t *, int, bpf_int32,
-    bpf_u_int32, int);
-struct block *gen_atmtype_abbrev(compiler_state_t *, int type);
-struct block *gen_atmmulti_abbrev(compiler_state_t *, int type);
+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 type);
+struct block *gen_mtp2type_abbrev(compiler_state_t *, int);
 struct block *gen_mtp3field_code(compiler_state_t *, int, bpf_u_int32,
-    bpf_u_int32, int);
+    int, int);
 
 struct block *gen_pf_ifname(compiler_state_t *, const char *);
 struct block *gen_pf_rnr(compiler_state_t *, int);
@@ -348,8 +362,8 @@
 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 *, int, int);
-struct block *gen_p80211_fcdir(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.
diff --git a/grammar.y b/grammar.y.in
similarity index 87%
rename from grammar.y
rename to grammar.y.in
index 32cb19c..fe56515 100644
--- a/grammar.y
+++ b/grammar.y.in
@@ -1,7 +1,7 @@
 /*
  * We want a reentrant parser.
  */
-%pure-parser
+@REENTRANT_PARSER@
 
 /*
  * We also want a reentrant scanner, so we have to pass the
@@ -19,6 +19,27 @@
 %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 }
@@ -210,8 +231,17 @@
 	int i;
 
 	for (i = 0; toks[i].s != NULL; i++) {
-		if (pcap_strcasecmp(toks[i].s, str) == 0)
+		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);
 }
@@ -235,7 +265,7 @@
 		if (pcap_strcasecmp(reason, reasons[i]) == 0)
 			return (i);
 	}
-	bpf_set_error(cstate, "unknown PF reason");
+	bpf_set_error(cstate, "unknown PF reason \"%s\"", reason);
 	return (-1);
 }
 
@@ -259,7 +289,7 @@
 		return (PF_NORDR);
 #endif
 	else {
-		bpf_set_error(cstate, "unknown PF action");
+		bpf_set_error(cstate, "unknown PF action \"%s\"", action);
 		return (-1);
 	}
 }
@@ -307,7 +337,8 @@
 %type	<blk>	head
 %type	<i>	pqual dqual aqual ndaqual
 %type	<a>	arth narth
-%type	<i>	byteop pname pnum relop irelop
+%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
@@ -324,6 +355,7 @@
 %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
@@ -348,7 +380,8 @@
 
 %type	<s> ID EID AID
 %type	<s> HID HID6
-%type	<i> NUM action reason type subtype type_subtype dir
+%type	<h> NUM
+%type	<i> action reason type subtype type_subtype dir
 
 %left OR AND
 %nonassoc  '!'
@@ -378,7 +411,7 @@
 or:	  OR			{ $$ = $<blk>0; }
 	;
 id:	  nid
-	| pnum			{ CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1,
+	| pnum			{ CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1,
 						   $$.q = $<blk>0.q))); }
 	| paren pid ')'		{ $$ = $2; }
 	;
@@ -392,17 +425,17 @@
 				  /* 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;
+					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;
+					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;
+					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;
+					bpf_set_error(cstate, "'protochain' modifier applied to ip host");
+					YYABORT;
 				  }
 				  CHECK_PTR_VAL(($$.b = gen_ncode(cstate, $1, 0, $$.q)));
 				}
@@ -440,7 +473,7 @@
 	| 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, (bpf_u_int32)$1,
+qid:	  pnum			{ CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1,
 						   $$.q = $<blk>0.q))); }
 	| pid
 	;
@@ -514,7 +547,7 @@
 	| IGRP			{ $$ = Q_IGRP; }
 	| PIM			{ $$ = Q_PIM; }
 	| VRRP			{ $$ = Q_VRRP; }
-	| CARP 			{ $$ = Q_CARP; }
+	| CARP			{ $$ = Q_CARP; }
 	| ATALK			{ $$ = Q_ATALK; }
 	| AARP			{ $$ = Q_AARP; }
 	| DECNET		{ $$ = Q_DECNET; }
@@ -549,14 +582,15 @@
 	| 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))); }
-	| VLAN pnum		{ CHECK_PTR_VAL(($$ = gen_vlan(cstate, (bpf_u_int32)$2, 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, (bpf_u_int32)$2, 1))); }
+	| 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, (bpf_u_int32)$2, 1))); }
+	| 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, (bpf_u_int32)$2, 1))); }
+	| GENEVE pnum		{ CHECK_PTR_VAL(($$ = gen_geneve(cstate, $2, 1))); }
 	| GENEVE		{ CHECK_PTR_VAL(($$ = gen_geneve(cstate, 0, 0))); }
 	| pfvar			{ $$ = $1; }
 	| pqual p80211		{ $$ = $2; }
@@ -586,27 +620,37 @@
 	| DIR dir		{ CHECK_PTR_VAL(($$ = gen_p80211_fcdir(cstate, $2))); }
 	;
 
-type:	  NUM
+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");
-				  	YYABORT;
+					bpf_set_error(cstate, "unknown 802.11 type name \"%s\"", $1);
+					YYABORT;
 				  }
 				}
 	;
 
-subtype:  NUM
+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 */
+					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) {
+					if (-1 == ieee80211_type_subtypes[i].type) {
 						types = ieee80211_type_subtypes[i].tok;
 						break;
 					}
@@ -614,7 +658,7 @@
 
 				  $$ = str2tok($1, types);
 				  if ($$ == -1) {
-					bpf_set_error(cstate, "unknown 802.11 subtype name");
+					bpf_set_error(cstate, "unknown 802.11 subtype name \"%s\"", $1);
 					YYABORT;
 				  }
 				}
@@ -623,8 +667,8 @@
 type_subtype:	ID		{ int i;
 				  CHECK_PTR_VAL($1);
 				  for (i = 0;; i++) {
-				  	if (ieee80211_type_subtypes[i].tok == NULL) {
-				  		/* Ran out of types */
+					if (ieee80211_type_subtypes[i].tok == NULL) {
+						/* Ran out of types */
 						bpf_set_error(cstate, "unknown 802.11 type name");
 						YYABORT;
 					}
@@ -654,9 +698,9 @@
 					} else {
 						subtype = str2tok($2, llc_u_subtypes);
 						if (subtype == -1) {
-					  		bpf_set_error(cstate, "unknown LLC type name \"%s\"", $2);
-					  		YYABORT;
-					  	}
+							bpf_set_error(cstate, "unknown LLC type name \"%s\"", $2);
+							YYABORT;
+						}
 						CHECK_PTR_VAL(($$ = gen_llc_u_subtype(cstate, subtype)));
 					}
 				  }
@@ -665,7 +709,7 @@
 	| LLC PF_RNR		{ CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, LLC_RNR))); }
 	;
 
-dir:	  NUM
+dir:	  NUM			{ $$ = (int)$1; }
 	| ID			{ CHECK_PTR_VAL($1);
 				  if (pcap_strcasecmp($1, "nods") == 0)
 					$$ = IEEE80211_FC1_DIR_NODS;
@@ -743,15 +787,15 @@
 	| VCI			{ $$.atmfieldtype = A_VCI; }
 	;
 atmvalue: atmfieldvalue
-	| relop NUM		{ CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 0))); }
-	| irelop NUM		{ CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 1))); }
+	| 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, (bpf_int32) $1, BPF_JEQ, 0)));
+		CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $$.atmfieldtype, $1, BPF_JEQ, 0)));
 	}
 	;
 atmlistvalue: atmfieldvalue
@@ -776,8 +820,8 @@
 	| HSLS                  { $$.mtp3fieldtype = MH_SLS; }
 	;
 mtp3value: mtp3fieldvalue
-	| relop NUM		{ CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, (u_int)$2, (u_int)$1, 0))); }
-	| irelop NUM		{ CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, (u_int)$2, (u_int)$1, 1))); }
+	| 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 {
@@ -790,7 +834,7 @@
 	    $$.mtp3fieldtype == MH_OPC ||
 	    $$.mtp3fieldtype == MH_DPC ||
 	    $$.mtp3fieldtype == MH_SLS)
-		CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, (u_int) $1, BPF_JEQ, 0)));
+		CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, $1, BPF_JEQ, 0)));
 	}
 	;
 mtp3listvalue: mtp3fieldvalue
diff --git a/lbl/os-osf4.h b/lbl/os-osf4.h
index 055eb80..f461eea 100644
--- a/lbl/os-osf4.h
+++ b/lbl/os-osf4.h
@@ -20,7 +20,7 @@
  */
 
 /* Prototypes missing in Digital UNIX 4.x */
-int	pcap_snprintf(char *, size_t, const char *, ...);
-int	pcap_vsnprintf(char *, size_t, const char *, va_list);
+int	snprintf(char *, size_t, const char *, ...);
+int	vsnprintf(char *, size_t, const char *, va_list);
 int	pfopen(char *, int);
 
diff --git a/lbl/os-osf5.h b/lbl/os-osf5.h
index 5422f18..52ab175 100644
--- a/lbl/os-osf5.h
+++ b/lbl/os-osf5.h
@@ -21,10 +21,10 @@
 
 /*
  * Prototypes missing in Tru64 UNIX 5.x
- * XXX - "pcap_snprintf()" and "pcap_vsnprintf()" aren't missing, but you have to
+ * XXX - "snprintf()" and "vsnprintf()" aren't missing, but you have to
  * #define the right value to get them defined by <stdio.h>.
  */
-int	pcap_snprintf(char *, size_t, const char *, ...);
-int	pcap_vsnprintf(char *, size_t, const char *, va_list);
+int	snprintf(char *, size_t, const char *, ...);
+int	vsnprintf(char *, size_t, const char *, va_list);
 int	pfopen(char *, int);
 
diff --git a/lbl/os-solaris2.h b/lbl/os-solaris2.h
index a555f5e..22948b4 100644
--- a/lbl/os-solaris2.h
+++ b/lbl/os-solaris2.h
@@ -21,4 +21,4 @@
 
 /* Prototypes missing in SunOS 5 */
 char    *strerror(int);
-int	pcap_snprintf(char *, size_t, const char *, ...);
+int	snprintf(char *, size_t, const char *, ...);
diff --git a/lbl/os-sunos4.h b/lbl/os-sunos4.h
index 6353fb0..ab032ef 100644
--- a/lbl/os-sunos4.h
+++ b/lbl/os-sunos4.h
@@ -155,7 +155,7 @@
 struct	sigvec;
 #endif
 int	sigvec(int, struct sigvec *, struct sigvec*);
-int	pcap_snprintf(char *, size_t, const char *, ...);
+int	snprintf(char *, size_t, const char *, ...);
 int	socket(int, int, int);
 int	socketpair(int, int, int, int *);
 int	symlink(const char *, const char *);
diff --git a/missing/getopt.c b/missing/getopt.c
index 7c897c6..c535776 100644
--- a/missing/getopt.c
+++ b/missing/getopt.c
@@ -80,9 +80,18 @@
 			place = EMSG;
 			return (-1);
 		}
-	}					/* option letter okay? */
-	if ((optopt = (int)*place++) == (int)':' ||
-	    !(oli = strchr(ostr, optopt))) {
+	}
+	optopt = (int)*place++;
+	if (optopt == (int)':') {		/* option letter okay? */
+		if (!*place)
+			++optind;
+		if (opterr && *ostr != ':')
+			(void)fprintf(stderr,
+			    "%s: illegal option -- %c\n", __progname, optopt);
+		return (BADCH);
+	}
+	oli = strchr(ostr, optopt);
+	if (!oli) {
 		/*
 		 * if the user didn't specify '-' as an option,
 		 * assume it means -1.
@@ -114,7 +123,7 @@
 				    __progname, optopt);
 			return (BADCH);
 		}
-	 	else				/* white space */
+		else				/* white space */
 			optarg = nargv[optind];
 		place = EMSG;
 		++optind;
diff --git a/missing/snprintf.c b/missing/snprintf.c
deleted file mode 100644
index 672aeb8..0000000
--- a/missing/snprintf.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
- */
-
-/*
- * We use this for platforms that don't have snprintf() at all.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <sys/types.h>
-
-#include "portability.h"
-
-enum format_flags {
-    minus_flag     =  1,
-    plus_flag      =  2,
-    space_flag     =  4,
-    alternate_flag =  8,
-    zero_flag      = 16
-};
-
-/*
- * Common state
- */
-
-struct state {
-  unsigned char *str;
-  unsigned char *s;
-  unsigned char *theend;
-  size_t sz;
-  size_t max_sz;
-  int (*append_char)(struct state *, unsigned char);
-  int (*reserve)(struct state *, size_t);
-  /* XXX - methods */
-};
-
-#ifndef HAVE_VSNPRINTF
-static int
-sn_reserve (struct state *state, size_t n)
-{
-  return state->s + n > state->theend;
-}
-
-static int
-sn_append_char (struct state *state, unsigned char c)
-{
-  if (sn_reserve (state, 1)) {
-    return 1;
-  } else {
-    *state->s++ = c;
-    return 0;
-  }
-}
-#endif
-
-#if 0
-static int
-as_reserve (struct state *state, size_t n)
-{
-  if (state->s + n > state->theend) {
-    int off = state->s - state->str;
-    unsigned char *tmp;
-
-    if (state->max_sz && state->sz >= state->max_sz)
-      return 1;
-
-    state->sz = max(state->sz * 2, state->sz + n);
-    if (state->max_sz)
-      state->sz = min(state->sz, state->max_sz);
-    tmp = realloc (state->str, state->sz);
-    if (tmp == NULL)
-      return 1;
-    state->str = tmp;
-    state->s = state->str + off;
-    state->theend = state->str + state->sz - 1;
-  }
-  return 0;
-}
-
-static int
-as_append_char (struct state *state, unsigned char c)
-{
-  if(as_reserve (state, 1))
-    return 1;
-  else {
-    *state->s++ = c;
-    return 0;
-  }
-}
-#endif
-
-static int
-append_number(struct state *state,
-	      unsigned long num, unsigned base, char *rep,
-	      int width, int prec, int flags, int minusp)
-{
-  int len = 0;
-  int i;
-
-  /* given precision, ignore zero flag */
-  if(prec != -1)
-    flags &= ~zero_flag;
-  else
-    prec = 1;
-  /* zero value with zero precision -> "" */
-  if(prec == 0 && num == 0)
-    return 0;
-  do{
-    if((*state->append_char)(state, rep[num % base]))
-      return 1;
-    len++;
-    num /= base;
-  }while(num);
-  prec -= len;
-  /* pad with prec zeros */
-  while(prec-- > 0){
-    if((*state->append_char)(state, '0'))
-      return 1;
-    len++;
-  }
-  /* add length of alternate prefix (added later) to len */
-  if(flags & alternate_flag && (base == 16 || base == 8))
-    len += base / 8;
-  /* pad with zeros */
-  if(flags & zero_flag){
-    width -= len;
-    if(minusp || (flags & space_flag) || (flags & plus_flag))
-      width--;
-    while(width-- > 0){
-      if((*state->append_char)(state, '0'))
-	return 1;
-      len++;
-    }
-  }
-  /* add alternate prefix */
-  if(flags & alternate_flag && (base == 16 || base == 8)){
-    if(base == 16)
-      if((*state->append_char)(state, rep[10] + 23)) /* XXX */
-	return 1;
-    if((*state->append_char)(state, '0'))
-      return 1;
-  }
-  /* add sign */
-  if(minusp){
-    if((*state->append_char)(state, '-'))
-      return 1;
-    len++;
-  } else if(flags & plus_flag) {
-    if((*state->append_char)(state, '+'))
-      return 1;
-    len++;
-  } else if(flags & space_flag) {
-    if((*state->append_char)(state, ' '))
-      return 1;
-    len++;
-  }
-  if(flags & minus_flag)
-    /* swap before padding with spaces */
-    for(i = 0; i < len / 2; i++){
-      char c = state->s[-i-1];
-      state->s[-i-1] = state->s[-len+i];
-      state->s[-len+i] = c;
-    }
-  width -= len;
-  while(width-- > 0){
-    if((*state->append_char)(state,  ' '))
-      return 1;
-    len++;
-  }
-  if(!(flags & minus_flag))
-    /* swap after padding with spaces */
-    for(i = 0; i < len / 2; i++){
-      char c = state->s[-i-1];
-      state->s[-i-1] = state->s[-len+i];
-      state->s[-len+i] = c;
-    }
-
-  return 0;
-}
-
-static int
-append_string (struct state *state,
-	       unsigned char *arg,
-	       int width,
-	       int prec,
-	       int flags)
-{
-  if(prec != -1)
-    width -= prec;
-  else
-    width -= strlen((char *)arg);
-  if(!(flags & minus_flag))
-    while(width-- > 0)
-      if((*state->append_char) (state, ' '))
-	return 1;
-  if (prec != -1) {
-    while (*arg && prec--)
-      if ((*state->append_char) (state, *arg++))
-	return 1;
-  } else {
-    while (*arg)
-      if ((*state->append_char) (state, *arg++))
-	return 1;
-  }
-  if(flags & minus_flag)
-    while(width-- > 0)
-      if((*state->append_char) (state, ' '))
-	return 1;
-  return 0;
-}
-
-static int
-append_char(struct state *state,
-	    unsigned char arg,
-	    int width,
-	    int flags)
-{
-  while(!(flags & minus_flag) && --width > 0)
-    if((*state->append_char) (state, ' '))
-      return 1;
-
-  if((*state->append_char) (state, arg))
-    return 1;
-  while((flags & minus_flag) && --width > 0)
-    if((*state->append_char) (state, ' '))
-      return 1;
-
-  return 0;
-}
-
-/*
- * This can't be made into a function...
- */
-
-#define PARSE_INT_FORMAT(res, arg, unsig) \
-if (long_flag) \
-     res = (unsig long)va_arg(arg, unsig long); \
-else if (short_flag) \
-     res = (unsig short)va_arg(arg, unsig int); \
-else \
-     res = (unsig int)va_arg(arg, unsig int)
-
-/*
- * zyxprintf - return 0 or -1
- */
-
-static int
-xyzprintf (struct state *state, const char *char_format, va_list ap)
-{
-  const unsigned char *format = (const unsigned char *)char_format;
-  unsigned char c;
-
-  while((c = *format++)) {
-    if (c == '%') {
-      int flags      = 0;
-      int width      = 0;
-      int prec       = -1;
-      int long_flag  = 0;
-      int short_flag = 0;
-
-      /* flags */
-      while((c = *format++)){
-	if(c == '-')
-	  flags |= minus_flag;
-	else if(c == '+')
-	  flags |= plus_flag;
-	else if(c == ' ')
-	  flags |= space_flag;
-	else if(c == '#')
-	  flags |= alternate_flag;
-	else if(c == '0')
-	  flags |= zero_flag;
-	else
-	  break;
-      }
-
-      if((flags & space_flag) && (flags & plus_flag))
-	flags ^= space_flag;
-
-      if((flags & minus_flag) && (flags & zero_flag))
-	flags ^= zero_flag;
-
-      /* width */
-      if (isdigit(c))
-	do {
-	  width = width * 10 + c - '0';
-	  c = *format++;
-	} while(isdigit(c));
-      else if(c == '*') {
-	width = va_arg(ap, int);
-	c = *format++;
-      }
-
-      /* precision */
-      if (c == '.') {
-	prec = 0;
-	c = *format++;
-	if (isdigit(c))
-	  do {
-	    prec = prec * 10 + c - '0';
-	    c = *format++;
-	  } while(isdigit(c));
-	else if (c == '*') {
-	  prec = va_arg(ap, int);
-	  c = *format++;
-	}
-      }
-
-      /* size */
-
-      if (c == 'h') {
-	short_flag = 1;
-	c = *format++;
-      } else if (c == 'l') {
-	long_flag = 1;
-	c = *format++;
-      }
-
-      switch (c) {
-      case 'c' :
-	if(append_char(state, va_arg(ap, int), width, flags))
-	  return -1;
-	break;
-      case 's' :
-	if (append_string(state,
-			  va_arg(ap, unsigned char*),
-			  width,
-			  prec,
-			  flags))
-	  return -1;
-	break;
-      case 'd' :
-      case 'i' : {
-	long arg;
-	unsigned long num;
-	int minusp = 0;
-
-	PARSE_INT_FORMAT(arg, ap, signed);
-
-	if (arg < 0) {
-	  minusp = 1;
-	  num = -arg;
-	} else
-	  num = arg;
-
-	if (append_number (state, num, 10, "0123456789",
-			   width, prec, flags, minusp))
-	  return -1;
-	break;
-      }
-      case 'u' : {
-	unsigned long arg;
-
-	PARSE_INT_FORMAT(arg, ap, unsigned);
-
-	if (append_number (state, arg, 10, "0123456789",
-			   width, prec, flags, 0))
-	  return -1;
-	break;
-      }
-      case 'o' : {
-	unsigned long arg;
-
-	PARSE_INT_FORMAT(arg, ap, unsigned);
-
-	if (append_number (state, arg, 010, "01234567",
-			   width, prec, flags, 0))
-	  return -1;
-	break;
-      }
-      case 'x' : {
-	unsigned long arg;
-
-	PARSE_INT_FORMAT(arg, ap, unsigned);
-
-	if (append_number (state, arg, 0x10, "0123456789abcdef",
-			   width, prec, flags, 0))
-	  return -1;
-	break;
-      }
-      case 'X' :{
-	unsigned long arg;
-
-	PARSE_INT_FORMAT(arg, ap, unsigned);
-
-	if (append_number (state, arg, 0x10, "0123456789ABCDEF",
-			   width, prec, flags, 0))
-	  return -1;
-	break;
-      }
-      case 'p' : {
-	unsigned long arg = (unsigned long)va_arg(ap, void*);
-
-	if (append_number (state, arg, 0x10, "0123456789ABCDEF",
-			   width, prec, flags, 0))
-	  return -1;
-	break;
-      }
-      case 'n' : {
-	int *arg = va_arg(ap, int*);
-	*arg = state->s - state->str;
-	break;
-      }
-      case '\0' :
-	  --format;
-	  /* FALLTHROUGH */
-      case '%' :
-	if ((*state->append_char)(state, c))
-	  return -1;
-	break;
-      default :
-	if (   (*state->append_char)(state, '%')
-	    || (*state->append_char)(state, c))
-	  return -1;
-	break;
-      }
-    } else
-      if ((*state->append_char) (state, c))
-	return -1;
-  }
-  return 0;
-}
-
-#ifndef HAVE_SNPRINTF
-int
-pcap_snprintf (char *str, size_t sz, const char *format, ...)
-{
-  va_list args;
-  int ret;
-
-  va_start(args, format);
-  ret = pcap_vsnprintf (str, sz, format, args);
-
-#ifdef PARANOIA
-  {
-    int ret2;
-    char *tmp;
-
-    tmp = malloc (sz);
-    if (tmp == NULL)
-      abort ();
-
-    ret2 = pcap_vsprintf (tmp, format, args);
-    if (ret != ret2 || strcmp(str, tmp))
-      abort ();
-    free (tmp);
-  }
-#endif
-
-  va_end(args);
-  return ret;
-}
-#endif
-
-#if 0
-#ifndef HAVE_ASPRINTF
-int
-asprintf (char **ret, const char *format, ...)
-{
-  va_list args;
-  int val;
-
-  va_start(args, format);
-  val = vasprintf (ret, format, args);
-
-#ifdef PARANOIA
-  {
-    int ret2;
-    char *tmp;
-    tmp = malloc (val + 1);
-    if (tmp == NULL)
-      abort ();
-
-    ret2 = vsprintf (tmp, format, args);
-    if (val != ret2 || strcmp(*ret, tmp))
-      abort ();
-    free (tmp);
-  }
-#endif
-
-  va_end(args);
-  return val;
-}
-#endif
-
-#ifndef HAVE_ASNPRINTF
-int
-pcap_asnprintf (char **ret, size_t max_sz, const char *format, ...)
-{
-  va_list args;
-  int val;
-
-  va_start(args, format);
-  val = pcap_vasnprintf (ret, max_sz, format, args);
-  va_end(args);
-
-#ifdef PARANOIA
-  {
-    int ret2;
-    char *tmp;
-    tmp = malloc (val + 1);
-    if (tmp == NULL)
-      abort ();
-
-    va_start(args, format);
-    ret2 = pcap_vsprintf (tmp, format, args);
-    va_end(args);
-    if (val != ret2 || strcmp(*ret, tmp))
-      abort ();
-    free (tmp);
-  }
-#endif
-
-  return val;
-}
-#endif
-
-#ifndef HAVE_VASPRINTF
-int
-pcap_vasprintf (char **ret, const char *format, va_list args)
-{
-  return pcap_vasnprintf (ret, 0, format, args);
-}
-#endif
-
-
-#ifndef HAVE_VASNPRINTF
-int
-pcap_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
-{
-  int st;
-  size_t len;
-  struct state state;
-
-  state.max_sz = max_sz;
-  state.sz     = 1;
-  state.str    = malloc(state.sz);
-  if (state.str == NULL) {
-    *ret = NULL;
-    return -1;
-  }
-  state.s = state.str;
-  state.theend = state.s + state.sz - 1;
-  state.append_char = as_append_char;
-  state.reserve     = as_reserve;
-
-  st = xyzprintf (&state, format, args);
-  if (st) {
-    free (state.str);
-    *ret = NULL;
-    return -1;
-  } else {
-    char *tmp;
-
-    *state.s = '\0';
-    len = state.s - state.str;
-    tmp = realloc (state.str, len+1);
-    if (tmp == NULL) {
-      free (state.str);
-      *ret = NULL;
-      return -1;
-    }
-    *ret = tmp;
-    return len;
-  }
-}
-#endif
-#endif
-
-#ifndef HAVE_VSNPRINTF
-int
-pcap_vsnprintf (char *str, size_t sz, const char *format, va_list args)
-{
-  struct state state;
-  int ret;
-  unsigned char *ustr = (unsigned char *)str;
-
-  state.max_sz = 0;
-  state.sz     = sz;
-  state.str    = ustr;
-  state.s      = ustr;
-  state.theend = ustr + sz - 1;
-  state.append_char = sn_append_char;
-  state.reserve     = sn_reserve;
-
-  ret = xyzprintf (&state, format, args);
-  *state.s = '\0';
-  if (ret)
-    return sz;
-  else
-    return state.s - state.str;
-}
-#endif
-
diff --git a/missing/win_asprintf.c b/missing/win_asprintf.c
index cce6296..e4bd13c 100644
--- a/missing/win_asprintf.c
+++ b/missing/win_asprintf.c
@@ -23,7 +23,7 @@
 		*strp = NULL;
 		return (-1);
 	}
-	ret = pcap_vsnprintf(str, str_size, format, args);
+	ret = vsnprintf(str, str_size, format, args);
 	if (ret == -1) {
 		free(str);
 		*strp = NULL;
@@ -31,7 +31,7 @@
 	}
 	*strp = str;
 	/*
-	 * pcap_vsnprintf() shouldn't truncate the string, as we have
+	 * vsnprintf() shouldn't truncate the string, as we have
 	 * allocated a buffer large enough to hold the string, so its
 	 * return value should be the number of characters printed.
 	 */
diff --git a/missing/win_snprintf.c b/missing/win_snprintf.c
deleted file mode 100644
index f422403..0000000
--- a/missing/win_snprintf.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <stdio.h>
-#include <stdarg.h>
-
-#include "portability.h"
-
-int
-pcap_vsnprintf(char *str, size_t str_size, const char *format, va_list args)
-{
-	int ret;
-
-	ret = _vsnprintf_s(str, str_size, _TRUNCATE, format, args);
-
-	/*
-	 * XXX - _vsnprintf() and _snprintf() do *not* guarantee
-	 * that str is null-terminated, but C99's vsnprintf()
-	 * and snprintf() do, and we want to offer C99 behavior,
-	 * so forcibly null-terminate the string.
-	 *
-	 * We don't, however, offer C99 behavior for the return
-	 * value; _vsnprintf_s() returns -1, not the number of
-	 * characters that would have been put into the buffer
-	 * had it been large enough, if the string is truncated.
-	 * The only way to get that value is to use _vscprintf();
-	 * getting that count isn't worth the re-formatting.
-	 *
-	 * XXX - does _vsnprintf_s() return -1 on a formatting
-	 * error?
-	 */
-	str[str_size - 1] = '\0';
-	return (ret);
-}
-
-int
-pcap_snprintf(char *str, size_t str_size, const char *format, ...)
-{
-	va_list args;
-	int ret;
-
-	va_start(args, format);
-	ret = pcap_vsnprintf(str, str_size, format, args);
-	va_end(args);
-	return (ret);
-}
diff --git a/mkdep b/mkdep
index 1486b18..6e8dbd6 100755
--- a/mkdep
+++ b/mkdep
@@ -16,7 +16,10 @@
 MAKE=Makefile			# default makefile name is "Makefile"
 CC=cc				# default C compiler is "cc"
 DEPENDENCY_CFLAG=-M		# default dependency-generation flag is -M
+SOURCE_DIRECTORY=.		# default source directory is the current directory
 
+# No command-line flags seen yet.
+flags=""
 while :
 	do case "$1" in
 		# -c allows you to specify the C compiler
@@ -39,13 +42,29 @@
 		-p)
 			SED='s;\.o;;'
 			shift ;;
+
+		# -s allows you to specify the source directory
+		-s)
+			SOURCE_DIRECTORY=$2
+			shift; shift ;;
+
+		# -include takes an argument
+		-include)
+			flags="$flags $1 $2"
+			shift; shift ;;
+
+		# other command-line flag
+		-*)
+			flags="$flags $1"
+			shift ;;
+
 		*)
 			break ;;
 	esac
 done
 
 if [ $# = 0 ] ; then
-	echo 'usage: mkdep [-p] [-c cc] [-f makefile] [-m dependency-cflag] [flags] file ...'
+	echo 'usage: mkdep [-p] [-c cc] [-f makefile] [-m dependency-cflag] [-s source-directory] [flags] file ...'
 	exit 1
 fi
 
@@ -76,8 +95,17 @@
 # egrep '^#include[ 	]*".*"' /dev/null $* |
 # sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' |
 
+#
+# Construct a list of source files with paths relative to the source directory.
+#
+sources=""
+for srcfile in $*
+do
+	sources="$sources $SOURCE_DIRECTORY/$srcfile"
+done
+
 # XXX this doesn't work with things like "-DDECLWAITSTATUS=union\ wait"
-$CC $DEPENDENCY_CFLAG $* |
+$CC $DEPENDENCY_CFLAG $flags $sources |
 sed "
 	s; \./; ;g
 	$SED" |
diff --git a/msdos/readme.dos b/msdos/readme.dos
index b95483f..ec056dd 100644
--- a/msdos/readme.dos
+++ b/msdos/readme.dos
@@ -24,7 +24,7 @@
   If you got the libpcap from the official site www.tcpdump, then that
   distribution does NOT contain any sources for building 32-bit drivers.
   Instead get the full version at
-     http://www.watt-32.net/pcap/libpcap.zip
+     https://www.watt-32.net/pcap/libpcap.zip
 
   and set "USE_32BIT_DRIVERS = 1" in msdos\common.dj.
 
@@ -51,12 +51,12 @@
    receive network data. It's mostly used to access the 'hosts'
    file and other <netdb.h> features. Get 'watt32s*.zip' at:
 
-     http://www.watt-32.net
+     https://www.watt-32.net
 
 2. Exception handler and disassember library (libexc.a) is needed if
    "USE_EXCEPT = 1" in common.dj. Available at:
 
-     http://www.watt-32.net/misc/exc_dx07.zip
+     https://www.watt-32.net/misc/exc_dx07.zip
 
 3. Flex & Bison is used to generate parser for the filter handler
    pcap_compile:
@@ -65,7 +65,7 @@
 
 4. NASM assembler v 0.98 or later is required when building djgpp and
    Watcom targets:
-     http://www.nasm.us/
+     https://www.nasm.us/
 
 5. sed (Stream Editor) is required for doing `make depend'.
    It's available at:
diff --git a/nametoaddr.c b/nametoaddr.c
index 7c48bd3..c944ad3 100644
--- a/nametoaddr.c
+++ b/nametoaddr.c
@@ -127,7 +127,6 @@
   #include <netdb.h>
 #endif /* _WIN32 */
 
-#include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -135,6 +134,8 @@
 
 #include "pcap-int.h"
 
+#include "diag-control.h"
+
 #include "gencode.h"
 #include <pcap/namedb.h>
 #include "nametoaddr.h"
@@ -162,7 +163,23 @@
 	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);
@@ -200,10 +217,10 @@
  *  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)
+pcap_nametonetaddr(const char *name _U_)
 {
-#ifdef _WIN32
 	/*
 	 * There's no "getnetbyname()" on Windows.
 	 *
@@ -217,7 +234,11 @@
 	 * of *UN*X* machines.)
 	 */
 	return 0;
-#else
+}
+#else /* _WIN32 */
+bpf_u_int32
+pcap_nametonetaddr(const char *name)
+{
 	/*
 	 * UN*X.
 	 */
@@ -291,8 +312,8 @@
 		return np->n_net;
 	else
 		return 0;
-#endif /* _WIN32 */
 }
+#endif /* _WIN32 */
 
 /*
  * Convert a port name to its port and protocol numbers.
@@ -569,28 +590,20 @@
  */
 PCAP_API struct eproto eproto_db[];
 PCAP_API_DEF struct eproto eproto_db[] = {
-	{ "pup", ETHERTYPE_PUP },
-	{ "xns", ETHERTYPE_NS },
+	{ "aarp", ETHERTYPE_AARP },
+	{ "arp", ETHERTYPE_ARP },
+	{ "atalk", ETHERTYPE_ATALK },
+	{ "decnet", ETHERTYPE_DN },
 	{ "ip", ETHERTYPE_IP },
 #ifdef INET6
 	{ "ip6", ETHERTYPE_IPV6 },
 #endif
-	{ "arp", ETHERTYPE_ARP },
-	{ "rarp", ETHERTYPE_REVARP },
-	{ "sprite", ETHERTYPE_SPRITE },
+	{ "lat", ETHERTYPE_LAT },
+	{ "loopback", ETHERTYPE_LOOPBACK },
 	{ "mopdl", ETHERTYPE_MOPDL },
 	{ "moprc", ETHERTYPE_MOPRC },
-	{ "decnet", ETHERTYPE_DN },
-	{ "lat", ETHERTYPE_LAT },
+	{ "rarp", ETHERTYPE_REVARP },
 	{ "sca", ETHERTYPE_SCA },
-	{ "lanbridge", ETHERTYPE_LANBRIDGE },
-	{ "vexp", ETHERTYPE_VEXP },
-	{ "vprod", ETHERTYPE_VPROD },
-	{ "atalk", ETHERTYPE_ATALK },
-	{ "atalkarp", ETHERTYPE_AARP },
-	{ "loopback", ETHERTYPE_LOOPBACK },
-	{ "decdts", ETHERTYPE_DECDTS },
-	{ "decdns", ETHERTYPE_DECDNS },
 	{ (char *)0, 0 }
 };
 
@@ -635,9 +648,9 @@
 static inline u_char
 xdtoi(u_char c)
 {
-	if (isdigit(c))
+	if (c >= '0' && c <= '9')
 		return (u_char)(c - '0');
-	else if (islower(c))
+	else if (c >= 'a' && c <= 'f')
 		return (u_char)(c - 'a' + 10);
 	else
 		return (u_char)(c - 'A' + 10);
@@ -653,8 +666,15 @@
 	len = 0;
 	for (;;) {
 		n = 0;
-		while (*s && *s != '.')
+		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;
@@ -709,7 +729,7 @@
 		if (*s == ':' || *s == '.' || *s == '-')
 			s += 1;
 		d = xdtoi(*s++);
-		if (isxdigit((unsigned char)*s)) {
+		if (PCAP_ISXDIGIT(*s)) {
 			d <<= 4;
 			d |= xdtoi(*s++);
 		}
diff --git a/optimize.c b/optimize.c
index 448452d..610a030 100644
--- a/optimize.c
+++ b/optimize.c
@@ -103,7 +103,7 @@
  * Takes a 32-bit integer as an argument.
  *
  * If handed a non-zero value, returns the index of the lowest set bit,
- * counting upwards fro zero.
+ * 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
@@ -115,7 +115,7 @@
   /*
    * GCC 3.4 and later; we have __builtin_ctz().
    */
-  #define lowest_set_bit(mask) __builtin_ctz(mask)
+  #define lowest_set_bit(mask) ((u_int)__builtin_ctz(mask))
 #elif defined(_MSC_VER)
   /*
    * Visual Studio; we support only 2005 and later, so use
@@ -127,7 +127,7 @@
 #pragma intrinsic(_BitScanForward)
 #endif
 
-static __forceinline int
+static __forceinline u_int
 lowest_set_bit(int mask)
 {
 	unsigned long bit;
@@ -137,15 +137,15 @@
 	 * (It's currently not, in MSVC, even on 64-bit platforms, but....)
 	 */
 	if (_BitScanForward(&bit, (unsigned int)mask) == 0)
-		return -1;	/* mask is zero */
-	return (int)bit;
+		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)	(ffs((mask)) - 1)
+  #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,
@@ -153,18 +153,18 @@
    * of the Single UNIX Specification).
    */
   #include <strings.h>
-  #define lowest_set_bit(mask)	(ffs((mask)) - 1)
+  #define lowest_set_bit(mask)	(u_int)((ffs((mask)) - 1))
 #else
 /*
  * None of the above.
  * Use a perfect-hash-function-based function.
  */
-static int
+static u_int
 lowest_set_bit(int mask)
 {
 	unsigned int v = (unsigned int)mask;
 
-	static const int MultiplyDeBruijnBitPosition[32] = {
+	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
 	};
@@ -213,17 +213,17 @@
  */
 struct valnode {
 	int code;
-	int v0, v1;
-	int val;
+	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, 0L)
+#define K(i) F(opt_state, BPF_LD|BPF_IMM|BPF_W, i, 0U)
 
 struct vmapinfo {
 	int is_const;
-	bpf_int32 const_val;
+	bpf_u_int32 const_val;
 };
 
 typedef struct {
@@ -240,21 +240,34 @@
 	/*
 	 * A flag to indicate that further optimization is needed.
 	 * Iterative passes are continued until a given pass yields no
-	 * branch movement.
+	 * code simplification or branch movement.
 	 */
 	int done;
 
-	int n_blocks;
+	/*
+	 * 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;
-	int n_edges;
+	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.
 	 */
-	int nodewords;
-	int edgewords;
+	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;
 
@@ -279,32 +292,35 @@
 
 /*
  * 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 int _n = n;\
-	while (--_n >= 0) *_x++ &= *_y++;\
+	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 int _n = n;\
-	while (--_n >= 0) *_x++ &=~ *_y++;\
+	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 int _n = n;\
-	while (--_n >= 0) *_x++ |= *_y++;\
+	register u_int _n = n;\
+	do *_x++ |= *_y++; while (--_n != 0);\
 }
 
 	uset all_dom_sets;
@@ -313,8 +329,8 @@
 
 #define MODULUS 213
 	struct valnode *hashtbl[MODULUS];
-	int curval;
-	int maxval;
+	bpf_u_int32 curval;
+	bpf_u_int32 maxval;
 
 	struct vmapinfo *vmap;
 	struct valnode *vnode_base;
@@ -401,7 +417,8 @@
 static void
 find_dom(opt_state_t *opt_state, struct block *root)
 {
-	int i;
+	u_int i;
+	int level;
 	struct block *b;
 	bpf_u_int32 *x;
 
@@ -409,16 +426,23 @@
 	 * 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)
+	while (i != 0) {
+		--i;
 		*x++ = 0xFFFFFFFFU;
+	}
 	/* Root starts off empty. */
-	for (i = opt_state->nodewords; --i >= 0;)
+	for (i = opt_state->nodewords; i != 0;) {
+		--i;
 		root->dom[i] = 0;
+	}
 
 	/* root->level is the highest level no found. */
-	for (i = root->level; i >= 0; --i) {
-		for (b = opt_state->levels[i]; b; b = b->link) {
+	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;
@@ -445,19 +469,25 @@
 static void
 find_edom(opt_state_t *opt_state, struct block *root)
 {
-	int i;
+	u_int i;
 	uset x;
+	int level;
 	struct block *b;
 
 	x = opt_state->all_edge_sets;
-	for (i = opt_state->n_edges * opt_state->edgewords; --i >= 0; )
+	/*
+	 * 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 (i = root->level; i >= 0; --i) {
-		for (b = opt_state->levels[i]; b != 0; b = b->link) {
+	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);
 		}
@@ -474,7 +504,7 @@
 static void
 find_closure(opt_state_t *opt_state, struct block *root)
 {
-	int i;
+	int level;
 	struct block *b;
 
 	/*
@@ -484,8 +514,8 @@
 	      opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->all_closure_sets));
 
 	/* root->level is the highest level no found. */
-	for (i = root->level; i >= 0; --i) {
-		for (b = opt_state->levels[i]; b; b = b->link) {
+	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;
@@ -496,8 +526,11 @@
 }
 
 /*
- * Return the register number that is used by s.  If A and X are both
- * used, return AX_ATOM.  If no register is used, return -1.
+ * 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.
  */
@@ -517,8 +550,12 @@
 
 	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) ? s->k : -1;
+			(BPF_MODE(c) == BPF_MEM) ? (int)s->k : -1;
 
 	case BPF_ST:
 		return A_ATOM;
@@ -676,21 +713,40 @@
 	memset((char *)opt_state->hashtbl, 0, sizeof opt_state->hashtbl);
 }
 
-/* Because we really don't have an IR, this stuff is a little messy. */
-static int
-F(opt_state_t *opt_state, int code, int v0, int v1)
+/*
+ * 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;
-	int val;
+	bpf_u_int32 val;
 	struct valnode *p;
 
-	hash = (u_int)code ^ ((u_int)v0 << 4) ^ ((u_int)v1 << 8);
+	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)) {
@@ -709,7 +765,7 @@
 }
 
 static inline void
-vstore(struct stmt *s, int *valp, int newval, int alter)
+vstore(struct stmt *s, bpf_u_int32 *valp, bpf_u_int32 newval, int alter)
 {
 	if (alter && newval != VAL_UNKNOWN && *valp == newval)
 		s->code = NOP;
@@ -722,7 +778,7 @@
  * (Unary operators are handled elsewhere.)
  */
 static void
-fold_op(opt_state_t *opt_state, struct stmt *s, int v0, int v1)
+fold_op(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 v0, bpf_u_int32 v1)
 {
 	bpf_u_int32 a, b;
 
@@ -807,6 +863,10 @@
 	}
 	s->k = a;
 	s->code = BPF_LD|BPF_IMM;
+	/*
+	 * XXX - optimizer loop detection.
+	 */
+	opt_state->non_branch_movement_performed = 1;
 	opt_state->done = 0;
 }
 
@@ -832,7 +892,7 @@
 {
 	struct slist *s;
 	struct slist *next, *last;
-	int val;
+	bpf_u_int32 val;
 
 	s = b->stmts;
 	if (s == 0)
@@ -863,6 +923,10 @@
 		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;
 		}
@@ -874,6 +938,10 @@
 		    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;
 		}
 		/*
@@ -953,6 +1021,10 @@
 			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;
 		}
 	}
@@ -965,10 +1037,10 @@
 	 */
 	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.
-	    	 */
+		/*
+		 * 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) {
@@ -983,6 +1055,10 @@
 				 */
 				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) {
 				/*
@@ -996,6 +1072,10 @@
 				 */
 				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;
 			}
 		}
@@ -1008,6 +1088,10 @@
 		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;
 		}
 		/*
@@ -1022,6 +1106,10 @@
 			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);
 		}
@@ -1033,7 +1121,7 @@
 	if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) {
 		if (b->s.k == 0)
 			JT(b) = JF(b);
-		if ((u_int)b->s.k == 0xffffffffU)
+		if (b->s.k == 0xffffffffU)
 			JF(b) = JT(b);
 	}
 	/*
@@ -1043,7 +1131,7 @@
 	 */
 	val = b->val[X_ATOM];
 	if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) {
-		bpf_int32 v = opt_state->vmap[val].const_val;
+		bpf_u_int32 v = opt_state->vmap[val].const_val;
 		b->s.code &= ~BPF_X;
 		b->s.k = v;
 	}
@@ -1053,7 +1141,7 @@
 	 */
 	val = b->val[A_ATOM];
 	if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) {
-		bpf_int32 v = opt_state->vmap[val].const_val;
+		bpf_u_int32 v = opt_state->vmap[val].const_val;
 		switch (BPF_OP(b->s.code)) {
 
 		case BPF_JEQ:
@@ -1061,11 +1149,11 @@
 			break;
 
 		case BPF_JGT:
-			v = (unsigned)v > (unsigned)b->s.k;
+			v = v > b->s.k;
 			break;
 
 		case BPF_JGE:
-			v = (unsigned)v >= (unsigned)b->s.k;
+			v = v >= b->s.k;
 			break;
 
 		case BPF_JSET:
@@ -1075,8 +1163,13 @@
 		default:
 			abort();
 		}
-		if (JF(b) != JT(b))
+		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
@@ -1091,10 +1184,10 @@
  * evaluation and code transformations weren't folded together.
  */
 static void
-opt_stmt(opt_state_t *opt_state, struct stmt *s, int val[], int alter)
+opt_stmt(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 val[], int alter)
 {
 	int op;
-	int v;
+	bpf_u_int32 v;
 
 	switch (s->code) {
 
@@ -1113,6 +1206,10 @@
 			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
@@ -1159,7 +1256,7 @@
 			 * about the result of negating 0x80000000 being
 			 * undefined.
 			 */
-			s->k = 0U - (bpf_u_int32)(opt_state->vmap[val[A_ATOM]].const_val);
+			s->k = 0U - opt_state->vmap[val[A_ATOM]].const_val;
 			val[A_ATOM] = K(s->k);
 		}
 		else
@@ -1236,16 +1333,14 @@
 			else {
 				s->code = BPF_ALU|BPF_K|op;
 				s->k = opt_state->vmap[val[X_ATOM]].const_val;
-				/*
-				 * XXX - we need to make up our minds
-				 * as to what integers are signed and
-				 * what integers are unsigned in BPF
-				 * programs and in our IR.
-				 */
 				if ((op == BPF_LSH || op == BPF_RSH) &&
-				    (s->k < 0 || s->k > 31))
+				    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));
@@ -1290,6 +1385,10 @@
 		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);
@@ -1304,6 +1403,10 @@
 		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);
@@ -1336,6 +1439,10 @@
 	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;
 		}
@@ -1359,6 +1466,10 @@
 	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;
 		}
 }
@@ -1369,7 +1480,7 @@
 	struct slist *s;
 	struct edge *p;
 	int i;
-	bpf_int32 aval, xval;
+	bpf_u_int32 aval, xval;
 
 #if 0
 	for (s = b->stmts; s && s->next; s = s->next)
@@ -1422,7 +1533,10 @@
 	 * value that is already there, or if this block is a return,
 	 * eliminate all the statements.
 	 *
-	 * XXX - what if it does a store?
+	 * 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
@@ -1446,6 +1560,10 @@
 	     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 {
@@ -1484,19 +1602,41 @@
 	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;
-	int aval0, aval1, oval0, oval1;
+	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
+	} 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;
 
@@ -1505,13 +1645,21 @@
 	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 result is true if a true
+		 * 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);
@@ -1536,21 +1684,58 @@
 	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 int i, k;
+	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, ep->succ->et.succ)) {
+		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);
 		}
@@ -1564,19 +1749,38 @@
 	 */
  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.
+			 * 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)
@@ -1590,11 +1794,30 @@
 	}
 }
 
-
+/*
+ * 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)
 {
-	int val, at_top;
+	bpf_u_int32 val;
+	int at_top;
 	struct block *pull;
 	struct block **diffp, **samep;
 	struct edge *ep;
@@ -1612,39 +1835,106 @@
 		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);
+		diffp = &JT(b->in_edges->pred);	/* jt */
 	else
-		diffp = &JF(b->in_edges->pred);
+		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;
 
@@ -1680,13 +1970,18 @@
 	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)
 {
-	int val, at_top;
+	bpf_u_int32 val;
+	int at_top;
 	struct block *pull;
 	struct block **diffp, **samep;
 	struct edge *ep;
@@ -1771,6 +2066,10 @@
 	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;
 }
 
@@ -1792,9 +2091,22 @@
 		/*
 		 * 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);
@@ -1821,7 +2133,8 @@
 static void
 find_inedges(opt_state_t *opt_state, struct block *root)
 {
-	int i;
+	u_int i;
+	int level;
 	struct block *b;
 
 	for (i = 0; i < opt_state->n_blocks; ++i)
@@ -1831,8 +2144,8 @@
 	 * Traverse the graph, adding each edge to the predecessor
 	 * list of its successors.  Skip the leaves (i.e. level 0).
 	 */
-	for (i = root->level; i > 0; --i) {
-		for (b = opt_state->levels[i]; b != 0; b = b->link) {
+	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));
 		}
@@ -1873,8 +2186,17 @@
 		opt_dump(opt_state, ic);
 	}
 #endif
-	do {
+
+	/*
+	 * 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);
@@ -1887,7 +2209,51 @@
 			opt_dump(opt_state, ic);
 		}
 #endif
-	} while (!opt_state->done);
+
+		/*
+		 * 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;
+			}
+		}
+	}
 }
 
 /*
@@ -1901,6 +2267,7 @@
 
 	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;
@@ -1987,7 +2354,7 @@
 intern_blocks(opt_state_t *opt_state, struct icode *ic)
 {
 	struct block *p;
-	int i, j;
+	u_int i, j;
 	int done1; /* don't shadow global */
  top:
 	done1 = 1;
@@ -1996,7 +2363,8 @@
 
 	mark_code(ic);
 
-	for (i = opt_state->n_blocks - 1; --i >= 0; ) {
+	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) {
@@ -2047,7 +2415,7 @@
 
 	if (opt_state->errbuf != NULL) {
 		va_start(ap, fmt);
-		(void)pcap_vsnprintf(opt_state->errbuf,
+		(void)vsnprintf(opt_state->errbuf,
 		    PCAP_ERRBUF_SIZE, fmt, ap);
 		va_end(ap);
 	}
@@ -2089,13 +2457,19 @@
 static void
 number_blks_r(opt_state_t *opt_state, struct icode *ic, struct block *p)
 {
-	int n;
+	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;
 
@@ -2143,6 +2517,8 @@
 {
 	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
@@ -2157,7 +2533,19 @@
 	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");
@@ -2171,12 +2559,62 @@
 		opt_error(opt_state, "malloc");
 	}
 
-	opt_state->edgewords = opt_state->n_edges / (8 * sizeof(bpf_u_int32)) + 1;
-	opt_state->nodewords = opt_state->n_blocks / (8 * sizeof(bpf_u_int32)) + 1;
+	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(2 * opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->space)
-				 + opt_state->n_edges * opt_state->edgewords * sizeof(*opt_state->space));
+	opt_state->space = (bpf_u_int32 *)malloc(block_memsize + edge_memsize);
 	if (opt_state->space == NULL) {
 		opt_error(opt_state, "malloc");
 	}
@@ -2250,7 +2688,6 @@
 	struct slist *src;
 	u_int slen;
 	u_int off;
-	u_int extrajmps;	/* number of extra jumps inserted */
 	struct slist **offset = NULL;
 
 	if (p == 0 || isMarked(ic, p))
@@ -2374,21 +2811,17 @@
 	dst->code = (u_short)p->s.code;
 	dst->k = p->s.k;
 	if (JT(p)) {
-		extrajmps = 0;
+		/* 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 */
+			/* mark this instruction and retry */
 			p->longjt++;
 			return(0);
 		    }
-		    /* branch if T to following jump */
-		    if (extrajmps >= 256) {
-			conv_error(conv_state, "too many extra jumps");
-			/*NOTREACHED*/
-		    }
-		    dst->jt = (u_char)extrajmps;
+		    dst->jt = extrajmps;
 		    extrajmps++;
 		    dst[extrajmps].code = BPF_JMP|BPF_JA;
 		    dst[extrajmps].k = off - extrajmps;
@@ -2399,17 +2832,13 @@
 		if (off >= 256) {
 		    /* offset too large for branch, must add a jump */
 		    if (p->longjf == 0) {
-		    	/* mark this instruction and retry */
+			/* 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 */
-		    if (extrajmps >= 256) {
-			conv_error(conv_state, "too many extra jumps");
-			/*NOTREACHED*/
-		    }
-		    dst->jf = (u_char)extrajmps;
+		    dst->jf = extrajmps;
 		    extrajmps++;
 		    dst[extrajmps].code = BPF_JMP|BPF_JA;
 		    dst[extrajmps].k = off - extrajmps;
@@ -2440,7 +2869,7 @@
  * 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, 
+icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp,
     char *errbuf)
 {
 	u_int n;
@@ -2464,7 +2893,7 @@
 
 	    fp = (struct bpf_insn *)malloc(sizeof(*fp) * n);
 	    if (fp == NULL) {
-		(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "malloc");
 		free(fp);
 		return NULL;
@@ -2491,7 +2920,7 @@
 	va_list ap;
 
 	va_start(ap, fmt);
-	(void)pcap_vsnprintf(conv_state->errbuf,
+	(void)vsnprintf(conv_state->errbuf,
 	    PCAP_ERRBUF_SIZE, fmt, ap);
 	va_end(ap);
 	longjmp(conv_state->top_ctx, 1);
@@ -2514,8 +2943,8 @@
 	/*
 	 * Validate the program.
 	 */
-	if (!bpf_validate(fp->bf_insns, fp->bf_len)) {
-		pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+	if (!pcap_validate_filter(fp->bf_insns, fp->bf_len)) {
+		snprintf(p->errbuf, sizeof(p->errbuf),
 			"BPF program is not valid");
 		return (-1);
 	}
@@ -2552,7 +2981,7 @@
 	icount = slength(block->stmts) + 1 + block->longjt + block->longjf;
 	noffset = min(block->offset + icount, (int)prog->bf_len);
 
-	fprintf(out, "\tblock%d [shape=ellipse, id=\"block-%d\" label=\"BLOCK%d\\n", block->id, block->id, block->id);
+	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));
 	}
@@ -2579,9 +3008,9 @@
 	Mark(ic, block);
 
 	if (JT(block)) {
-		fprintf(out, "\t\"block%d\":se -> \"block%d\":n [label=\"T\"]; \n",
+		fprintf(out, "\t\"block%u\":se -> \"block%u\":n [label=\"T\"]; \n",
 				block->id, JT(block)->id);
-		fprintf(out, "\t\"block%d\":sw -> \"block%d\":n [label=\"F\"]; \n",
+		fprintf(out, "\t\"block%u\":sw -> \"block%u\":n [label=\"F\"]; \n",
 			   block->id, JF(block)->id);
 	}
 	dot_dump_edge(ic, JT(block), out);
@@ -2604,7 +3033,7 @@
     	"block1":sw -> "block3":n [label="F"];
     }
  *
- *  After install graphviz on http://www.graphviz.org/, save it as bpf.dot
+ *  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
diff --git a/org.tcpdump.chmod_bpf.plist b/org.tcpdump.chmod_bpf.plist
index 8ad6852..f6fdfec 100644
--- a/org.tcpdump.chmod_bpf.plist
+++ b/org.tcpdump.chmod_bpf.plist
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
 	<key>Label</key>
diff --git a/pcap-airpcap.c b/pcap-airpcap.c
new file mode 100644
index 0000000..703f23a
--- /dev/null
+++ b/pcap-airpcap.c
@@ -0,0 +1,1044 @@
+/*
+ * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2010 CACE Technologies, 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, CACE Technologies
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pcap-int.h"
+
+#include <airpcap.h>
+
+#include "pcap-airpcap.h"
+
+/* Default size of the buffer we allocate in userland. */
+#define	AIRPCAP_DEFAULT_USER_BUFFER_SIZE 256000
+
+/* Default size of the buffer for the AirPcap adapter. */
+#define	AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE 1000000
+
+//
+// We load the AirPcap DLL dynamically, so that the code will
+// work whether you have it installed or not, and there don't
+// have to be two different versions of the library, one linked
+// to the AirPcap library and one not linked to it.
+//
+static pcap_code_handle_t airpcap_lib;
+
+typedef PCHAR (*AirpcapGetLastErrorHandler)(PAirpcapHandle);
+typedef BOOL (*AirpcapGetDeviceListHandler)(PAirpcapDeviceDescription *, PCHAR);
+typedef VOID (*AirpcapFreeDeviceListHandler)(PAirpcapDeviceDescription);
+typedef PAirpcapHandle (*AirpcapOpenHandler)(PCHAR, PCHAR);
+typedef VOID (*AirpcapCloseHandler)(PAirpcapHandle);
+typedef BOOL (*AirpcapSetDeviceMacFlagsHandler)(PAirpcapHandle, UINT);
+typedef BOOL (*AirpcapSetLinkTypeHandler)(PAirpcapHandle, AirpcapLinkType);
+typedef BOOL (*AirpcapGetLinkTypeHandler)(PAirpcapHandle, PAirpcapLinkType);
+typedef BOOL (*AirpcapSetKernelBufferHandler)(PAirpcapHandle, UINT);
+typedef BOOL (*AirpcapSetFilterHandler)(PAirpcapHandle, PVOID, UINT);
+typedef BOOL (*AirpcapSetMinToCopyHandler)(PAirpcapHandle, UINT);
+typedef BOOL (*AirpcapGetReadEventHandler)(PAirpcapHandle, HANDLE *);
+typedef BOOL (*AirpcapReadHandler)(PAirpcapHandle, PBYTE, UINT, PUINT);
+typedef BOOL (*AirpcapWriteHandler)(PAirpcapHandle, PCHAR, ULONG);
+typedef BOOL (*AirpcapGetStatsHandler)(PAirpcapHandle, PAirpcapStats);
+
+static AirpcapGetLastErrorHandler p_AirpcapGetLastError;
+static AirpcapGetDeviceListHandler p_AirpcapGetDeviceList;
+static AirpcapFreeDeviceListHandler p_AirpcapFreeDeviceList;
+static AirpcapOpenHandler p_AirpcapOpen;
+static AirpcapCloseHandler p_AirpcapClose;
+static AirpcapSetDeviceMacFlagsHandler p_AirpcapSetDeviceMacFlags;
+static AirpcapSetLinkTypeHandler p_AirpcapSetLinkType;
+static AirpcapGetLinkTypeHandler p_AirpcapGetLinkType;
+static AirpcapSetKernelBufferHandler p_AirpcapSetKernelBuffer;
+static AirpcapSetFilterHandler p_AirpcapSetFilter;
+static AirpcapSetMinToCopyHandler p_AirpcapSetMinToCopy;
+static AirpcapGetReadEventHandler p_AirpcapGetReadEvent;
+static AirpcapReadHandler p_AirpcapRead;
+static AirpcapWriteHandler p_AirpcapWrite;
+static AirpcapGetStatsHandler p_AirpcapGetStats;
+
+typedef enum LONG
+{
+	AIRPCAP_API_UNLOADED = 0,
+	AIRPCAP_API_LOADED,
+	AIRPCAP_API_CANNOT_LOAD,
+	AIRPCAP_API_LOADING
+} AIRPCAP_API_LOAD_STATUS;
+
+static AIRPCAP_API_LOAD_STATUS	airpcap_load_status;
+
+/*
+ * NOTE: this function should be called by the pcap functions that can
+ *       theoretically deal with the AirPcap library for the first time,
+ *       namely listing the adapters and creating a pcap_t for an adapter.
+ *       All the other ones (activate, close, read, write, set parameters)
+ *       work on a pcap_t for an AirPcap device, meaning we've already
+ *       created the pcap_t and thus have loaded the functions, so we do
+ *       not need to call this function.
+ */
+static AIRPCAP_API_LOAD_STATUS
+load_airpcap_functions(void)
+{
+	AIRPCAP_API_LOAD_STATUS current_status;
+
+	/*
+	 * We don't use a mutex because there's no place that
+	 * we can guarantee we'll be called before any threads
+	 * other than the main thread exists.  (For example,
+	 * this might be a static library, so we can't arrange
+	 * to be called by DllMain(), and there's no guarantee
+	 * that the application called pcap_init() - which is
+	 * supposed to be called only from one thread - so
+	 * we can't arrange to be called from it.)
+	 *
+	 * If nobody's tried to load it yet, mark it as
+	 * loading; in any case, return the status before
+	 * we modified it.
+	 */
+	current_status = InterlockedCompareExchange((LONG *)&airpcap_load_status,
+	    AIRPCAP_API_LOADING, AIRPCAP_API_UNLOADED);
+
+	/*
+	 * If the status was AIRPCAP_API_UNLOADED, we've set it
+	 * to AIRPCAP_API_LOADING, because we're going to be
+	 * the ones to load the library but current_status is
+	 * AIRPCAP_API_UNLOADED.
+	 *
+	 * if it was AIRPCAP_API_LOADING, meaning somebody else
+	 * was trying to load it, spin until they finish and
+	 * set the status to a value reflecting whether they
+	 * succeeded.
+	 */
+	while (current_status == AIRPCAP_API_LOADING) {
+		current_status = InterlockedCompareExchange((LONG*)&airpcap_load_status,
+		    AIRPCAP_API_LOADING, AIRPCAP_API_LOADING);
+		Sleep(10);
+	}
+
+	/*
+	 * At this point, current_status is either:
+	 *
+	 *	AIRPCAP_API_LOADED, in which case another thread
+	 *	loaded the library, so we're done;
+	 *
+	 *	AIRPCAP_API_CANNOT_LOAD, in which another thread
+	 *	tried and failed to load the library, so we're
+	 *	done - we won't try it ourselves;
+	 *
+	 *	AIRPCAP_API_LOADING, in which case *we're* the
+	 *	ones loading it, and should now try to do so.
+	 */
+	if (current_status  == AIRPCAP_API_LOADED)
+		return AIRPCAP_API_LOADED;
+
+	if (current_status == AIRPCAP_API_CANNOT_LOAD)
+		return AIRPCAP_API_CANNOT_LOAD;
+
+	/*
+	 * Start out assuming we can't load it.
+	 */
+	current_status = AIRPCAP_API_CANNOT_LOAD;
+
+	airpcap_lib = pcap_load_code("airpcap.dll");
+	if (airpcap_lib != NULL) {
+		/*
+		 * OK, we've loaded the library; now try to find the
+		 * functions we need in it.
+		 */
+		p_AirpcapGetLastError = (AirpcapGetLastErrorHandler) pcap_find_function(airpcap_lib, "AirpcapGetLastError");
+		p_AirpcapGetDeviceList = (AirpcapGetDeviceListHandler) pcap_find_function(airpcap_lib, "AirpcapGetDeviceList");
+		p_AirpcapFreeDeviceList = (AirpcapFreeDeviceListHandler) pcap_find_function(airpcap_lib, "AirpcapFreeDeviceList");
+		p_AirpcapOpen = (AirpcapOpenHandler) pcap_find_function(airpcap_lib, "AirpcapOpen");
+		p_AirpcapClose = (AirpcapCloseHandler) pcap_find_function(airpcap_lib, "AirpcapClose");
+		p_AirpcapSetDeviceMacFlags = (AirpcapSetDeviceMacFlagsHandler) pcap_find_function(airpcap_lib, "AirpcapSetDeviceMacFlags");
+		p_AirpcapSetLinkType = (AirpcapSetLinkTypeHandler) pcap_find_function(airpcap_lib, "AirpcapSetLinkType");
+		p_AirpcapGetLinkType = (AirpcapGetLinkTypeHandler) pcap_find_function(airpcap_lib, "AirpcapGetLinkType");
+		p_AirpcapSetKernelBuffer = (AirpcapSetKernelBufferHandler) pcap_find_function(airpcap_lib, "AirpcapSetKernelBuffer");
+		p_AirpcapSetFilter = (AirpcapSetFilterHandler) pcap_find_function(airpcap_lib, "AirpcapSetFilter");
+		p_AirpcapSetMinToCopy = (AirpcapSetMinToCopyHandler) pcap_find_function(airpcap_lib, "AirpcapSetMinToCopy");
+		p_AirpcapGetReadEvent = (AirpcapGetReadEventHandler) pcap_find_function(airpcap_lib, "AirpcapGetReadEvent");
+		p_AirpcapRead = (AirpcapReadHandler) pcap_find_function(airpcap_lib, "AirpcapRead");
+		p_AirpcapWrite = (AirpcapWriteHandler) pcap_find_function(airpcap_lib, "AirpcapWrite");
+		p_AirpcapGetStats = (AirpcapGetStatsHandler) pcap_find_function(airpcap_lib, "AirpcapGetStats");
+
+		//
+		// Make sure that we found everything
+		//
+		if (p_AirpcapGetLastError != NULL &&
+		    p_AirpcapGetDeviceList != NULL &&
+		    p_AirpcapFreeDeviceList != NULL &&
+		    p_AirpcapOpen != NULL &&
+		    p_AirpcapClose != NULL &&
+		    p_AirpcapSetDeviceMacFlags != NULL &&
+		    p_AirpcapSetLinkType != NULL &&
+		    p_AirpcapGetLinkType != NULL &&
+		    p_AirpcapSetKernelBuffer != NULL &&
+		    p_AirpcapSetFilter != NULL &&
+		    p_AirpcapSetMinToCopy != NULL &&
+		    p_AirpcapGetReadEvent != NULL &&
+		    p_AirpcapRead != NULL &&
+		    p_AirpcapWrite != NULL &&
+		    p_AirpcapGetStats != NULL) {
+			/*
+			 * We have all we need.
+			 */
+			current_status = AIRPCAP_API_LOADED;
+		}
+	}
+
+	if (current_status != AIRPCAP_API_LOADED) {
+		/*
+		 * We failed; if we found the DLL, close the
+		 * handle for it.
+		 */
+		if (airpcap_lib != NULL) {
+			FreeLibrary(airpcap_lib);
+			airpcap_lib = NULL;
+		}
+	}
+
+	/*
+	 * Now set the status appropriately - and atomically.
+	 */
+	InterlockedExchange((LONG *)&airpcap_load_status, current_status);
+
+	return current_status;
+}
+
+/*
+ * Private data for capturing on AirPcap devices.
+ */
+struct pcap_airpcap {
+	PAirpcapHandle adapter;
+	int filtering_in_kernel;
+	int nonblock;
+	int read_timeout;
+	HANDLE read_event;
+	struct pcap_stat stat;
+};
+
+static int
+airpcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+	struct pcap_airpcap *pa = p->priv;
+
+	if (!p_AirpcapSetFilter(pa->adapter, fp->bf_insns,
+	    fp->bf_len * sizeof(struct bpf_insn))) {
+		/*
+		 * Kernel filter not installed.
+		 *
+		 * XXX - we don't know whether this failed because:
+		 *
+		 *  the kernel rejected the filter program as invalid,
+		 *  in which case we should fall back on userland
+		 *  filtering;
+		 *
+		 *  the kernel rejected the filter program as too big,
+		 *  in which case we should again fall back on
+		 *  userland filtering;
+		 *
+		 *  there was some other problem, in which case we
+		 *  should probably report an error;
+		 *
+		 * So we just fall back on userland filtering in
+		 * all cases.
+		 */
+
+		/*
+		 * install_bpf_program() validates the program.
+		 *
+		 * XXX - what if we already have a filter in the kernel?
+		 */
+		if (install_bpf_program(p, fp) < 0)
+			return (-1);
+		pa->filtering_in_kernel = 0;	/* filtering in userland */
+		return (0);
+	}
+
+	/*
+	 * It worked.
+	 */
+	pa->filtering_in_kernel = 1;	/* filtering in the kernel */
+
+	/*
+	 * Discard any previously-received packets, as they might have
+	 * passed whatever filter was formerly in effect, but might
+	 * not pass this filter (BIOCSETF discards packets buffered
+	 * in the kernel, so you can lose packets in any case).
+	 */
+	p->cc = 0;
+	return (0);
+}
+
+static int
+airpcap_set_datalink(pcap_t *p, int dlt)
+{
+	struct pcap_airpcap *pa = p->priv;
+	AirpcapLinkType type;
+
+	switch (dlt) {
+
+	case DLT_IEEE802_11_RADIO:
+		type = AIRPCAP_LT_802_11_PLUS_RADIO;
+		break;
+
+	case DLT_PPI:
+		type = AIRPCAP_LT_802_11_PLUS_PPI;
+		break;
+
+	case DLT_IEEE802_11:
+		type = AIRPCAP_LT_802_11;
+		break;
+
+	default:
+		/* This can't happen; just return. */
+		return (0);
+	}
+	if (!p_AirpcapSetLinkType(pa->adapter, type)) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapSetLinkType() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		return (-1);
+	}
+	p->linktype = dlt;
+	return (0);
+}
+
+static int
+airpcap_getnonblock(pcap_t *p)
+{
+	struct pcap_airpcap *pa = p->priv;
+
+	return (pa->nonblock);
+}
+
+static int
+airpcap_setnonblock(pcap_t *p, int nonblock)
+{
+	struct pcap_airpcap *pa = p->priv;
+	int newtimeout;
+
+	if (nonblock) {
+		/*
+		 * Set the packet buffer timeout to -1 for non-blocking
+		 * mode.
+		 */
+		newtimeout = -1;
+	} else {
+		/*
+		 * Restore the timeout set when the device was opened.
+		 * (Note that this may be -1, in which case we're not
+		 * really leaving non-blocking mode.  However, although
+		 * the timeout argument to pcap_set_timeout() and
+		 * pcap_open_live() is an int, you're not supposed to
+		 * supply a negative value, so that "shouldn't happen".)
+		 */
+		newtimeout = p->opt.timeout;
+	}
+	pa->read_timeout = newtimeout;
+	pa->nonblock = (newtimeout == -1);
+	return (0);
+}
+
+static int
+airpcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+	struct pcap_airpcap *pa = p->priv;
+	AirpcapStats tas;
+
+	/*
+	 * Try to get statistics.
+	 */
+	if (!p_AirpcapGetStats(pa->adapter, &tas)) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapGetStats() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		return (-1);
+	}
+
+	ps->ps_drop = tas.Drops;
+	ps->ps_recv = tas.Recvs;
+	ps->ps_ifdrop = tas.IfDrops;
+
+	return (0);
+}
+
+/*
+ * Win32-only routine for getting statistics.
+ *
+ * This way is definitely safer than passing the pcap_stat * from the userland.
+ * In fact, there could happen than the user allocates a variable which is not
+ * big enough for the new structure, and the library will write in a zone
+ * which is not allocated to this variable.
+ *
+ * In this way, we're pretty sure we are writing on memory allocated to this
+ * variable.
+ *
+ * XXX - but this is the wrong way to handle statistics.  Instead, we should
+ * have an API that returns data in a form like the Options section of a
+ * pcapng Interface Statistics Block:
+ *
+ *    https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6
+ *
+ * which would let us add new statistics straightforwardly and indicate which
+ * statistics we are and are *not* providing, rather than having to provide
+ * possibly-bogus values for statistics we can't provide.
+ */
+static struct pcap_stat *
+airpcap_stats_ex(pcap_t *p, int *pcap_stat_size)
+{
+	struct pcap_airpcap *pa = p->priv;
+	AirpcapStats tas;
+
+	*pcap_stat_size = sizeof (p->stat);
+
+	/*
+	 * Try to get statistics.
+	 */
+	if (!p_AirpcapGetStats(pa->adapter, &tas)) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapGetStats() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		return (NULL);
+	}
+
+	p->stat.ps_recv = tas.Recvs;
+	p->stat.ps_drop = tas.Drops;
+	p->stat.ps_ifdrop = tas.IfDrops;
+	/*
+	 * Just in case this is ever compiled for a target other than
+	 * Windows, which is extremely unlikely at best.
+	 */
+#ifdef _WIN32
+	p->stat.ps_capt = tas.Capt;
+#endif
+	return (&p->stat);
+}
+
+/* Set the dimension of the kernel-level capture buffer */
+static int
+airpcap_setbuff(pcap_t *p, int dim)
+{
+	struct pcap_airpcap *pa = p->priv;
+
+	if (!p_AirpcapSetKernelBuffer(pa->adapter, dim)) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapSetKernelBuffer() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		return (-1);
+	}
+	return (0);
+}
+
+/* Set the driver working mode */
+static int
+airpcap_setmode(pcap_t *p, int mode)
+{
+	 if (mode != MODE_CAPT) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "Only MODE_CAPT is supported on an AirPcap adapter");
+		return (-1);
+	 }
+	 return (0);
+}
+
+/*set the minimum amount of data that will release a read call*/
+static int
+airpcap_setmintocopy(pcap_t *p, int size)
+{
+	struct pcap_airpcap *pa = p->priv;
+
+	if (!p_AirpcapSetMinToCopy(pa->adapter, size)) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapSetMinToCopy() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		return (-1);
+	}
+	return (0);
+}
+
+static HANDLE
+airpcap_getevent(pcap_t *p)
+{
+	struct pcap_airpcap *pa = p->priv;
+
+	return (pa->read_event);
+}
+
+static int
+airpcap_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+    size_t *lenp _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Getting OID values is not supported on an AirPcap adapter");
+	return (PCAP_ERROR);
+}
+
+static int
+airpcap_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,
+	    "Setting OID values is not supported on an AirPcap adapter");
+	return (PCAP_ERROR);
+}
+
+static u_int
+airpcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "Cannot queue packets for transmission on an AirPcap adapter");
+	return (0);
+}
+
+static int
+airpcap_setuserbuffer(pcap_t *p, int size)
+{
+	unsigned char *new_buff;
+
+	if (size <= 0) {
+		/* Bogus parameter */
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "Error: invalid size %d",size);
+		return (-1);
+	}
+
+	/* Allocate the buffer */
+	new_buff = (unsigned char *)malloc(sizeof(char)*size);
+
+	if (!new_buff) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "Error: not enough memory");
+		return (-1);
+	}
+
+	free(p->buffer);
+
+	p->buffer = new_buff;
+	p->bufsize = size;
+
+	return (0);
+}
+
+static int
+airpcap_live_dump(pcap_t *p, char *filename _U_, int maxsize _U_,
+    int maxpacks _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "AirPcap adapters don't support live dump");
+	return (-1);
+}
+
+static int
+airpcap_live_dump_ended(pcap_t *p, int sync _U_)
+{
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	    "AirPcap adapters don't support live dump");
+	return (-1);
+}
+
+static PAirpcapHandle
+airpcap_get_airpcap_handle(pcap_t *p)
+{
+	struct pcap_airpcap *pa = p->priv;
+
+	return (pa->adapter);
+}
+
+static int
+airpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+	struct pcap_airpcap *pa = p->priv;
+	int cc;
+	int n;
+	register u_char *bp, *ep;
+	UINT bytes_read;
+	u_char *datap;
+
+	cc = p->cc;
+	if (cc == 0) {
+		/*
+		 * Has "pcap_breakloop()" been called?
+		 */
+		if (p->break_loop) {
+			/*
+			 * Yes - clear the flag that indicates that it
+			 * has, and return PCAP_ERROR_BREAK to indicate
+			 * that we were told to break out of the loop.
+			 */
+			p->break_loop = 0;
+			return (PCAP_ERROR_BREAK);
+		}
+
+		//
+		// If we're not in non-blocking mode, wait for data to
+		// arrive.
+		//
+		if (pa->read_timeout != -1) {
+			WaitForSingleObject(pa->read_event,
+			    (pa->read_timeout ==0 )? INFINITE: pa->read_timeout);
+		}
+
+		//
+		// Read the data.
+		// p_AirpcapRead doesn't block.
+		//
+		if (!p_AirpcapRead(pa->adapter, (PBYTE)p->buffer,
+		    p->bufsize, &bytes_read)) {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "AirpcapRead() failed: %s",
+			    p_AirpcapGetLastError(pa->adapter));
+			return (-1);
+		}
+		cc = bytes_read;
+		bp = (u_char *)p->buffer;
+	} else
+		bp = p->bp;
+
+	/*
+	 * Loop through each packet.
+	 */
+#define bhp ((AirpcapBpfHeader *)bp)
+	n = 0;
+	ep = bp + cc;
+	for (;;) {
+		register u_int caplen, hdrlen;
+
+		/*
+		 * Has "pcap_breakloop()" been called?
+		 * If so, return immediately - if we haven't read any
+		 * packets, clear the flag and return PCAP_ERROR_BREAK
+		 * to indicate that we were told to break out of the loop,
+		 * otherwise leave the flag set, so that the *next* call
+		 * will break out of the loop without having read any
+		 * packets, and return the number of packets we've
+		 * processed so far.
+		 */
+		if (p->break_loop) {
+			if (n == 0) {
+				p->break_loop = 0;
+				return (PCAP_ERROR_BREAK);
+			} else {
+				p->bp = bp;
+				p->cc = (int) (ep - bp);
+				return (n);
+			}
+		}
+		if (bp >= ep)
+			break;
+
+		caplen = bhp->Caplen;
+		hdrlen = bhp->Hdrlen;
+		datap = bp + hdrlen;
+		/*
+		 * Short-circuit evaluation: if using BPF filter
+		 * in the AirPcap adapter, no need to do it now -
+		 * we already know the packet passed the filter.
+		 */
+		if (pa->filtering_in_kernel ||
+		    p->fcode.bf_insns == NULL ||
+		    pcap_filter(p->fcode.bf_insns, datap, bhp->Originallen, caplen)) {
+			struct pcap_pkthdr pkthdr;
+
+			pkthdr.ts.tv_sec = bhp->TsSec;
+			pkthdr.ts.tv_usec = bhp->TsUsec;
+			pkthdr.caplen = caplen;
+			pkthdr.len = bhp->Originallen;
+			(*callback)(user, &pkthdr, datap);
+			bp += AIRPCAP_WORDALIGN(caplen + hdrlen);
+			if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
+				p->bp = bp;
+				p->cc = (int)(ep - bp);
+				return (n);
+			}
+		} else {
+			/*
+			 * Skip this packet.
+			 */
+			bp += AIRPCAP_WORDALIGN(caplen + hdrlen);
+		}
+	}
+#undef bhp
+	p->cc = 0;
+	return (n);
+}
+
+static int
+airpcap_inject(pcap_t *p, const void *buf, int size)
+{
+	struct pcap_airpcap *pa = p->priv;
+
+	/*
+	 * XXX - the second argument to AirpcapWrite() *should* have
+	 * been declared as a const pointer - a write function that
+	 * stomps on what it writes is *extremely* rude - but such
+	 * is life.  We assume it is, in fact, not going to write on
+	 * our buffer.
+	 */
+	if (!p_AirpcapWrite(pa->adapter, (void *)buf, size)) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapWrite() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		return (-1);
+	}
+
+	/*
+	 * We assume it all got sent if "AirpcapWrite()" succeeded.
+	 * "pcap_inject()" is expected to return the number of bytes
+	 * sent.
+	 */
+	return (size);
+}
+
+static void
+airpcap_cleanup(pcap_t *p)
+{
+	struct pcap_airpcap *pa = p->priv;
+
+	if (pa->adapter != NULL) {
+		p_AirpcapClose(pa->adapter);
+		pa->adapter = NULL;
+	}
+	pcap_cleanup_live_common(p);
+}
+
+static void
+airpcap_breakloop(pcap_t *p)
+{
+	HANDLE read_event;
+
+	pcap_breakloop_common(p);
+	struct pcap_airpcap *pa = p->priv;
+
+	/* XXX - what if either of these fail? */
+	/*
+	 * XXX - will SetEvent() force a wakeup and, if so, will
+	 * the AirPcap read code handle that sanely?
+	 */
+	if (!p_AirpcapGetReadEvent(pa->adapter, &read_event))
+		return;
+	SetEvent(read_event);
+}
+
+static int
+airpcap_activate(pcap_t *p)
+{
+	struct pcap_airpcap *pa = p->priv;
+	char *device = p->opt.device;
+	char airpcap_errbuf[AIRPCAP_ERRBUF_SIZE];
+	BOOL status;
+	AirpcapLinkType link_type;
+
+	pa->adapter = p_AirpcapOpen(device, airpcap_errbuf);
+	if (pa->adapter == NULL) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", airpcap_errbuf);
+		return (PCAP_ERROR);
+	}
+
+	/*
+	 * Set monitor mode appropriately.
+	 * Always turn off the "ACK frames sent to the card" mode.
+	 */
+	if (p->opt.rfmon) {
+		status = p_AirpcapSetDeviceMacFlags(pa->adapter,
+		    AIRPCAP_MF_MONITOR_MODE_ON);
+	} else
+		status = p_AirpcapSetDeviceMacFlags(pa->adapter,
+		    AIRPCAP_MF_ACK_FRAMES_ON);
+	if (!status) {
+		p_AirpcapClose(pa->adapter);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapSetDeviceMacFlags() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		return (PCAP_ERROR);
+	}
+
+	/*
+	 * Turn a negative snapshot value (invalid), a snapshot value of
+	 * 0 (unspecified), or a value bigger than the normal maximum
+	 * value, into the maximum allowed value.
+	 *
+	 * If some application really *needs* a bigger snapshot
+	 * length, we should just increase MAXIMUM_SNAPLEN.
+	 */
+	if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
+		p->snapshot = MAXIMUM_SNAPLEN;
+
+	/*
+	 * If the buffer size wasn't explicitly set, default to
+	 * AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE.
+	 */
+	if (p->opt.buffer_size == 0)
+		p->opt.buffer_size = AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE;
+
+	if (!p_AirpcapSetKernelBuffer(pa->adapter, p->opt.buffer_size)) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapSetKernelBuffer() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		goto bad;
+	}
+
+	if(!p_AirpcapGetReadEvent(pa->adapter, &pa->read_event)) {
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapGetReadEvent() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		goto bad;
+	}
+
+	/* Set the buffer size */
+	p->bufsize = AIRPCAP_DEFAULT_USER_BUFFER_SIZE;
+	p->buffer = malloc(p->bufsize);
+	if (p->buffer == NULL) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		goto bad;
+	}
+
+	if (p->opt.immediate) {
+		/* Tell the driver to copy the buffer as soon as data arrives. */
+		if (!p_AirpcapSetMinToCopy(pa->adapter, 0)) {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "AirpcapSetMinToCopy() failed: %s",
+			    p_AirpcapGetLastError(pa->adapter));
+			goto bad;
+		}
+	} else {
+		/*
+		 * Tell the driver to copy the buffer only if it contains
+		 * at least 16K.
+		 */
+		if (!p_AirpcapSetMinToCopy(pa->adapter, 16000)) {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "AirpcapSetMinToCopy() failed: %s",
+			    p_AirpcapGetLastError(pa->adapter));
+			goto bad;
+		}
+	}
+
+	/*
+	 * Find out what the default link-layer header type is,
+	 * and set p->datalink to that.
+	 *
+	 * We don't force it to another value because there
+	 * might be some programs using WinPcap/Npcap that,
+	 * when capturing on AirPcap devices, assume the
+	 * default value set with the AirPcap configuration
+	 * program is what you get.
+	 *
+	 * The out-of-the-box default appears to be radiotap.
+	 */
+	if (!p_AirpcapGetLinkType(pa->adapter, &link_type)) {
+		/* That failed. */
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapGetLinkType() failed: %s",
+		    p_AirpcapGetLastError(pa->adapter));
+		goto bad;
+	}
+	switch (link_type) {
+
+	case AIRPCAP_LT_802_11_PLUS_RADIO:
+		p->linktype = DLT_IEEE802_11_RADIO;
+		break;
+
+	case AIRPCAP_LT_802_11_PLUS_PPI:
+		p->linktype = DLT_PPI;
+		break;
+
+	case AIRPCAP_LT_802_11:
+		p->linktype = DLT_IEEE802_11;
+		break;
+
+	case AIRPCAP_LT_UNKNOWN:
+	default:
+		/* OK, what? */
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapGetLinkType() returned unknown link type %u",
+		    link_type);
+		goto bad;
+	}
+
+	/*
+	 * Now provide a list of all the supported types; we
+	 * assume they all work.  We put radiotap at the top,
+	 * followed by PPI, followed by "no radio metadata".
+	 */
+	p->dlt_list = (u_int *) malloc(sizeof(u_int) * 3);
+	if (p->dlt_list == NULL)
+		goto bad;
+	p->dlt_list[0] = DLT_IEEE802_11_RADIO;
+	p->dlt_list[1] = DLT_PPI;
+	p->dlt_list[2] = DLT_IEEE802_11;
+	p->dlt_count = 3;
+
+	p->read_op = airpcap_read;
+	p->inject_op = airpcap_inject;
+	p->setfilter_op = airpcap_setfilter;
+	p->setdirection_op = NULL;	/* Not implemented. */
+	p->set_datalink_op = airpcap_set_datalink;
+	p->getnonblock_op = airpcap_getnonblock;
+	p->setnonblock_op = airpcap_setnonblock;
+	p->breakloop_op = airpcap_breakloop;
+	p->stats_op = airpcap_stats;
+	p->stats_ex_op = airpcap_stats_ex;
+	p->setbuff_op = airpcap_setbuff;
+	p->setmode_op = airpcap_setmode;
+	p->setmintocopy_op = airpcap_setmintocopy;
+	p->getevent_op = airpcap_getevent;
+	p->oid_get_request_op = airpcap_oid_get_request;
+	p->oid_set_request_op = airpcap_oid_set_request;
+	p->sendqueue_transmit_op = airpcap_sendqueue_transmit;
+	p->setuserbuffer_op = airpcap_setuserbuffer;
+	p->live_dump_op = airpcap_live_dump;
+	p->live_dump_ended_op = airpcap_live_dump_ended;
+	p->get_airpcap_handle_op = airpcap_get_airpcap_handle;
+	p->cleanup_op = airpcap_cleanup;
+
+	return (0);
+ bad:
+	airpcap_cleanup(p);
+	return (PCAP_ERROR);
+}
+
+/*
+ * Monitor mode is supported.
+ */
+static int
+airpcap_can_set_rfmon(pcap_t *p)
+{
+	return (1);
+}
+
+int
+device_is_airpcap(const char *device, char *ebuf)
+{
+	static const char airpcap_prefix[] = "\\\\.\\airpcap";
+
+	/*
+	 * We don't determine this by calling AirpcapGetDeviceList()
+	 * and looking at the list, as that appears to be a costly
+	 * operation.
+	 *
+	 * Instead, we just check whether it begins with "\\.\airpcap".
+	 */
+	if (strncmp(device, airpcap_prefix, sizeof airpcap_prefix - 1) == 0) {
+		/*
+		 * Yes, it's an AirPcap device.
+		 */
+		return (1);
+	}
+
+	/*
+	 * No, it's not an AirPcap device.
+	 */
+	return (0);
+}
+
+pcap_t *
+airpcap_create(const char *device, char *ebuf, int *is_ours)
+{
+	int ret;
+	pcap_t *p;
+
+	/*
+	 * This can be called before we've tried loading the library,
+	 * so do so if we haven't already tried to do so.
+	 */
+	if (load_airpcap_functions() != AIRPCAP_API_LOADED) {
+		snprintf(ebuf, PCAP_ERRBUF_SIZE, "Couldn't load AirPcap DLL\n");
+		return (NULL);
+	}
+
+	/*
+	 * Is this an AirPcap device?
+	 */
+	ret = device_is_airpcap(device, ebuf);
+	if (ret == 0) {
+		/* No. */
+		*is_ours = 0;
+		return (NULL);
+	}
+
+	/*
+	 * Yes.
+	 */
+	*is_ours = 1;
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_airpcap);
+	if (p == NULL)
+		return (NULL);
+
+	p->activate_op = airpcap_activate;
+	p->can_set_rfmon_op = airpcap_can_set_rfmon;
+	return (p);
+}
+
+/*
+ * Add all AirPcap devices.
+ */
+int
+airpcap_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
+{
+	AirpcapDeviceDescription *airpcap_devices, *airpcap_device;
+	char airpcap_errbuf[AIRPCAP_ERRBUF_SIZE];
+
+	/*
+	 * This can be called before we've tried loading the library,
+	 * so do so if we haven't already tried to do so.
+	 */
+	if (load_airpcap_functions() != AIRPCAP_API_LOADED) {
+		/*
+		 * XXX - unless the error is "no such DLL", report this
+		 * as an error rather than as "no AirPcap devices"?
+		 */
+		return (0);
+	}
+
+	if (!p_AirpcapGetDeviceList(&airpcap_devices, airpcap_errbuf)) {
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "AirpcapGetDeviceList() failed: %s", airpcap_errbuf);
+		return (-1);
+	}
+
+	for (airpcap_device = airpcap_devices; airpcap_device != NULL;
+	    airpcap_device = airpcap_device->next) {
+		if (add_dev(devlistp, airpcap_device->Name, 0,
+		    airpcap_device->Description, errbuf) == NULL) {
+			/*
+			 * Failure.
+			 */
+			p_AirpcapFreeDeviceList(airpcap_devices);
+			return (-1);
+		}
+	}
+	p_AirpcapFreeDeviceList(airpcap_devices);
+	return (0);
+}
diff --git a/pcap-airpcap.h b/pcap-airpcap.h
new file mode 100644
index 0000000..aa1164e
--- /dev/null
+++ b/pcap-airpcap.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2010 CACE Technologies, 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, CACE Technologies
+ * 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.
+ *
+ */
+
+pcap_t *airpcap_create(const char *, char *, int *);
+int airpcap_findalldevs(pcap_if_list_t *devlistp, char *errbuf);
+int device_is_airpcap(const char *device, char *ebuf);
diff --git a/pcap-bpf.c b/pcap-bpf.c
index 4f1a0af..f0ccb96 100644
--- a/pcap-bpf.c
+++ b/pcap-bpf.c
@@ -115,7 +115,6 @@
 
 #endif /* _AIX */
 
-#include <ctype.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <netdb.h>
@@ -153,7 +152,7 @@
 	 * As there is a header on the front size of the mmap'd buffer, only
 	 * some of the buffer is exposed to libpcap as a whole via bufsize;
 	 * zbufsize is the true size.  zbuffer tracks the current zbuf
-	 * assocated with buffer so that it can be used to decide which the
+	 * associated with buffer so that it can be used to decide which the
 	 * next buffer to read will be.
 	 */
 	u_char *zbuf1, *zbuf2, *zbuffer;
@@ -313,7 +312,7 @@
 		    atomic_load_acq_int(&bzh->bzh_kernel_gen)) {
 			pb->bzh = bzh;
 			pb->zbuffer = (u_char *)pb->zbuf2;
-  			p->buffer = pb->zbuffer + sizeof(*bzh);
+			p->buffer = pb->zbuffer + sizeof(*bzh);
 			*cc = bzh->bzh_kernel_len;
 			return (1);
 		}
@@ -445,7 +444,7 @@
 {
 	pcap_t *p;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_bpf));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_bpf);
 	if (p == NULL)
 		return (NULL);
 
@@ -456,7 +455,6 @@
 	 * We claim that we support microsecond and nanosecond time
 	 * stamps.
 	 */
-	p->tstamp_precision_count = 2;
 	p->tstamp_precision_list = malloc(2 * sizeof(u_int));
 	if (p->tstamp_precision_list == NULL) {
 		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno,
@@ -466,6 +464,7 @@
 	}
 	p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
 	p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
+	p->tstamp_precision_count = 2;
 #endif /* BIOCSTSTAMP */
 	return (p);
 }
@@ -522,7 +521,7 @@
 		 * that isn't in use.
 		 */
 		do {
-			(void)pcap_snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+			(void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
 			/*
 			 * Initially try a read/write open (to allow the inject
 			 * method to work).  If that fails due to permission
@@ -557,7 +556,7 @@
 				 * means we probably have no BPF
 				 * devices.
 				 */
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "(there are no BPF devices)");
 			} else {
 				/*
@@ -566,7 +565,7 @@
 				 * devices, but all the ones
 				 * that exist are busy.
 				 */
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "(all BPF devices are busy)");
 			}
 			break;
@@ -597,6 +596,102 @@
 }
 
 /*
+ * Bind a network adapter to a BPF device, given a descriptor for the
+ * BPF device and the name of the network adapter.
+ *
+ * Use BIOCSETLIF if available (meaning "on Solaris"), as it supports
+ * longer device names.
+ *
+ * If the name is longer than will fit, return PCAP_ERROR_NO_SUCH_DEVICE
+ * before trying to bind the interface, as there cannot be such a device.
+ *
+ * If the attempt succeeds, return BPF_BIND_SUCCEEDED.
+ *
+ * If the attempt fails:
+ *
+ *    if it fails with ENXIO, return PCAP_ERROR_NO_SUCH_DEVICE, as
+ *    the device doesn't exist;
+ *
+ *    if it fails with ENETDOWN, return PCAP_ERROR_IFACE_NOT_UP, as
+ *    the interface exists but isn't up and the OS doesn't allow
+ *    binding to an interface that isn't up;
+ *
+ *    if it fails with ENOBUFS, return BPF_BIND_BUFFER_TOO_BIG, and
+ *    fill in an error message, as the buffer being requested is too
+ *    large;
+ *
+ *    otherwise, return PCAP_ERROR and fill in an error message.
+ */
+#define BPF_BIND_SUCCEEDED	0
+#define BPF_BIND_BUFFER_TOO_BIG	1
+
+static int
+bpf_bind(int fd, const char *name, char *errbuf)
+{
+	int status;
+#ifdef LIFNAMSIZ
+	struct lifreq ifr;
+
+	if (strlen(name) >= sizeof(ifr.lifr_name)) {
+		/* The name is too long, so it can't possibly exist. */
+		return (PCAP_ERROR_NO_SUCH_DEVICE);
+	}
+	(void)pcap_strlcpy(ifr.lifr_name, name, sizeof(ifr.lifr_name));
+	status = ioctl(fd, BIOCSETLIF, (caddr_t)&ifr);
+#else
+	struct ifreq ifr;
+
+	if (strlen(name) >= sizeof(ifr.ifr_name)) {
+		/* The name is too long, so it can't possibly exist. */
+		return (PCAP_ERROR_NO_SUCH_DEVICE);
+	}
+	(void)pcap_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	status = ioctl(fd, BIOCSETIF, (caddr_t)&ifr);
+#endif
+
+	if (status < 0) {
+		switch (errno) {
+
+		case ENXIO:
+			/*
+			 * There's no such device.
+			 */
+			return (PCAP_ERROR_NO_SUCH_DEVICE);
+
+		case ENETDOWN:
+			/*
+			 * Return a "network down" indication, so that
+			 * the application can report that rather than
+			 * saying we had a mysterious failure and
+			 * suggest that they report a problem to the
+			 * libpcap developers.
+			 */
+			return (PCAP_ERROR_IFACE_NOT_UP);
+
+		case ENOBUFS:
+			/*
+			 * The buffer size is too big.
+			 * Return a special indication so that, if we're
+			 * trying to crank the buffer size down, we know
+			 * we have to continue; add an error message that
+			 * tells the user what needs to be fixed.
+			 */
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "The requested buffer size for %s is too large",
+			    name);
+			return (BPF_BIND_BUFFER_TOO_BIG);
+
+		default:
+			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "Binding interface %s to BPF device failed",
+			    name);
+			return (PCAP_ERROR);
+		}
+	}
+	return (BPF_BIND_SUCCEEDED);
+}
+
+/*
  * Open and bind to a device; used if we're not actually going to use
  * the device, but are just testing whether it can be opened, or opening
  * it to get information about it.
@@ -608,7 +703,7 @@
 bpf_open_and_bind(const char *name, char *errbuf)
 {
 	int fd;
-	struct ifreq ifr;
+	int status;
 
 	/*
 	 * First, open a BPF device.
@@ -620,34 +715,18 @@
 	/*
 	 * Now bind to the device.
 	 */
-	(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-	if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
-		switch (errno) {
-
-		case ENXIO:
+	status = bpf_bind(fd, name, errbuf);
+	if (status != BPF_BIND_SUCCEEDED) {
+		close(fd);
+		if (status == BPF_BIND_BUFFER_TOO_BIG) {
 			/*
-			 * There's no such device.
+			 * We didn't specify a buffer size, so
+			 * this *really* shouldn't fail because
+			 * there's no buffer space.  Fail.
 			 */
-			close(fd);
-			return (PCAP_ERROR_NO_SUCH_DEVICE);
-
-		case ENETDOWN:
-			/*
-			 * Return a "network down" indication, so that
-			 * the application can report that rather than
-			 * saying we had a mysterious failure and
-			 * suggest that they report a problem to the
-			 * libpcap developers.
-			 */
-			close(fd);
-			return (PCAP_ERROR_IFACE_NOT_UP);
-
-		default:
-			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
-			    errno, "BIOCSETIF: %s", name);
-			close(fd);
 			return (PCAP_ERROR);
 		}
+		return (status);
 	}
 
 	/*
@@ -656,6 +735,47 @@
 	return (fd);
 }
 
+#ifdef __APPLE__
+static int
+device_exists(int fd, const char *name, char *errbuf)
+{
+	int status;
+	struct ifreq ifr;
+
+	if (strlen(name) >= sizeof(ifr.ifr_name)) {
+		/* The name is too long, so it can't possibly exist. */
+		return (PCAP_ERROR_NO_SUCH_DEVICE);
+	}
+	(void)pcap_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	status = ioctl(fd, SIOCGIFFLAGS, (caddr_t)&ifr);
+
+	if (status < 0) {
+		if (errno == ENXIO || errno == EINVAL) {
+			/*
+			 * macOS and *BSD return one of those two
+			 * errors if the device doesn't exist.
+			 * Don't fill in an error, as this is
+			 * an "expected" condition.
+			 */
+			return (PCAP_ERROR_NO_SUCH_DEVICE);
+		}
+
+		/*
+		 * Some other error - provide a message for it, as
+		 * it's "unexpected".
+		 */
+		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno,
+		    "Can't get interface flags on %s", name);
+		return (PCAP_ERROR);
+	}
+
+	/*
+	 * The device exists.
+	 */
+	return (0);
+}
+#endif
+
 #ifdef BIOCGDLTLIST
 static int
 get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf)
@@ -742,10 +862,10 @@
 pcap_can_set_rfmon_bpf(pcap_t *p)
 {
 	struct utsname osinfo;
-	struct ifreq ifr;
 	int fd;
 #ifdef BIOCGDLTLIST
 	struct bpf_dltlist bdl;
+	int err;
 #endif
 
 	/*
@@ -783,6 +903,9 @@
 		return (0);
 	}
 	if (osinfo.release[0] == '8' && osinfo.release[1] == '.') {
+		char *wlt_name;
+		int status;
+
 		/*
 		 * 10.4 (Darwin 8.x).  s/en/wlt/, and check
 		 * whether the device exists.
@@ -799,16 +922,24 @@
 			    errno, "socket");
 			return (PCAP_ERROR);
 		}
-		pcap_strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name));
-		pcap_strlcat(ifr.ifr_name, p->opt.device + 2, sizeof(ifr.ifr_name));
-		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
-			/*
-			 * No such device?
-			 */
+		if (pcap_asprintf(&wlt_name, "wlt%s", p->opt.device + 2) == -1) {
+			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
 			close(fd);
-			return (0);
+			return (PCAP_ERROR);
 		}
+		status = device_exists(fd, wlt_name, p->errbuf);
+		free(wlt_name);
 		close(fd);
+		if (status != 0) {
+			if (status == PCAP_ERROR_NO_SUCH_DEVICE)
+				return (0);
+
+			/*
+			 * Error.
+			 */
+			return (status);
+		}
 		return (1);
 	}
 
@@ -827,34 +958,18 @@
 	/*
 	 * Now bind to the device.
 	 */
-	(void)strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name));
-	if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
-		switch (errno) {
-
-		case ENXIO:
+	err = bpf_bind(fd, p->opt.device, p->errbuf);
+	if (err != BPF_BIND_SUCCEEDED) {
+		close(fd);
+		if (err == BPF_BIND_BUFFER_TOO_BIG) {
 			/*
-			 * There's no such device.
+			 * We didn't specify a buffer size, so
+			 * this *really* shouldn't fail because
+			 * there's no buffer space.  Fail.
 			 */
-			close(fd);
-			return (PCAP_ERROR_NO_SUCH_DEVICE);
-
-		case ENETDOWN:
-			/*
-			 * Return a "network down" indication, so that
-			 * the application can report that rather than
-			 * saying we had a mysterious failure and
-			 * suggest that they report a problem to the
-			 * libpcap developers.
-			 */
-			close(fd);
-			return (PCAP_ERROR_IFACE_NOT_UP);
-
-		default:
-			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
-			    errno, "BIOCSETIF: %s", p->opt.device);
-			close(fd);
 			return (PCAP_ERROR);
 		}
+		return (err);
 	}
 
 	/*
@@ -982,7 +1097,7 @@
 		} else
 #endif
 		{
-			cc = read(p->fd, p->buffer, p->bufsize);
+			cc = (int)read(p->fd, p->buffer, p->bufsize);
 		}
 		if (cc < 0) {
 			/* Don't choke when we get ptraced */
@@ -1033,7 +1148,7 @@
 				 * documented as having error returns
 				 * other than PCAP_ERROR or PCAP_ERROR_BREAK.
 				 */
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				    "The interface disappeared");
 				return (PCAP_ERROR);
 
@@ -1087,7 +1202,7 @@
 		 */
 		if (p->break_loop) {
 			p->bp = bp;
-			p->cc = ep - bp;
+			p->cc = (int)(ep - bp);
 			/*
 			 * ep is set based on the return value of read(),
 			 * but read() from a BPF device doesn't necessarily
@@ -1127,7 +1242,7 @@
 #endif
 		 */
 		if (pb->filtering_in_kernel ||
-		    bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
+		    pcap_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
 			struct pcap_pkthdr pkthdr;
 #ifdef BIOCSTSTAMP
 			struct bintime bt;
@@ -1177,7 +1292,7 @@
 			bp += BPF_WORDALIGN(caplen + hdrlen);
 			if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
 				p->bp = bp;
-				p->cc = ep - bp;
+				p->cc = (int)(ep - bp);
 				/*
 				 * See comment above about p->cc < 0.
 				 */
@@ -1198,11 +1313,11 @@
 }
 
 static int
-pcap_inject_bpf(pcap_t *p, const void *buf, size_t size)
+pcap_inject_bpf(pcap_t *p, const void *buf, int size)
 {
 	int ret;
 
-	ret = write(p->fd, buf, size);
+	ret = (int)write(p->fd, buf, size);
 #ifdef __APPLE__
 	if (ret == -1 && errno == EAFNOSUPPORT) {
 		/*
@@ -1234,7 +1349,7 @@
 		/*
 		 * Now try the write again.
 		 */
-		ret = write(p->fd, buf, size);
+		ret = (int)write(p->fd, buf, size);
 	}
 #endif /* __APPLE__ */
 	if (ret == -1) {
@@ -1254,7 +1369,7 @@
 	if (odm_initialize() == -1) {
 		if (odm_err_msg(odmerrno, &errstr) == -1)
 			errstr = "Unknown error";
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "bpf_load: odm_initialize failed: %s",
 		    errstr);
 		return (PCAP_ERROR);
@@ -1263,7 +1378,7 @@
 	if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) {
 		if (odm_err_msg(odmerrno, &errstr) == -1)
 			errstr = "Unknown error";
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s",
 		    errstr);
 		(void)odm_terminate();
@@ -1282,7 +1397,7 @@
 		if (errbuf != NULL) {
 			if (odm_err_msg(odmerrno, &errstr) == -1)
 				errstr = "Unknown error";
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "bpf_load: odm_unlock failed: %s",
 			    errstr);
 		}
@@ -1293,7 +1408,7 @@
 		if (errbuf != NULL) {
 			if (odm_err_msg(odmerrno, &errstr) == -1)
 				errstr = "Unknown error";
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "bpf_load: odm_terminate failed: %s",
 			    errstr);
 		}
@@ -1356,7 +1471,7 @@
 
 	if (rc == -1 || getmajor(sbuf.st_rdev) != major) {
 		for (i = 0; i < BPF_MINORS; i++) {
-			pcap_snprintf(buf, sizeof(buf), "%s%d", BPF_NODE, i);
+			snprintf(buf, sizeof(buf), "%s%d", BPF_NODE, i);
 			unlink(buf);
 			if (mknod(buf, S_IRUSR | S_IFCHR, domakedev(major, i)) == -1) {
 				pcap_fmt_errmsg_for_errno(errbuf,
@@ -1369,7 +1484,7 @@
 
 	/* Check if the driver is loaded */
 	memset(&cfg_ld, 0x0, sizeof(cfg_ld));
-	pcap_snprintf(buf, sizeof(buf), "%s/%s", DRIVER_PATH, BPF_NAME);
+	snprintf(buf, sizeof(buf), "%s/%s", DRIVER_PATH, BPF_NAME);
 	cfg_ld.path = buf;
 	if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) ||
 	    (cfg_ld.kmid == 0)) {
@@ -1437,7 +1552,7 @@
 				    strerror(errno));
 			} else {
 				memset(&req, 0, sizeof(req));
-				strncpy(req.ifm_name, pb->device,
+				pcap_strlcpy(req.ifm_name, pb->device,
 				    sizeof(req.ifm_name));
 				if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
 					fprintf(stderr,
@@ -1451,7 +1566,7 @@
 						 * turn it off.
 						 */
 						memset(&ifr, 0, sizeof(ifr));
-						(void)strncpy(ifr.ifr_name,
+						(void)pcap_strlcpy(ifr.ifr_name,
 						    pb->device,
 						    sizeof(ifr.ifr_name));
 						ifr.ifr_media =
@@ -1519,20 +1634,17 @@
 	pcap_cleanup_live_common(p);
 }
 
+#ifdef __APPLE__
 static int
 check_setif_failure(pcap_t *p, int error)
 {
-#ifdef __APPLE__
 	int fd;
-	struct ifreq ifr;
 	int err;
-#endif
 
-	if (error == ENXIO) {
+	if (error == PCAP_ERROR_NO_SUCH_DEVICE) {
 		/*
 		 * No such device exists.
 		 */
-#ifdef __APPLE__
 		if (p->opt.rfmon && strncmp(p->opt.device, "wlt", 3) == 0) {
 			/*
 			 * Monitor mode was requested, and we're trying
@@ -1543,33 +1655,38 @@
 			 */
 			fd = socket(AF_INET, SOCK_DGRAM, 0);
 			if (fd != -1) {
-				pcap_strlcpy(ifr.ifr_name, "en",
-				    sizeof(ifr.ifr_name));
-				pcap_strlcat(ifr.ifr_name, p->opt.device + 3,
-				    sizeof(ifr.ifr_name));
-				if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+				char *en_name;
+
+				if (pcap_asprintf(&en_name, "en%s",
+				    p->opt.device + 3) == -1) {
 					/*
-					 * We assume this failed because
-					 * the underlying device doesn't
-					 * exist.
+					 * We can't find out whether there's
+					 * an underlying "enN" device, so
+					 * just report "no such device".
 					 */
-					err = PCAP_ERROR_NO_SUCH_DEVICE;
 					pcap_fmt_errmsg_for_errno(p->errbuf,
 					    PCAP_ERRBUF_SIZE, errno,
-					    "SIOCGIFFLAGS on %s failed",
-					    ifr.ifr_name);
-				} else {
-					/*
-					 * The underlying "enN" device
-					 * exists, but there's no
-					 * corresponding "wltN" device;
-					 * that means that the "enN"
-					 * device doesn't support
-					 * monitor mode, probably because
-					 * it's an Ethernet device rather
-					 * than a wireless device.
-					 */
-					err = PCAP_ERROR_RFMON_NOTSUP;
+					    "malloc");
+					close(fd);
+					return (PCAP_ERROR_NO_SUCH_DEVICE);
+				}
+				err = device_exists(fd, en_name, p->errbuf);
+				free(en_name);
+				if (err != 0) {
+					if (err == PCAP_ERROR_NO_SUCH_DEVICE) {
+						/*
+						 * The underlying "enN" device
+						 * exists, but there's no
+						 * corresponding "wltN" device;
+						 * that means that the "enN"
+						 * device doesn't support
+						 * monitor mode, probably
+						 * because it's an Ethernet
+						 * device rather than a
+						 * wireless device.
+						 */
+						err = PCAP_ERROR_RFMON_NOTSUP;
+					}
 				}
 				close(fd);
 			} else {
@@ -1585,32 +1702,30 @@
 			}
 			return (err);
 		}
-#endif
+
 		/*
 		 * No such device.
 		 */
-		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "BIOCSETIF failed");
 		return (PCAP_ERROR_NO_SUCH_DEVICE);
-	} else if (errno == ENETDOWN) {
-		/*
-		 * Return a "network down" indication, so that
-		 * the application can report that rather than
-		 * saying we had a mysterious failure and
-		 * suggest that they report a problem to the
-		 * libpcap developers.
-		 */
-		return (PCAP_ERROR_IFACE_NOT_UP);
-	} else {
-		/*
-		 * Some other error; fill in the error string, and
-		 * return PCAP_ERROR.
-		 */
-		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "BIOCSETIF: %s", p->opt.device);
-		return (PCAP_ERROR);
 	}
+
+	/*
+	 * Just return the error status; it's what we want, and, if it's
+	 * PCAP_ERROR, the error string has been filled in.
+	 */
+	return (error);
 }
+#else
+static int
+check_setif_failure(pcap_t *p _U_, int error)
+{
+	/*
+	 * Just return the error status; it's what we want, and, if it's
+	 * PCAP_ERROR, the error string has been filled in.
+	 */
+	return (error);
+}
+#endif
 
 /*
  * Default capture buffer size.
@@ -1636,15 +1751,9 @@
 	int retv;
 #endif
 	int fd;
-#ifdef LIFNAMSIZ
-	char *zonesep;
+#if defined(LIFNAMSIZ) && defined(ZONENAME_MAX) && defined(lifr_zoneid)
 	struct lifreq ifr;
-	char *ifrname = ifr.lifr_name;
-	const size_t ifnamsiz = sizeof(ifr.lifr_name);
-#else
-	struct ifreq ifr;
-	char *ifrname = ifr.ifr_name;
-	const size_t ifnamsiz = sizeof(ifr.ifr_name);
+	char *zonesep;
 #endif
 	struct bpf_version bv;
 #ifdef __APPLE__
@@ -1686,7 +1795,7 @@
 	}
 	if (bv.bv_major != BPF_MAJOR_VERSION ||
 	    bv.bv_minor < BPF_MINOR_VERSION) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "kernel bpf filter out of date");
 		status = PCAP_ERROR;
 		goto bad;
@@ -1726,7 +1835,7 @@
 		char *lnamep;
 
 		if (ifr.lifr_zoneid != GLOBAL_ZONEID) {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "zonename/linkname only valid in global zone.");
 			status = PCAP_ERROR;
 			goto bad;
@@ -1797,24 +1906,19 @@
 					 */
 					sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 					if (sockfd != -1) {
-						pcap_strlcpy(ifrname,
-						    p->opt.device, ifnamsiz);
-						if (ioctl(sockfd, SIOCGIFFLAGS,
-						    (char *)&ifr) < 0) {
+						status = device_exists(sockfd,
+						    p->opt.device, p->errbuf);
+						if (status == 0) {
 							/*
-							 * We assume this
-							 * failed because
-							 * the underlying
-							 * device doesn't
-							 * exist.
+							 * The device exists,
+							 * but it's not an
+							 * enN device; that
+							 * means it doesn't
+							 * support monitor
+							 * mode.
 							 */
-							status = PCAP_ERROR_NO_SUCH_DEVICE;
-							pcap_fmt_errmsg_for_errno(p->errbuf,
-							    PCAP_ERRBUF_SIZE,
-							    errno,
-							    "SIOCGIFFLAGS failed");
-						} else
 							status = PCAP_ERROR_RFMON_NOTSUP;
+						}
 						close(sockfd);
 					} else {
 						/*
@@ -1866,6 +1970,7 @@
 			 * it when the pcap_t is closed.
 			 */
 			int s;
+			struct ifreq ifr;
 
 			/*
 			 * Open a socket to use for ioctls to
@@ -1889,7 +1994,7 @@
 				 * "atexit()" failed; don't create the
 				 * interface, just give up.
 				 */
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				     "atexit failed");
 				close(s);
 				status = PCAP_ERROR;
@@ -1902,7 +2007,7 @@
 			pcap_strlcpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name));
 			if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) {
 				if (errno == EINVAL) {
-					pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+					snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 					    "Invalid USB bus interface %s",
 					    p->opt.device);
 				} else {
@@ -1994,11 +2099,19 @@
 			status = PCAP_ERROR;
 			goto bad;
 		}
-		(void)strncpy(ifrname, p->opt.device, ifnamsiz);
-		if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
-			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
-			    errno, "BIOCSETIF: %s", p->opt.device);
-			status = PCAP_ERROR;
+		status = bpf_bind(fd, p->opt.device, ifnamsiz, p->errbuf);
+		if (status != BPF_BIND_SUCCEEDED) {
+			if (status == BPF_BIND_BUFFER_TOO_BIG) {
+				/*
+				 * The requested buffer size
+				 * is too big.  Fail.
+				 *
+				 * XXX - should we do the "keep cutting
+				 * the buffer size in half" loop here if
+				 * we're using the default buffer size?
+				 */
+				status = PCAP_ERROR;
+			}
 			goto bad;
 		}
 		v = pb->zbufsize - sizeof(struct bpf_zbuf_header);
@@ -2025,14 +2138,23 @@
 			/*
 			 * Now bind to the device.
 			 */
-			(void)strncpy(ifrname, p->opt.device, ifnamsiz);
-#ifdef BIOCSETLIF
-			if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) < 0)
-#else
-			if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0)
-#endif
-			{
-				status = check_setif_failure(p, errno);
+			status = bpf_bind(fd, p->opt.device, p->errbuf);
+			if (status != BPF_BIND_SUCCEEDED) {
+				if (status == BPF_BIND_BUFFER_TOO_BIG) {
+					/*
+					 * The requested buffer size
+					 * is too big.  Fail.
+					 */
+					status = PCAP_ERROR;
+					goto bad;
+				}
+
+				/*
+				 * Special checks on macOS to deal with
+				 * the way monitor mode was done on
+				 * 10.4 Tiger.
+				 */
+				status = check_setif_failure(p, status);
 				goto bad;
 			}
 		} else {
@@ -2058,22 +2180,30 @@
 				 */
 				(void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
 
-				(void)strncpy(ifrname, p->opt.device, ifnamsiz);
-#ifdef BIOCSETLIF
-				if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) >= 0)
-#else
-				if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
-#endif
+				status = bpf_bind(fd, p->opt.device, p->errbuf);
+				if (status == BPF_BIND_SUCCEEDED)
 					break;	/* that size worked; we're done */
 
-				if (errno != ENOBUFS) {
-					status = check_setif_failure(p, errno);
+				/*
+				 * If the attempt failed because the
+				 * buffer was too big, cut the buffer
+				 * size in half and try again.
+				 *
+				 * Otherwise, fail.
+				 */
+				if (errno != BPF_BIND_BUFFER_TOO_BIG) {
+					/*
+					 * Special checks on macOS to deal
+					 * with the way monitor mode was
+					 * done on 10.4 Tiger.
+					 */
+					status = check_setif_failure(p, status);
 					goto bad;
 				}
 			}
 
 			if (v == 0) {
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				    "BIOCSBLEN: %s: No buffer size worked",
 				    p->opt.device);
 				status = PCAP_ERROR;
@@ -2117,7 +2247,7 @@
 		/*
 		 * We don't know what to map this to yet.
 		 */
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
 		    v);
 		status = PCAP_ERROR;
 		goto bad;
@@ -2177,9 +2307,9 @@
 	 * we try to select DLT_IEEE802_11.
 	 */
 	if (have_osinfo) {
-		if (isdigit((unsigned)osinfo.release[0]) &&
+		if (PCAP_ISDIGIT((unsigned)osinfo.release[0]) &&
 		     (osinfo.release[0] == '9' ||
-		     isdigit((unsigned)osinfo.release[1]))) {
+		     PCAP_ISDIGIT((unsigned)osinfo.release[1]))) {
 			/*
 			 * 10.5 (Darwin 9.x), or later.
 			 */
@@ -2429,7 +2559,7 @@
 		/*
 		 * We don't support immediate mode.  Fail.
 		 */
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Immediate mode not supported");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Immediate mode not supported");
 		status = PCAP_ERROR;
 		goto bad;
 	}
@@ -2756,10 +2886,14 @@
 		return (-1);
 	}
 	memset(&req, 0, sizeof(req));
-	strncpy(req.ifm_name, name, sizeof(req.ifm_name));
+	pcap_strlcpy(req.ifm_name, name, sizeof(req.ifm_name));
 	if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
 		if (errno == EOPNOTSUPP || errno == EINVAL || errno == ENOTTY ||
-		    errno == ENODEV || errno == EPERM) {
+		    errno == ENODEV || errno == EPERM
+#ifdef EPWROFF
+		    || errno == EPWROFF
+#endif
+		    ) {
 			/*
 			 * Not supported, so we can't provide any
 			 * additional information.  Assume that
@@ -2774,6 +2908,18 @@
 			 * So, just as we do for some ethtool ioctls
 			 * on Linux, which makes the same mistake, we
 			 * also treat EPERM as meaning "not supported".
+			 *
+			 * And it appears that Apple's llw0 device, which
+			 * appears to be part of the Skywalk subsystem:
+			 *
+			 *    http://newosxbook.com/bonus/vol1ch16.html
+			 *
+			 * can sometimes return EPWROFF ("Device power
+			 * is off") for that ioctl, so we treat *that*
+			 * as another indication that we can't get a
+			 * connection status.  (If it *isn't* "powered
+			 * off", it's reported as a wireless device,
+			 * complete with an active/inactive state.)
 			 */
 			*flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
 			close(sock);
@@ -2883,7 +3029,7 @@
 	}
 
 	memset(&req, 0, sizeof req);
-	strncpy(req.ifm_name, p->opt.device, sizeof req.ifm_name);
+	pcap_strlcpy(req.ifm_name, p->opt.device, sizeof req.ifm_name);
 
 	/*
 	 * Find out how many media types we have.
@@ -2993,7 +3139,7 @@
 				return (PCAP_ERROR);
 			}
 			memset(&ifr, 0, sizeof(ifr));
-			(void)strncpy(ifr.ifr_name, p->opt.device,
+			(void)pcap_strlcpy(ifr.ifr_name, p->opt.device,
 			    sizeof(ifr.ifr_name));
 			ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR;
 			if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) {
@@ -3259,14 +3405,101 @@
 pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
 {
 	u_int direction;
+	const char *direction_name;
 
-	direction = (d == PCAP_D_IN) ? BPF_D_IN :
-	    ((d == PCAP_D_OUT) ? BPF_D_OUT : BPF_D_INOUT);
+	/*
+	 * FreeBSD and NetBSD.
+	 */
+	switch (d) {
+
+	case PCAP_D_IN:
+		/*
+		 * Incoming, but not outgoing, so accept only
+		 * incoming packets.
+		 */
+		direction = BPF_D_IN;
+		direction_name = "\"incoming only\"";
+		break;
+
+	case PCAP_D_OUT:
+		/*
+		 * Outgoing, but not incoming, so accept only
+		 * outgoing packets.
+		 */
+		direction = BPF_D_OUT;
+		direction_name = "\"outgoing only\"";
+		break;
+
+	default:
+		/*
+		 * Incoming and outgoing, so accept both
+		 * incoming and outgoing packets.
+		 *
+		 * It's guaranteed, at this point, that d is a valid
+		 * direction value, so we know that this is PCAP_D_INOUT
+		 * if it's not PCAP_D_IN or PCAP_D_OUT.
+		 */
+		direction = BPF_D_INOUT;
+		direction_name = "\"incoming and outgoing\"";
+		break;
+	}
+
 	if (ioctl(p->fd, BIOCSDIRECTION, &direction) == -1) {
 		pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
-		    errno, "Cannot set direction to %s",
-		        (d == PCAP_D_IN) ? "PCAP_D_IN" :
-			((d == PCAP_D_OUT) ? "PCAP_D_OUT" : "PCAP_D_INOUT"));
+		    errno, "Cannot set direction to %s", direction_name);
+		return (-1);
+	}
+	return (0);
+}
+#elif defined(BIOCSDIRFILT)
+static int
+pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
+{
+	u_int dirfilt;
+	const char *direction_name;
+
+	/*
+	 * OpenBSD; same functionality, different names, different
+	 * semantics (the flags mean "*don't* capture packets in
+	 * that direction", not "*capture only* packets in that
+	 * direction").
+	 */
+	switch (d) {
+
+	case PCAP_D_IN:
+		/*
+		 * Incoming, but not outgoing, so filter out
+		 * outgoing packets.
+		 */
+		dirfilt = BPF_DIRECTION_OUT;
+		direction_name = "\"incoming only\"";
+		break;
+
+	case PCAP_D_OUT:
+		/*
+		 * Outgoing, but not incoming, so filter out
+		 * incoming packets.
+		 */
+		dirfilt = BPF_DIRECTION_IN;
+		direction_name = "\"outgoing only\"";
+		break;
+
+	default:
+		/*
+		 * Incoming and outgoing, so don't filter out
+		 * any packets based on direction.
+		 *
+		 * It's guaranteed, at this point, that d is a valid
+		 * direction value, so we know that this is PCAP_D_INOUT
+		 * if it's not PCAP_D_IN or PCAP_D_OUT.
+		 */
+		dirfilt = 0;
+		direction_name = "\"incoming and outgoing\"";
+		break;
+	}
+	if (ioctl(p->fd, BIOCSDIRFILT, &dirfilt) == -1) {
+		pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+		    errno, "Cannot set direction to %s", direction_name);
 		return (-1);
 	}
 	return (0);
@@ -3276,21 +3509,47 @@
 pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
 {
 	u_int seesent;
+	const char *direction_name;
 
 	/*
-	 * We don't support PCAP_D_OUT.
+	 * OS with just BIOCSSEESENT.
 	 */
-	if (d == PCAP_D_OUT) {
-		pcap_snprintf(p->errbuf, sizeof(p->errbuf),
-		    "Setting direction to PCAP_D_OUT is not supported on BPF");
-		return -1;
+	switch (d) {
+
+	case PCAP_D_IN:
+		/*
+		 * Incoming, but not outgoing, so we don't want to
+		 * see transmitted packets.
+		 */
+		seesent = 0;
+		direction_name = "\"incoming only\"";
+		break;
+
+	case PCAP_D_OUT:
+		/*
+		 * Outgoing, but not incoming; we can't specify that.
+		 */
+		snprintf(p->errbuf, sizeof(p->errbuf),
+		    "Setting direction to \"outgoing only\" is not supported on this device");
+		return (-1);
+
+	default:
+		/*
+		 * Incoming and outgoing, so we want to see transmitted
+		 * packets.
+		 *
+		 * It's guaranteed, at this point, that d is a valid
+		 * direction value, so we know that this is PCAP_D_INOUT
+		 * if it's not PCAP_D_IN or PCAP_D_OUT.
+		 */
+		seesent = 1;
+		direction_name = "\"incoming and outgoing\"";
+		break;
 	}
 
-	seesent = (d == PCAP_D_INOUT);
 	if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) {
 		pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
-		    errno, "Cannot set direction to %s",
-		    (d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN");
+		    errno, "Cannot set direction to %s", direction_name);
 		return (-1);
 	}
 	return (0);
@@ -3299,8 +3558,8 @@
 static int
 pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d _U_)
 {
-	(void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
-	    "This system doesn't support BIOCSSEESENT, so the direction can't be set");
+	(void) snprintf(p->errbuf, sizeof(p->errbuf),
+	    "Setting direction is not supported on this device");
 	return (-1);
 }
 #endif
diff --git a/pcap-bt-linux.c b/pcap-bt-linux.c
index 9c8712e..2969ff8 100644
--- a/pcap-bt-linux.c
+++ b/pcap-bt-linux.c
@@ -58,7 +58,7 @@
 /* forward declaration */
 static int bt_activate(pcap_t *);
 static int bt_read_linux(pcap_t *, int , pcap_handler , u_char *);
-static int bt_inject_linux(pcap_t *, const void *, size_t);
+static int bt_inject_linux(pcap_t *, const void *, int);
 static int bt_setdirection_linux(pcap_t *, pcap_direction_t);
 static int bt_stats_linux(pcap_t *, struct pcap_stat *);
 
@@ -92,7 +92,7 @@
 	dev_list = malloc(HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list));
 	if (!dev_list)
 	{
-		pcap_snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't allocate %zu bytes for Bluetooth device list",
+		snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't allocate %zu bytes for Bluetooth device list",
 			HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list));
 		ret = -1;
 		goto done;
@@ -112,8 +112,8 @@
 	for (i = 0; i < dev_list->dev_num; i++, dev_req++) {
 		char dev_name[20], dev_descr[40];
 
-		pcap_snprintf(dev_name, sizeof(dev_name), BT_IFACE"%u", dev_req->dev_id);
-		pcap_snprintf(dev_descr, sizeof(dev_descr), "Bluetooth adapter number %u", i);
+		snprintf(dev_name, sizeof(dev_name), BT_IFACE"%u", dev_req->dev_id);
+		snprintf(dev_descr, sizeof(dev_descr), "Bluetooth adapter number %u", i);
 
 		/*
 		 * Bluetooth is a wireless technology.
@@ -173,7 +173,7 @@
 	/* OK, it's probably ours. */
 	*is_ours = 1;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_bt));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt);
 	if (p == NULL)
 		return (NULL);
 
@@ -194,7 +194,7 @@
 	/* get bt interface id */
 	if (sscanf(handle->opt.device, BT_IFACE"%d", &dev_id) != 1)
 	{
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			"Can't get Bluetooth device index from %s",
 			 handle->opt.device);
 		return PCAP_ERROR;
@@ -346,7 +346,7 @@
 		return -1;
 	}
 
-	pkth.caplen = ret;
+	pkth.caplen = (bpf_u_int32)ret;
 
 	/* get direction and timestamp*/
 	cmsg = CMSG_FIRSTHDR(&msg);
@@ -362,15 +362,27 @@
 		}
 		cmsg = CMSG_NXTHDR(&msg, cmsg);
 	}
-	if ((in && (handle->direction == PCAP_D_OUT)) ||
-				((!in) && (handle->direction == PCAP_D_IN)))
-		return 0;
+	switch (handle->direction) {
+
+	case PCAP_D_IN:
+		if (!in)
+			return 0;
+		break;
+
+	case PCAP_D_OUT:
+		if (in)
+			return 0;
+		break;
+
+	default:
+		break;
+	}
 
 	bthdr->direction = htonl(in != 0);
 	pkth.caplen+=sizeof(pcap_bluetooth_h4_header);
 	pkth.len = pkth.caplen;
 	if (handle->fcode.bf_insns == NULL ||
-	    bpf_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
+	    pcap_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
 		callback(user, &pkth, pktd);
 		return 1;
 	}
@@ -378,9 +390,9 @@
 }
 
 static int
-bt_inject_linux(pcap_t *handle, const void *buf _U_, size_t size _U_)
+bt_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_)
 {
-	pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 	    "Packet injection is not supported on Bluetooth devices");
 	return (-1);
 }
@@ -418,6 +430,10 @@
 static int
 bt_setdirection_linux(pcap_t *p, pcap_direction_t d)
 {
+	/*
+	 * It's guaranteed, at this point, that d is a valid
+	 * direction value.
+	 */
 	p->direction = d;
 	return 0;
 }
diff --git a/pcap-bt-monitor-linux.c b/pcap-bt-monitor-linux.c
index a693949..ad4fc37 100644
--- a/pcap-bt-monitor-linux.c
+++ b/pcap-bt-monitor-linux.c
@@ -50,6 +50,14 @@
 #define INTERFACE_NAME "bluetooth-monitor"
 
 /*
+ * Private data.
+ * Currently contains nothing.
+ */
+struct pcap_bt_monitor {
+	int	dummy;
+};
+
+/*
  * Fields and alignment must match the declaration in the Linux kernel 3.4+.
  * See struct hci_mon_hdr in include/net/bluetooth/hci_mon.h.
  */
@@ -124,7 +132,7 @@
         return -1;
     }
 
-    pkth.caplen = ret - sizeof(hdr) + sizeof(pcap_bluetooth_linux_monitor_header);
+    pkth.caplen = (bpf_u_int32)(ret - sizeof(hdr) + sizeof(pcap_bluetooth_linux_monitor_header));
     pkth.len = pkth.caplen;
 
     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
@@ -139,7 +147,7 @@
     bthdr->opcode = htons(hdr.opcode);
 
     if (handle->fcode.bf_insns == NULL ||
-        bpf_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
+        pcap_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
         callback(user, &pkth, pktd);
         return 1;
     }
@@ -147,21 +155,14 @@
 }
 
 static int
-bt_monitor_inject(pcap_t *handle, const void *buf _U_, size_t size _U_)
+bt_monitor_inject(pcap_t *handle, const void *buf _U_, int size _U_)
 {
-    pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+    snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
         "Packet injection is not supported yet on Bluetooth monitor devices");
     return -1;
 }
 
 static int
-bt_monitor_setdirection(pcap_t *p, pcap_direction_t d)
-{
-    p->direction = d;
-    return 0;
-}
-
-static int
 bt_monitor_stats(pcap_t *handle _U_, struct pcap_stat *stats)
 {
     stats->ps_recv = 0;
@@ -200,7 +201,7 @@
     handle->read_op = bt_monitor_read;
     handle->inject_op = bt_monitor_inject;
     handle->setfilter_op = install_bpf_program; /* no kernel filtering */
-    handle->setdirection_op = bt_monitor_setdirection;
+    handle->setdirection_op = NULL; /* Not implemented */
     handle->set_datalink_op = NULL; /* can't change data link type */
     handle->getnonblock_op = pcap_getnonblock_fd;
     handle->setnonblock_op = pcap_setnonblock_fd;
@@ -263,7 +264,7 @@
     }
 
     *is_ours = 1;
-    p = pcap_create_common(ebuf, 0);
+    p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt_monitor);
     if (p == NULL)
         return NULL;
 
diff --git a/pcap-common.c b/pcap-common.c
index 2a745f0..51d0666 100644
--- a/pcap-common.c
+++ b/pcap-common.c
@@ -326,7 +326,7 @@
  * 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 accomodate
+ * The first byte of the PPP header (0xff03) is modified to accommodate
  * the direction - 0x00 = IN, 0x01 = OUT.
  */
 #define LINKTYPE_PPP_PPPD	166
@@ -361,7 +361,7 @@
 /*
  * Link types requested by Gregor Maier <gregor@endace.com> of Endace
  * Measurement Systems.  They add an ERF header (see
- * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of
  * the link-layer header.
  */
 #define LINKTYPE_ERF_ETH	175	/* Ethernet */
@@ -495,7 +495,7 @@
 
 /*
  * Various link-layer types, with a pseudo-header, for SITA
- * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
  */
 #define LINKTYPE_SITA		196
 
@@ -558,7 +558,6 @@
  */
 #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
@@ -608,7 +607,7 @@
 
 /*
  * Media Oriented Systems Transport (MOST) bus for multimedia
- * transport - http://www.mostcooperation.com/ - as requested
+ * transport - https://www.mostcooperation.com/ - as requested
  * by Hannes Kaelber <hannes.kaelber@x2e.de>.
  */
 #define LINKTYPE_MOST		211
@@ -794,16 +793,16 @@
 /*
  * Raw D-Bus:
  *
- *	http://www.freedesktop.org/wiki/Software/dbus
+ *	https://www.freedesktop.org/wiki/Software/dbus
  *
  * messages:
  *
- *	http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-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:
  *
- *	http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ *	https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
  *
  * Requested by Martin Vidner <martin@vidner.net>.
  */
@@ -821,7 +820,7 @@
  * DVB-CI (DVB Common Interface for communication between a PC Card
  * module and a DVB receiver).  See
  *
- *	http://www.kaiser.cx/pcap-dvbci.html
+ *	https://www.kaiser.cx/pcap-dvbci.html
  *
  * for the specification.
  *
@@ -945,7 +944,7 @@
  *
  * Requested by Chris Bontje <chris_bontje@selinc.com>.
  */
-#define DLT_RTAC_SERIAL		250
+#define LINKTYPE_RTAC_SERIAL		250
 
 /*
  * Bluetooth Low Energy air interface link-layer packets.
@@ -1079,9 +1078,9 @@
 
 /*
  * per: Stefanha at gmail.com for
- *   http://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
+ *   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: http://qemu-project.org/Features/VirtioVsock
+ * for: https://qemu-project.org/Features/VirtioVsock
  */
 #define LINKTYPE_VSOCK          271
 
@@ -1093,7 +1092,7 @@
 /*
  * Excentis DOCSIS 3.1 RF sniffer (XRA-31)
  *   per: bruno.verstuyft at excentis.com
- *        http://www.xra31.com/xra-header
+ *        https://www.xra31.com/xra-header
  */
 #define LINKTYPE_DOCSIS31_XRA31	273
 
@@ -1105,7 +1104,7 @@
 
 /*
  * DisplayPort AUX channel monitoring data as specified by VESA
- * DisplayPort(DP) Standard preceeded by a pseudo-header.
+ * DisplayPort(DP) Standard preceded by a pseudo-header.
  *    per dirk.eibach at gdsys.cc
  */
 #define LINKTYPE_DISPLAYPORT_AUX	275
@@ -1115,7 +1114,84 @@
  */
 #define LINKTYPE_LINUX_SLL2	276
 
-#define LINKTYPE_MATCHING_MAX	276		/* highest value in the "matching" range */
+/*
+ * 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
@@ -1144,7 +1220,7 @@
 	{ DLT_ARCNET,		LINKTYPE_ARCNET_BSD },
 	{ DLT_SLIP,		LINKTYPE_SLIP },
 	{ DLT_PPP,		LINKTYPE_PPP },
-	{ DLT_FDDI,	 	LINKTYPE_FDDI },
+	{ DLT_FDDI,		LINKTYPE_FDDI },
 	{ DLT_SYMANTEC_FIREWALL, LINKTYPE_SYMANTEC_FIREWALL },
 
 	/*
@@ -1248,11 +1324,20 @@
 		return (DLT_PKTAP);
 
 	/*
-	 * For all other values in the matching range, the LINKTYPE
-	 * value is the same as the DLT value.
+	 * 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_MATCHING_MAX &&
+	    linktype != LINKTYPE_ATM_CLIP)
 		return (linktype);
 
 	/*
@@ -1265,7 +1350,7 @@
 
 	/*
 	 * If we don't have an entry for this LINKTYPE, return
-	 * the link type value; it may be a DLT from an older
+	 * the link type value; it may be a DLT from an newer
 	 * version of libpcap.
 	 */
 	return linktype;
@@ -1280,6 +1365,10 @@
  *
  *    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
@@ -1292,6 +1381,9 @@
 	case DLT_DBUS:
 		return 128*1024*1024;
 
+	case DLT_EBHSCR:
+		return 8*1024*1024;
+
 	case DLT_USBPCAP:
 		return 1024*1024;
 
@@ -1324,7 +1416,7 @@
 		return;
 	}
 
-	protocol = EXTRACT_16BITS(&shdr->sll_protocol);
+	protocol = EXTRACT_BE_U_2(&shdr->sll_protocol);
 	if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
 		return;
 
diff --git a/pcap-config.1 b/pcap-config.1
index 0388d0f..fe8d799 100644
--- a/pcap-config.1
+++ b/pcap-config.1
@@ -69,4 +69,4 @@
 flag causes it to write flags appropriate for compiling with a
 statically-linked version of libpcap.
 .SH "SEE ALSO"
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap-dag.c b/pcap-dag.c
index e076676..b207dd8 100644
--- a/pcap-dag.c
+++ b/pcap-dag.c
@@ -19,7 +19,6 @@
 
 #include "pcap-int.h"
 
-#include <ctype.h>
 #include <netinet/in.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
@@ -208,7 +207,6 @@
 #define dag_size_t uint32_t
 #endif
 
-static int dag_setfilter(pcap_t *p, struct bpf_program *fp);
 static int dag_stats(pcap_t *p, struct pcap_stat *ps);
 static int dag_set_datalink(pcap_t *p, int dlt);
 static int dag_get_datalink(pcap_t *p);
@@ -335,7 +333,7 @@
 /*
  *  Read at most max_packets from the capture stream and call the callback
  *  for each of them. Returns the number of packets handled, -1 if an
- *  error occured, or -2 if we were told to break out of the loop.
+ *  error occurred, or -2 if we were told to break out of the loop.
  */
 static int
 dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
@@ -421,7 +419,8 @@
 		rlen = ntohs(header->rlen);
 		if (rlen < dag_record_size)
 		{
-			strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE);
+			pcap_strlcpy(p->errbuf, "dag_read: record too small",
+			    PCAP_ERRBUF_SIZE);
 			return -1;
 		}
 		pd->dag_mem_bottom += rlen;
@@ -664,7 +663,7 @@
 			caplen = p->snapshot;
 
 		/* Run the packet filter if there is one. */
-		if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
+		if ((p->fcode.bf_insns == NULL) || pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
 
 			/* convert between timestamp formats */
 			register unsigned long long ts;
@@ -718,7 +717,7 @@
 }
 
 static int
-dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
+dag_inject(pcap_t *p, const void *buf _U_, int size _U_)
 {
 	pcap_strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards",
 	    PCAP_ERRBUF_SIZE);
@@ -750,7 +749,7 @@
 	struct timeval poll;
 
 	if (device == NULL) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
 		return PCAP_ERROR;
 	}
 
@@ -780,7 +779,7 @@
 
 	if (pd->dag_stream%2) {
 		ret = PCAP_ERROR;
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture");
 		goto fail;
 	}
 
@@ -936,7 +935,7 @@
 				pd->dag_fcs_bits = n;
 			} else {
 				ret = PCAP_ERROR;
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 					"pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment", device, n);
 				goto failstop;
 			}
@@ -983,7 +982,7 @@
 
 	p->read_op = dag_read;
 	p->inject_op = dag_inject;
-	p->setfilter_op = dag_setfilter;
+	p->setfilter_op = install_bpf_program;
 	p->setdirection_op = NULL; /* Not implemented.*/
 	p->set_datalink_op = dag_set_datalink;
 	p->getnonblock_op = pcap_getnonblock_fd;
@@ -1072,7 +1071,7 @@
 	/* OK, it's probably ours. */
 	*is_ours = 1;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_dag));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_dag);
 	if (p == NULL)
 		return NULL;
 
@@ -1085,7 +1084,6 @@
 	 * XXX Our native precision is 2^-32s, but libpcap doesn't support
 	 * power of two precisions yet. We can convert to either MICRO or NANO.
 	 */
-	p->tstamp_precision_count = 2;
 	p->tstamp_precision_list = malloc(2 * sizeof(u_int));
 	if (p->tstamp_precision_list == NULL) {
 		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
@@ -1095,6 +1093,7 @@
 	}
 	p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
 	p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
+	p->tstamp_precision_count = 2;
 	return p;
 }
 
@@ -1115,10 +1114,10 @@
 		/* Note this counter is cleared at start of capture and will wrap at UINT_MAX.
 		 * The application is responsible for polling ps_drop frequently enough
 		 * to detect each wrap and integrate total drop with a wider counter */
-		if ((dag_error = dag_config_get_uint32_attribute_ex(pd->dag_ref, pd->drop_attr, &stream_drop) == kDagErrNone)) {
+		if ((dag_error = dag_config_get_uint32_attribute_ex(pd->dag_ref, pd->drop_attr, &stream_drop)) == kDagErrNone) {
 			pd->stat.ps_drop = stream_drop;
 		} else {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "reading stream drop attribute: %s",
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "reading stream drop attribute: %s",
 				 dag_config_strerror(dag_error));
 			return -1;
 		}
@@ -1146,10 +1145,10 @@
 
 	/* Try all the DAGs 0-DAG_MAX_BOARDS */
 	for (c = 0; c < DAG_MAX_BOARDS; c++) {
-		pcap_snprintf(name, 12, "dag%d", c);
+		snprintf(name, 12, "dag%d", c);
 		if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream))
 		{
-			(void) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			(void) snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "dag: device name %s can't be parsed", name);
 			return (-1);
 		}
@@ -1177,7 +1176,7 @@
 				if (0 == dag_attach_stream64(dagfd, stream, 0, 0)) {
 					dag_detach_stream(dagfd, stream);
 
-					pcap_snprintf(name,  10, "dag%d:%d", c, stream);
+					snprintf(name,  10, "dag%d:%d", c, stream);
 					if (add_dev(devlistp, name, 0, description, errbuf) == NULL) {
 						/*
 						 * Failure.
@@ -1198,30 +1197,6 @@
 	return (0);
 }
 
-/*
- * Installs the given bpf filter program in the given pcap structure.  There is
- * no attempt to store the filter in kernel memory as that is not supported
- * with DAG cards.
- */
-static int
-dag_setfilter(pcap_t *p, struct bpf_program *fp)
-{
-	if (!p)
-		return -1;
-	if (!fp) {
-		strncpy(p->errbuf, "setfilter: No filter specified",
-			sizeof(p->errbuf));
-		return -1;
-	}
-
-	/* Make our private copy of the filter */
-
-	if (install_bpf_program(p, fp) < 0)
-		return -1;
-
-	return (0);
-}
-
 static int
 dag_set_datalink(pcap_t *p, int dlt)
 {
@@ -1451,7 +1426,7 @@
 pcap_t *
 pcap_create_interface(const char *device, char *errbuf)
 {
-	pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(errbuf, PCAP_ERRBUF_SIZE,
 	    "This version of libpcap only supports DAG cards");
 	return NULL;
 }
diff --git a/pcap-dbus.c b/pcap-dbus.c
index 1252975..506f150 100644
--- a/pcap-dbus.c
+++ b/pcap-dbus.c
@@ -68,7 +68,7 @@
 	while (!message) {
 		/* XXX handle->opt.timeout = timeout_ms; */
 		if (!dbus_connection_read_write(handlep->conn, 100)) {
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed");
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed");
 			return -1;
 		}
 
@@ -81,7 +81,7 @@
 	}
 
 	if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected");
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected");
 		return -1;
 	}
 
@@ -91,7 +91,7 @@
 
 		gettimeofday(&pkth.ts, NULL);
 		if (handle->fcode.bf_insns == NULL ||
-		    bpf_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) {
+		    pcap_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) {
 			handlep->packets_read++;
 			callback(user, &pkth, (u_char *)raw_msg);
 			count++;
@@ -103,7 +103,7 @@
 }
 
 static int
-dbus_write(pcap_t *handle, const void *buf, size_t size)
+dbus_write(pcap_t *handle, const void *buf, int size)
 {
 	/* XXX, not tested */
 	struct pcap_dbus *handlep = handle->priv;
@@ -112,7 +112,7 @@
 	DBusMessage *msg;
 
 	if (!(msg = dbus_message_demarshal(buf, size, &error))) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message);
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message);
 		dbus_error_free(&error);
 		return -1;
 	}
@@ -154,7 +154,7 @@
 static int
 dbus_getnonblock(pcap_t *p)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Non-blocking mode isn't supported for capturing on D-Bus");
 	return (-1);
 }
@@ -162,7 +162,7 @@
 static int
 dbus_setnonblock(pcap_t *p, int nonblock _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Non-blocking mode isn't supported for capturing on D-Bus");
 	return (-1);
 }
@@ -189,14 +189,14 @@
 
 	if (strcmp(dev, "dbus-system") == 0) {
 		if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message);
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message);
 			dbus_error_free(&error);
 			return PCAP_ERROR;
 		}
 
 	} else if (strcmp(dev, "dbus-session") == 0) {
 		if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) {
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message);
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message);
 			dbus_error_free(&error);
 			return PCAP_ERROR;
 		}
@@ -205,19 +205,19 @@
 		const char *addr = dev + 7;
 
 		if (!(handlep->conn = dbus_connection_open(addr, &error))) {
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message);
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message);
 			dbus_error_free(&error);
 			return PCAP_ERROR;
 		}
 
 		if (!dbus_bus_register(handlep->conn, &error)) {
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message);
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message);
 			dbus_error_free(&error);
 			return PCAP_ERROR;
 		}
 
 	} else {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device);
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device);
 		return PCAP_ERROR;
 	}
 
@@ -289,7 +289,7 @@
 			/* try without eavesdrop */
 			dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error);
 			if (dbus_error_is_set(&error)) {
-				pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message);
+				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message);
 				dbus_error_free(&error);
 				dbus_cleanup(handle);
 				return PCAP_ERROR;
@@ -314,7 +314,7 @@
 	}
 
 	*is_ours = 1;
-	p = pcap_create_common(ebuf, sizeof (struct pcap_dbus));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_dbus);
 	if (p == NULL)
 		return (NULL);
 
diff --git a/pcap-dlpi.c b/pcap-dlpi.c
index 3ed8fa7..208a63b 100644
--- a/pcap-dlpi.c
+++ b/pcap-dlpi.c
@@ -96,7 +96,6 @@
 #include <net/if.h>
 #endif
 
-#include <ctype.h>
 #ifdef HAVE_HPUX9
 #include <nlist.h>
 #endif
@@ -108,12 +107,7 @@
 #include <string.h>
 #include <stropts.h>
 #include <unistd.h>
-
-#ifdef HAVE_LIMITS_H
 #include <limits.h>
-#else
-#define INT_MAX		2147483647
-#endif
 
 #include "pcap-int.h"
 #include "dlpisubs.h"
@@ -252,7 +246,7 @@
 }
 
 static int
-pcap_inject_dlpi(pcap_t *p, const void *buf, size_t size)
+pcap_inject_dlpi(pcap_t *p, const void *buf, int size)
 {
 #ifdef DL_HP_RAWDLS
 	struct pcap_dlpi *pd = p->priv;
@@ -268,7 +262,7 @@
 	}
 #elif defined(DL_HP_RAWDLS)
 	if (pd->send_fd < 0) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "send: Output FD couldn't be opened");
 		return (-1);
 	}
@@ -417,7 +411,7 @@
 	if (*name == '/')
 		pcap_strlcpy(dname, name, sizeof(dname));
 	else
-		pcap_snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
+		snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
 		    name);
 
 	/*
@@ -475,7 +469,7 @@
 				 * interface is just a symptom of that
 				 * inability.
 				 */
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "%s: No DLPI device found", name);
 			} else {
 				if (errno == EPERM || errno == EACCES)
@@ -639,7 +633,7 @@
 	**/
 	if (dlbindreq(p->fd, 0, p->errbuf) < 0 ||
 	    dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) {
-	    	status = PCAP_ERROR;
+		status = PCAP_ERROR;
 		goto bad;
 	}
 #endif /* AIX vs. HP-UX vs. other */
@@ -767,7 +761,7 @@
 	*/
 	if (dlinforeq(p->fd, p->errbuf) < 0 ||
 	    dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) {
-	    	status = PCAP_ERROR;
+		status = PCAP_ERROR;
 		goto bad;
 	}
 
@@ -805,7 +799,7 @@
 	get_release(release, sizeof (release), &osmajor, &osminor, &osmicro);
 	if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) &&
 	    getenv("BUFMOD_FIXED") == NULL) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		"WARNING: bufmod is broken in SunOS %s; ignoring snaplen.",
 		    release);
 		ss = 0;
@@ -880,7 +874,7 @@
 	 */
 	cp = device + strlen(device) - 1;
 	if (*cp < '0' || *cp > '9') {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
+		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
 		    device);
 		return (NULL);
 	}
@@ -892,16 +886,16 @@
 	errno = 0;
 	unit = strtol(cp, &eos, 10);
 	if (*eos != '\0') {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
+		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
 		return (NULL);
 	}
 	if (errno == ERANGE || unit > INT_MAX) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large",
+		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large",
 		    device);
 		return (NULL);
 	}
 	if (unit < 0) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative",
+		snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative",
 		    device);
 		return (NULL);
 	}
@@ -1115,7 +1109,7 @@
 		return (-1);
 	}
 	for (i = 0; i < buf.nunits; i++) {
-		pcap_snprintf(baname, sizeof baname, "ba%u", i);
+		snprintf(baname, sizeof baname, "ba%u", i);
 		/*
 		 * XXX - is there a notion of "up" and "running"?
 		 * And is there a way to determine whether the
@@ -1202,7 +1196,7 @@
 			break;
 
 		default:
-			pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
 			    "recv_ack: %s: %s", what,
 			    dlstrerror(errmsgbuf, sizeof (errmsgbuf), dlp->error_ack.dl_errno));
 			if (dlp->error_ack.dl_errno == DL_BADPPA)
@@ -1214,14 +1208,14 @@
 		return (PCAP_ERROR);
 
 	default:
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
 		    "recv_ack: %s: Unexpected primitive ack %s",
 		    what, dlprim(dlprimbuf, sizeof (dlprimbuf), dlp->dl_primitive));
 		return (PCAP_ERROR);
 	}
 
 	if (ctl.len < size) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
 		    "recv_ack: %s: Ack too small (%d < %d)",
 		    what, ctl.len, size);
 		return (PCAP_ERROR);
@@ -1332,7 +1326,7 @@
 		return ("Pending outstanding connect indications");
 
 	default:
-		pcap_snprintf(errbuf, errbufsize, "Error %02x", dl_errno);
+		snprintf(errbuf, errbufsize, "Error %02x", dl_errno);
 		return (errbuf);
 	}
 }
@@ -1424,7 +1418,7 @@
 		return ("DL_RESET_CON");
 
 	default:
-		pcap_snprintf(primbuf, primbufsize, "unknown primitive 0x%x",
+		snprintf(primbuf, primbufsize, "unknown primitive 0x%x",
 		    prim);
 		return (primbuf);
 	}
@@ -1551,7 +1545,7 @@
 		return;
 	}
 	cp = buf;
-	if (!isdigit((unsigned char)*cp))
+	if (!PCAP_ISDIGIT((unsigned char)*cp))
 		return;
 	*majorp = strtol(cp, &cp, 10);
 	if (*cp++ != '.')
@@ -1651,21 +1645,21 @@
 		return (PCAP_ERROR);
 	}
 	if (ctl.len == -1) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
 		    "get_dlpi_ppa: hpppa getmsg: control buffer has no data");
 		return (PCAP_ERROR);
 	}
 
 	dlp = (dl_hp_ppa_ack_t *)ctl.buf;
 	if (dlp->dl_primitive != DL_HP_PPA_ACK) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
 		    "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x",
 		    (bpf_u_int32)dlp->dl_primitive);
 		return (PCAP_ERROR);
 	}
 
 	if ((size_t)ctl.len < DL_HP_PPA_ACK_SIZE) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
 		    "get_dlpi_ppa: hpppa ack too small (%d < %lu)",
 		     ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE);
 		return (PCAP_ERROR);
@@ -1688,12 +1682,12 @@
 		return (PCAP_ERROR);
 	}
 	if (ctl.len == -1) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
 		    "get_dlpi_ppa: hpppa getmsg: control buffer has no data");
 		return (PCAP_ERROR);
 	}
 	if ((u_int)ctl.len < dlp->dl_length) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
 		    "get_dlpi_ppa: hpppa ack too small (%d < %lu)",
 		    ctl.len, (unsigned long)dlp->dl_length);
 		free(ppa_data_buf);
@@ -1750,7 +1744,7 @@
 		 * device number of a device with the name "/dev/<dev><unit>",
 		 * if such a device exists, as the old code did.
 		 */
-		pcap_snprintf(dname, sizeof(dname), "/dev/%s%u", device, unit);
+		snprintf(dname, sizeof(dname), "/dev/%s%u", device, unit);
 		if (stat(dname, &statbuf) < 0) {
 			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
 			    errno, "stat: %s", dname);
@@ -1769,12 +1763,12 @@
 		}
 	}
 	if (i == ap->dl_count) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
 		    "can't find /dev/dlpi PPA for %s%u", device, unit);
 		return (PCAP_ERROR_NO_SUCH_DEVICE);
 	}
 	if (ip->dl_hdw_state == HDW_DEAD) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
 		    "%s%d: hardware state: DOWN\n", device, unit);
 		free(ppa_data_buf);
 		return (PCAP_ERROR);
@@ -1813,13 +1807,13 @@
 	if (cp != NULL)
 		ifname = cp + 1;
 	if (nlist(path_vmunix, &nl) < 0) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
+		snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
 		    path_vmunix);
 		return (PCAP_ERROR);
 	}
 	if (nl[NL_IFNET].n_value == 0) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
-		    "could't find %s kernel symbol",
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
+		    "couldn't find %s kernel symbol",
 		    nl[NL_IFNET].n_name);
 		return (PCAP_ERROR);
 	}
@@ -1849,7 +1843,7 @@
 		}
 	}
 
-	pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
+	snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
 	return (PCAP_ERROR_NO_SUCH_DEVICE);
 }
 
@@ -1870,7 +1864,7 @@
 		    errno, "read");
 		return (-1);
 	} else if (cc != len) {
-		pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
+		snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
 		    len);
 		return (-1);
 	}
@@ -1886,7 +1880,7 @@
 	struct pcap_dlpi *pd;
 #endif
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_dlpi));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_dlpi);
 	if (p == NULL)
 		return (NULL);
 
diff --git a/pcap-dos.c b/pcap-dos.c
index c159b55..cdd60ea 100644
--- a/pcap-dos.c
+++ b/pcap-dos.c
@@ -153,7 +153,7 @@
 {
 	pcap_t *p;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_dos));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_dos);
 	if (p == NULL)
 		return (NULL);
 
@@ -215,7 +215,7 @@
   }
   else if (stricmp(active_dev->name,pcap->opt.device))
   {
-    pcap_snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
+    snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
                    "Cannot use different devices simultaneously "
                    "(`%s' vs. `%s')", active_dev->name, pcap->opt.device);
     /* XXX - free pcap->buffer? */
@@ -283,7 +283,7 @@
       pcap.len    = rx_len;
 
       if (callback &&
-          (!p->fcode.bf_insns || bpf_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen)))
+          (!p->fcode.bf_insns || pcap_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen)))
       {
         filter_count++;
 
@@ -539,7 +539,7 @@
        net = IN_CLASSC_NET;
     else
     {
-      pcap_snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask);
+      snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask);
       return (-1);
     }
   }
@@ -667,7 +667,7 @@
 
       if (!(*dev->probe)(dev))    /* call the xx_probe() function */
       {
-        pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name);
+        snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name);
         return (NULL);
       }
       probed_dev = dev;  /* device is probed okay and may be used */
@@ -689,7 +689,7 @@
 
     if (!(*dev->open)(dev))
     {
-      pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name);
+      snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name);
       if (pktInfo.error && !strncmp(dev->name,"pkt",3))
       {
         strcat (ebuf, ": ");
@@ -698,7 +698,7 @@
       return (NULL);
     }
 
-    /* Some devices need this to operate in promiscous mode
+    /* Some devices need this to operate in promiscuous mode
      */
     if (promisc && dev->set_multicast_list)
        (*dev->set_multicast_list) (dev);
@@ -711,14 +711,14 @@
    */
   if (!dev)
   {
-    pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name);
+    snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name);
     return (NULL);
   }
 
 not_probed:
   if (!probed_dev)
   {
-    pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name);
+    snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name);
     return (NULL);
   }
   return (dev);
@@ -943,7 +943,7 @@
 }
 
 /*
- * Supress PRINT message from Watt-32's sock_init()
+ * Suppress PRINT message from Watt-32's sock_init()
  */
 static void null_print (void) {}
 
@@ -1005,7 +1005,7 @@
   }
   else if (rc && using_pktdrv)
   {
-    pcap_snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc);
+    snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc);
     return (0);
   }
 
@@ -1031,11 +1031,9 @@
   pcap_save.linktype       = _eth_get_hwtype (NULL, NULL);
   pcap_save.snapshot       = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */
 
-#if 1
   /* prevent use of resolve() and resolve_ip()
    */
   last_nameserver = 0;
-#endif
   return (1);
 }
 
diff --git a/pcap-dpdk.c b/pcap-dpdk.c
new file mode 100644
index 0000000..765abe5
--- /dev/null
+++ b/pcap-dpdk.c
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (C) 2018 jingle YANG. 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.
+ *
+ * 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.
+ */
+
+/*
+Date: Dec 16, 2018
+
+Description:
+1. Pcap-dpdk provides libpcap the ability to use DPDK with the device name as dpdk:{portid}, such as dpdk:0.
+2. DPDK is a set of libraries and drivers for fast packet processing. (https://www.dpdk.org/)
+3. The testprogs/capturetest provides 6.4Gbps/800,000 pps on Intel 10-Gigabit X540-AT2 with DPDK 18.11.
+
+Limitations:
+1. DPDK support will be on if DPDK is available. Please set DIR for --with-dpdk[=DIR] with ./configure or -DDPDK_DIR[=DIR] with cmake if DPDK is installed manually.
+2. Only support link libdpdk.so dynamically, because the libdpdk.a will not work correctly.
+3. Only support read operation, and packet injection has not been supported yet.
+
+Usage:
+1. Compile DPDK as shared library and install.(https://github.com/DPDK/dpdk.git)
+
+You shall modify the file $RTE_SDK/$RTE_TARGET/.config and set:
+CONFIG_RTE_BUILD_SHARED_LIB=y
+By the following command:
+sed -i 's/CONFIG_RTE_BUILD_SHARED_LIB=n/CONFIG_RTE_BUILD_SHARED_LIB=y/' $RTE_SDK/$RTE_TARGET/.config
+
+2. Launch l2fwd that is one of DPDK examples correctly, and get device information.
+
+You shall learn how to bind nic with DPDK-compatible driver by $RTE_SDK/usertools/dpdk-devbind.py, such as igb_uio.
+And enable hugepages by dpdk-setup.sh
+
+Then launch the l2fwd with dynamic dirver support. For example:
+$RTE_SDK/examples/l2fwd/$RTE_TARGET/l2fwd -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so -- -p 0x1
+
+3. Compile libpcap with dpdk options.
+
+If DPDK has not been found automatically, you shall export DPDK environment variable which are used for compiling DPDK. And then pass $RTE_SDK/$RTE_TARGET to --with-dpdk or -DDPDK_DIR
+
+export RTE_SDK={your DPDK base directory}
+export RTE_TARGET={your target name}
+
+3.1 With configure
+
+./configure --with-dpdk=$RTE_SDK/$RTE_TARGET && make -s all && make -s testprogs && make install
+
+3.2 With cmake
+
+mkdir -p build && cd build && cmake -DDPDK_DIR=$RTE_SDK/$RTE_TARGET ../ && make -s all && make -s testprogs && make install
+
+4. Link your own program with libpcap, and use DPDK with the device name as dpdk:{portid}, such as dpdk:0.
+And you shall set DPDK configure options by environment variable DPDK_CFG
+For example, the testprogs/capturetest could be lanched by:
+
+env DPDK_CFG="--log-level=debug -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so" ./capturetest -i dpdk:0
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/time.h>
+
+//header for calling dpdk
+#include <rte_config.h>
+#include <rte_common.h>
+#include <rte_errno.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_eal.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_bus.h>
+
+#include "pcap-int.h"
+#include "pcap-dpdk.h"
+
+/*
+ * Deal with API changes that break source compatibility.
+ */
+
+#ifdef HAVE_STRUCT_RTE_ETHER_ADDR
+#define ETHER_ADDR_TYPE	struct rte_ether_addr
+#else
+#define ETHER_ADDR_TYPE	struct ether_addr
+#endif
+
+#define DPDK_DEF_LOG_LEV RTE_LOG_ERR
+//
+// This is set to 0 if we haven't initialized DPDK yet, 1 if we've
+// successfully initialized it, a negative value, which is the negative
+// of the rte_errno from rte_eal_init(), if we tried to initialize it
+// and got an error.
+//
+static int is_dpdk_pre_inited=0;
+#define DPDK_LIB_NAME "libpcap_dpdk"
+#define DPDK_DESC "Data Plane Development Kit (DPDK) Interface"
+#define DPDK_ERR_PERM_MSG "permission denied, DPDK needs root permission"
+#define DPDK_ARGC_MAX 64
+#define DPDK_CFG_MAX_LEN 1024
+#define DPDK_DEV_NAME_MAX 32
+#define DPDK_DEV_DESC_MAX 512
+#define DPDK_CFG_ENV_NAME "DPDK_CFG"
+#define DPDK_DEF_MIN_SLEEP_MS 1
+static char dpdk_cfg_buf[DPDK_CFG_MAX_LEN];
+#define DPDK_MAC_ADDR_SIZE 32
+#define DPDK_DEF_MAC_ADDR "00:00:00:00:00:00"
+#define DPDK_PCI_ADDR_SIZE 16
+#define DPDK_DEF_CFG "--log-level=error -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so"
+#define DPDK_PREFIX "dpdk:"
+#define DPDK_PORTID_MAX 65535U
+#define MBUF_POOL_NAME "mbuf_pool"
+#define DPDK_TX_BUF_NAME "tx_buffer"
+//The number of elements in the mbuf pool.
+#define DPDK_NB_MBUFS 8192U
+#define MEMPOOL_CACHE_SIZE 256
+#define MAX_PKT_BURST 32
+// Configurable number of RX/TX ring descriptors
+#define RTE_TEST_RX_DESC_DEFAULT 1024
+#define RTE_TEST_TX_DESC_DEFAULT 1024
+
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+#ifdef RTE_ETHER_MAX_JUMBO_FRAME_LEN
+#define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
+#else
+#define RTE_ETH_PCAP_SNAPLEN ETHER_MAX_JUMBO_FRAME_LEN
+#endif
+
+static struct rte_eth_dev_tx_buffer *tx_buffer;
+
+struct dpdk_ts_helper{
+	struct timeval start_time;
+	uint64_t start_cycles;
+	uint64_t hz;
+};
+struct pcap_dpdk{
+	pcap_t * orig;
+	uint16_t portid; // portid of DPDK
+	int must_clear_promisc;
+	uint64_t bpf_drop;
+	int nonblock;
+	struct timeval required_select_timeout;
+	struct timeval prev_ts;
+	struct rte_eth_stats prev_stats;
+	struct timeval curr_ts;
+	struct rte_eth_stats curr_stats;
+	uint64_t pps;
+	uint64_t bps;
+	struct rte_mempool * pktmbuf_pool;
+	struct dpdk_ts_helper ts_helper;
+	ETHER_ADDR_TYPE eth_addr;
+	char mac_addr[DPDK_MAC_ADDR_SIZE];
+	char pci_addr[DPDK_PCI_ADDR_SIZE];
+	unsigned char pcap_tmp_buf[RTE_ETH_PCAP_SNAPLEN];
+};
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static void	dpdk_fmt_errmsg_for_rte_errno(char *, size_t, int,
+    PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5);
+
+/*
+ * Generate an error message based on a format, arguments, and an
+ * rte_errno, with a message for the rte_errno after the formatted output.
+ */
+static void dpdk_fmt_errmsg_for_rte_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';
+	msglen += 2;
+	errbuflen_remaining -= 2;
+
+	/*
+	 * Now append the string for the error code.
+	 * rte_strerror() is thread-safe, at least as of dpdk 18.11,
+	 * unlike strerror() - it uses strerror_r() rather than strerror()
+	 * for UN*X errno values, and prints to what I assume is a per-thread
+	 * buffer (based on the "PER_LCORE" in "RTE_DEFINE_PER_LCORE" used
+	 * to declare the buffers statically) for DPDK errors.
+	 */
+	snprintf(p, errbuflen_remaining, "%s", rte_strerror(errnum));
+}
+
+static int dpdk_init_timer(struct pcap_dpdk *pd){
+	gettimeofday(&(pd->ts_helper.start_time),NULL);
+	pd->ts_helper.start_cycles = rte_get_timer_cycles();
+	pd->ts_helper.hz = rte_get_timer_hz();
+	if (pd->ts_helper.hz == 0){
+		return -1;
+	}
+	return 0;
+}
+static inline void calculate_timestamp(struct dpdk_ts_helper *helper,struct timeval *ts)
+{
+	uint64_t cycles;
+	// delta
+	struct timeval cur_time;
+	cycles = rte_get_timer_cycles() - helper->start_cycles;
+	cur_time.tv_sec = (time_t)(cycles/helper->hz);
+	cur_time.tv_usec = (suseconds_t)((cycles%helper->hz)*1e6/helper->hz);
+	timeradd(&(helper->start_time), &cur_time, ts);
+}
+
+static uint32_t dpdk_gather_data(unsigned char *data, uint32_t len, struct rte_mbuf *mbuf)
+{
+	uint32_t total_len = 0;
+	while (mbuf && (total_len+mbuf->data_len) < len ){
+		rte_memcpy(data+total_len, rte_pktmbuf_mtod(mbuf,void *),mbuf->data_len);
+		total_len+=mbuf->data_len;
+		mbuf=mbuf->next;
+	}
+	return total_len;
+}
+
+
+static int dpdk_read_with_timeout(pcap_t *p, struct rte_mbuf **pkts_burst, const uint16_t burst_cnt){
+	struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
+	int nb_rx = 0;
+	int timeout_ms = p->opt.timeout;
+	int sleep_ms = 0;
+	if (pd->nonblock){
+		// In non-blocking mode, just read once, no matter how many packets are captured.
+		nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt);
+	}else{
+		// In blocking mode, read many times until packets are captured or timeout or break_loop is set.
+		// if timeout_ms == 0, it may be blocked forever.
+		while (timeout_ms == 0 || sleep_ms < timeout_ms){
+			nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt);
+			if (nb_rx){ // got packets within timeout_ms
+				break;
+			}else{ // no packet arrives at this round.
+				if (p->break_loop){
+					break;
+				}
+				// sleep for a very short while.
+				// block sleep is the only choice, since usleep() will impact performance dramatically.
+				rte_delay_us_block(DPDK_DEF_MIN_SLEEP_MS*1000);
+				sleep_ms += DPDK_DEF_MIN_SLEEP_MS;
+			}
+		}
+	}
+	return nb_rx;
+}
+
+static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *cb_arg)
+{
+	struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
+	int burst_cnt = 0;
+	int nb_rx = 0;
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	struct pcap_pkthdr pcap_header;
+	// In DPDK, pkt_len is sum of lengths for all segments. And data_len is for one segment
+	uint32_t pkt_len = 0;
+	uint32_t caplen = 0;
+	u_char *bp = NULL;
+	int i=0;
+	unsigned int gather_len =0;
+	int pkt_cnt = 0;
+	u_char *large_buffer=NULL;
+	int timeout_ms = p->opt.timeout;
+
+	if ( !PACKET_COUNT_IS_UNLIMITED(max_cnt) && max_cnt < MAX_PKT_BURST){
+		burst_cnt = max_cnt;
+	}else{
+		burst_cnt = MAX_PKT_BURST;
+	}
+
+	while( PACKET_COUNT_IS_UNLIMITED(max_cnt) || pkt_cnt < max_cnt){
+		if (p->break_loop){
+			p->break_loop = 0;
+			return PCAP_ERROR_BREAK;
+		}
+		// read once in non-blocking mode, or try many times waiting for timeout_ms.
+		// if timeout_ms == 0, it will be blocked until one packet arrives or break_loop is set.
+		nb_rx = dpdk_read_with_timeout(p, pkts_burst, burst_cnt);
+		if (nb_rx == 0){
+			if (pd->nonblock){
+				RTE_LOG(DEBUG, USER1, "dpdk: no packets available in non-blocking mode.\n");
+			}else{
+				if (p->break_loop){
+					RTE_LOG(DEBUG, USER1, "dpdk: no packets available and break_loop is set in blocking mode.\n");
+					p->break_loop = 0;
+					return PCAP_ERROR_BREAK;
+
+				}
+				RTE_LOG(DEBUG, USER1, "dpdk: no packets available for timeout %d ms in blocking mode.\n", timeout_ms);
+			}
+			// break if dpdk reads 0 packet, no matter in blocking(timeout) or non-blocking mode.
+			break;
+		}
+		pkt_cnt += nb_rx;
+		for ( i = 0; i < nb_rx; i++) {
+			m = pkts_burst[i];
+			calculate_timestamp(&(pd->ts_helper),&(pcap_header.ts));
+			pkt_len = rte_pktmbuf_pkt_len(m);
+			// caplen = min(pkt_len, p->snapshot);
+			// caplen will not be changed, no matter how long the rte_pktmbuf
+			caplen = pkt_len < (uint32_t)p->snapshot ? pkt_len: (uint32_t)p->snapshot;
+			pcap_header.caplen = caplen;
+			pcap_header.len = pkt_len;
+			// volatile prefetch
+			rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+			bp = NULL;
+			if (m->nb_segs == 1)
+			{
+				bp = rte_pktmbuf_mtod(m, u_char *);
+			}else{
+				// use fast buffer pcap_tmp_buf if pkt_len is small, no need to call malloc and free
+				if ( pkt_len <= RTE_ETH_PCAP_SNAPLEN)
+				{
+					gather_len = dpdk_gather_data(pd->pcap_tmp_buf, RTE_ETH_PCAP_SNAPLEN, m);
+					bp = pd->pcap_tmp_buf;
+				}else{
+					// need call free later
+					large_buffer = (u_char *)malloc(caplen*sizeof(u_char));
+					gather_len = dpdk_gather_data(large_buffer, caplen, m);
+					bp = large_buffer;
+				}
+
+			}
+			if (bp){
+				if (p->fcode.bf_insns==NULL || pcap_filter(p->fcode.bf_insns, bp, pcap_header.len, pcap_header.caplen)){
+					cb(cb_arg, &pcap_header, bp);
+				}else{
+					pd->bpf_drop++;
+				}
+			}
+			//free all pktmbuf
+			rte_pktmbuf_free(m);
+			if (large_buffer){
+				free(large_buffer);
+				large_buffer=NULL;
+			}
+		}
+	}
+	return pkt_cnt;
+}
+
+static int pcap_dpdk_inject(pcap_t *p, const void *buf _U_, int size _U_)
+{
+	//not implemented yet
+	pcap_strlcpy(p->errbuf,
+	    "dpdk error: Inject function has not been implemented yet",
+	    PCAP_ERRBUF_SIZE);
+	return PCAP_ERROR;
+}
+
+static void pcap_dpdk_close(pcap_t *p)
+{
+	struct pcap_dpdk *pd = p->priv;
+	if (pd==NULL)
+	{
+		return;
+	}
+	if (pd->must_clear_promisc)
+	{
+		rte_eth_promiscuous_disable(pd->portid);
+	}
+	rte_eth_dev_stop(pd->portid);
+	rte_eth_dev_close(pd->portid);
+	pcap_cleanup_live_common(p);
+}
+
+static void nic_stats_display(struct pcap_dpdk *pd)
+{
+	uint16_t portid = pd->portid;
+	struct rte_eth_stats stats;
+	rte_eth_stats_get(portid, &stats);
+	RTE_LOG(INFO,USER1, "portid:%d, RX-packets: %-10"PRIu64"  RX-errors:  %-10"PRIu64
+	       "  RX-bytes:  %-10"PRIu64"  RX-Imissed:  %-10"PRIu64"\n", portid, stats.ipackets, stats.ierrors,
+	       stats.ibytes,stats.imissed);
+	RTE_LOG(INFO,USER1, "portid:%d, RX-PPS: %-10"PRIu64" RX-Mbps: %.2lf\n", portid, pd->pps, pd->bps/1e6f );
+}
+
+static int pcap_dpdk_stats(pcap_t *p, struct pcap_stat *ps)
+{
+	struct pcap_dpdk *pd = p->priv;
+	calculate_timestamp(&(pd->ts_helper), &(pd->curr_ts));
+	rte_eth_stats_get(pd->portid,&(pd->curr_stats));
+	if (ps){
+		ps->ps_recv = pd->curr_stats.ipackets;
+		ps->ps_drop = pd->curr_stats.ierrors;
+		ps->ps_drop += pd->bpf_drop;
+		ps->ps_ifdrop = pd->curr_stats.imissed;
+	}
+	uint64_t delta_pkt = pd->curr_stats.ipackets - pd->prev_stats.ipackets;
+	struct timeval delta_tm;
+	timersub(&(pd->curr_ts),&(pd->prev_ts), &delta_tm);
+	uint64_t delta_usec = delta_tm.tv_sec*1e6+delta_tm.tv_usec;
+	uint64_t delta_bit = (pd->curr_stats.ibytes-pd->prev_stats.ibytes)*8;
+	RTE_LOG(DEBUG, USER1, "delta_usec: %-10"PRIu64" delta_pkt: %-10"PRIu64" delta_bit: %-10"PRIu64"\n", delta_usec, delta_pkt, delta_bit);
+	pd->pps = (uint64_t)(delta_pkt*1e6f/delta_usec);
+	pd->bps = (uint64_t)(delta_bit*1e6f/delta_usec);
+	nic_stats_display(pd);
+	pd->prev_stats = pd->curr_stats;
+	pd->prev_ts = pd->curr_ts;
+	return 0;
+}
+
+static int pcap_dpdk_setnonblock(pcap_t *p, int nonblock){
+	struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
+	pd->nonblock = nonblock;
+	return 0;
+}
+
+static int pcap_dpdk_getnonblock(pcap_t *p){
+	struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
+	return pd->nonblock;
+}
+static int check_link_status(uint16_t portid, struct rte_eth_link *plink)
+{
+	// wait up to 9 seconds to get link status
+	rte_eth_link_get(portid, plink);
+	return plink->link_status == ETH_LINK_UP;
+}
+static void eth_addr_str(ETHER_ADDR_TYPE *addrp, char* mac_str, int len)
+{
+	int offset=0;
+	if (addrp == NULL){
+		snprintf(mac_str, len-1, DPDK_DEF_MAC_ADDR);
+		return;
+	}
+	for (int i=0; i<6; i++)
+	{
+		if (offset >= len)
+		{ // buffer overflow
+			return;
+		}
+		if (i==0)
+		{
+			snprintf(mac_str+offset, len-1-offset, "%02X",addrp->addr_bytes[i]);
+			offset+=2; // FF
+		}else{
+			snprintf(mac_str+offset, len-1-offset, ":%02X", addrp->addr_bytes[i]);
+			offset+=3; // :FF
+		}
+	}
+	return;
+}
+// return portid by device name, otherwise return -1
+static uint16_t portid_by_device(char * device)
+{
+	uint16_t ret = DPDK_PORTID_MAX;
+	int len = strlen(device);
+	int prefix_len = strlen(DPDK_PREFIX);
+	unsigned long ret_ul = 0L;
+	char *pEnd;
+	if (len<=prefix_len || strncmp(device, DPDK_PREFIX, prefix_len)) // check prefix dpdk:
+	{
+		return ret;
+	}
+	//check all chars are digital
+	for (int i=prefix_len; device[i]; i++){
+		if (device[i]<'0' || device[i]>'9'){
+			return ret;
+		}
+	}
+	ret_ul = strtoul(&(device[prefix_len]), &pEnd, 10);
+	if (pEnd == &(device[prefix_len]) || *pEnd != '\0'){
+		return ret;
+	}
+	// too large for portid
+	if (ret_ul >= DPDK_PORTID_MAX){
+		return ret;
+	}
+	ret = (uint16_t)ret_ul;
+	return ret;
+}
+
+static int parse_dpdk_cfg(char* dpdk_cfg,char** dargv)
+{
+	int cnt=0;
+	memset(dargv,0,sizeof(dargv[0])*DPDK_ARGC_MAX);
+	//current process name
+	int skip_space = 1;
+	int i=0;
+	RTE_LOG(INFO, USER1,"dpdk cfg: %s\n",dpdk_cfg);
+	// find first non space char
+	// The last opt is NULL
+	for (i=0;dpdk_cfg[i] && cnt<DPDK_ARGC_MAX-1;i++){
+		if (skip_space && dpdk_cfg[i]!=' '){ // not space
+			skip_space=!skip_space; // skip normal char
+			dargv[cnt++] = dpdk_cfg+i;
+		}
+		if (!skip_space && dpdk_cfg[i]==' '){ // fint a space
+			dpdk_cfg[i]=0x00; // end of this opt
+			skip_space=!skip_space; // skip space char
+		}
+	}
+	dargv[cnt]=NULL;
+	return cnt;
+}
+
+// only called once
+// Returns:
+//
+//    1 on success;
+//
+//    0 if "the EAL cannot initialize on this system", which we treat as
+//    meaning "DPDK isn't available";
+//
+//    a PCAP_ERROR_ code for other errors.
+//
+// If eaccess_not_fatal is non-zero, treat "a permissions issue" the way
+// we treat "the EAL cannot initialize on this system".  We use that
+// when trying to find DPDK devices, as we don't want to fail to return
+// *any* devices just because we can't support DPDK; when we're trying
+// to open a device, we need to return a permissions error in that case.
+static int dpdk_pre_init(char * ebuf, int eaccess_not_fatal)
+{
+	int dargv_cnt=0;
+	char *dargv[DPDK_ARGC_MAX];
+	char *ptr_dpdk_cfg = NULL;
+	int ret;
+	// globale var
+	if (is_dpdk_pre_inited != 0)
+	{
+		// already inited; did that succeed?
+		if (is_dpdk_pre_inited < 0)
+		{
+			// failed
+			goto error;
+		}
+		else
+		{
+			// succeeded
+			return 1;
+		}
+	}
+	// init EAL
+	ptr_dpdk_cfg = getenv(DPDK_CFG_ENV_NAME);
+	// set default log level to debug
+	rte_log_set_global_level(DPDK_DEF_LOG_LEV);
+	if (ptr_dpdk_cfg == NULL)
+	{
+		RTE_LOG(INFO,USER1,"env $DPDK_CFG is unset, so using default: %s\n",DPDK_DEF_CFG);
+		ptr_dpdk_cfg = DPDK_DEF_CFG;
+	}
+	memset(dpdk_cfg_buf,0,sizeof(dpdk_cfg_buf));
+	snprintf(dpdk_cfg_buf,DPDK_CFG_MAX_LEN-1,"%s %s",DPDK_LIB_NAME,ptr_dpdk_cfg);
+	dargv_cnt = parse_dpdk_cfg(dpdk_cfg_buf,dargv);
+	ret = rte_eal_init(dargv_cnt,dargv);
+	if (ret == -1)
+	{
+		// Indicate that we've called rte_eal_init() by setting
+		// is_dpdk_pre_inited to the negative of the error code,
+		// and process the error.
+		is_dpdk_pre_inited = -rte_errno;
+		goto error;
+	}
+	// init succeeded, so we do not need to do it again later.
+	is_dpdk_pre_inited = 1;
+	return 1;
+
+error:
+	switch (-is_dpdk_pre_inited)
+	{
+		case EACCES:
+			// This "indicates a permissions issue.".
+			RTE_LOG(ERR, USER1, "%s\n", DPDK_ERR_PERM_MSG);
+			// If we were told to treat this as just meaning
+			// DPDK isn't available, do so.
+			if (eaccess_not_fatal)
+				return 0;
+			// Otherwise report a fatal error.
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			    "DPDK requires that it run as root");
+			return PCAP_ERROR_PERM_DENIED;
+
+		case EAGAIN:
+			// This "indicates either a bus or system
+			// resource was not available, setup may
+			// be attempted again."
+			// There's no such error in pcap, so I'm
+			// not sure what we should do here.
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			    "Bus or system resource was not available");
+			break;
+
+		case EALREADY:
+			// This "indicates that the rte_eal_init
+			// function has already been called, and
+			// cannot be called again."
+			// That's not an error; set the "we've
+			// been here before" flag and return
+			// success.
+			is_dpdk_pre_inited = 1;
+			return 1;
+
+		case EFAULT:
+			// This "indicates the tailq configuration
+			// name was not found in memory configuration."
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			    "The tailq configuration name was not found in the memory configuration");
+			return PCAP_ERROR;
+
+		case EINVAL:
+			// This "indicates invalid parameters were
+			// passed as argv/argc."  Those came from
+			// the configuration file.
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			    "The configuration file has invalid parameters");
+			break;
+
+		case ENOMEM:
+			// This "indicates failure likely caused by
+			// an out-of-memory condition."
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			    "Out of memory");
+			break;
+
+		case ENODEV:
+			// This "indicates memory setup issues."
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			    "An error occurred setting up memory");
+			break;
+
+		case ENOTSUP:
+			// This "indicates that the EAL cannot
+			// initialize on this system."  We treat
+			// that as meaning DPDK isn't available
+			// on this machine, rather than as a
+			// fatal error, and let our caller decide
+			// whether that's a fatal error (if trying
+			// to activate a DPDK device) or not (if
+			// trying to enumerate devices).
+			return 0;
+
+		case EPROTO:
+			// This "indicates that the PCI bus is
+			// either not present, or is not readable
+			// by the eal."  Does "the PCI bus is not
+			// present" mean "this machine has no PCI
+			// bus", which strikes me as a "not available"
+			// case?  If so, should "is not readable by
+			// the EAL" also something we should treat
+			// as a "not available" case?  If not, we
+			// can't distinguish between the two, so
+			// we're stuck.
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			    "PCI bus is not present or not readable by the EAL");
+			break;
+
+		case ENOEXEC:
+			// This "indicates that a service core
+			// failed to launch successfully."
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			    "A service core failed to launch successfully");
+			break;
+
+		default:
+			//
+			// That's not in the list of errors in
+			// the documentation; let it be reported
+			// as an error.
+			//
+			dpdk_fmt_errmsg_for_rte_errno(ebuf,
+			    PCAP_ERRBUF_SIZE, -is_dpdk_pre_inited,
+			    "dpdk error: dpdk_pre_init failed");
+			break;
+	}
+	// Error.
+	return PCAP_ERROR;
+}
+
+static int pcap_dpdk_activate(pcap_t *p)
+{
+	struct pcap_dpdk *pd = p->priv;
+	pd->orig = p;
+	int ret = PCAP_ERROR;
+	uint16_t nb_ports=0;
+	uint16_t portid= DPDK_PORTID_MAX;
+	unsigned nb_mbufs = DPDK_NB_MBUFS;
+	struct rte_eth_rxconf rxq_conf;
+	struct rte_eth_txconf txq_conf;
+	struct rte_eth_conf local_port_conf = port_conf;
+	struct rte_eth_dev_info dev_info;
+	int is_port_up = 0;
+	struct rte_eth_link link;
+	do{
+		//init EAL; fail if we have insufficient permission
+		char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE];
+		ret = dpdk_pre_init(dpdk_pre_init_errbuf, 0);
+		if (ret < 0)
+		{
+			// This returns a negative value on an error.
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "Can't open device %s: %s",
+			    p->opt.device, dpdk_pre_init_errbuf);
+			// ret is set to the correct error
+			break;
+		}
+		if (ret == 0)
+		{
+			// This means DPDK isn't available on this machine.
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "Can't open device %s: DPDK is not available on this machine",
+			    p->opt.device);
+			return PCAP_ERROR_NO_SUCH_DEVICE;
+		}
+
+		ret = dpdk_init_timer(pd);
+		if (ret<0)
+		{
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				"dpdk error: Init timer is zero with device %s",
+				p->opt.device);
+			ret = PCAP_ERROR;
+			break;
+		}
+
+		nb_ports = rte_eth_dev_count_avail();
+		if (nb_ports == 0)
+		{
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "dpdk error: No Ethernet ports");
+			ret = PCAP_ERROR;
+			break;
+		}
+
+		portid = portid_by_device(p->opt.device);
+		if (portid == DPDK_PORTID_MAX){
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "dpdk error: portid is invalid. device %s",
+			    p->opt.device);
+			ret = PCAP_ERROR_NO_SUCH_DEVICE;
+			break;
+		}
+
+		pd->portid = portid;
+
+		if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
+		{
+			p->snapshot = MAXIMUM_SNAPLEN;
+		}
+		// create the mbuf pool
+		pd->pktmbuf_pool = rte_pktmbuf_pool_create(MBUF_POOL_NAME, nb_mbufs,
+			MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
+			rte_socket_id());
+		if (pd->pktmbuf_pool == NULL)
+		{
+			dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+			    PCAP_ERRBUF_SIZE, rte_errno,
+			    "dpdk error: Cannot init mbuf pool");
+			ret = PCAP_ERROR;
+			break;
+		}
+		// config dev
+		rte_eth_dev_info_get(portid, &dev_info);
+		if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
+		{
+			local_port_conf.txmode.offloads |=DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+		}
+		// only support 1 queue
+		ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
+		if (ret < 0)
+		{
+			dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+			    PCAP_ERRBUF_SIZE, -ret,
+			    "dpdk error: Cannot configure device: port=%u",
+			    portid);
+			ret = PCAP_ERROR;
+			break;
+		}
+		// adjust rx tx
+		ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, &nb_txd);
+		if (ret < 0)
+		{
+			dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+			    PCAP_ERRBUF_SIZE, -ret,
+			    "dpdk error: Cannot adjust number of descriptors: port=%u",
+			    portid);
+			ret = PCAP_ERROR;
+			break;
+		}
+		// get MAC addr
+		rte_eth_macaddr_get(portid, &(pd->eth_addr));
+		eth_addr_str(&(pd->eth_addr), pd->mac_addr, DPDK_MAC_ADDR_SIZE-1);
+
+		// init one RX queue
+		rxq_conf = dev_info.default_rxconf;
+		rxq_conf.offloads = local_port_conf.rxmode.offloads;
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					     rte_eth_dev_socket_id(portid),
+					     &rxq_conf,
+					     pd->pktmbuf_pool);
+		if (ret < 0)
+		{
+			dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+			    PCAP_ERRBUF_SIZE, -ret,
+			    "dpdk error: rte_eth_rx_queue_setup:port=%u",
+			    portid);
+			ret = PCAP_ERROR;
+			break;
+		}
+
+		// init one TX queue
+		txq_conf = dev_info.default_txconf;
+		txq_conf.offloads = local_port_conf.txmode.offloads;
+		ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				&txq_conf);
+		if (ret < 0)
+		{
+			dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+			    PCAP_ERRBUF_SIZE, -ret,
+			    "dpdk error: rte_eth_tx_queue_setup:port=%u",
+			    portid);
+			ret = PCAP_ERROR;
+			break;
+		}
+		// Initialize TX buffers
+		tx_buffer = rte_zmalloc_socket(DPDK_TX_BUF_NAME,
+				RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
+				rte_eth_dev_socket_id(portid));
+		if (tx_buffer == NULL)
+		{
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "dpdk error: Cannot allocate buffer for tx on port %u", portid);
+			ret = PCAP_ERROR;
+			break;
+		}
+		rte_eth_tx_buffer_init(tx_buffer, MAX_PKT_BURST);
+		// Start device
+		ret = rte_eth_dev_start(portid);
+		if (ret < 0)
+		{
+			dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+			    PCAP_ERRBUF_SIZE, -ret,
+			    "dpdk error: rte_eth_dev_start:port=%u",
+			    portid);
+			ret = PCAP_ERROR;
+			break;
+		}
+		// set promiscuous mode
+		if (p->opt.promisc){
+			pd->must_clear_promisc=1;
+			rte_eth_promiscuous_enable(portid);
+		}
+		// check link status
+		is_port_up = check_link_status(portid, &link);
+		if (!is_port_up){
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			    "dpdk error: link is down, port=%u",portid);
+			ret = PCAP_ERROR_IFACE_NOT_UP;
+			break;
+		}
+		// reset statistics
+		rte_eth_stats_reset(pd->portid);
+		calculate_timestamp(&(pd->ts_helper), &(pd->prev_ts));
+		rte_eth_stats_get(pd->portid,&(pd->prev_stats));
+		// format pcap_t
+		pd->portid = portid;
+		p->fd = pd->portid;
+		if (p->snapshot <=0 || p->snapshot> MAXIMUM_SNAPLEN)
+		{
+			p->snapshot = MAXIMUM_SNAPLEN;
+		}
+		p->linktype = DLT_EN10MB; // Ethernet, the 10MB is historical.
+		p->selectable_fd = p->fd;
+		p->read_op = pcap_dpdk_dispatch;
+		p->inject_op = pcap_dpdk_inject;
+		// using pcap_filter currently, though DPDK provides their own BPF function. Because DPDK BPF needs load a ELF file as a filter.
+		p->setfilter_op = install_bpf_program;
+		p->setdirection_op = NULL;
+		p->set_datalink_op = NULL;
+		p->getnonblock_op = pcap_dpdk_getnonblock;
+		p->setnonblock_op = pcap_dpdk_setnonblock;
+		p->stats_op = pcap_dpdk_stats;
+		p->cleanup_op = pcap_dpdk_close;
+		p->breakloop_op = pcap_breakloop_common;
+		// set default timeout
+		pd->required_select_timeout.tv_sec = 0;
+		pd->required_select_timeout.tv_usec = DPDK_DEF_MIN_SLEEP_MS*1000;
+		p->required_select_timeout = &pd->required_select_timeout;
+		ret = 0; // OK
+	}while(0);
+
+	if (ret <= PCAP_ERROR) // all kinds of error code
+	{
+		pcap_cleanup_live_common(p);
+	}else{
+		rte_eth_dev_get_name_by_port(portid,pd->pci_addr);
+		RTE_LOG(INFO, USER1,"Port %d device: %s, MAC:%s, PCI:%s\n", portid, p->opt.device, pd->mac_addr, pd->pci_addr);
+		RTE_LOG(INFO, USER1,"Port %d Link Up. Speed %u Mbps - %s\n",
+							portid, link.link_speed,
+					(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") : ("half-duplex\n"));
+	}
+	return ret;
+}
+
+// device name for dpdk should be in the form as dpdk:number, such as dpdk:0
+pcap_t * pcap_dpdk_create(const char *device, char *ebuf, int *is_ours)
+{
+	pcap_t *p=NULL;
+	*is_ours = 0;
+
+	*is_ours = !strncmp(device, "dpdk:", 5);
+	if (! *is_ours)
+		return NULL;
+	//memset will happen
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_dpdk);
+
+	if (p == NULL)
+		return NULL;
+	p->activate_op = pcap_dpdk_activate;
+	return p;
+}
+
+int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *ebuf)
+{
+	int ret=0;
+	unsigned int nb_ports = 0;
+	char dpdk_name[DPDK_DEV_NAME_MAX];
+	char dpdk_desc[DPDK_DEV_DESC_MAX];
+	ETHER_ADDR_TYPE eth_addr;
+	char mac_addr[DPDK_MAC_ADDR_SIZE];
+	char pci_addr[DPDK_PCI_ADDR_SIZE];
+	do{
+		// init EAL; return "DPDK not available" if we
+		// have insufficient permission
+		char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE];
+		ret = dpdk_pre_init(dpdk_pre_init_errbuf, 1);
+		if (ret < 0)
+		{
+			// This returns a negative value on an error.
+			snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			    "Can't look for DPDK devices: %s",
+			    dpdk_pre_init_errbuf);
+			ret = PCAP_ERROR;
+			break;
+		}
+		if (ret == 0)
+		{
+			// This means DPDK isn't available on this machine.
+			// That just means "don't return any devices".
+			break;
+		}
+		nb_ports = rte_eth_dev_count_avail();
+		if (nb_ports == 0)
+		{
+			// That just means "don't return any devices".
+			ret = 0;
+			break;
+		}
+		for (unsigned int i=0; i<nb_ports; i++){
+			snprintf(dpdk_name, DPDK_DEV_NAME_MAX-1,
+			    "%s%u", DPDK_PREFIX, i);
+			// mac addr
+			rte_eth_macaddr_get(i, &eth_addr);
+			eth_addr_str(&eth_addr,mac_addr,DPDK_MAC_ADDR_SIZE);
+			// PCI addr
+			rte_eth_dev_get_name_by_port(i,pci_addr);
+			snprintf(dpdk_desc,DPDK_DEV_DESC_MAX-1,"%s %s, MAC:%s, PCI:%s", DPDK_DESC, dpdk_name, mac_addr, pci_addr);
+			if (add_dev(devlistp, dpdk_name, 0, dpdk_desc, ebuf)==NULL){
+				ret = PCAP_ERROR;
+				break;
+			}
+		}
+	}while(0);
+	return ret;
+}
+
+#ifdef DPDK_ONLY
+/*
+ * This libpcap build supports only DPDK, not regular network interfaces.
+ */
+
+/*
+ * There are no regular interfaces, just DPDK interfaces.
+ */
+int
+pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf)
+{
+	return (0);
+}
+
+/*
+ * Attempts to open a regular interface fail.
+ */
+pcap_t *
+pcap_create_interface(const char *device, char *errbuf)
+{
+	snprintf(errbuf, PCAP_ERRBUF_SIZE,
+	    "This version of libpcap only supports DPDK");
+	return NULL;
+}
+
+/*
+ * Libpcap version string.
+ */
+const char *
+pcap_lib_version(void)
+{
+	return (PCAP_VERSION_STRING " (DPDK-only)");
+}
+#endif
diff --git a/pcap-dpdk.h b/pcap-dpdk.h
new file mode 100644
index 0000000..b759b7f
--- /dev/null
+++ b/pcap-dpdk.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 jingle YANG. 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.
+ *
+ * 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.
+ */
+
+pcap_t *pcap_dpdk_create(const char *, char *, int *);
+int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *errbuf);
diff --git a/pcap-enet.c b/pcap-enet.c
index cd8cdbb..6f0512f 100644
--- a/pcap-enet.c
+++ b/pcap-enet.c
@@ -75,7 +75,7 @@
 			ph = (struct packet_header *)bp;
 			caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap
 .th_wirelen ;
-			if (bpf_filter(fcode, (char *)ph->packet,
+			if (pcap_filter(fcode, (char *)ph->packet,
 						ph->tap.th_wirelen, caplen)) {
 				if (cnt >= 0 && --cnt < 0)
 					goto out;
@@ -89,7 +89,7 @@
 		}
 #else	/* !IBMRTPC */
 		caplen = cc > snaplen ? snaplen : cc ;
-		if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) {
+		if (pcap_filter(fcode, buf.hdr.packet, cc, caplen)) {
 			if (cnt >= 0 && --cnt < 0)
 				goto out;
 			(*printit)(buf.hdr.packet, &tv, cc, caplen);
diff --git a/pcap-filter.manmisc.in b/pcap-filter.manmisc.in
index 777e735..e0f883d 100644
--- a/pcap-filter.manmisc.in
+++ b/pcap-filter.manmisc.in
@@ -18,22 +18,22 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP-FILTER @MAN_MISC_INFO@ "5 November 2017"
+.TH PCAP-FILTER @MAN_MISC_INFO@ "2 September 2020"
 .SH NAME
 pcap-filter \- packet filter syntax
 .br
 .ad
 .SH DESCRIPTION
 .LP
-.B pcap_compile()
+.BR pcap_compile ()
 is used to compile a string into a filter program.
 The resulting filter program can then be applied to
 some stream of packets to determine which packets will be supplied to
-.BR pcap_loop(3PCAP) ,
-.BR pcap_dispatch(3PCAP) ,
-.BR pcap_next(3PCAP) ,
+.BR pcap_loop (3PCAP),
+.BR pcap_dispatch (3PCAP),
+.BR pcap_next (3PCAP),
 or
-.BR pcap_next_ex(3PCAP) .
+.BR pcap_next_ex (3PCAP).
 .LP
 The \fIfilter expression\fP consists of one or more
 .IR primitives .
@@ -47,11 +47,11 @@
 qualifiers say what kind of thing the id name or number refers to.
 Possible types are
 .BR host ,
-.B net ,
+.BR net ,
 .B port
 and
 .BR portrange .
-E.g., `host foo', `net 128.3', `port 20', `portrange 6000-6008'.
+E.g., `\fBhost\fP foo', `\fBnet\fP 128.3', `\fBport\fP 20', `\fBportrange\fP 6000-6008'.
 If there is no type
 qualifier,
 .B host
@@ -72,11 +72,9 @@
 .BR addr3 ,
 and
 .BR addr4 .
-E.g., `src foo', `dst net 128.3', `src or dst port ftp-data'.
+E.g., `\fBsrc\fP foo', `\fBdst net\fP 128.3', `\fBsrc or dst port\fP ftp-data'.
 If
-there is no dir qualifier,
-.B "src or dst"
-is assumed.
+there is no dir qualifier, `\fBsrc or dst\fP' is assumed.
 The
 .BR ra ,
 .BR ta ,
@@ -103,25 +101,26 @@
 .B tcp
 and
 .BR udp .
-E.g., `ether src foo', `arp net 128.3', `tcp port 21', `udp portrange
-7000-7009', `wlan addr2 0:2:3:4:5:6'.
+E.g., `\fBether src\fP foo', `\fBarp net\fP 128.3', `\fBtcp port\fP 21',
+`\fBudp portrange\fP 7000-7009', `\fBwlan addr2\fP 0:2:3:4:5:6'.
 If there is
 no proto qualifier, all protocols consistent with the type are
 assumed.
-E.g., `src foo' means `(ip or arp or rarp) src foo'
-(except the latter is not legal syntax), `net bar' means `(ip or
-arp or rarp) net bar' and `port 53' means `(tcp or udp) port 53'.
+E.g., `\fBsrc\fP foo' means `\fB(ip or arp or rarp) src\fP foo'
+(except the latter is not legal syntax), `\fBnet\fP bar' means `\fB(ip or
+arp or rarp) net\fP bar' and `\fBport\fP 53' means `\fB(tcp or udp)
+port\fP 53'.
 .LP
-[`fddi' is actually an alias for `ether'; the parser treats them
+[\fBfddi\fP is actually an alias for \fBether\fP; the parser treats them
 identically as meaning ``the data link level used on the specified
-network interface.''  FDDI headers contain Ethernet-like source
+network interface''.  FDDI headers contain Ethernet-like source
 and destination addresses, and often contain Ethernet-like packet
 types, so you can filter on these FDDI fields just as with the
 analogous Ethernet fields.
 FDDI headers also contain other fields,
 but you cannot name them explicitly in a filter expression.
 .LP
-Similarly, `tr' and `wlan' are aliases for `ether'; the previous
+Similarly, \fBtr\fP and \fBwlan\fP are aliases for \fBether\fP; the previous
 paragraph's statements about FDDI headers also apply to Token Ring
 and 802.11 wireless LAN headers.  For 802.11 headers, the destination
 address is the DA field and the source address is the SA field; the
@@ -141,12 +140,13 @@
 .B or
 and
 .B not
+(or equivalently: `\fB&&\fP', `\fB||\fP' and `\fB!\fP' respectively)
 to combine primitives.
-E.g., `host foo and not port ftp and not port ftp-data'.
+E.g., `\fBhost\fP foo \fBand not port\fP ftp \fBand not port\fP ftp-data'.
 To save typing, identical qualifier lists can be omitted.
 E.g.,
-`tcp dst port ftp or ftp-data or domain' is exactly the same as
-`tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'.
+`\fBtcp dst port\fP ftp \fBor\fP ftp-data \fBor\fP domain' is exactly the same as
+`\fBtcp dst port\fP ftp \fBor tcp dst port\fP ftp-data \fBor tcp dst port\fP domain'.
 .LP
 Allowable primitives are:
 .IP "\fBdst host \fIhost\fR"
@@ -167,10 +167,10 @@
 which is equivalent to:
 .in +.5i
 .nf
-\fBether proto \fI\\ip\fB and host \fIhost\fR
+\fBether proto \\ip and host \fIhost\fR
 .fi
 .in -.5i
-If \fIhost\fR is a name with multiple IP addresses, each address will
+If \fIhost\fR is a name with multiple IPv4 addresses, each address will
 be checked for a match.
 .IP "\fBether dst \fIehost\fP"
 True if the Ethernet destination address is \fIehost\fP.
@@ -228,24 +228,24 @@
 bits wide.
 May be qualified with \fBsrc\fR or \fBdst\fR.
 .IP "\fBdst port \fIport\fR"
-True if the packet is ip/tcp, ip/udp, ip6/tcp or ip6/udp and has a
+True if the packet is IPv4 TCP, IPv4 UDP, IPv6 TCP or IPv6 UDP and has a
 destination port value of \fIport\fP.
 The \fIport\fP can be a number or a name used in /etc/services (see
-.IR tcp (4P)
+.BR tcp (4P)
 and
-.IR udp (4P)).
+.BR udp (4P)).
 If a name is used, both the port
 number and protocol are checked.
 If a number or ambiguous name is used,
-only the port number is checked (e.g., \fBdst port 513\fR will print both
-tcp/login traffic and udp/who traffic, and \fBport domain\fR will print
+only the port number is checked (e.g., `\fBdst port\fR 513' will print both
+tcp/login traffic and udp/who traffic, and `\fBport domain\fR' will print
 both tcp/domain and udp/domain traffic).
 .IP "\fBsrc port \fIport\fR"
 True if the packet has a source port value of \fIport\fP.
 .IP "\fBport \fIport\fR"
 True if either the source or destination port of the packet is \fIport\fP.
-.IP "\fBdst portrange \fIport1\fB-\fIport2\fR"
-True if the packet is ip/tcp, ip/udp, ip6/tcp or ip6/udp and has a
+.IP "\fBdst portrange \fIport1-port2\fR"
+True if the packet is IPv4 TCP, IPv4 UDP, IPv6 TCP or IPv6 UDP and has a
 destination port value between \fIport1\fP and \fIport2\fP.
 .I port1
 and
@@ -254,10 +254,10 @@
 .I port
 parameter for
 .BR port .
-.IP "\fBsrc portrange \fIport1\fB-\fIport2\fR"
+.IP "\fBsrc portrange \fIport1-port2\fR"
 True if the packet has a source port value between \fIport1\fP and
 \fIport2\fP.
-.IP "\fBportrange \fIport1\fB-\fIport2\fR"
+.IP "\fBportrange \fIport1-port2\fR"
 True if either the source or destination port of the packet is between
 \fIport1\fP and \fIport2\fP.
 .IP
@@ -268,13 +268,13 @@
 \fBtcp src port \fIport\fR
 .fi
 .in -.5i
-which matches only tcp packets whose source port is \fIport\fP.
+which matches only TCP packets whose source port is \fIport\fP.
 .IP "\fBless \fIlength\fR"
 True if the packet has a length less than or equal to \fIlength\fP.
 This is equivalent to:
 .in +.5i
 .nf
-\fBlen <= \fIlength\fP.
+\fBlen <= \fIlength\fP
 .fi
 .in -.5i
 .IP "\fBgreater \fIlength\fR"
@@ -282,12 +282,12 @@
 This is equivalent to:
 .in +.5i
 .nf
-\fBlen >= \fIlength\fP.
+\fBlen >= \fIlength\fP
 .fi
 .in -.5i
 .IP "\fBip proto \fIprotocol\fR"
 True if the packet is an IPv4 packet (see
-.IR ip (4P))
+.BR ip (4P))
 of protocol type \fIprotocol\fP.
 \fIProtocol\fP can be a number or one of the names
 \fBicmp\fP, \fBicmp6\fP, \fBigmp\fP, \fBigrp\fP, \fBpim\fP, \fBah\fP,
@@ -306,10 +306,10 @@
 Abbreviations for:
 .in +.5i
 .nf
-\fBproto \fIp\fR\fB
+\fBproto \\\fIprotocol\fR\fB
 .fi
 .in -.5i
-where \fIp\fR is one of the above protocols.
+where \fIprotocol\fR is one of the above protocols.
 .IP "\fBip6 protochain \fIprotocol\fR"
 True if the packet is IPv6 packet,
 and contains protocol header with type \fIprotocol\fR
@@ -317,7 +317,7 @@
 For example,
 .in +.5i
 .nf
-\fBip6 protochain 6\fR
+\fBip6 protochain\fR 6
 .fi
 .in -.5i
 matches any IPv6 packet with TCP protocol header in the protocol header chain.
@@ -336,7 +336,7 @@
 header chain.
 .IP "\fBether broadcast\fR"
 True if the packet is an Ethernet broadcast packet.
-The \fIether\fP
+The \fBether\fP
 keyword is optional.
 .IP "\fBip broadcast\fR"
 True if the packet is an IPv4 broadcast packet.
@@ -353,7 +353,7 @@
 True if the packet is an Ethernet multicast packet.
 The \fBether\fP
 keyword is optional.
-This is shorthand for `\fBether[0] & 1 != 0\fP'.
+This is shorthand for `\fBether[\fP0\fB] & \fP1\fB != \fP0'.
 .IP "\fBip multicast\fR"
 True if the packet is an IPv4 multicast packet.
 .IP "\fBip6 multicast\fR"
@@ -361,15 +361,15 @@
 .IP  "\fBether proto \fIprotocol\fR"
 True if the packet is of ether type \fIprotocol\fR.
 \fIProtocol\fP can be a number or one of the names
-\fBip\fP, \fBip6\fP, \fBarp\fP, \fBrarp\fP, \fBatalk\fP, \fBaarp\fP,
-\fBdecnet\fP, \fBsca\fP, \fBlat\fP, \fBmopdl\fP, \fBmoprc\fP,
-\fBiso\fP, \fBstp\fP, \fBipx\fP, or \fBnetbeui\fP.
-Note these identifiers are also keywords
+\fBaarp\fP, \fBarp\fP, \fBatalk\fP, \fBdecnet\fP, \fBip\fP, \fBip6\fP,
+\fBipx\fP, \fBiso\fP, \fBlat\fP, \fBloopback\fP, \fBmopdl\fP, \fBmoprc\fP, \fBnetbeui\fP,
+\fBrarp\fP, \fBsca\fP or \fBstp\fP.
+Note these identifiers (except \fBloopback\fP) are also keywords
 and must be escaped via backslash (\\).
 .IP
-[In the case of FDDI (e.g., `\fBfddi proto arp\fR'), Token Ring
-(e.g., `\fBtr proto arp\fR'), and IEEE 802.11 wireless LANS (e.g.,
-`\fBwlan proto arp\fR'), for most of those protocols, the
+[In the case of FDDI (e.g., `\fBfddi proto \\arp\fR'), Token Ring
+(e.g., `\fBtr proto \\arp\fR'), and IEEE 802.11 wireless LANs (e.g.,
+`\fBwlan proto \\arp\fR'), for most of those protocols, the
 protocol identification comes from the 802.2 Logical Link Control (LLC)
 header, which is usually layered on top of the FDDI, Token Ring, or
 802.11 header.
@@ -419,33 +419,33 @@
 Abbreviations for:
 .in +.5i
 .nf
-\fBether proto \fIp\fR
+\fBether proto \\\fIprotocol\fR
 .fi
 .in -.5i
-where \fIp\fR is one of the above protocols.
+where \fIprotocol\fR is one of the above protocols.
 .IP "\fBlat\fR, \fBmoprc\fR, \fBmopdl\fR"
 Abbreviations for:
 .in +.5i
 .nf
-\fBether proto \fIp\fR
+\fBether proto \\\fIprotocol\fR
 .fi
 .in -.5i
-where \fIp\fR is one of the above protocols.
+where \fIprotocol\fR is one of the above protocols.
 Note that not all applications using
 .BR pcap (3PCAP)
 currently know how to parse these protocols.
 .IP "\fBdecnet src \fIhost\fR"
-True if the DECNET source address is
+True if the DECnet source address is
 .IR host ,
-which may be an address of the form ``10.123'', or a DECNET host
+which may be an address of the form ``10.123'', or a DECnet host
 name.
-[DECNET host name support is only available on ULTRIX systems
-that are configured to run DECNET.]
+[DECnet host name support is only available on ULTRIX systems
+that are configured to run DECnet.]
 .IP "\fBdecnet dst \fIhost\fR"
-True if the DECNET destination address is
+True if the DECnet destination address is
 .IR host .
 .IP "\fBdecnet host \fIhost\fR"
-True if either the DECNET source or destination address is
+True if either the DECnet source or destination address is
 .IR host .
 .IP \fBllc\fP
 True if the packet has an 802.2 LLC header.  This includes:
@@ -460,7 +460,7 @@
 FDDI packets (no check is done for LLC frames);
 .IP
 LLC-encapsulated ATM packets, for SunATM on Solaris.
-.IP "\fBllc\fP \Fitype\fR"
+.IP "\fBllc\fP \fItype\fR"
 True if the packet has an 802.2 LLC header and has the specified
 .IR type .
 .I type
@@ -668,51 +668,51 @@
 or a numeric value.
 .IP "\fBvlan \fI[vlan_id]\fR"
 True if the packet is an IEEE 802.1Q VLAN packet.
-If \fI[vlan_id]\fR is specified, only true if the packet has the specified
+If the optional \fIvlan_id\fR is specified, only true if the packet has the specified
 \fIvlan_id\fR.
-Note that the first \fBvlan\fR keyword encountered in \fIexpression\fR
-changes the decoding offsets for the remainder of \fIexpression\fR on
-the assumption that the packet is a VLAN packet.  The \fBvlan
-\fI[vlan_id]\fR expression may be used more than once, to filter on VLAN
-hierarchies.  Each use of that expression increments the filter offsets
+Note that the first \fBvlan\fR keyword encountered in an expression
+changes the decoding offsets for the remainder of the expression on
+the assumption that the packet is a VLAN packet.  The `\fBvlan
+\fI[vlan_id]\fR` keyword may be used more than once, to filter on VLAN
+hierarchies.  Each use of that keyword increments the filter offsets
 by 4.
 .IP
 For example:
 .in +.5i
 .nf
-\fBvlan 100 && vlan 200\fR
+\fBvlan\fP 100 \fB&& vlan\fR 200
 .fi
 .in -.5i
 filters on VLAN 200 encapsulated within VLAN 100, and
 .in +.5i
 .nf
-\fBvlan && vlan 300 && ip\fR
+\fBvlan && vlan \fP300 \fB&& ip\fR
 .fi
 .in -.5i
-filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any
+filters IPv4 protocol encapsulated in VLAN 300 encapsulated within any
 higher order VLAN.
 .IP "\fBmpls \fI[label_num]\fR"
 True if the packet is an MPLS packet.
-If \fI[label_num]\fR is specified, only true is the packet has the specified
+If the optional \fIlabel_num\fR is specified, only true if the packet has the specified
 \fIlabel_num\fR.
-Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR
-changes the decoding offsets for the remainder of \fIexpression\fR on
+Note that the first \fBmpls\fR keyword encountered in an expression
+changes the decoding offsets for the remainder of the expression on
 the assumption that the packet is a MPLS-encapsulated IP packet.  The
-\fBmpls \fI[label_num]\fR expression may be used more than once, to
-filter on MPLS hierarchies.  Each use of that expression increments the
+`\fBmpls \fI[label_num]\fR` keyword may be used more than once, to
+filter on MPLS hierarchies.  Each use of that keyword increments the
 filter offsets by 4.
 .IP
 For example:
 .in +.5i
 .nf
-\fBmpls 100000 && mpls 1024\fR
+\fBmpls\fP 100000 \fB&& mpls\fR 1024
 .fi
 .in -.5i
 filters packets with an outer label of 100000 and an inner label of
 1024, and
 .in +.5i
 .nf
-\fBmpls && mpls 1024 && host 192.9.200.1\fR
+\fBmpls && mpls\fP 1024 \fB&& host\fR 192.9.200.1
 .fi
 .in -.5i
 filters packets to or from 192.9.200.1 with an inner label of 1024 and
@@ -723,34 +723,34 @@
 .IP "\fBpppoes \fI[session_id]\fR"
 True if the packet is a PPP-over-Ethernet Session packet (Ethernet
 type 0x8864).
-If \fI[session_id]\fR is specified, only true if the packet has the specified
+If the optional \fIsession_id\fR is specified, only true if the packet has the specified
 \fIsession_id\fR.
-Note that the first \fBpppoes\fR keyword encountered in \fIexpression\fR
-changes the decoding offsets for the remainder of \fIexpression\fR on
+Note that the first \fBpppoes\fR keyword encountered in an expression
+changes the decoding offsets for the remainder of the expression on
 the assumption that the packet is a PPPoE session packet.
 .IP
 For example:
 .in +.5i
 .nf
-\fBpppoes 0x27 && ip\fR
+\fBpppoes\fP 0x27 \fB&& ip\fR
 .fi
 .in -.5i
-filters IPv4 protocols encapsulated in PPPoE session id 0x27.
+filters IPv4 protocol encapsulated in PPPoE session id 0x27.
 .IP "\fBgeneve \fI[vni]\fR"
-True if the packet is a Geneve packet (UDP port 6081). If \fI[vni]\fR
+True if the packet is a Geneve packet (UDP port 6081). If the optional \fIvni\fR
 is specified, only true if the packet has the specified \fIvni\fR.
 Note that when the \fBgeneve\fR keyword is encountered in
-\fIexpression\fR, it changes the decoding offsets for the remainder of
-\fIexpression\fR on the assumption that the packet is a Geneve packet.
+an expression, it changes the decoding offsets for the remainder of
+the expression on the assumption that the packet is a Geneve packet.
 .IP
 For example:
 .in +.5i
 .nf
-\fBgeneve 0xb && ip\fR
+\fBgeneve\fP 0xb \fB&& ip\fR
 .fi
 .in -.5i
-filters IPv4 protocols encapsulated in Geneve with VNI 0xb. This will
-match both IP directly encapsulated in Geneve as well as IP contained
+filters IPv4 protocol encapsulated in Geneve with VNI 0xb. This will
+match both IPv4 directly encapsulated in Geneve as well as IPv4 contained
 inside an Ethernet frame.
 .IP "\fBiso proto \fIprotocol\fR"
 True if the packet is an OSI packet of protocol type \fIprotocol\fP.
@@ -760,10 +760,10 @@
 Abbreviations for:
 .in +.5i
 .nf
-\fBiso proto \fIp\fR
+\fBiso proto \\\fIprotocol\fR
 .fi
 .in -.5i
-where \fIp\fR is one of the above protocols.
+where \fIprotocol\fR is one of the above protocols.
 .IP "\fBl1\fR, \fBl2\fR, \fBiih\fR, \fBlsp\fR, \fBsnp\fR, \fBcsnp\fR, \fBpsnp\fR"
 Abbreviations for IS-IS PDU types.
 .IP "\fBvpi\fP \fIn\fR"
@@ -777,8 +777,8 @@
 .IP \fBlane\fP
 True if the packet is an ATM packet, for SunATM on Solaris, and is
 an ATM LANE packet.
-Note that the first \fBlane\fR keyword encountered in \fIexpression\fR
-changes the tests done in the remainder of \fIexpression\fR
+Note that the first \fBlane\fR keyword encountered in an expression
+changes the tests done in the remainder of the expression
 on the assumption that the packet is either a LANE emulated Ethernet
 packet or a LANE LE Control packet.  If \fBlane\fR isn't specified, the
 tests are done under the assumption that the packet is an
@@ -841,7 +841,7 @@
 (\fBether, fddi, wlan, tr, ppp, slip\fR and \fBlink\fR all refer to the
 link layer. \fBradio\fR refers to the "radio header" added to some
 802.11 captures.)
-Note that \fItcp, udp\fR and other upper-layer protocol types only
+Note that \fBtcp\fR, \fBudp\fR and other upper-layer protocol types only
 apply to IPv4, not IPv6 (this will be fixed in the future).
 The byte offset, relative to the indicated protocol layer, is
 given by \fIexpr\fR.
@@ -850,24 +850,24 @@
 The length operator, indicated by the keyword \fBlen\fP, gives the
 length of the packet.
 
-For example, `\fBether[0] & 1 != 0\fP' catches all multicast traffic.
-The expression `\fBip[0] & 0xf != 5\fP'
+For example, `\fBether[\fP0\fB] &\fP 1 \fB!=\fP 0' catches all multicast traffic.
+The expression `\fBip[\fP0\fB] &\fP 0xf \fB!=\fP 5'
 catches all IPv4 packets with options.
 The expression
-`\fBip[6:2] & 0x1fff = 0\fP'
+`\fBip[\fP6:2\fB] &\fP 0x1fff \fB=\fP 0'
 catches only unfragmented IPv4 datagrams and frag zero of fragmented
 IPv4 datagrams.
 This check is implicitly applied to the \fBtcp\fP and \fBudp\fP
 index operations.
-For instance, \fBtcp[0]\fP always means the first
+For instance, \fBtcp[\fP0\fB]\fP always means the first
 byte of the TCP \fIheader\fP, and never means the first byte of an
 intervening fragment.
 
 Some offsets and field values may be expressed as names rather than
 as numeric values.
 The following protocol header field offsets are
-available: \fBicmptype\fP (ICMP type field), \fBicmp6type (ICMP v6 type field)
-\fBicmpcode\fP (ICMP code field), \fBicmp6code\fP (ICMP v6 code field), and
+available: \fBicmptype\fP (ICMP type field), \fBicmp6type\fP (ICMPv6 type field),
+\fBicmpcode\fP (ICMP code field), \fBicmp6code\fP (ICMPv6 code field) and
 \fBtcpflags\fP (TCP flags field).
 
 The following ICMP type field values are available: \fBicmp-echoreply\fP,
@@ -877,7 +877,9 @@
 \fBicmp-tstampreply\fP, \fBicmp-ireq\fP, \fBicmp-ireqreply\fP,
 \fBicmp-maskreq\fP, \fBicmp-maskreply\fP.
 
-The following ICMPv6 type fields are available: \fBicmp6-echo\fP,
+The following ICMPv6 type fields are available: \fBicmp6-destinationrunreach\fP,
+\fBicmp6-packettoobig\fP, \fBicmp6-timeexceeded\fP,
+\fBicmp6-parameterproblem\fP, \fBicmp6-echo\fP,
 \fBicmp6-echoreply\fP, \fBicmp6-multicastlistenerquery\fP,
 \fBicmp6-multicastlistenerreportv1\fP, \fBicmp6-multicastlistenerdone\fP,
 \fBicmp6-routersolicit\fP, \fBicmp6-routeradvert\fP,
@@ -906,7 +908,7 @@
 .IP
 Alternation (`\fB||\fP' or `\fBor\fP').
 .LP
-Negation has highest precedence.
+Negation has the highest precedence.
 Alternation and concatenation have equal precedence and associate
 left to right.
 Note that explicit \fBand\fR tokens, not juxtaposition,
@@ -917,67 +919,64 @@
 For example,
 .in +.5i
 .nf
-\fBnot host vs and ace\fR
+\fBnot host\fP vs \fBand\fR ace
 .fi
 .in -.5i
 is short for
 .in +.5i
 .nf
-\fBnot host vs and host ace\fR
+\fBnot host\fP vs \fBand host\fR ace
 .fi
 .in -.5i
 which should not be confused with
 .in +.5i
 .nf
-\fBnot ( host vs or ace )\fR
+\fBnot (host \fPvs\fB or \fPace\fB)\fR
 .fi
 .in -.5i
 .SH EXAMPLES
 .LP
-To select all packets arriving at or departing from \fIsundown\fP:
+To select all packets arriving at or departing from `sundown':
 .RS
 .nf
-\fBhost sundown\fP
+\fBhost\fP sundown
 .fi
 .RE
 .LP
-To select traffic between \fIhelios\fR and either \fIhot\fR or \fIace\fR:
+To select traffic between `helios' and either `hot' or `ace':
 .RS
 .nf
-\fBhost helios and \\( hot or ace \\)\fP
+\fBhost\fP helios \fBand (\fPhot \fBor\fP ace\fB)\fP
 .fi
 .RE
 .LP
-To select all IP packets between \fIace\fR and any host except \fIhelios\fR:
+To select all IPv4 packets between `ace' and any host except `helios':
 .RS
 .nf
-\fBip host ace and not helios\fP
+\fBip host\fP ace \fBand not\fP helios
 .fi
 .RE
 .LP
 To select all traffic between local hosts and hosts at Berkeley:
 .RS
 .nf
-.B
-net ucb-ether
+\fBnet\fP ucb-ether
 .fi
 .RE
 .LP
-To select all ftp traffic through internet gateway \fIsnup\fP:
+To select all FTP traffic through Internet gateway `snup':
 .RS
 .nf
-.B
-gateway snup and (port ftp or ftp-data)
+\fBgateway\fP snup \fBand (port\fP ftp \fBor\fP ftp-data\fB)\fP
 .fi
 .RE
 .LP
-To select traffic neither sourced from nor destined for local hosts
+To select IPv4 traffic neither sourced from nor destined for local hosts
 (if you gateway to one other net, this stuff should never make it
 onto your local net).
 .RS
 .nf
-.B
-ip and not net \fIlocalnet\fP
+\fBip and not net \fPlocalnet
 .fi
 .RE
 .LP
@@ -985,8 +984,17 @@
 TCP conversation that involves a non-local host.
 .RS
 .nf
+\fBtcp[tcpflags] & (tcp-syn|tcp-fin) !=\fP 0 \fBand not src and dst net\fP localnet
+.fi
+.RE
+.LP
+To select the TCP packets with flags RST and ACK both set.
+(i.e. select only the RST and ACK flags in the flags field, and if the result
+is "RST and ACK both set", match)
+.RS
+.nf
 .B
-tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net \fIlocalnet\fP
+tcp[tcpflags] & (tcp-rst|tcp-ack) == (tcp-rst|tcp-ack)
 .fi
 .RE
 .LP
@@ -995,26 +1003,23 @@
 ACK-only packets.  (IPv6 is left as an exercise for the reader.)
 .RS
 .nf
-.B
-tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)
+\fBtcp port\fP 80 \fBand (((ip[\fP2:2\fB] - ((ip[\fP0\fB]&\fP0xf\fB)<<\fP2\fB)) - ((tcp[\fP12\fB]&\fP0xf0\fB)>>\fP2\fB)) != \fP0\fB)
 .fi
 .RE
 .LP
-To select IP packets longer than 576 bytes sent through gateway \fIsnup\fP:
+To select IPv4 packets longer than 576 bytes sent through gateway `snup':
 .RS
 .nf
-.B
-gateway snup and ip[2:2] > 576
+\fBgateway\fP snup \fBand ip[\fP2:2\fB] >\fP 576
 .fi
 .RE
 .LP
-To select IP broadcast or multicast packets that were
+To select IPv4 broadcast or multicast packets that were
 .I not
 sent via Ethernet broadcast or multicast:
 .RS
 .nf
-.B
-ether[0] & 1 = 0 and ip[16] >= 224
+\fBether[\fP0\fB] &\fP 1 \fB=\fP 0 \fBand ip[\fP16\fB] >=\fP 224
 .fi
 .RE
 .LP
@@ -1024,16 +1029,18 @@
 .nf
 .B
 icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply
+.B
+icmp6[icmp6type] != icmp6-echo and icmp6[icmp6type] != icmp6-echoreply
 .fi
 .RE
 .SH "SEE ALSO"
-pcap(3PCAP)
+.BR pcap (3PCAP)
 .SH BUGS
 To report a security issue please send an e-mail to security@tcpdump.org.
 .LP
 To report bugs and other problems, contribute patches, request a
 feature, provide generic feedback etc please see the file
-.I CONTRIBUTING
+.I CONTRIBUTING.md
 in the libpcap source tree root.
 .LP
 Filter expressions on fields other than those in Token Ring headers will
@@ -1042,10 +1049,11 @@
 Filter expressions on fields other than those in 802.11 headers will not
 correctly handle 802.11 data packets with both To DS and From DS set.
 .LP
-.BR "ip6 proto"
+`\fBip6 proto\fP'
 should chase header chain, but at this moment it does not.
-.BR "ip6 protochain"
-is supplied for this behavior.
+`\fBip6 protochain\fP'
+is supplied for this behavior.  For example, to match IPv6 fragments:
+`\fBip6 protochain\fP 44'
 .LP
 Arithmetic expression against transport layer headers, like \fBtcp[0]\fP,
 does not work against IPv6 packets.
diff --git a/pcap-haiku.cpp b/pcap-haiku.cpp
new file mode 100644
index 0000000..701cac3
--- /dev/null
+++ b/pcap-haiku.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Axel Dörfler, axeld@pinc-software.de
+ *		James Woodcock
+ */
+
+
+#include "config.h"
+#include "pcap-int.h"
+
+#include <OS.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+ * Private data for capturing on Haiku sockets.
+ */
+struct pcap_haiku {
+	struct pcap_stat	stat;
+	char	*device;	/* device name */
+};
+
+
+bool
+prepare_request(struct ifreq& request, const char* name)
+{
+	if (strlen(name) >= IF_NAMESIZE)
+		return false;
+
+	strcpy(request.ifr_name, name);
+	return true;
+}
+
+
+static int
+pcap_read_haiku(pcap_t* handle, int maxPackets, pcap_handler callback,
+	u_char* userdata)
+{
+	// Receive a single packet
+
+	struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
+	u_char* buffer = (u_char*)handle->buffer + handle->offset;
+	struct sockaddr_dl from;
+	ssize_t bytesReceived;
+	do {
+		if (handle->break_loop) {
+			// Clear the break loop flag, and return -2 to indicate our
+			// reasoning
+			handle->break_loop = 0;
+			return -2;
+		}
+
+		socklen_t fromLength = sizeof(from);
+		bytesReceived = recvfrom(handle->fd, buffer, handle->bufsize, MSG_TRUNC,
+			(struct sockaddr*)&from, &fromLength);
+	} while (bytesReceived < 0 && errno == B_INTERRUPTED);
+
+	if (bytesReceived < 0) {
+		if (errno == B_WOULD_BLOCK) {
+			// there is no packet for us
+			return 0;
+		}
+
+		snprintf(handle->errbuf, sizeof(handle->errbuf),
+			"recvfrom: %s", strerror(errno));
+		return -1;
+	}
+
+	int32 captureLength = bytesReceived;
+	if (captureLength > handle->snapshot)
+		captureLength = handle->snapshot;
+
+	// run the packet filter
+	if (handle->fcode.bf_insns) {
+		if (pcap_filter(handle->fcode.bf_insns, buffer, bytesReceived,
+				captureLength) == 0) {
+			// packet got rejected
+			return 0;
+		}
+	}
+
+	// fill in pcap_header
+	pcap_pkthdr header;
+	header.caplen = captureLength;
+	header.len = bytesReceived;
+	header.ts.tv_usec = system_time() % 1000000;
+	header.ts.tv_sec = system_time() / 1000000;
+	// TODO: get timing from packet!!!
+
+	/* Call the user supplied callback function */
+	callback(userdata, &header, buffer);
+	return 1;
+}
+
+
+static int
+pcap_inject_haiku(pcap_t *handle, const void *buffer, int size)
+{
+	// we don't support injecting packets yet
+	// TODO: use the AF_LINK protocol (we need another socket for this) to
+	// inject the packets
+	strlcpy(handle->errbuf, "Sending packets isn't supported yet",
+		PCAP_ERRBUF_SIZE);
+	return -1;
+}
+
+
+static int
+pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats)
+{
+	struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
+	ifreq request;
+	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
+	if (socket < 0) {
+		return -1;
+	}
+	prepare_request(request, handlep->device);
+	if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) < 0) {
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "pcap_stats: %s",
+			strerror(errno));
+		close(socket);
+		return -1;
+	}
+
+	close(socket);
+	handlep->stat.ps_recv += request.ifr_stats.receive.packets;
+	handlep->stat.ps_drop += request.ifr_stats.receive.dropped;
+	*stats = handlep->stat;
+	return 0;
+}
+
+
+static int
+pcap_activate_haiku(pcap_t *handle)
+{
+	struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
+
+	const char* device = handle->opt.device;
+
+	handle->read_op = pcap_read_haiku;
+	handle->setfilter_op = install_bpf_program; /* no kernel filtering */
+	handle->inject_op = pcap_inject_haiku;
+	handle->stats_op = pcap_stats_haiku;
+
+	// use default hooks where possible
+	handle->getnonblock_op = pcap_getnonblock_fd;
+	handle->setnonblock_op = pcap_setnonblock_fd;
+
+	handlep->device	= strdup(device);
+	if (handlep->device == NULL) {
+		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+			errno, "strdup");
+		return PCAP_ERROR;
+	}
+
+	handle->bufsize = 65536;
+	// TODO: should be determined by interface MTU
+
+	// allocate buffer for monitoring the device
+	handle->buffer = (u_char*)malloc(handle->bufsize);
+	if (handle->buffer == NULL) {
+		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+			errno, "buffer malloc");
+		return PCAP_ERROR;
+	}
+
+	handle->offset = 0;
+	handle->linktype = DLT_EN10MB;
+	// TODO: check interface type!
+
+	return 0;
+}
+
+
+//	#pragma mark - pcap API
+
+
+extern "C" pcap_t *
+pcap_create_interface(const char *device, char *errorBuffer)
+{
+	// TODO: handle promiscuous mode!
+
+	// we need a socket to talk to the networking stack
+	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
+	if (socket < 0) {
+		snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
+			"The networking stack doesn't seem to be available.\n");
+		return NULL;
+	}
+
+	struct ifreq request;
+	if (!prepare_request(request, device)) {
+		snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
+			"Interface name \"%s\" is too long.", device);
+		close(socket);
+		return NULL;
+	}
+
+	// check if the interface exist
+	if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) {
+		snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
+			"Interface \"%s\" does not exist.\n", device);
+		close(socket);
+		return NULL;
+	}
+
+	close(socket);
+	// no longer needed after this point
+
+	// get link level interface for this interface
+
+	socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
+	if (socket < 0) {
+		snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "No link level: %s\n",
+			strerror(errno));
+		return NULL;
+	}
+
+	// start monitoring
+	if (ioctl(socket, SIOCSPACKETCAP, &request, sizeof(struct ifreq)) < 0) {
+		snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Cannot start monitoring: %s\n",
+			strerror(errno));
+		close(socket);
+		return NULL;
+	}
+
+	pcap_t* handle = PCAP_CREATE_COMMON(errorBuffer, struct pcap_haiku);
+	if (handle == NULL) {
+		snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "malloc: %s", strerror(errno));
+		close(socket);
+		return NULL;
+	}
+
+	handle->selectable_fd = socket;
+	handle->fd = socket;
+
+	handle->activate_op = pcap_activate_haiku;
+
+	return handle;
+}
+
+static int
+can_be_bound(const char *name)
+{
+	return 1;
+}
+
+static int
+get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
+{
+	/* TODO */
+	if (*flags & PCAP_IF_LOOPBACK) {
+		/*
+		 * Loopback devices aren't wireless, and "connected"/
+		 * "disconnected" doesn't apply to them.
+		 */
+		*flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
+		return (0);
+	}
+	return (0);
+}
+
+extern "C" int
+pcap_platform_finddevs(pcap_if_list_t* _allDevices, char* errorBuffer)
+{
+	return pcap_findalldevs_interfaces(_allDevices, errorBuffer, can_be_bound,
+		get_if_flags);
+}
diff --git a/pcap-int.h b/pcap-int.h
index 5295f8f..3c18dae 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -34,6 +34,8 @@
 #ifndef pcap_int_h
 #define	pcap_int_h
 
+#include <stddef.h>
+
 #include <signal.h>
 
 #include <pcap/pcap.h>
@@ -51,6 +53,33 @@
 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;
+
 #ifdef MSDOS
   #include <fcntl.h>
   #include <io.h>
@@ -77,7 +106,7 @@
  *    1) big enough for maximum-size Linux loopback packets (65549)
  *       and some USB packets captured with USBPcap:
  *
- *           http://desowin.org/usbpcap/
+ *           https://desowin.org/usbpcap/
  *
  *       (> 131072, < 262144)
  *
@@ -97,6 +126,18 @@
  */
 #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 */
@@ -123,7 +164,7 @@
 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 *, size_t);
+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);
@@ -131,6 +172,7 @@
 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);
@@ -200,8 +242,7 @@
 
 	int snapshot;
 	int linktype;		/* Network linktype */
-	int linktype_ext;       /* Extended information stored in the linktype field of a file */
-	int tzoff;		/* timezone offset */
+	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() */
@@ -239,7 +280,7 @@
 	 * pcap_t's with a required timeout, and the code must be
 	 * prepared not to see any packets from the attempt.
 	 */
-	struct timeval *required_select_timeout;
+	const struct timeval *required_select_timeout;
 #endif
 
 	/*
@@ -248,6 +289,9 @@
 	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;
@@ -270,6 +314,7 @@
 	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().
@@ -340,7 +385,7 @@
  *
  * Then supply the changes by forking the branch at
  *
- *	https://github.com/the-tcpdump-group/libpcap/issues
+ *	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
@@ -350,7 +395,7 @@
 struct pcap_sf_pkthdr {
     struct pcap_timeval ts;	/* time stamp */
     bpf_u_int32 caplen;		/* length of portion present */
-    bpf_u_int32 len;		/* length this packet (off wire) */
+    bpf_u_int32 len;		/* length of this packet (off wire) */
 };
 
 /*
@@ -366,7 +411,7 @@
 struct pcap_sf_patched_pkthdr {
     struct pcap_timeval ts;	/* time stamp */
     bpf_u_int32 caplen;		/* length of portion present */
-    bpf_u_int32 len;		/* length this packet (off wire) */
+    bpf_u_int32 len;		/* length of this packet (off wire) */
     int		index;
     unsigned short protocol;
     unsigned char pkt_type;
@@ -418,12 +463,25 @@
  * by pcap_create routines.
  */
 pcap_t	*pcap_create_interface(const char *, char *);
-pcap_t	*pcap_create_common(char *, size_t);
+
+/*
+ * 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()".
@@ -472,7 +530,8 @@
 #endif
 
 /*
- * Internal interfaces for "pcap_open_offline()".
+ * 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.
@@ -483,10 +542,46 @@
  * "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.
  */
-pcap_t	*pcap_open_offline_common(char *ebuf, size_t size);
+
+/*
+ * 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
@@ -506,10 +601,20 @@
  * Filtering routine that takes the auxiliary data as an additional
  * argument.
  */
-u_int	bpf_filter_with_aux_data(const struct bpf_insn *,
+u_int	pcap_filter_with_aux_data(const struct bpf_insn *,
     const u_char *, u_int, u_int, const struct 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.
  *
@@ -522,6 +627,16 @@
 
 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
diff --git a/pcap-libdlpi.c b/pcap-libdlpi.c
index a38da8b..ef3fdac 100644
--- a/pcap-libdlpi.c
+++ b/pcap-libdlpi.c
@@ -46,7 +46,7 @@
 /* Forwards. */
 static int dlpromiscon(pcap_t *, bpf_u_int32);
 static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *);
-static int pcap_inject_libdlpi(pcap_t *, const void *, size_t);
+static int pcap_inject_libdlpi(pcap_t *, const void *, int);
 static void pcap_libdlpi_err(const char *, const char *, int, char *);
 static void pcap_cleanup_libdlpi(pcap_t *);
 
@@ -427,7 +427,7 @@
 }
 
 static int
-pcap_inject_libdlpi(pcap_t *p, const void *buf, size_t size)
+pcap_inject_libdlpi(pcap_t *p, const void *buf, int size)
 {
 	struct pcap_dlpi *pd = p->priv;
 	int retv;
@@ -468,7 +468,7 @@
 static void
 pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf)
 {
-	pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s",
+	snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s",
 	    func, linkname, dlpi_strerror(err));
 }
 
@@ -477,7 +477,7 @@
 {
 	pcap_t *p;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_dlpi));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_dlpi);
 	if (p == NULL)
 		return (NULL);
 
diff --git a/pcap-linktype.manmisc.in b/pcap-linktype.manmisc.in
index 777e9dc..736a91c 100644
--- a/pcap-linktype.manmisc.in
+++ b/pcap-linktype.manmisc.in
@@ -18,7 +18,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP-LINKTYPE @MAN_MISC_INFO@ "7 April 2014"
+.TH PCAP-LINKTYPE @MAN_MISC_INFO@ "6 April 2020"
 .SH NAME
 pcap-linktype \- link-layer header types supported by libpcap
 .SH DESCRIPTION
@@ -38,11 +38,11 @@
 The values stored in the link-layer header type field in the savefile
 header are, in most but not all cases, the same as the values returned
 by
-.BR pcap_datalink() .
+.BR pcap_datalink ().
 The names for those values begin with
 .BR LINKTYPE_ .
 .PP
 The link-layer header types supported by libpcap are described at
-https://www.tcpdump.org/linktypes.html.
+https://www.tcpdump.org/linktypes.html .
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap-linux.c b/pcap-linux.c
index 70334b3..7481689 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -67,48 +67,6 @@
  * SUCH DAMAGE.
  */
 
-/*
- * Known problems with 2.0[.x] kernels:
- *
- *   - The loopback device gives every packet twice; on 2.2[.x] kernels,
- *     if we use PF_PACKET, we can filter out the transmitted version
- *     of the packet by using data in the "sockaddr_ll" returned by
- *     "recvfrom()", but, on 2.0[.x] kernels, we have to use
- *     PF_INET/SOCK_PACKET, which means "recvfrom()" supplies a
- *     "sockaddr_pkt" which doesn't give us enough information to let
- *     us do that.
- *
- *   - We have to set the interface's IFF_PROMISC flag ourselves, if
- *     we're to run in promiscuous mode, which means we have to turn
- *     it off ourselves when we're done; the kernel doesn't keep track
- *     of how many sockets are listening promiscuously, which means
- *     it won't get turned off automatically when no sockets are
- *     listening promiscuously.  We catch "pcap_close()" and, for
- *     interfaces we put into promiscuous mode, take them out of
- *     promiscuous mode - which isn't necessarily the right thing to
- *     do, if another socket also requested promiscuous mode between
- *     the time when we opened the socket and the time when we close
- *     the socket.
- *
- *   - MSG_TRUNC isn't supported, so you can't specify that "recvfrom()"
- *     return the amount of data that you could have read, rather than
- *     the amount that was returned, so we can't just allocate a buffer
- *     whose size is the snapshot length and pass the snapshot length
- *     as the byte count, and also pass MSG_TRUNC, so that the return
- *     value tells us how long the packet was on the wire.
- *
- *     This means that, if we want to get the actual size of the packet,
- *     so we can return it in the "len" field of the packet header,
- *     we have to read the entire packet, not just the part that fits
- *     within the snapshot length, and thus waste CPU time copying data
- *     from the kernel that our caller won't see.
- *
- *     We have to get the actual size, and supply it in "len", because
- *     otherwise, the IP dissector in tcpdump, for example, will complain
- *     about "truncated-ip", as the packet will appear to have been
- *     shorter, on the wire, than the IP header said it should have been.
- */
-
 
 #define _GNU_SOURCE
 
@@ -119,7 +77,6 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <ctype.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <string.h>
@@ -132,114 +89,56 @@
 #include <linux/if.h>
 #include <linux/if_packet.h>
 #include <linux/sockios.h>
+#include <linux/ethtool.h>
 #include <netinet/in.h>
 #include <linux/if_ether.h>
-#include <net/if_arp.h>
+#include <linux/if_arp.h>
 #include <poll.h>
 #include <dirent.h>
+#include <sys/eventfd.h>
 
 #include "pcap-int.h"
 #include "pcap/sll.h"
 #include "pcap/vlan.h"
 
+#include "diag-control.h"
+
 /*
- * If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET
- * sockets rather than SOCK_PACKET sockets.
- *
- * To use them, we include <linux/if_packet.h> rather than
- * <netpacket/packet.h>; we do so because
- *
- *	some Linux distributions (e.g., Slackware 4.0) have 2.2 or
- *	later kernels and libc5, and don't provide a <netpacket/packet.h>
- *	file;
- *
- *	not all versions of glibc2 have a <netpacket/packet.h> file
- *	that defines stuff needed for some of the 2.4-or-later-kernel
- *	features, so if the system has a 2.4 or later kernel, we
- *	still can't use those features.
- *
- * We're already including a number of other <linux/XXX.h> headers, and
- * this code is Linux-specific (no other OS has PF_PACKET sockets as
- * a raw packet capture mechanism), so it's not as if you gain any
- * useful portability by using <netpacket/packet.h>
- *
- * XXX - should we just include <linux/if_packet.h> even if PF_PACKET
- * isn't defined?  It only defines one data structure in 2.0.x, so
- * it shouldn't cause any problems.
+ * We require TPACKET_V2 support.
  */
-#ifdef PF_PACKET
-# include <linux/if_packet.h>
+#ifndef TPACKET2_HDRLEN
+#error "Libpcap will only work if TPACKET_V2 is supported; you must build for a 2.6.27 or later kernel"
+#endif
 
- /*
-  * On at least some Linux distributions (for example, Red Hat 5.2),
-  * there's no <netpacket/packet.h> file, but PF_PACKET is defined if
-  * you include <sys/socket.h>, but <linux/if_packet.h> doesn't define
-  * any of the PF_PACKET stuff such as "struct sockaddr_ll" or any of
-  * the PACKET_xxx stuff.
-  *
-  * So we check whether PACKET_HOST is defined, and assume that we have
-  * PF_PACKET sockets only if it is defined.
-  */
-# ifdef PACKET_HOST
-#  define HAVE_PF_PACKET_SOCKETS
-#  ifdef PACKET_AUXDATA
-#   define HAVE_PACKET_AUXDATA
-#  endif /* PACKET_AUXDATA */
-# endif /* PACKET_HOST */
+/* check for memory mapped access avaibility. We assume every needed
+ * struct is defined if the macro TPACKET_HDRLEN is defined, because it
+ * uses many ring related structs and macros */
+#ifdef TPACKET3_HDRLEN
+# define HAVE_TPACKET3
+#endif /* TPACKET3_HDRLEN */
 
+#define packet_mmap_acquire(pkt) \
+	(__atomic_load_n(&pkt->tp_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL)
+#define packet_mmap_release(pkt) \
+	(__atomic_store_n(&pkt->tp_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE))
+#define packet_mmap_v3_acquire(pkt) \
+	(__atomic_load_n(&pkt->hdr.bh1.block_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL)
+#define packet_mmap_v3_release(pkt) \
+	(__atomic_store_n(&pkt->hdr.bh1.block_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE))
 
- /* check for memory mapped access avaibility. We assume every needed
-  * struct is defined if the macro TPACKET_HDRLEN is defined, because it
-  * uses many ring related structs and macros */
-# ifdef PCAP_SUPPORT_PACKET_RING
-# ifdef TPACKET_HDRLEN
-#  define HAVE_PACKET_RING
-#  ifdef TPACKET3_HDRLEN
-#   define HAVE_TPACKET3
-#  endif /* TPACKET3_HDRLEN */
-#  ifdef TPACKET2_HDRLEN
-#   define HAVE_TPACKET2
-#  else  /* TPACKET2_HDRLEN */
-#   define TPACKET_V1	0    /* Old kernel with only V1, so no TPACKET_Vn defined */
-#  endif /* TPACKET2_HDRLEN */
-# endif /* TPACKET_HDRLEN */
-# endif /* PCAP_SUPPORT_PACKET_RING */
-#endif /* PF_PACKET */
-
-#ifdef SO_ATTACH_FILTER
 #include <linux/types.h>
 #include <linux/filter.h>
-#endif
 
 #ifdef HAVE_LINUX_NET_TSTAMP_H
 #include <linux/net_tstamp.h>
 #endif
 
-#ifdef HAVE_LINUX_SOCKIOS_H
-#include <linux/sockios.h>
-#endif
-
-#ifdef HAVE_LINUX_IF_BONDING_H
+/*
+ * For checking whether a device is a bonding device.
+ */
 #include <linux/if_bonding.h>
 
 /*
- * The ioctl code to use to check whether a device is a bonding device.
- */
-#if defined(SIOCBONDINFOQUERY)
-	#define BOND_INFO_QUERY_IOCTL SIOCBONDINFOQUERY
-#elif defined(BOND_INFO_QUERY_OLD)
-	#define BOND_INFO_QUERY_IOCTL BOND_INFO_QUERY_OLD
-#endif
-#endif /* HAVE_LINUX_IF_BONDING_H */
-
-/*
- * Got Wireless Extensions?
- */
-#ifdef HAVE_LINUX_WIRELESS_H
-#include <linux/wireless.h>
-#endif /* HAVE_LINUX_WIRELESS_H */
-
-/*
  * Got libnl?
  */
 #ifdef HAVE_LIBNL
@@ -252,39 +151,10 @@
 #include <netlink/attr.h>
 #endif /* HAVE_LIBNL */
 
-/*
- * Got ethtool support?
- */
-#ifdef HAVE_LINUX_ETHTOOL_H
-#include <linux/ethtool.h>
-#endif
-
 #ifndef HAVE_SOCKLEN_T
 typedef int		socklen_t;
 #endif
 
-#ifndef MSG_TRUNC
-/*
- * This is being compiled on a system that lacks MSG_TRUNC; define it
- * with the value it has in the 2.2 and later kernels, so that, on
- * those kernels, when we pass it in the flags argument to "recvfrom()"
- * we're passing the right value and thus get the MSG_TRUNC behavior
- * we want.  (We don't get that behavior on 2.0[.x] kernels, because
- * they didn't support MSG_TRUNC.)
- */
-#define MSG_TRUNC	0x20
-#endif
-
-#ifndef SOL_PACKET
-/*
- * This is being compiled on a system that lacks SOL_PACKET; define it
- * with the value it has in the 2.2 and later kernels, so that we can
- * set promiscuous mode in the good modern way rather than the old
- * 2.0-kernel crappy way.
- */
-#define SOL_PACKET	263
-#endif
-
 #define MAX_LINKHEADER_SIZE	256
 
 /*
@@ -295,11 +165,10 @@
 #define BIGGER_THAN_ALL_MTUS	(64*1024)
 
 /*
- * Private data for capturing on Linux SOCK_PACKET or PF_PACKET sockets.
+ * Private data for capturing on Linux PF_PACKET sockets.
  */
 struct pcap_linux {
-	u_int	packets_read;	/* count of packets read with recvfrom() */
-	long	proc_dropped;	/* packets reported dropped by /proc/net/dev */
+	long long sysfs_dropped; /* packets reported dropped by /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors */
 	struct pcap_stat stat;
 
 	char	*device;	/* device name */
@@ -307,10 +176,10 @@
 	int	blocks_to_filter_in_userland;
 	int	must_do_on_close; /* stuff we must do when we close */
 	int	timeout;	/* timeout for buffering */
-	int	sock_packet;	/* using Linux 2.0 compatible interface */
 	int	cooked;		/* using SOCK_DGRAM rather than SOCK_RAW */
 	int	ifindex;	/* interface index of device we're bound to */
 	int	lo_ifindex;	/* interface index of the loopback device */
+	int	netdown;	/* we got an ENETDOWN and haven't resolved it */
 	bpf_u_int32 oldmode;	/* mode to restore when turning monitor mode off */
 	char	*mondevice;	/* mac80211 monitor device we created */
 	u_char	*mmapbuf;	/* memory-mapped region pointer */
@@ -324,90 +193,54 @@
 	unsigned char *current_packet; /* Current packet within the TPACKET_V3 block. Move to next block if NULL. */
 	int packets_left; /* Unhandled packets left within the block from previous call to pcap_read_linux_mmap_v3 in case of TPACKET_V3. */
 #endif
+	int poll_breakloop_fd; /* fd to an eventfd to break from blocking operations */
 };
 
 /*
  * Stuff to do when we close.
  */
-#define MUST_CLEAR_PROMISC	0x00000001	/* clear promiscuous mode */
-#define MUST_CLEAR_RFMON	0x00000002	/* clear rfmon (monitor) mode */
-#define MUST_DELETE_MONIF	0x00000004	/* delete monitor-mode interface */
+#define MUST_CLEAR_RFMON	0x00000001	/* clear rfmon (monitor) mode */
+#define MUST_DELETE_MONIF	0x00000002	/* delete monitor-mode interface */
 
 /*
  * Prototypes for internal functions and methods.
  */
 static int get_if_flags(const char *, bpf_u_int32 *, char *);
-static int is_wifi(int, const char *);
-static void map_arphrd_to_dlt(pcap_t *, int, int, const char *, int);
+static int is_wifi(const char *);
+static void map_arphrd_to_dlt(pcap_t *, int, const char *, int);
 static int pcap_activate_linux(pcap_t *);
-static int activate_old(pcap_t *);
-static int activate_new(pcap_t *);
-static int activate_mmap(pcap_t *, int *);
+static int activate_pf_packet(pcap_t *, int);
+static int setup_mmapped(pcap_t *, int *);
 static int pcap_can_set_rfmon_linux(pcap_t *);
-static int pcap_read_linux(pcap_t *, int, pcap_handler, u_char *);
-static int pcap_read_packet(pcap_t *, pcap_handler, u_char *);
-static int pcap_inject_linux(pcap_t *, const void *, size_t);
+static int pcap_inject_linux(pcap_t *, const void *, int);
 static int pcap_stats_linux(pcap_t *, struct pcap_stat *);
 static int pcap_setfilter_linux(pcap_t *, struct bpf_program *);
 static int pcap_setdirection_linux(pcap_t *, pcap_direction_t);
 static int pcap_set_datalink_linux(pcap_t *, int);
 static void pcap_cleanup_linux(pcap_t *);
 
-/*
- * This is what the header structure looks like in a 64-bit kernel;
- * we use this, rather than struct tpacket_hdr, if we're using
- * TPACKET_V1 in 32-bit code running on a 64-bit kernel.
- */
-struct tpacket_hdr_64 {
-	uint64_t	tp_status;
-	unsigned int	tp_len;
-	unsigned int	tp_snaplen;
-	unsigned short	tp_mac;
-	unsigned short	tp_net;
-	unsigned int	tp_sec;
-	unsigned int	tp_usec;
-};
-
-/*
- * We use this internally as the tpacket version for TPACKET_V1 in
- * 32-bit code on a 64-bit kernel.
- */
-#define TPACKET_V1_64 99
-
 union thdr {
-	struct tpacket_hdr		*h1;
-	struct tpacket_hdr_64		*h1_64;
-#ifdef HAVE_TPACKET2
 	struct tpacket2_hdr		*h2;
-#endif
 #ifdef HAVE_TPACKET3
 	struct tpacket_block_desc	*h3;
 #endif
-	void				*raw;
+	u_char				*raw;
 };
 
-#ifdef HAVE_PACKET_RING
-#define RING_GET_FRAME_AT(h, offset) (((union thdr **)h->buffer)[(offset)])
+#define RING_GET_FRAME_AT(h, offset) (((u_char **)h->buffer)[(offset)])
 #define RING_GET_CURRENT_FRAME(h) RING_GET_FRAME_AT(h, h->offset)
 
 static void destroy_ring(pcap_t *handle);
 static int create_ring(pcap_t *handle, int *status);
 static int prepare_tpacket_socket(pcap_t *handle);
-static void pcap_cleanup_linux_mmap(pcap_t *);
-static int pcap_read_linux_mmap_v1(pcap_t *, int, pcap_handler , u_char *);
-static int pcap_read_linux_mmap_v1_64(pcap_t *, int, pcap_handler , u_char *);
-#ifdef HAVE_TPACKET2
 static int pcap_read_linux_mmap_v2(pcap_t *, int, pcap_handler , u_char *);
-#endif
 #ifdef HAVE_TPACKET3
 static int pcap_read_linux_mmap_v3(pcap_t *, int, pcap_handler , u_char *);
 #endif
-static int pcap_setfilter_linux_mmap(pcap_t *, struct bpf_program *);
-static int pcap_setnonblock_mmap(pcap_t *p, int nonblock);
-static int pcap_getnonblock_mmap(pcap_t *p);
-static void pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h,
+static int pcap_setnonblock_linux(pcap_t *p, int nonblock);
+static int pcap_getnonblock_linux(pcap_t *p);
+static void pcap_oneshot_linux(u_char *user, const struct pcap_pkthdr *h,
     const u_char *bytes);
-#endif
 
 /*
  * In pre-3.0 kernels, the tp_vlan_tci field is set to whatever the
@@ -456,33 +289,29 @@
 #endif
 
 /*
+ * Required select timeout if we're polling for an "interface disappeared"
+ * indication - 1 millisecond.
+ */
+static const struct timeval netdown_timeout = {
+	0, 1000		/* 1000 microseconds = 1 millisecond */
+};
+
+/*
  * Wrap some ioctl calls
  */
-#ifdef HAVE_PF_PACKET_SOCKETS
 static int	iface_get_id(int fd, const char *device, char *ebuf);
-#endif /* HAVE_PF_PACKET_SOCKETS */
 static int	iface_get_mtu(int fd, const char *device, char *ebuf);
 static int 	iface_get_arptype(int fd, const char *device, char *ebuf);
-#ifdef HAVE_PF_PACKET_SOCKETS
 static int 	iface_bind(int fd, int ifindex, char *ebuf, int protocol);
-#ifdef IW_MODE_MONITOR
-static int	has_wext(int sock_fd, const char *device, char *ebuf);
-#endif /* IW_MODE_MONITOR */
 static int	enter_rfmon_mode(pcap_t *handle, int sock_fd,
     const char *device);
-#endif /* HAVE_PF_PACKET_SOCKETS */
 #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
 static int	iface_ethtool_get_ts_info(const char *device, pcap_t *handle,
     char *ebuf);
 #endif
-#ifdef HAVE_PACKET_RING
 static int	iface_get_offload(pcap_t *handle);
-#endif
-static int 	iface_bind_old(int fd, const char *device, char *ebuf);
 
-#ifdef SO_ATTACH_FILTER
-static int	fix_program(pcap_t *handle, struct sock_fprog *fcode,
-    int is_mapped);
+static int	fix_program(pcap_t *handle, struct sock_fprog *fcode);
 static int	fix_offset(pcap_t *handle, struct bpf_insn *p);
 static int	set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode);
 static int	reset_kernel_filter(pcap_t *handle);
@@ -491,14 +320,15 @@
 	= BPF_STMT(BPF_RET | BPF_K, 0);
 static struct sock_fprog	total_fcode
 	= { 1, &total_insn };
-#endif /* SO_ATTACH_FILTER */
+
+static int	iface_dsa_get_proto_info(const char *device, pcap_t *handle);
 
 pcap_t *
 pcap_create_interface(const char *device, char *ebuf)
 {
 	pcap_t *handle;
 
-	handle = pcap_create_common(ebuf, sizeof (struct pcap_linux));
+	handle = PCAP_CREATE_COMMON(ebuf, struct pcap_linux);
 	if (handle == NULL)
 		return NULL;
 
@@ -515,7 +345,6 @@
 	}
 #endif
 
-#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS)
 	/*
 	 * We claim that we support microsecond and nanosecond time
 	 * stamps.
@@ -524,7 +353,6 @@
 	 * microsecond or nanosecond time stamps on arbitrary
 	 * adapters?
 	 */
-	handle->tstamp_precision_count = 2;
 	handle->tstamp_precision_list = malloc(2 * sizeof(u_int));
 	if (handle->tstamp_precision_list == NULL) {
 		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
@@ -534,16 +362,19 @@
 	}
 	handle->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
 	handle->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
-#endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */
+	handle->tstamp_precision_count = 2;
+
+	struct pcap_linux *handlep = handle->priv;
+	handlep->poll_breakloop_fd = eventfd(0, EFD_NONBLOCK);
 
 	return handle;
 }
 
 #ifdef HAVE_LIBNL
 /*
- * If interface {if} is a mac80211 driver, the file
- * /sys/class/net/{if}/phy80211 is a symlink to
- * /sys/class/ieee80211/{phydev}, for some {phydev}.
+ * If interface {if_name} is a mac80211 driver, the file
+ * /sys/class/net/{if_name}/phy80211 is a symlink to
+ * /sys/class/ieee80211/{phydev_name}, for some {phydev_name}.
  *
  * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at
  * least, has a "wmaster0" device and a "wlan0" device; the
@@ -554,24 +385,30 @@
  * airmon-ng searches through /sys/class/net for devices named
  * monN, starting with mon0; as soon as one *doesn't* exist,
  * it chooses that as the monitor device name.  If the "iw"
- * command exists, it does "iw dev {if} interface add {monif}
- * type monitor", where {monif} is the monitor device.  It
- * then (sigh) sleeps .1 second, and then configures the
- * device up.  Otherwise, if /sys/class/ieee80211/{phydev}/add_iface
- * is a file, it writes {mondev}, without a newline, to that file,
- * and again (sigh) sleeps .1 second, and then iwconfig's that
- * device into monitor mode and configures it up.  Otherwise,
- * you can't do monitor mode.
+ * command exists, it does
+ *
+ *    iw dev {if_name} interface add {monif_name} type monitor
+ *
+ * where {monif_name} is the monitor device.  It then (sigh) sleeps
+ * .1 second, and then configures the device up.  Otherwise, if
+ * /sys/class/ieee80211/{phydev_name}/add_iface is a file, it writes
+ * {mondev_name}, without a newline, to that file, and again (sigh)
+ * sleeps .1 second, and then iwconfig's that device into monitor
+ * mode and configures it up.  Otherwise, you can't do monitor mode.
  *
  * All these devices are "glued" together by having the
- * /sys/class/net/{device}/phy80211 links pointing to the same
+ * /sys/class/net/{if_name}/phy80211 links pointing to the same
  * place, so, given a wmaster, wlan, or mon device, you can
  * find the other devices by looking for devices with
  * the same phy80211 link.
  *
  * To turn monitor mode off, delete the monitor interface,
- * either with "iw dev {monif} interface del" or by sending
- * {monif}, with no NL, down /sys/class/ieee80211/{phydev}/remove_iface
+ * either with
+ *
+ *    iw dev {monif_name} interface del
+ *
+ * or by sending {monif_name}, with no NL, down
+ * /sys/class/ieee80211/{phydev_name}/remove_iface
  *
  * Note: if you try to create a monitor device named "monN", and
  * there's already a "monN" device, it fails, as least with
@@ -599,7 +436,7 @@
 	 * Generate the path string for the symlink to the physical device.
 	 */
 	if (asprintf(&pathstr, "/sys/class/net/%s/phy80211", device) == -1) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: Can't generate path name string for /sys/class/net device",
 		    device);
 		return PCAP_ERROR;
@@ -624,39 +461,6 @@
 	return 1;
 }
 
-#ifdef HAVE_LIBNL_SOCKETS
-#define get_nl_errmsg	nl_geterror
-#else
-/* libnl 2.x compatibility code */
-
-#define nl_sock nl_handle
-
-static inline struct nl_handle *
-nl_socket_alloc(void)
-{
-	return nl_handle_alloc();
-}
-
-static inline void
-nl_socket_free(struct nl_handle *h)
-{
-	nl_handle_destroy(h);
-}
-
-#define get_nl_errmsg	strerror
-
-static inline int
-__genl_ctrl_alloc_cache(struct nl_handle *h, struct nl_cache **cache)
-{
-	struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
-	if (!tmp)
-		return -ENOMEM;
-	*cache = tmp;
-	return 0;
-}
-#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
-#endif /* !HAVE_LIBNL_SOCKETS */
-
 struct nl80211_state {
 	struct nl_sock *nl_sock;
 	struct nl_cache *nl_cache;
@@ -670,28 +474,28 @@
 
 	state->nl_sock = nl_socket_alloc();
 	if (!state->nl_sock) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: failed to allocate netlink handle", device);
 		return PCAP_ERROR;
 	}
 
 	if (genl_connect(state->nl_sock)) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: failed to connect to generic netlink", device);
 		goto out_handle_destroy;
 	}
 
 	err = genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache);
 	if (err < 0) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: failed to allocate generic netlink cache: %s",
-		    device, get_nl_errmsg(-err));
+		    device, nl_geterror(-err));
 		goto out_handle_destroy;
 	}
 
 	state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
 	if (!state->nl80211) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: nl80211 not found", device);
 		goto out_cache_free;
 	}
@@ -732,7 +536,7 @@
 
 	msg = nlmsg_alloc();
 	if (!msg) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: failed to allocate netlink msg", device);
 		return PCAP_ERROR;
 	}
@@ -740,16 +544,14 @@
 	genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
 		    0, NL80211_CMD_NEW_INTERFACE, 0);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+DIAG_OFF_NARROWING
 	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice);
+DIAG_ON_NARROWING
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
 
 	err = nl_send_auto_complete(state->nl_sock, msg);
 	if (err < 0) {
-#if defined HAVE_LIBNL_NLE
 		if (err == -NLE_FAILURE) {
-#else
-		if (err == -ENFILE) {
-#endif
 			/*
 			 * Device not available; our caller should just
 			 * keep trying.  (libnl 2.x maps ENFILE to
@@ -764,20 +566,16 @@
 			 * Real failure, not just "that device is not
 			 * available.
 			 */
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			    "%s: nl_send_auto_complete failed adding %s interface: %s",
-			    device, mondevice, get_nl_errmsg(-err));
+			    device, mondevice, nl_geterror(-err));
 			nlmsg_free(msg);
 			return PCAP_ERROR;
 		}
 	}
 	err = nl_wait_for_ack(state->nl_sock);
 	if (err < 0) {
-#if defined HAVE_LIBNL_NLE
 		if (err == -NLE_FAILURE) {
-#else
-		if (err == -ENFILE) {
-#endif
 			/*
 			 * Device not available; our caller should just
 			 * keep trying.  (libnl 2.x maps ENFILE to
@@ -792,9 +590,9 @@
 			 * Real failure, not just "that device is not
 			 * available.
 			 */
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			    "%s: nl_wait_for_ack failed adding %s interface: %s",
-			    device, mondevice, get_nl_errmsg(-err));
+			    device, mondevice, nl_geterror(-err));
 			nlmsg_free(msg);
 			return PCAP_ERROR;
 		}
@@ -821,7 +619,7 @@
 	return 1;
 
 nla_put_failure:
-	pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 	    "%s: nl_put failed adding %s interface",
 	    device, mondevice);
 	nlmsg_free(msg);
@@ -842,7 +640,7 @@
 
 	msg = nlmsg_alloc();
 	if (!msg) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: failed to allocate netlink msg", device);
 		return PCAP_ERROR;
 	}
@@ -853,17 +651,17 @@
 
 	err = nl_send_auto_complete(state->nl_sock, msg);
 	if (err < 0) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: nl_send_auto_complete failed deleting %s interface: %s",
-		    device, mondevice, get_nl_errmsg(-err));
+		    device, mondevice, nl_geterror(-err));
 		nlmsg_free(msg);
 		return PCAP_ERROR;
 	}
 	err = nl_wait_for_ack(state->nl_sock);
 	if (err < 0) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: nl_wait_for_ack failed adding %s interface: %s",
-		    device, mondevice, get_nl_errmsg(-err));
+		    device, mondevice, nl_geterror(-err));
 		nlmsg_free(msg);
 		return PCAP_ERROR;
 	}
@@ -875,177 +673,14 @@
 	return 1;
 
 nla_put_failure:
-	pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 	    "%s: nl_put failed deleting %s interface",
 	    device, mondevice);
 	nlmsg_free(msg);
 	return PCAP_ERROR;
 }
-
-static int
-enter_rfmon_mode_mac80211(pcap_t *handle, int sock_fd, const char *device)
-{
-	struct pcap_linux *handlep = handle->priv;
-	int ret;
-	char phydev_path[PATH_MAX+1];
-	struct nl80211_state nlstate;
-	struct ifreq ifr;
-	u_int n;
-
-	/*
-	 * Is this a mac80211 device?
-	 */
-	ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX);
-	if (ret < 0)
-		return ret;	/* error */
-	if (ret == 0)
-		return 0;	/* no error, but not mac80211 device */
-
-	/*
-	 * XXX - is this already a monN device?
-	 * If so, we're done.
-	 * Is that determined by old Wireless Extensions ioctls?
-	 */
-
-	/*
-	 * OK, it's apparently a mac80211 device.
-	 * Try to find an unused monN device for it.
-	 */
-	ret = nl80211_init(handle, &nlstate, device);
-	if (ret != 0)
-		return ret;
-	for (n = 0; n < UINT_MAX; n++) {
-		/*
-		 * Try mon{n}.
-		 */
-		char mondevice[3+10+1];	/* mon{UINT_MAX}\0 */
-
-		pcap_snprintf(mondevice, sizeof mondevice, "mon%u", n);
-		ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice);
-		if (ret == 1) {
-			/*
-			 * Success.  We don't clean up the libnl state
-			 * yet, as we'll be using it later.
-			 */
-			goto added;
-		}
-		if (ret < 0) {
-			/*
-			 * Hard failure.  Just return ret; handle->errbuf
-			 * has already been set.
-			 */
-			nl80211_cleanup(&nlstate);
-			return ret;
-		}
-	}
-
-	pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
-	    "%s: No free monN interfaces", device);
-	nl80211_cleanup(&nlstate);
-	return PCAP_ERROR;
-
-added:
-
-#if 0
-	/*
-	 * Sleep for .1 seconds.
-	 */
-	delay.tv_sec = 0;
-	delay.tv_nsec = 500000000;
-	nanosleep(&delay, NULL);
-#endif
-
-	/*
-	 * If we haven't already done so, arrange to have
-	 * "pcap_close_all()" called when we exit.
-	 */
-	if (!pcap_do_addexit(handle)) {
-		/*
-		 * "atexit()" failed; don't put the interface
-		 * in rfmon mode, just give up.
-		 */
-		del_mon_if(handle, sock_fd, &nlstate, device,
-		    handlep->mondevice);
-		nl80211_cleanup(&nlstate);
-		return PCAP_ERROR;
-	}
-
-	/*
-	 * Now configure the monitor interface up.
-	 */
-	memset(&ifr, 0, sizeof(ifr));
-	pcap_strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name));
-	if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
-		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "%s: Can't get flags for %s", device,
-		    handlep->mondevice);
-		del_mon_if(handle, sock_fd, &nlstate, device,
-		    handlep->mondevice);
-		nl80211_cleanup(&nlstate);
-		return PCAP_ERROR;
-	}
-	ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
-	if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
-		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "%s: Can't set flags for %s", device,
-		    handlep->mondevice);
-		del_mon_if(handle, sock_fd, &nlstate, device,
-		    handlep->mondevice);
-		nl80211_cleanup(&nlstate);
-		return PCAP_ERROR;
-	}
-
-	/*
-	 * Success.  Clean up the libnl state.
-	 */
-	nl80211_cleanup(&nlstate);
-
-	/*
-	 * Note that we have to delete the monitor device when we close
-	 * the handle.
-	 */
-	handlep->must_do_on_close |= MUST_DELETE_MONIF;
-
-	/*
-	 * Add this to the list of pcaps to close when we exit.
-	 */
-	pcap_add_to_pcaps_to_close(handle);
-
-	return 1;
-}
 #endif /* HAVE_LIBNL */
 
-#ifdef IW_MODE_MONITOR
-/*
- * Bonding devices mishandle unknown ioctls; they fail with ENODEV
- * rather than ENOTSUP, EOPNOTSUPP, or ENOTTY, so Wireless Extensions
- * will fail with ENODEV if we try to do them on a bonding device,
- * making us return a "no such device" indication rather than just
- * saying "no Wireless Extensions".
- *
- * So we check for bonding devices, if we can, before trying those
- * ioctls, by trying a bonding device information query ioctl to see
- * whether it succeeds.
- */
-static int
-is_bonding_device(int fd, const char *device)
-{
-#ifdef BOND_INFO_QUERY_IOCTL
-	struct ifreq ifr;
-	ifbond ifb;
-
-	memset(&ifr, 0, sizeof ifr);
-	pcap_strlcpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
-	memset(&ifb, 0, sizeof ifb);
-	ifr.ifr_data = (caddr_t)&ifb;
-	if (ioctl(fd, BOND_INFO_QUERY_IOCTL, &ifr) == 0)
-		return 1;	/* success, so it's a bonding device */
-#endif /* BOND_INFO_QUERY_IOCTL */
-
-	return 0;	/* no, it's not a bonding device */
-}
-#endif /* IW_MODE_MONITOR */
-
 static int pcap_protocol(pcap_t *handle)
 {
 	int protocol;
@@ -1064,10 +699,6 @@
 	char phydev_path[PATH_MAX+1];
 	int ret;
 #endif
-#ifdef IW_MODE_MONITOR
-	int sock_fd;
-	struct iwreq ireq;
-#endif
 
 	if (strcmp(handle->opt.device, "any") == 0) {
 		/*
@@ -1083,11 +714,6 @@
 	 * we'll just check whether the device appears to be a
 	 * mac80211 device and, if so, assume the device supports
 	 * monitor mode.
-	 *
-	 * wmaster devices don't appear to support the Wireless
-	 * Extensions, but we can create a mon device for a
-	 * wmaster device, so we don't bother checking whether
-	 * a mac80211 device supports the Wireless Extensions.
 	 */
 	ret = get_mac80211_phydev(handle, handle->opt.device, phydev_path,
 	    PATH_MAX);
@@ -1097,229 +723,69 @@
 		return 1;	/* mac80211 device */
 #endif
 
-#ifdef IW_MODE_MONITOR
-	/*
-	 * Bleah.  There doesn't appear to be an ioctl to use to ask
-	 * whether a device supports monitor mode; we'll just do
-	 * SIOCGIWMODE and, if it succeeds, assume the device supports
-	 * monitor mode.
-	 *
-	 * Open a socket on which to attempt to get the mode.
-	 * (We assume that if we have Wireless Extensions support
-	 * we also have PF_PACKET support.)
-	 */
-	sock_fd = socket(PF_PACKET, SOCK_RAW, pcap_protocol(handle));
-	if (sock_fd == -1) {
-		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "socket");
-		return PCAP_ERROR;
-	}
-
-	if (is_bonding_device(sock_fd, handle->opt.device)) {
-		/* It's a bonding device, so don't even try. */
-		close(sock_fd);
-		return 0;
-	}
-
-	/*
-	 * Attempt to get the current mode.
-	 */
-	pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, handle->opt.device,
-	    sizeof ireq.ifr_ifrn.ifrn_name);
-	if (ioctl(sock_fd, SIOCGIWMODE, &ireq) != -1) {
-		/*
-		 * Well, we got the mode; assume we can set it.
-		 */
-		close(sock_fd);
-		return 1;
-	}
-	if (errno == ENODEV) {
-		/* The device doesn't even exist. */
-		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "SIOCGIWMODE failed");
-		close(sock_fd);
-		return PCAP_ERROR_NO_SUCH_DEVICE;
-	}
-	close(sock_fd);
-#endif
 	return 0;
 }
 
 /*
- * Grabs the number of dropped packets by the interface from /proc/net/dev.
+ * Grabs the number of missed packets by the interface from
+ * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors.
  *
- * XXX - what about /sys/class/net/{interface name}/rx_*?  There are
- * individual devices giving, in ASCII, various rx_ and tx_ statistics.
- *
- * Or can we get them in binary form from netlink?
+ * Compared to /proc/net/dev this avoids counting software drops,
+ * but may be unimplemented and just return 0.
+ * The author has found no straigthforward way to check for support.
  */
-static long int
-linux_if_drops(const char * if_name)
-{
-	char buffer[512];
-	FILE *file;
-	char *bufptr, *nameptr, *colonptr;
-	int field_to_convert = 3;
-	long int dropped_pkts = 0;
+static long long int
+linux_get_stat(const char * if_name, const char * stat) {
+	ssize_t bytes_read;
+	int fd;
+	char buffer[PATH_MAX];
 
-	file = fopen("/proc/net/dev", "r");
-	if (!file)
+	snprintf(buffer, sizeof(buffer), "/sys/class/net/%s/statistics/%s", if_name, stat);
+	fd = open(buffer, O_RDONLY);
+	if (fd == -1)
 		return 0;
 
-	while (fgets(buffer, sizeof(buffer), file) != NULL)
-	{
-		/* 	search for 'bytes' -- if its in there, then
-			that means we need to grab the fourth field. otherwise
-			grab the third field. */
-		if (field_to_convert != 4 && strstr(buffer, "bytes"))
-		{
-			field_to_convert = 4;
-			continue;
-		}
+	bytes_read = read(fd, buffer, sizeof(buffer) - 1);
+	close(fd);
+	if (bytes_read == -1)
+		return 0;
+	buffer[bytes_read] = '\0';
 
-		/*
-		 * See whether this line corresponds to this device.
-		 * The line should have zero or more leading blanks,
-		 * followed by a device name, followed by a colon,
-		 * followed by the statistics.
-		 */
-		bufptr = buffer;
-		/* Skip leading blanks */
-		while (*bufptr == ' ')
-			bufptr++;
-		nameptr = bufptr;
-		/* Look for the colon */
-		colonptr = strchr(nameptr, ':');
-		if (colonptr == NULL)
-		{
-			/*
-			 * Not found; this could, for example, be the
-			 * header line.
-			 */
-			continue;
-		}
-		/* Null-terminate the interface name. */
-		*colonptr = '\0';
-		if (strcmp(if_name, nameptr) == 0)
-		{
-			/*
-			 * OK, this line has the statistics for the interface.
-			 * Skip past the interface name.
-			 */
-			bufptr = colonptr + 1;
+	return strtoll(buffer, NULL, 10);
+}
 
-			/* grab the nth field from it */
-			while (--field_to_convert && *bufptr != '\0')
-			{
-				/*
-				 * This isn't the field we want.
-				 * First, skip any leading blanks before
-				 * the field.
-				 */
-				while (*bufptr == ' ')
-					bufptr++;
-
-				/*
-				 * Now skip the non-blank characters of
-				 * the field.
-				 */
-				while (*bufptr != '\0' && *bufptr != ' ')
-					bufptr++;
-			}
-
-			if (field_to_convert == 0)
-			{
-				/*
-				 * We've found the field we want.
-				 * Skip any leading blanks before it.
-				 */
-				while (*bufptr == ' ')
-					bufptr++;
-
-				/*
-				 * Now extract the value, if we have one.
-				 */
-				if (*bufptr != '\0')
-					dropped_pkts = strtol(bufptr, NULL, 10);
-			}
-			break;
-		}
-	}
-
-	fclose(file);
-	return dropped_pkts;
+static long long int
+linux_if_drops(const char * if_name)
+{
+	long long int missed = linux_get_stat(if_name, "rx_missed_errors");
+	long long int fifo = linux_get_stat(if_name, "rx_fifo_errors");
+	return missed + fifo;
 }
 
 
 /*
- * With older kernels promiscuous mode is kind of interesting because we
- * have to reset the interface before exiting. The problem can't really
- * be solved without some daemon taking care of managing usage counts.
- * If we put the interface into promiscuous mode, we set a flag indicating
- * that we must take it out of that mode when the interface is closed,
- * and, when closing the interface, if that flag is set we take it out
- * of promiscuous mode.
- *
- * Even with newer kernels, we have the same issue with rfmon mode.
+ * Monitor mode is kind of interesting because we have to reset the
+ * interface before exiting. The problem can't really be solved without
+ * some daemon taking care of managing usage counts.  If we put the
+ * interface into monitor mode, we set a flag indicating that we must
+ * take it out of that mode when the interface is closed, and, when
+ * closing the interface, if that flag is set we take it out of monitor
+ * mode.
  */
 
 static void	pcap_cleanup_linux( pcap_t *handle )
 {
 	struct pcap_linux *handlep = handle->priv;
-	struct ifreq	ifr;
 #ifdef HAVE_LIBNL
 	struct nl80211_state nlstate;
 	int ret;
 #endif /* HAVE_LIBNL */
-#ifdef IW_MODE_MONITOR
-	int oldflags;
-	struct iwreq ireq;
-#endif /* IW_MODE_MONITOR */
 
 	if (handlep->must_do_on_close != 0) {
 		/*
 		 * There's something we have to do when closing this
 		 * pcap_t.
 		 */
-		if (handlep->must_do_on_close & MUST_CLEAR_PROMISC) {
-			/*
-			 * We put the interface into promiscuous mode;
-			 * take it out of promiscuous mode.
-			 *
-			 * XXX - if somebody else wants it in promiscuous
-			 * mode, this code cannot know that, so it'll take
-			 * it out of promiscuous mode.  That's not fixable
-			 * in 2.0[.x] kernels.
-			 */
-			memset(&ifr, 0, sizeof(ifr));
-			pcap_strlcpy(ifr.ifr_name, handlep->device,
-			    sizeof(ifr.ifr_name));
-			if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
-				fprintf(stderr,
-				    "Can't restore interface %s flags (SIOCGIFFLAGS failed: %s).\n"
-				    "Please adjust manually.\n"
-				    "Hint: This can't happen with Linux >= 2.2.0.\n",
-				    handlep->device, strerror(errno));
-			} else {
-				if (ifr.ifr_flags & IFF_PROMISC) {
-					/*
-					 * Promiscuous mode is currently on;
-					 * turn it off.
-					 */
-					ifr.ifr_flags &= ~IFF_PROMISC;
-					if (ioctl(handle->fd, SIOCSIFFLAGS,
-					    &ifr) == -1) {
-						fprintf(stderr,
-						    "Can't restore interface %s flags (SIOCSIFFLAGS failed: %s).\n"
-						    "Please adjust manually.\n"
-						    "Hint: This can't happen with Linux >= 2.2.0.\n",
-						    handlep->device,
-						    strerror(errno));
-					}
-				}
-			}
-		}
-
 #ifdef HAVE_LIBNL
 		if (handlep->must_do_on_close & MUST_DELETE_MONIF) {
 			ret = nl80211_init(handle, &nlstate, handlep->device);
@@ -1337,68 +803,6 @@
 		}
 #endif /* HAVE_LIBNL */
 
-#ifdef IW_MODE_MONITOR
-		if (handlep->must_do_on_close & MUST_CLEAR_RFMON) {
-			/*
-			 * We put the interface into rfmon mode;
-			 * take it out of rfmon mode.
-			 *
-			 * XXX - if somebody else wants it in rfmon
-			 * mode, this code cannot know that, so it'll take
-			 * it out of rfmon mode.
-			 */
-
-			/*
-			 * First, take the interface down if it's up;
-			 * otherwise, we might get EBUSY.
-			 * If we get errors, just drive on and print
-			 * a warning if we can't restore the mode.
-			 */
-			oldflags = 0;
-			memset(&ifr, 0, sizeof(ifr));
-			pcap_strlcpy(ifr.ifr_name, handlep->device,
-			    sizeof(ifr.ifr_name));
-			if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) != -1) {
-				if (ifr.ifr_flags & IFF_UP) {
-					oldflags = ifr.ifr_flags;
-					ifr.ifr_flags &= ~IFF_UP;
-					if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1)
-						oldflags = 0;	/* didn't set, don't restore */
-				}
-			}
-
-			/*
-			 * Now restore the mode.
-			 */
-			pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, handlep->device,
-			    sizeof ireq.ifr_ifrn.ifrn_name);
-			ireq.u.mode = handlep->oldmode;
-			if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) {
-				/*
-				 * Scientist, you've failed.
-				 */
-				fprintf(stderr,
-				    "Can't restore interface %s wireless mode (SIOCSIWMODE failed: %s).\n"
-				    "Please adjust manually.\n",
-				    handlep->device, strerror(errno));
-			}
-
-			/*
-			 * Now bring the interface back up if we brought
-			 * it down.
-			 */
-			if (oldflags != 0) {
-				ifr.ifr_flags = oldflags;
-				if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) {
-					fprintf(stderr,
-					    "Can't bring interface %s back up (SIOCSIFFLAGS failed: %s).\n"
-					    "Please adjust manually.\n",
-					    handlep->device, strerror(errno));
-				}
-			}
-		}
-#endif /* IW_MODE_MONITOR */
-
 		/*
 		 * Take this pcap out of the list of pcaps for which we
 		 * have to take the interface out of some mode.
@@ -1406,6 +810,19 @@
 		pcap_remove_from_pcaps_to_close(handle);
 	}
 
+	if (handle->fd != -1) {
+		/*
+		 * Destroy the ring buffer (assuming we've set it up),
+		 * and unmap it if it's mapped.
+		 */
+		destroy_ring(handle);
+	}
+
+	if (handlep->oneshot_buffer != NULL) {
+		free(handlep->oneshot_buffer);
+		handlep->oneshot_buffer = NULL;
+	}
+
 	if (handlep->mondevice != NULL) {
 		free(handlep->mondevice);
 		handlep->mondevice = NULL;
@@ -1414,9 +831,49 @@
 		free(handlep->device);
 		handlep->device = NULL;
 	}
+
+	close(handlep->poll_breakloop_fd);
 	pcap_cleanup_live_common(handle);
 }
 
+#ifdef HAVE_TPACKET3
+/*
+ * Some versions of TPACKET_V3 have annoying bugs/misfeatures
+ * around which we have to work.  Determine if we have those
+ * problems or not.
+ * 3.19 is the first release with a fixed version of
+ * TPACKET_V3.  We treat anything before that as
+ * not having a fixed version; that may really mean
+ * it has *no* version.
+ */
+static int has_broken_tpacket_v3(void)
+{
+	struct utsname utsname;
+	const char *release;
+	long major, minor;
+	int matches, verlen;
+
+	/* No version information, assume broken. */
+	if (uname(&utsname) == -1)
+		return 1;
+	release = utsname.release;
+
+	/* A malformed version, ditto. */
+	matches = sscanf(release, "%ld.%ld%n", &major, &minor, &verlen);
+	if (matches != 2)
+		return 1;
+	if (release[verlen] != '.' && release[verlen] != '\0')
+		return 1;
+
+	/* OK, a fixed version. */
+	if (major > 3 || (major == 3 && minor >= 19))
+		return 0;
+
+	/* Too old :( */
+	return 1;
+}
+#endif
+
 /*
  * Set the timeout to be used in poll() with memory-mapped packet capture.
  */
@@ -1424,45 +881,7 @@
 set_poll_timeout(struct pcap_linux *handlep)
 {
 #ifdef HAVE_TPACKET3
-	struct utsname utsname;
-	char *version_component, *endp;
-	int major, minor;
-	int broken_tpacket_v3 = 1;
-
-	/*
-	 * Some versions of TPACKET_V3 have annoying bugs/misfeatures
-	 * around which we have to work.  Determine if we have those
-	 * problems or not.
-	 */
-	if (uname(&utsname) == 0) {
-		/*
-		 * 3.19 is the first release with a fixed version of
-		 * TPACKET_V3.  We treat anything before that as
-		 * not haveing a fixed version; that may really mean
-		 * it has *no* version.
-		 */
-		version_component = utsname.release;
-		major = strtol(version_component, &endp, 10);
-		if (endp != version_component && *endp == '.') {
-			/*
-			 * OK, that was a valid major version.
-			 * Get the minor version.
-			 */
-			version_component = endp + 1;
-			minor = strtol(version_component, &endp, 10);
-			if (endp != version_component &&
-			    (*endp == '.' || *endp == '\0')) {
-				/*
-				 * OK, that was a valid minor version.
-				 * Is this 3.19 or newer?
-				 */
-				if (major >= 4 || (major == 3 && minor >= 19)) {
-					/* Yes. TPACKET_V3 works correctly. */
-					broken_tpacket_v3 = 0;
-				}
-			}
-		}
-	}
+	int broken_tpacket_v3 = has_broken_tpacket_v3();
 #endif
 	if (handlep->timeout == 0) {
 #ifdef HAVE_TPACKET3
@@ -1505,11 +924,21 @@
 	}
 }
 
+static void pcap_breakloop_linux(pcap_t *handle)
+{
+	pcap_breakloop_common(handle);
+	struct pcap_linux *handlep = handle->priv;
+
+	uint64_t value = 1;
+	/* XXX - what if this fails? */
+	(void)write(handlep->poll_breakloop_fd, &value, sizeof(value));
+}
+
 /*
  *  Get a handle for a live capture from the given device. You can
  *  pass NULL as device to get all packages (without link level
  *  information of course). If you pass 1 as promisc the interface
- *  will be set to promiscous mode (XXX: I think this usage should
+ *  will be set to promiscuous mode (XXX: I think this usage should
  *  be deprecated and functions be added to select that later allow
  *  modification of that values -- Torsten).
  */
@@ -1518,8 +947,10 @@
 {
 	struct pcap_linux *handlep = handle->priv;
 	const char	*device;
+	int		is_any_device;
 	struct ifreq	ifr;
 	int		status = 0;
+	int		status2 = 0;
 	int		ret;
 
 	device = handle->opt.device;
@@ -1551,31 +982,6 @@
 	if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
 		handle->snapshot = MAXIMUM_SNAPLEN;
 
-	handle->inject_op = pcap_inject_linux;
-	handle->setfilter_op = pcap_setfilter_linux;
-	handle->setdirection_op = pcap_setdirection_linux;
-	handle->set_datalink_op = pcap_set_datalink_linux;
-	handle->getnonblock_op = pcap_getnonblock_fd;
-	handle->setnonblock_op = pcap_setnonblock_fd;
-	handle->cleanup_op = pcap_cleanup_linux;
-	handle->read_op = pcap_read_linux;
-	handle->stats_op = pcap_stats_linux;
-
-	/*
-	 * The "any" device is a special device which causes us not
-	 * to bind to a particular device and thus to look at all
-	 * devices.
-	 */
-	if (strcmp(device, "any") == 0) {
-		if (handle->opt.promisc) {
-			handle->opt.promisc = 0;
-			/* Just a warning. */
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
-			    "Promiscuous mode not supported on the \"any\" device");
-			status = PCAP_WARNING_PROMISC_NOTSUP;
-		}
-	}
-
 	handlep->device	= strdup(device);
 	if (handlep->device == NULL) {
 		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
@@ -1584,118 +990,101 @@
 		goto fail;
 	}
 
+	/*
+	 * The "any" device is a special device which causes us not
+	 * to bind to a particular device and thus to look at all
+	 * devices.
+	 */
+	is_any_device = (strcmp(device, "any") == 0);
+	if (is_any_device) {
+		if (handle->opt.promisc) {
+			handle->opt.promisc = 0;
+			/* Just a warning. */
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+			    "Promiscuous mode not supported on the \"any\" device");
+			status = PCAP_WARNING_PROMISC_NOTSUP;
+		}
+	}
+
 	/* copy timeout value */
 	handlep->timeout = handle->opt.timeout;
 
 	/*
 	 * If we're in promiscuous mode, then we probably want
 	 * to see when the interface drops packets too, so get an
-	 * initial count from /proc/net/dev
+	 * initial count from
+	 * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors
 	 */
 	if (handle->opt.promisc)
-		handlep->proc_dropped = linux_if_drops(handlep->device);
+		handlep->sysfs_dropped = linux_if_drops(handlep->device);
 
 	/*
-	 * Current Linux kernels use the protocol family PF_PACKET to
-	 * allow direct access to all packets on the network while
-	 * older kernels had a special socket type SOCK_PACKET to
-	 * implement this feature.
-	 * While this old implementation is kind of obsolete we need
-	 * to be compatible with older kernels for a while so we are
-	 * trying both methods with the newer method preferred.
+	 * If the "any" device is specified, try to open a SOCK_DGRAM.
+	 * Otherwise, open a SOCK_RAW.
 	 */
-	ret = activate_new(handle);
+	ret = activate_pf_packet(handle, is_any_device);
 	if (ret < 0) {
 		/*
-		 * Fatal error with the new way; just fail.
-		 * ret has the error return; if it's PCAP_ERROR,
-		 * handle->errbuf has been set appropriately.
+		 * Fatal error; the return value is the error code,
+		 * and handle->errbuf has been set to an appropriate
+		 * error message.
 		 */
 		status = ret;
 		goto fail;
 	}
-	if (ret == 1) {
-		/*
-		 * Success.
-		 * Try to use memory-mapped access.
-		 */
-		switch (activate_mmap(handle, &status)) {
-
-		case 1:
-			/*
-			 * We succeeded.  status has been
-			 * set to the status to return,
-			 * which might be 0, or might be
-			 * a PCAP_WARNING_ value.
-			 *
-			 * Set the timeout to use in poll() before
-			 * returning.
-			 */
-			set_poll_timeout(handlep);
-			return status;
-
-		case 0:
-			/*
-			 * Kernel doesn't support it - just continue
-			 * with non-memory-mapped access.
-			 */
-			break;
-
-		case -1:
-			/*
-			 * We failed to set up to use it, or the kernel
-			 * supports it, but we failed to enable it.
-			 * status has been set to the error status to
-			 * return and, if it's PCAP_ERROR, handle->errbuf
-			 * contains the error message.
-			 */
-			goto fail;
-		}
-	}
-	else if (ret == 0) {
-		/* Non-fatal error; try old way */
-		if ((ret = activate_old(handle)) != 1) {
-			/*
-			 * Both methods to open the packet socket failed.
-			 * Tidy up and report our failure (handle->errbuf
-			 * is expected to be set by the functions above).
-			 */
-			status = ret;
-			goto fail;
-		}
-	}
-
 	/*
-	 * We set up the socket, but not with memory-mapped access.
+	 * Success.
+	 * Try to set up memory-mapped access.
 	 */
-	if (handle->opt.buffer_size != 0) {
+	ret = setup_mmapped(handle, &status);
+	if (ret == -1) {
 		/*
-		 * Set the socket buffer size to the specified value.
+		 * We failed to set up to use it, or the
+		 * kernel supports it, but we failed to
+		 * enable it.  status has been set to the
+		 * error status to return and, if it's
+		 * PCAP_ERROR, handle->errbuf contains
+		 * the error message.
 		 */
-		if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF,
-		    &handle->opt.buffer_size,
-		    sizeof(handle->opt.buffer_size)) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "SO_RCVBUF");
-			status = PCAP_ERROR;
-			goto fail;
-		}
-	}
-
-	/* Allocate the buffer */
-
-	handle->buffer	 = malloc(handle->bufsize + handle->offset);
-	if (!handle->buffer) {
-		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "malloc");
-		status = PCAP_ERROR;
 		goto fail;
 	}
 
 	/*
-	 * "handle->fd" is a socket, so "select()" and "poll()"
-	 * should work on it.
+	 * We succeeded.  status has been set to the status to return,
+	 * which might be 0, or might be a PCAP_WARNING_ value.
 	 */
+	/*
+	 * Now that we have activated the mmap ring, we can
+	 * set the correct protocol.
+	 */
+	if ((status2 = iface_bind(handle->fd, handlep->ifindex,
+	    handle->errbuf, pcap_protocol(handle))) != 0) {
+		status = status2;
+		goto fail;
+	}
+
+	handle->inject_op = pcap_inject_linux;
+	handle->setfilter_op = pcap_setfilter_linux;
+	handle->setdirection_op = pcap_setdirection_linux;
+	handle->set_datalink_op = pcap_set_datalink_linux;
+	handle->setnonblock_op = pcap_setnonblock_linux;
+	handle->getnonblock_op = pcap_getnonblock_linux;
+	handle->cleanup_op = pcap_cleanup_linux;
+	handle->stats_op = pcap_stats_linux;
+	handle->breakloop_op = pcap_breakloop_linux;
+
+	switch (handlep->tp_version) {
+
+	case TPACKET_V2:
+		handle->read_op = pcap_read_linux_mmap_v2;
+		break;
+#ifdef HAVE_TPACKET3
+	case TPACKET_V3:
+		handle->read_op = pcap_read_linux_mmap_v3;
+		break;
+#endif
+	}
+	handle->oneshot_callback = pcap_oneshot_linux;
 	handle->selectable_fd = handle->fd;
 
 	return status;
@@ -1705,21 +1094,6 @@
 	return status;
 }
 
-/*
- *  Read at most max_packets from the capture stream and call the callback
- *  for each of them. Returns the number of packets handled or -1 if an
- *  error occured.
- */
-static int
-pcap_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user)
-{
-	/*
-	 * Currently, on Linux only one packet is delivered per read,
-	 * so we don't loop.
-	 */
-	return pcap_read_packet(handle, callback, user);
-}
-
 static int
 pcap_set_datalink_linux(pcap_t *handle, int dlt)
 {
@@ -1780,434 +1154,83 @@
 }
 
 /*
- *  Read a packet from the socket calling the handler provided by
- *  the user. Returns the number of packets received or -1 if an
- *  error occured.
+ * Check whether the device to which the pcap_t is bound still exists.
+ * We do so by asking what address the socket is bound to, and checking
+ * whether the ifindex in the address is -1, meaning "that device is gone",
+ * or some other value, meaning "that device still exists".
  */
 static int
-pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
+device_still_exists(pcap_t *handle)
 {
-	struct pcap_linux	*handlep = handle->priv;
-	u_char			*bp;
-	int			offset;
-#ifdef HAVE_PF_PACKET_SOCKETS
-	struct sockaddr_ll	from;
-#else
-	struct sockaddr		from;
-#endif
-#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
-	struct iovec		iov;
-	struct msghdr		msg;
-	struct cmsghdr		*cmsg;
-	union {
-		struct cmsghdr	cmsg;
-		char		buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))];
-	} cmsg_buf;
-#else /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
-	socklen_t		fromlen;
-#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
-	int			packet_len, caplen;
-	struct pcap_pkthdr	pcap_header;
-
-        struct bpf_aux_data     aux_data;
-#ifdef HAVE_PF_PACKET_SOCKETS
-	/*
-	 * If this is a cooked device, leave extra room for a
-	 * fake packet header.
-	 */
-	if (handlep->cooked) {
-		if (handle->linktype == DLT_LINUX_SLL2)
-			offset = SLL2_HDR_LEN;
-		else
-			offset = SLL_HDR_LEN;
-	} else
-		offset = 0;
-#else
-	/*
-	 * This system doesn't have PF_PACKET sockets, so it doesn't
-	 * support cooked devices.
-	 */
-	offset = 0;
-#endif
+	struct pcap_linux *handlep = handle->priv;
+	struct sockaddr_ll addr;
+	socklen_t addr_len;
 
 	/*
-	 * Receive a single packet from the kernel.
-	 * We ignore EINTR, as that might just be due to a signal
-	 * being delivered - if the signal should interrupt the
-	 * loop, the signal handler should call pcap_breakloop()
-	 * to set handle->break_loop (we ignore it on other
-	 * platforms as well).
-	 * We also ignore ENETDOWN, so that we can continue to
-	 * capture traffic if the interface goes down and comes
-	 * back up again; comments in the kernel indicate that
-	 * we'll just block waiting for packets if we try to
-	 * receive from a socket that delivered ENETDOWN, and,
-	 * if we're using a memory-mapped buffer, we won't even
-	 * get notified of "network down" events.
+	 * If handlep->ifindex is -1, the socket isn't bound, meaning
+	 * we're capturing on the "any" device; that device never
+	 * disappears.  (It should also never be configured down, so
+	 * we shouldn't even get here, but let's make sure.)
 	 */
-	bp = (u_char *)handle->buffer + handle->offset;
+	if (handlep->ifindex == -1)
+		return (1);	/* it's still here */
 
-#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
-	msg.msg_name		= &from;
-	msg.msg_namelen		= sizeof(from);
-	msg.msg_iov		= &iov;
-	msg.msg_iovlen		= 1;
-	msg.msg_control		= &cmsg_buf;
-	msg.msg_controllen	= sizeof(cmsg_buf);
-	msg.msg_flags		= 0;
-
-	iov.iov_len		= handle->bufsize - offset;
-	iov.iov_base		= bp + offset;
-#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
-
-	do {
+	/*
+	 * OK, now try to get the address for the socket.
+	 */
+	addr_len = sizeof (addr);
+	if (getsockname(handle->fd, (struct sockaddr *) &addr, &addr_len) == -1) {
 		/*
-		 * Has "pcap_breakloop()" been called?
+		 * Error - report an error and return -1.
 		 */
-		if (handle->break_loop) {
-			/*
-			 * Yes - clear the flag that indicates that it has,
-			 * and return PCAP_ERROR_BREAK as an indication that
-			 * we were told to break out of the loop.
-			 */
-			handle->break_loop = 0;
-			return PCAP_ERROR_BREAK;
-		}
-
-#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
-		packet_len = recvmsg(handle->fd, &msg, MSG_TRUNC);
-#else /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
-		fromlen = sizeof(from);
-		packet_len = recvfrom(
-			handle->fd, bp + offset,
-			handle->bufsize - offset, MSG_TRUNC,
-			(struct sockaddr *) &from, &fromlen);
-#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
-	} while (packet_len == -1 && errno == EINTR);
-
-	/* Check if an error occured */
-
-	if (packet_len == -1) {
-		switch (errno) {
-
-		case EAGAIN:
-			return 0;	/* no packet there */
-
-		case ENETDOWN:
-			/*
-			 * The device on which we're capturing went away.
-			 *
-			 * XXX - we should really return
-			 * PCAP_ERROR_IFACE_NOT_UP, but pcap_dispatch()
-			 * etc. aren't defined to return that.
-			 */
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
-				"The interface went down");
-			return PCAP_ERROR;
-
-		default:
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "recvfrom");
-			return PCAP_ERROR;
-		}
+		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "getsockname failed");
+		return (-1);
 	}
-
-#ifdef HAVE_PF_PACKET_SOCKETS
-	if (!handlep->sock_packet) {
+	if (addr.sll_ifindex == -1) {
 		/*
-		 * Unfortunately, there is a window between socket() and
-		 * bind() where the kernel may queue packets from any
-		 * interface.  If we're bound to a particular interface,
-		 * discard packets not from that interface.
-		 *
-		 * (If socket filters are supported, we could do the
-		 * same thing we do when changing the filter; however,
-		 * that won't handle packet sockets without socket
-		 * filter support, and it's a bit more complicated.
-		 * It would save some instructions per packet, however.)
+		 * This means the device went away.
 		 */
-		if (handlep->ifindex != -1 &&
-		    from.sll_ifindex != handlep->ifindex)
-			return 0;
-
-		/*
-		 * Do checks based on packet direction.
-		 * We can only do this if we're using PF_PACKET; the
-		 * address returned for SOCK_PACKET is a "sockaddr_pkt"
-		 * which lacks the relevant packet type information.
-		 */
-		if (!linux_check_direction(handle, &from))
-			return 0;
-	}
-#endif
-
-#ifdef HAVE_PF_PACKET_SOCKETS
-	/*
-	 * If this is a cooked device, fill in the fake packet header.
-	 */
-	if (handlep->cooked) {
-		/*
-		 * Add the length of the fake header to the length
-		 * of packet data we read.
-		 */
-		if (handle->linktype == DLT_LINUX_SLL2) {
-			struct sll2_header	*hdrp;
-
-			packet_len += SLL2_HDR_LEN;
-
-			hdrp = (struct sll2_header *)bp;
-			hdrp->sll2_protocol = from.sll_protocol;
-			hdrp->sll2_reserved_mbz = 0;
-			hdrp->sll2_if_index = htonl(from.sll_ifindex);
-			hdrp->sll2_hatype = htons(from.sll_hatype);
-			hdrp->sll2_pkttype = from.sll_pkttype;
-			hdrp->sll2_halen = from.sll_halen;
-			memcpy(hdrp->sll2_addr, from.sll_addr,
-			    (from.sll_halen > SLL_ADDRLEN) ?
-			      SLL_ADDRLEN :
-			      from.sll_halen);
-		} else {
-			struct sll_header	*hdrp;
-
-			packet_len += SLL_HDR_LEN;
-
-			hdrp = (struct sll_header *)bp;
-			hdrp->sll_pkttype = htons(from.sll_pkttype);
-			hdrp->sll_hatype = htons(from.sll_hatype);
-			hdrp->sll_halen = htons(from.sll_halen);
-			memcpy(hdrp->sll_addr, from.sll_addr,
-			    (from.sll_halen > SLL_ADDRLEN) ?
-			      SLL_ADDRLEN :
-			      from.sll_halen);
-			hdrp->sll_protocol = from.sll_protocol;
-		}
+		return (0);
 	}
 
 	/*
-	 * Start out with no VLAN information.
+	 * The device presumably just went down.
 	 */
-	aux_data.vlan_tag_present = 0;
-	aux_data.vlan_tag = 0;
-#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
-	if (handlep->vlan_offset != -1) {
-		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
-			struct tpacket_auxdata *aux;
-			unsigned int len;
-			struct vlan_tag *tag;
-
-			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) ||
-			    cmsg->cmsg_level != SOL_PACKET ||
-			    cmsg->cmsg_type != PACKET_AUXDATA) {
-				/*
-				 * This isn't a PACKET_AUXDATA auxiliary
-				 * data item.
-				 */
-				continue;
-			}
-
-			aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
-			if (!VLAN_VALID(aux, aux)) {
-				/*
-				 * There is no VLAN information in the
-				 * auxiliary data.
-				 */
-				continue;
-			}
-
-			len = (u_int)packet_len > iov.iov_len ? iov.iov_len : (u_int)packet_len;
-			if (len < (u_int)handlep->vlan_offset)
-				break;
-
-			/*
-			 * Move everything in the header, except the
-			 * type field, down VLAN_TAG_LEN bytes, to
-			 * allow us to insert the VLAN tag between
-			 * that stuff and the type field.
-			 */
-			bp -= VLAN_TAG_LEN;
-			memmove(bp, bp + VLAN_TAG_LEN, handlep->vlan_offset);
-
-			/*
-			 * Now insert the tag.
-			 */
-			tag = (struct vlan_tag *)(bp + handlep->vlan_offset);
-			tag->vlan_tpid = htons(VLAN_TPID(aux, aux));
-			tag->vlan_tci = htons(aux->tp_vlan_tci);
-
-			/*
-			 * Save a flag indicating that we have a VLAN tag,
-			 * and the VLAN TCI, to bpf_aux_data struct for
-			 * use by the BPF filter if we're doing the
-			 * filtering in userland.
-			 */
-			aux_data.vlan_tag_present = 1;
-			aux_data.vlan_tag = htons(aux->tp_vlan_tci) & 0x0fff;
-
-			/*
-			 * Add the tag to the packet lengths.
-			 */
-			packet_len += VLAN_TAG_LEN;
-		}
-	}
-#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
-#endif /* HAVE_PF_PACKET_SOCKETS */
-
-	/*
-	 * XXX: According to the kernel source we should get the real
-	 * packet len if calling recvfrom with MSG_TRUNC set. It does
-	 * not seem to work here :(, but it is supported by this code
-	 * anyway.
-	 * To be honest the code RELIES on that feature so this is really
-	 * broken with 2.2.x kernels.
-	 * I spend a day to figure out what's going on and I found out
-	 * that the following is happening:
-	 *
-	 * The packet comes from a random interface and the packet_rcv
-	 * hook is called with a clone of the packet. That code inserts
-	 * the packet into the receive queue of the packet socket.
-	 * If a filter is attached to that socket that filter is run
-	 * first - and there lies the problem. The default filter always
-	 * cuts the packet at the snaplen:
-	 *
-	 * # tcpdump -d
-	 * (000) ret      #68
-	 *
-	 * So the packet filter cuts down the packet. The recvfrom call
-	 * says "hey, it's only 68 bytes, it fits into the buffer" with
-	 * the result that we don't get the real packet length. This
-	 * is valid at least until kernel 2.2.17pre6.
-	 *
-	 * We currently handle this by making a copy of the filter
-	 * program, fixing all "ret" instructions with non-zero
-	 * operands to have an operand of MAXIMUM_SNAPLEN so that the
-	 * filter doesn't truncate the packet, and supplying that modified
-	 * filter to the kernel.
-	 */
-
-	caplen = packet_len;
-	if (caplen > handle->snapshot)
-		caplen = handle->snapshot;
-
-	/* Run the packet filter if not using kernel filter */
-	if (handlep->filter_in_userland && handle->fcode.bf_insns) {
-		if (bpf_filter_with_aux_data(handle->fcode.bf_insns, bp,
-		    packet_len, caplen, &aux_data) == 0) {
-			/* rejected by filter */
-			return 0;
-		}
-	}
-
-	/* Fill in our own header data */
-
-	/* get timestamp for this packet */
-#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS)
-	if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) {
-		if (ioctl(handle->fd, SIOCGSTAMPNS, &pcap_header.ts) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "SIOCGSTAMPNS");
-			return PCAP_ERROR;
-		}
-        } else
-#endif
-	{
-		if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "SIOCGSTAMP");
-			return PCAP_ERROR;
-		}
-        }
-
-	pcap_header.caplen	= caplen;
-	pcap_header.len		= packet_len;
-
-	/*
-	 * Count the packet.
-	 *
-	 * Arguably, we should count them before we check the filter,
-	 * as on many other platforms "ps_recv" counts packets
-	 * handed to the filter rather than packets that passed
-	 * the filter, but if filtering is done in the kernel, we
-	 * can't get a count of packets that passed the filter,
-	 * and that would mean the meaning of "ps_recv" wouldn't
-	 * be the same on all Linux systems.
-	 *
-	 * XXX - it's not the same on all systems in any case;
-	 * ideally, we should have a "get the statistics" call
-	 * that supplies more counts and indicates which of them
-	 * it supplies, so that we supply a count of packets
-	 * handed to the filter only on platforms where that
-	 * information is available.
-	 *
-	 * We count them here even if we can get the packet count
-	 * from the kernel, as we can only determine at run time
-	 * whether we'll be able to get it from the kernel (if
-	 * HAVE_STRUCT_TPACKET_STATS isn't defined, we can't get it from
-	 * the kernel, but if it is defined, the library might
-	 * have been built with a 2.4 or later kernel, but we
-	 * might be running on a 2.2[.x] kernel without Alexey
-	 * Kuznetzov's turbopacket patches, and thus the kernel
-	 * might not be able to supply those statistics).  We
-	 * could, I guess, try, when opening the socket, to get
-	 * the statistics, and if we can not increment the count
-	 * here, but it's not clear that always incrementing
-	 * the count is more expensive than always testing a flag
-	 * in memory.
-	 *
-	 * We keep the count in "handlep->packets_read", and use that
-	 * for "ps_recv" if we can't get the statistics from the kernel.
-	 * We do that because, if we *can* get the statistics from
-	 * the kernel, we use "handlep->stat.ps_recv" and
-	 * "handlep->stat.ps_drop" as running counts, as reading the
-	 * statistics from the kernel resets the kernel statistics,
-	 * and if we directly increment "handlep->stat.ps_recv" here,
-	 * that means it will count packets *twice* on systems where
-	 * we can get kernel statistics - once here, and once in
-	 * pcap_stats_linux().
-	 */
-	handlep->packets_read++;
-
-	/* Call the user supplied callback function */
-	callback(userdata, &pcap_header, bp);
-
-	return 1;
+	return (1);
 }
 
 static int
-pcap_inject_linux(pcap_t *handle, const void *buf, size_t size)
+pcap_inject_linux(pcap_t *handle, const void *buf, int size)
 {
 	struct pcap_linux *handlep = handle->priv;
 	int ret;
 
-#ifdef HAVE_PF_PACKET_SOCKETS
-	if (!handlep->sock_packet) {
-		/* PF_PACKET socket */
-		if (handlep->ifindex == -1) {
-			/*
-			 * We don't support sending on the "any" device.
-			 */
-			pcap_strlcpy(handle->errbuf,
-			    "Sending packets isn't supported on the \"any\" device",
-			    PCAP_ERRBUF_SIZE);
-			return (-1);
-		}
-
-		if (handlep->cooked) {
-			/*
-			 * We don't support sending on cooked-mode sockets.
-			 *
-			 * XXX - how do you send on a bound cooked-mode
-			 * socket?
-			 * Is a "sendto()" required there?
-			 */
-			pcap_strlcpy(handle->errbuf,
-			    "Sending packets isn't supported in cooked mode",
-			    PCAP_ERRBUF_SIZE);
-			return (-1);
-		}
+	if (handlep->ifindex == -1) {
+		/*
+		 * We don't support sending on the "any" device.
+		 */
+		pcap_strlcpy(handle->errbuf,
+		    "Sending packets isn't supported on the \"any\" device",
+		    PCAP_ERRBUF_SIZE);
+		return (-1);
 	}
-#endif
 
-	ret = send(handle->fd, buf, size, 0);
+	if (handlep->cooked) {
+		/*
+		 * We don't support sending on cooked-mode sockets.
+		 *
+		 * XXX - how do you send on a bound cooked-mode
+		 * socket?
+		 * Is a "sendto()" required there?
+		 */
+		pcap_strlcpy(handle->errbuf,
+		    "Sending packets isn't supported in cooked mode",
+		    PCAP_ERRBUF_SIZE);
+		return (-1);
+	}
+
+	ret = (int)send(handle->fd, buf, size, 0);
 	if (ret == -1) {
 		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    errno, "send");
@@ -2218,27 +1241,20 @@
 
 /*
  *  Get the statistics for the given packet capture handle.
- *  Reports the number of dropped packets iff the kernel supports
- *  the PACKET_STATISTICS "getsockopt()" argument (2.4 and later
- *  kernels, and 2.2[.x] kernels with Alexey Kuznetzov's turbopacket
- *  patches); otherwise, that information isn't available, and we lie
- *  and report 0 as the count of dropped packets.
  */
 static int
 pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
 {
 	struct pcap_linux *handlep = handle->priv;
-#ifdef HAVE_STRUCT_TPACKET_STATS
 #ifdef HAVE_TPACKET3
 	/*
-	 * For sockets using TPACKET_V1 or TPACKET_V2, the extra
-	 * stuff at the end of a struct tpacket_stats_v3 will not
-	 * be filled in, and we don't look at it so this is OK even
-	 * for those sockets.  In addition, the PF_PACKET socket
-	 * code in the kernel only uses the length parameter to
-	 * compute how much data to copy out and to indicate how
-	 * much data was copied out, so it's OK to base it on the
-	 * size of a struct tpacket_stats.
+	 * For sockets using TPACKET_V2, the extra stuff at the end
+	 * of a struct tpacket_stats_v3 will not be filled in, and
+	 * we don't look at it so this is OK even for those sockets.
+	 * In addition, the PF_PACKET socket code in the kernel only
+	 * uses the length parameter to compute how much data to
+	 * copy out and to indicate how much data was copied out, so
+	 * it's OK to base it on the size of a struct tpacket_stats.
 	 *
 	 * XXX - it's probably OK, in fact, to just use a
 	 * struct tpacket_stats for V3 sockets, as we don't
@@ -2249,52 +1265,77 @@
 	struct tpacket_stats kstats;
 #endif /* HAVE_TPACKET3 */
 	socklen_t len = sizeof (struct tpacket_stats);
-#endif /* HAVE_STRUCT_TPACKET_STATS */
 
-	long if_dropped = 0;
+	long long if_dropped = 0;
 
 	/*
-	 *	To fill in ps_ifdrop, we parse /proc/net/dev for the number
+	 * To fill in ps_ifdrop, we parse
+	 * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors
+	 * for the numbers
 	 */
 	if (handle->opt.promisc)
 	{
-		if_dropped = handlep->proc_dropped;
-		handlep->proc_dropped = linux_if_drops(handlep->device);
-		handlep->stat.ps_ifdrop += (handlep->proc_dropped - if_dropped);
+		/*
+		 * XXX - is there any reason to do this by remembering
+		 * the last counts value, subtracting it from the
+		 * current counts value, and adding that to stat.ps_ifdrop,
+		 * maintaining stat.ps_ifdrop as a count, rather than just
+		 * saving the *initial* counts value and setting
+		 * stat.ps_ifdrop to the difference between the current
+		 * value and the initial value?
+		 *
+		 * One reason might be to handle the count wrapping
+		 * around, on platforms where the count is 32 bits
+		 * and where you might get more than 2^32 dropped
+		 * packets; is there any other reason?
+		 *
+		 * (We maintain the count as a long long int so that,
+		 * if the kernel maintains the counts as 64-bit even
+		 * on 32-bit platforms, we can handle the real count.
+		 *
+		 * Unfortunately, we can't report 64-bit counts; we
+		 * need a better API for reporting statistics, such as
+		 * one that reports them in a style similar to the
+		 * pcapng Interface Statistics Block, so that 1) the
+		 * counts are 64-bit, 2) it's easier to add new statistics
+		 * without breaking the ABI, and 3) it's easier to
+		 * indicate to a caller that wants one particular
+		 * statistic that it's not available by just not supplying
+		 * it.)
+		 */
+		if_dropped = handlep->sysfs_dropped;
+		handlep->sysfs_dropped = linux_if_drops(handlep->device);
+		handlep->stat.ps_ifdrop += (u_int)(handlep->sysfs_dropped - if_dropped);
 	}
 
-#ifdef HAVE_STRUCT_TPACKET_STATS
 	/*
 	 * Try to get the packet counts from the kernel.
 	 */
 	if (getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS,
 			&kstats, &len) > -1) {
 		/*
-		 * On systems where the PACKET_STATISTICS "getsockopt()"
-		 * argument is supported on PF_PACKET sockets:
+		 * "ps_recv" counts only packets that *passed* the
+		 * filter, not packets that didn't pass the filter.
+		 * This includes packets later dropped because we
+		 * ran out of buffer space.
 		 *
-		 *	"ps_recv" counts only packets that *passed* the
-		 *	filter, not packets that didn't pass the filter.
-		 *	This includes packets later dropped because we
-		 *	ran out of buffer space.
+		 * "ps_drop" counts packets dropped because we ran
+		 * out of buffer space.  It doesn't count packets
+		 * dropped by the interface driver.  It counts only
+		 * packets that passed the filter.
 		 *
-		 *	"ps_drop" counts packets dropped because we ran
-		 *	out of buffer space.  It doesn't count packets
-		 *	dropped by the interface driver.  It counts only
-		 *	packets that passed the filter.
+		 * See above for ps_ifdrop.
 		 *
-		 *	See above for ps_ifdrop.
+		 * Both statistics include packets not yet read from
+		 * the kernel by libpcap, and thus not yet seen by
+		 * the application.
 		 *
-		 *	Both statistics include packets not yet read from
-		 *	the kernel by libpcap, and thus not yet seen by
-		 *	the application.
-		 *
-		 * In "linux/net/packet/af_packet.c", at least in the
-		 * 2.4.9 kernel, "tp_packets" is incremented for every
-		 * packet that passes the packet filter *and* is
-		 * successfully queued on the socket; "tp_drops" is
+		 * In "linux/net/packet/af_packet.c", at least in 2.6.27
+		 * through 5.6 kernels, "tp_packets" is incremented for
+		 * every packet that passes the packet filter *and* is
+		 * successfully copied to the ring buffer; "tp_drops" is
 		 * incremented for every packet dropped because there's
-		 * not enough free space in the socket buffer.
+		 * not enough free space in the ring buffer.
 		 *
 		 * When the statistics are returned for a PACKET_STATISTICS
 		 * "getsockopt()" call, "tp_drops" is added to "tp_packets",
@@ -2321,336 +1362,10 @@
 		*stats = handlep->stat;
 		return 0;
 	}
-	else
-	{
-		/*
-		 * If the error was EOPNOTSUPP, fall through, so that
-		 * if you build the library on a system with
-		 * "struct tpacket_stats" and run it on a system
-		 * that doesn't, it works as it does if the library
-		 * is built on a system without "struct tpacket_stats".
-		 */
-		if (errno != EOPNOTSUPP) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "pcap_stats");
-			return -1;
-		}
-	}
-#endif
-	/*
-	 * On systems where the PACKET_STATISTICS "getsockopt()" argument
-	 * is not supported on PF_PACKET sockets:
-	 *
-	 *	"ps_recv" counts only packets that *passed* the filter,
-	 *	not packets that didn't pass the filter.  It does not
-	 *	count packets dropped because we ran out of buffer
-	 *	space.
-	 *
-	 *	"ps_drop" is not supported.
-	 *
-	 *	"ps_ifdrop" is supported. It will return the number
-	 *	of drops the interface reports in /proc/net/dev,
-	 *	if that is available.
-	 *
-	 *	"ps_recv" doesn't include packets not yet read from
-	 *	the kernel by libpcap.
-	 *
-	 * We maintain the count of packets processed by libpcap in
-	 * "handlep->packets_read", for reasons described in the comment
-	 * at the end of pcap_read_packet().  We have no idea how many
-	 * packets were dropped by the kernel buffers -- but we know
-	 * how many the interface dropped, so we can return that.
-	 */
 
-	stats->ps_recv = handlep->packets_read;
-	stats->ps_drop = 0;
-	stats->ps_ifdrop = handlep->stat.ps_ifdrop;
-	return 0;
-}
-
-static int
-add_linux_if(pcap_if_list_t *devlistp, const char *ifname, int fd, char *errbuf)
-{
-	const char *p;
-	char name[512];	/* XXX - pick a size */
-	char *q, *saveq;
-	struct ifreq ifrflags;
-
-	/*
-	 * Get the interface name.
-	 */
-	p = ifname;
-	q = &name[0];
-	while (*p != '\0' && isascii(*p) && !isspace(*p)) {
-		if (*p == ':') {
-			/*
-			 * This could be the separator between a
-			 * name and an alias number, or it could be
-			 * the separator between a name with no
-			 * alias number and the next field.
-			 *
-			 * If there's a colon after digits, it
-			 * separates the name and the alias number,
-			 * otherwise it separates the name and the
-			 * next field.
-			 */
-			saveq = q;
-			while (isascii(*p) && isdigit(*p))
-				*q++ = *p++;
-			if (*p != ':') {
-				/*
-				 * That was the next field,
-				 * not the alias number.
-				 */
-				q = saveq;
-			}
-			break;
-		} else
-			*q++ = *p++;
-	}
-	*q = '\0';
-
-	/*
-	 * Get the flags for this interface.
-	 */
-	pcap_strlcpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name));
-	if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
-		if (errno == ENXIO || errno == ENODEV)
-			return (0);	/* device doesn't actually exist - ignore it */
-		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "SIOCGIFFLAGS: %.*s",
-		    (int)sizeof(ifrflags.ifr_name),
-		    ifrflags.ifr_name);
-		return (-1);
-	}
-
-	/*
-	 * Add an entry for this interface, with no addresses, if it's
-	 * not already in the list.
-	 */
-	if (find_or_add_if(devlistp, name, ifrflags.ifr_flags,
-	    get_if_flags, errbuf) == NULL) {
-		/*
-		 * Failure.
-		 */
-		return (-1);
-	}
-
-	return (0);
-}
-
-/*
- * Get from "/sys/class/net" all interfaces listed there; if they're
- * already in the list of interfaces we have, that won't add another
- * instance, but if they're not, that'll add them.
- *
- * We don't bother getting any addresses for them; it appears you can't
- * use SIOCGIFADDR on Linux to get IPv6 addresses for interfaces, and,
- * although some other types of addresses can be fetched with SIOCGIFADDR,
- * we don't bother with them for now.
- *
- * We also don't fail if we couldn't open "/sys/class/net"; we just leave
- * the list of interfaces as is, and return 0, so that we can try
- * scanning /proc/net/dev.
- *
- * Otherwise, we return 1 if we don't get an error and -1 if we do.
- */
-static int
-scan_sys_class_net(pcap_if_list_t *devlistp, char *errbuf)
-{
-	DIR *sys_class_net_d;
-	int fd;
-	struct dirent *ent;
-	char subsystem_path[PATH_MAX+1];
-	struct stat statb;
-	int ret = 1;
-
-	sys_class_net_d = opendir("/sys/class/net");
-	if (sys_class_net_d == NULL) {
-		/*
-		 * Don't fail if it doesn't exist at all.
-		 */
-		if (errno == ENOENT)
-			return (0);
-
-		/*
-		 * Fail if we got some other error.
-		 */
-		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "Can't open /sys/class/net");
-		return (-1);
-	}
-
-	/*
-	 * Create a socket from which to fetch interface information.
-	 */
-	fd = socket(PF_UNIX, SOCK_RAW, 0);
-	if (fd < 0) {
-		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "socket");
-		(void)closedir(sys_class_net_d);
-		return (-1);
-	}
-
-	for (;;) {
-		errno = 0;
-		ent = readdir(sys_class_net_d);
-		if (ent == NULL) {
-			/*
-			 * Error or EOF; if errno != 0, it's an error.
-			 */
-			break;
-		}
-
-		/*
-		 * Ignore "." and "..".
-		 */
-		if (strcmp(ent->d_name, ".") == 0 ||
-		    strcmp(ent->d_name, "..") == 0)
-			continue;
-
-		/*
-		 * Ignore plain files; they do not have subdirectories
-		 * and thus have no attributes.
-		 */
-		if (ent->d_type == DT_REG)
-			continue;
-
-		/*
-		 * Is there an "ifindex" file under that name?
-		 * (We don't care whether it's a directory or
-		 * a symlink; older kernels have directories
-		 * for devices, newer kernels have symlinks to
-		 * directories.)
-		 */
-		pcap_snprintf(subsystem_path, sizeof subsystem_path,
-		    "/sys/class/net/%s/ifindex", ent->d_name);
-		if (lstat(subsystem_path, &statb) != 0) {
-			/*
-			 * Stat failed.  Either there was an error
-			 * other than ENOENT, and we don't know if
-			 * this is an interface, or it's ENOENT,
-			 * and either some part of "/sys/class/net/{if}"
-			 * disappeared, in which case it probably means
-			 * the interface disappeared, or there's no
-			 * "ifindex" file, which means it's not a
-			 * network interface.
-			 */
-			continue;
-		}
-
-		/*
-		 * Attempt to add the interface.
-		 */
-		if (add_linux_if(devlistp, &ent->d_name[0], fd, errbuf) == -1) {
-			/* Fail. */
-			ret = -1;
-			break;
-		}
-	}
-	if (ret != -1) {
-		/*
-		 * Well, we didn't fail for any other reason; did we
-		 * fail due to an error reading the directory?
-		 */
-		if (errno != 0) {
-			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
-			    errno, "Error reading /sys/class/net");
-			ret = -1;
-		}
-	}
-
-	(void)close(fd);
-	(void)closedir(sys_class_net_d);
-	return (ret);
-}
-
-/*
- * Get from "/proc/net/dev" all interfaces listed there; if they're
- * already in the list of interfaces we have, that won't add another
- * instance, but if they're not, that'll add them.
- *
- * See comments from scan_sys_class_net().
- */
-static int
-scan_proc_net_dev(pcap_if_list_t *devlistp, char *errbuf)
-{
-	FILE *proc_net_f;
-	int fd;
-	char linebuf[512];
-	int linenum;
-	char *p;
-	int ret = 0;
-
-	proc_net_f = fopen("/proc/net/dev", "r");
-	if (proc_net_f == NULL) {
-		/*
-		 * Don't fail if it doesn't exist at all.
-		 */
-		if (errno == ENOENT)
-			return (0);
-
-		/*
-		 * Fail if we got some other error.
-		 */
-		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "Can't open /proc/net/dev");
-		return (-1);
-	}
-
-	/*
-	 * Create a socket from which to fetch interface information.
-	 */
-	fd = socket(PF_UNIX, SOCK_RAW, 0);
-	if (fd < 0) {
-		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "socket");
-		(void)fclose(proc_net_f);
-		return (-1);
-	}
-
-	for (linenum = 1;
-	    fgets(linebuf, sizeof linebuf, proc_net_f) != NULL; linenum++) {
-		/*
-		 * Skip the first two lines - they're headers.
-		 */
-		if (linenum <= 2)
-			continue;
-
-		p = &linebuf[0];
-
-		/*
-		 * Skip leading white space.
-		 */
-		while (*p != '\0' && isascii(*p) && isspace(*p))
-			p++;
-		if (*p == '\0' || *p == '\n')
-			continue;	/* blank line */
-
-		/*
-		 * Attempt to add the interface.
-		 */
-		if (add_linux_if(devlistp, p, fd, errbuf) == -1) {
-			/* Fail. */
-			ret = -1;
-			break;
-		}
-	}
-	if (ret != -1) {
-		/*
-		 * Well, we didn't fail for any other reason; did we
-		 * fail due to an error reading the file?
-		 */
-		if (ferror(proc_net_f)) {
-			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
-			    errno, "Error reading /proc/net/dev");
-			ret = -1;
-		}
-	}
-
-	(void)close(fd);
-	(void)fclose(proc_net_f);
-	return (ret);
+	pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno,
+	    "failed to get statistics from socket");
+	return -1;
 }
 
 /*
@@ -2659,7 +1374,7 @@
 static const char any_descr[] = "Pseudo-device that captures on all interfaces";
 
 /*
- * A SOCK_PACKET or PF_PACKET socket can be bound to any network interface.
+ * A PF_PACKET socket can be bound to any network interface.
  */
 static int
 can_be_bound(const char *name _U_)
@@ -2668,6 +1383,126 @@
 }
 
 /*
+ * Get a socket to use with various interface ioctls.
+ */
+static int
+get_if_ioctl_socket(void)
+{
+	int fd;
+
+	/*
+	 * This is a bit ugly.
+	 *
+	 * There isn't a socket type that's guaranteed to work.
+	 *
+	 * AF_NETLINK will work *if* you have Netlink configured into the
+	 * kernel (can it be configured out if you have any networking
+	 * support at all?) *and* if you're running a sufficiently recent
+	 * kernel, but not all the kernels we support are sufficiently
+	 * recent - that feature was introduced in Linux 4.6.
+	 *
+	 * AF_UNIX will work *if* you have UNIX-domain sockets configured
+	 * into the kernel and *if* you're not on a system that doesn't
+	 * allow them - some SELinux systems don't allow you create them.
+	 * Most systems probably have them configured in, but not all systems
+	 * have them configured in and allow them to be created.
+	 *
+	 * AF_INET will work *if* you have IPv4 configured into the kernel,
+	 * but, apparently, some systems have network adapters but have
+	 * kernels without IPv4 support.
+	 *
+	 * AF_INET6 will work *if* you have IPv6 configured into the
+	 * kernel, but if you don't have AF_INET, you might not have
+	 * AF_INET6, either (that is, independently on its own grounds).
+	 *
+	 * AF_PACKET would work, except that some of these calls should
+	 * work even if you *don't* have capture permission (you should be
+	 * able to enumerate interfaces and get information about them
+	 * without capture permission; you shouldn't get a failure until
+	 * you try pcap_activate()).  (If you don't allow programs to
+	 * get as much information as possible about interfaces if you
+	 * don't have permission to capture, you run the risk of users
+	 * asking "why isn't it showing XXX" - or, worse, if you don't
+	 * show interfaces *at all* if you don't have permission to
+	 * capture on them, "why do no interfaces show up?" - when the
+	 * real problem is a permissions problem.  Error reports of that
+	 * type require a lot more back-and-forth to debug, as evidenced
+	 * by many Wireshark bugs/mailing list questions/Q&A questoins.)
+	 *
+	 * So:
+	 *
+	 * we first try an AF_NETLINK socket, where "try" includes
+	 * "try to do a device ioctl on it", as, in the future, once
+	 * pre-4.6 kernels are sufficiently rare, that will probably
+	 * be the mechanism most likely to work;
+	 *
+	 * if that fails, we try an AF_UNIX socket, as that's less
+	 * likely to be configured out on a networking-capable system
+	 * than is IP;
+	 *
+	 * if that fails, we try an AF_INET6 socket;
+	 *
+	 * if that fails, we try an AF_INET socket.
+	 */
+	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+	if (fd != -1) {
+		/*
+		 * OK, let's make sure we can do an SIOCGIFNAME
+		 * ioctl.
+		 */
+		struct ifreq ifr;
+
+		memset(&ifr, 0, sizeof(ifr));
+		if (ioctl(fd, SIOCGIFNAME, &ifr) == 0 ||
+		    errno != EOPNOTSUPP) {
+			/*
+			 * It succeeded, or failed for some reason
+			 * other than "netlink sockets don't support
+			 * device ioctls".  Go with the AF_NETLINK
+			 * socket.
+			 */
+			return (fd);
+		}
+
+		/*
+		 * OK, that didn't work, so it's as bad as "netlink
+		 * sockets aren't available".  Close the socket and
+		 * drive on.
+		 */
+		close(fd);
+	}
+
+	/*
+	 * Now try an AF_UNIX socket.
+	 */
+	fd = socket(AF_UNIX, SOCK_RAW, 0);
+	if (fd != -1) {
+		/*
+		 * OK, we got it!
+		 */
+		return (fd);
+	}
+
+	/*
+	 * Now try an AF_INET6 socket.
+	 */
+	fd = socket(AF_INET6, SOCK_DGRAM, 0);
+	if (fd != -1) {
+		return (fd);
+	}
+
+	/*
+	 * Now try an AF_INET socket.
+	 *
+	 * XXX - if that fails, is there anything else we should try?
+	 * AF_CAN, for embedded systems in vehicles, in case they're
+	 * built without Internet protocol support?  Any other socket
+	 * types popular in non-Internet embedded systems?
+	 */
+	return (socket(AF_INET, SOCK_DGRAM, 0));
+}
+
+/*
  * Get additional flags for a device, using SIOCGIFMEDIA.
  */
 static int
@@ -2688,7 +1523,7 @@
 		return 0;
 	}
 
-	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	sock = get_if_ioctl_socket();
 	if (sock == -1) {
 		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno,
 		    "Can't create socket to get ethtool information for %s",
@@ -2700,14 +1535,14 @@
 	 * OK, what type of network is this?
 	 * In particular, is it wired or wireless?
 	 */
-	if (is_wifi(sock, name)) {
+	if (is_wifi(name)) {
 		/*
 		 * Wi-Fi, hence wireless.
 		 */
 		*flags |= PCAP_IF_WIRELESS;
 	} else {
 		/*
-		 * OK, what does /sys/class/net/{if}/type contain?
+		 * OK, what does /sys/class/net/{if_name}/type contain?
 		 * (We don't use that for Wi-Fi, as it'll report
 		 * "Ethernet", i.e. ARPHRD_ETHER, for non-monitor-
 		 * mode devices.)
@@ -2715,7 +1550,7 @@
 		char *pathstr;
 
 		if (asprintf(&pathstr, "/sys/class/net/%s/type", name) == -1) {
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "%s: Can't generate path name string for /sys/class/net device",
 			    name);
 			close(sock);
@@ -2729,7 +1564,6 @@
 				 */
 				switch (arptype) {
 
-#ifdef ARPHRD_LOOPBACK
 				case ARPHRD_LOOPBACK:
 					/*
 					 * These are types to which
@@ -2743,7 +1577,6 @@
 					fclose(fh);
 					free(pathstr);
 					return 0;
-#endif
 
 				case ARPHRD_IRDA:
 				case ARPHRD_IEEE80211:
@@ -2774,6 +1607,17 @@
 	memset(&ifr, 0, sizeof(ifr));
 	pcap_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
 	info.cmd = ETHTOOL_GLINK;
+	/*
+	 * XXX - while Valgrind handles SIOCETHTOOL and knows that
+	 * the ETHTOOL_GLINK command sets the .data member of the
+	 * structure, Memory Sanitizer doesn't yet do so:
+	 *
+	 *    https://bugs.llvm.org/show_bug.cgi?id=45814
+	 *
+	 * For now, we zero it out to squelch warnings; if the bug
+	 * in question is fixed, we can remove this.
+	 */
+	info.data = 0;
 	ifr.ifr_data = (caddr_t)&info;
 	if (ioctl(sock, SIOCETHTOOL, &ifr) == -1) {
 		int save_errno = errno;
@@ -2841,8 +1685,6 @@
 int
 pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
 {
-	int ret;
-
 	/*
 	 * Get the list of regular interfaces first.
 	 */
@@ -2851,25 +1693,6 @@
 		return (-1);	/* failure */
 
 	/*
-	 * Read "/sys/class/net", and add to the list of interfaces all
-	 * interfaces listed there that we don't already have, because,
-	 * on Linux, SIOCGIFCONF reports only interfaces with IPv4 addresses,
-	 * and even getifaddrs() won't return information about
-	 * interfaces with no addresses, so you need to read "/sys/class/net"
-	 * to get the names of the rest of the interfaces.
-	 */
-	ret = scan_sys_class_net(devlistp, errbuf);
-	if (ret == -1)
-		return (-1);	/* failed */
-	if (ret == 0) {
-		/*
-		 * No /sys/class/net; try reading /proc/net/dev instead.
-		 */
-		if (scan_proc_net_dev(devlistp, errbuf) == -1)
-			return (-1);
-	}
-
-	/*
 	 * Add the "any" device.
 	 * As it refers to all network devices, not to any particular
 	 * network device, the notion of "connected" vs. "disconnected"
@@ -2884,223 +1707,25 @@
 }
 
 /*
- *  Attach the given BPF code to the packet capture device.
- */
-static int
-pcap_setfilter_linux_common(pcap_t *handle, struct bpf_program *filter,
-    int is_mmapped)
-{
-	struct pcap_linux *handlep;
-#ifdef SO_ATTACH_FILTER
-	struct sock_fprog	fcode;
-	int			can_filter_in_kernel;
-	int			err = 0;
-#endif
-
-	if (!handle)
-		return -1;
-	if (!filter) {
-	        pcap_strlcpy(handle->errbuf, "setfilter: No filter specified",
-			PCAP_ERRBUF_SIZE);
-		return -1;
-	}
-
-	handlep = handle->priv;
-
-	/* Make our private copy of the filter */
-
-	if (install_bpf_program(handle, filter) < 0)
-		/* install_bpf_program() filled in errbuf */
-		return -1;
-
-	/*
-	 * Run user level packet filter by default. Will be overriden if
-	 * installing a kernel filter succeeds.
-	 */
-	handlep->filter_in_userland = 1;
-
-	/* Install kernel level filter if possible */
-
-#ifdef SO_ATTACH_FILTER
-#ifdef USHRT_MAX
-	if (handle->fcode.bf_len > USHRT_MAX) {
-		/*
-		 * fcode.len is an unsigned short for current kernel.
-		 * I have yet to see BPF-Code with that much
-		 * instructions but still it is possible. So for the
-		 * sake of correctness I added this check.
-		 */
-		fprintf(stderr, "Warning: Filter too complex for kernel\n");
-		fcode.len = 0;
-		fcode.filter = NULL;
-		can_filter_in_kernel = 0;
-	} else
-#endif /* USHRT_MAX */
-	{
-		/*
-		 * Oh joy, the Linux kernel uses struct sock_fprog instead
-		 * of struct bpf_program and of course the length field is
-		 * of different size. Pointed out by Sebastian
-		 *
-		 * Oh, and we also need to fix it up so that all "ret"
-		 * instructions with non-zero operands have MAXIMUM_SNAPLEN
-		 * as the operand if we're not capturing in memory-mapped
-		 * mode, and so that, if we're in cooked mode, all memory-
-		 * reference instructions use special magic offsets in
-		 * references to the link-layer header and assume that the
-		 * link-layer payload begins at 0; "fix_program()" will do
-		 * that.
-		 */
-		switch (fix_program(handle, &fcode, is_mmapped)) {
-
-		case -1:
-		default:
-			/*
-			 * Fatal error; just quit.
-			 * (The "default" case shouldn't happen; we
-			 * return -1 for that reason.)
-			 */
-			return -1;
-
-		case 0:
-			/*
-			 * The program performed checks that we can't make
-			 * work in the kernel.
-			 */
-			can_filter_in_kernel = 0;
-			break;
-
-		case 1:
-			/*
-			 * We have a filter that'll work in the kernel.
-			 */
-			can_filter_in_kernel = 1;
-			break;
-		}
-	}
-
-	/*
-	 * NOTE: at this point, we've set both the "len" and "filter"
-	 * fields of "fcode".  As of the 2.6.32.4 kernel, at least,
-	 * those are the only members of the "sock_fprog" structure,
-	 * so we initialize every member of that structure.
-	 *
-	 * If there is anything in "fcode" that is not initialized,
-	 * it is either a field added in a later kernel, or it's
-	 * padding.
-	 *
-	 * If a new field is added, this code needs to be updated
-	 * to set it correctly.
-	 *
-	 * If there are no other fields, then:
-	 *
-	 *	if the Linux kernel looks at the padding, it's
-	 *	buggy;
-	 *
-	 *	if the Linux kernel doesn't look at the padding,
-	 *	then if some tool complains that we're passing
-	 *	uninitialized data to the kernel, then the tool
-	 *	is buggy and needs to understand that it's just
-	 *	padding.
-	 */
-	if (can_filter_in_kernel) {
-		if ((err = set_kernel_filter(handle, &fcode)) == 0)
-		{
-			/*
-			 * Installation succeded - using kernel filter,
-			 * so userland filtering not needed.
-			 */
-			handlep->filter_in_userland = 0;
-		}
-		else if (err == -1)	/* Non-fatal error */
-		{
-			/*
-			 * Print a warning if we weren't able to install
-			 * the filter for a reason other than "this kernel
-			 * isn't configured to support socket filters.
-			 */
-			if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) {
-				fprintf(stderr,
-				    "Warning: Kernel filter failed: %s\n",
-					pcap_strerror(errno));
-			}
-		}
-	}
-
-	/*
-	 * If we're not using the kernel filter, get rid of any kernel
-	 * filter that might've been there before, e.g. because the
-	 * previous filter could work in the kernel, or because some other
-	 * code attached a filter to the socket by some means other than
-	 * calling "pcap_setfilter()".  Otherwise, the kernel filter may
-	 * filter out packets that would pass the new userland filter.
-	 */
-	if (handlep->filter_in_userland) {
-		if (reset_kernel_filter(handle) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno,
-			    "can't remove kernel filter");
-			err = -2;	/* fatal error */
-		}
-	}
-
-	/*
-	 * Free up the copy of the filter that was made by "fix_program()".
-	 */
-	if (fcode.filter != NULL)
-		free(fcode.filter);
-
-	if (err == -2)
-		/* Fatal error */
-		return -1;
-#endif /* SO_ATTACH_FILTER */
-
-	return 0;
-}
-
-static int
-pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter)
-{
-	return pcap_setfilter_linux_common(handle, filter, 0);
-}
-
-
-/*
  * Set direction flag: Which packets do we accept on a forwarding
  * single device? IN, OUT or both?
  */
 static int
 pcap_setdirection_linux(pcap_t *handle, pcap_direction_t d)
 {
-#ifdef HAVE_PF_PACKET_SOCKETS
-	struct pcap_linux *handlep = handle->priv;
-
-	if (!handlep->sock_packet) {
-		handle->direction = d;
-		return 0;
-	}
-#endif
 	/*
-	 * We're not using PF_PACKET sockets, so we can't determine
-	 * the direction of the packet.
+	 * It's guaranteed, at this point, that d is a valid
+	 * direction value.
 	 */
-	pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
-	    "Setting direction is not supported on SOCK_PACKET sockets");
-	return -1;
+	handle->direction = d;
+	return 0;
 }
 
 static int
-is_wifi(int sock_fd
-#ifndef IW_MODE_MONITOR
-_U_
-#endif
-, const char *device)
+is_wifi(const char *device)
 {
 	char *pathstr;
 	struct stat statb;
-#ifdef IW_MODE_MONITOR
-	char errbuf[PCAP_ERRBUF_SIZE];
-#endif
 
 	/*
 	 * See if there's a sysfs wireless directory for it.
@@ -3118,19 +1743,6 @@
 	}
 	free(pathstr);
 
-#ifdef IW_MODE_MONITOR
-	/*
-	 * OK, maybe it's not wireless, or maybe this kernel doesn't
-	 * support sysfs.  Try the wireless extensions.
-	 */
-	if (has_wext(sock_fd, device, errbuf) == 1) {
-		/*
-		 * It supports the wireless extensions, so it's a Wi-Fi
-		 * device.
-		 */
-		return 1;
-	}
-#endif
 	return 0;
 }
 
@@ -3152,7 +1764,7 @@
  *
  *  Sets the link type to -1 if unable to map the type.
  */
-static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
+static void map_arphrd_to_dlt(pcap_t *handle, int arptype,
 			      const char *device, int cooked_ok)
 {
 	static const char cdma_rmnet[] = "cdma_rmnet";
@@ -3190,12 +1802,33 @@
 		 * XXX - are there any other sorts of "fake Ethernet" that
 		 * have ARPHRD_ETHER but that shouldn't offer DLT_DOCSIS as
 		 * a Cisco CMTS won't put traffic onto it or get traffic
-		 * bridged onto it?  ISDN is handled in "activate_new()",
+		 * bridged onto it?  ISDN is handled in "activate_pf_packet()",
 		 * as we fall back on cooked mode there, and we use
 		 * is_wifi() to check for 802.11 devices; are there any
 		 * others?
 		 */
-		if (!is_wifi(sock_fd, device)) {
+		if (!is_wifi(device)) {
+			int ret;
+
+			/*
+			 * This is not a Wi-Fi device but it could be
+			 * a DSA master/management network device.
+			 */
+			ret = iface_dsa_get_proto_info(device, handle);
+			if (ret < 0)
+				return;
+
+			if (ret == 1) {
+				/*
+				 * This is a DSA master/management network
+				 * device linktype is already set by
+				 * iface_dsa_get_proto_info() set an
+				 * appropriate offset here.
+				 */
+				handle->offset = 2;
+				break;
+			}
+
 			/*
 			 * It's not a Wi-Fi device; offer DOCSIS.
 			 */
@@ -3461,7 +2094,7 @@
 		 * Back in 2002, Donald Lee at Cray wanted a DLT_ for
 		 * IP-over-FC:
 		 *
-		 *	http://www.mail-archive.com/tcpdump-workers@sandelman.ottawa.on.ca/msg01043.html
+		 *	https://www.mail-archive.com/tcpdump-workers@sandelman.ottawa.on.ca/msg01043.html
 		 *
 		 * and one was assigned.
 		 *
@@ -3525,7 +2158,7 @@
 		/* We need to save packet direction for IrDA decoding,
 		 * so let's use "Linux-cooked" mode. Jean II
 		 *
-		 * XXX - this is handled in activate_new(). */
+		 * XXX - this is handled in activate_pf_packet(). */
 		/* handlep->cooked = 1; */
 		break;
 
@@ -3567,7 +2200,7 @@
 		 * pick up the netlink protocol type such as NETLINK_ROUTE,
 		 * NETLINK_GENERIC, NETLINK_FIB_LOOKUP, etc.
 		 *
-		 * XXX - this is handled in activate_new().
+		 * XXX - this is handled in activate_pf_packet().
 		 */
 		/* handlep->cooked = 1; */
 		break;
@@ -3585,8 +2218,6 @@
 	}
 }
 
-/* ===== Functions to interface to the newer kernels ================== */
-
 #ifdef PACKET_RESERVE
 static void
 set_dlt_list_cooked(pcap_t *handle, int sock_fd)
@@ -3601,9 +2232,9 @@
 	len = sizeof(tp_reserve);
 	if (getsockopt(sock_fd, SOL_PACKET, PACKET_RESERVE, &tp_reserve,
 	    &len) == 0) {
-	    	/*
-	    	 * Yes, we can do DLL_LINUX_SLL2.
-	    	 */
+		/*
+		 * Yes, we can do DLL_LINUX_SLL2.
+		 */
 		handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
 		/*
 		 * If that fails, just leave the list empty.
@@ -3615,7 +2246,7 @@
 		}
 	}
 }
-#else
+#else/* PACKET_RESERVE */
 /*
  * The build environment doesn't define PACKET_RESERVE, so we can't reserve
  * extra space for a DLL_LINUX_SLL2 header, so we can't support DLT_LINUX_SLL2.
@@ -3624,24 +2255,19 @@
 set_dlt_list_cooked(pcap_t *handle _U_, int sock_fd _U_)
 {
 }
-#endif
+#endif /* PACKET_RESERVE */
 
 /*
- * Try to open a packet socket using the new kernel PF_PACKET interface.
- * Returns 1 on success, 0 on an error that means the new interface isn't
- * present (so the old SOCK_PACKET interface should be tried), and a
- * PCAP_ERROR_ value on an error that means that the old mechanism won't
- * work either (so it shouldn't be tried).
+ * Try to set up a PF_PACKET socket.
+ * Returns 0 on success and a PCAP_ERROR_ value on failure.
  */
 static int
-activate_new(pcap_t *handle)
+activate_pf_packet(pcap_t *handle, int is_any_device)
 {
-#ifdef HAVE_PF_PACKET_SOCKETS
 	struct pcap_linux *handlep = handle->priv;
 	const char		*device = handle->opt.device;
-	int			is_any_device = (strcmp(device, "any") == 0);
-	int			protocol = pcap_protocol(handle);
-	int			sock_fd = -1, arptype, ret;
+	int			status = 0;
+	int			sock_fd, arptype;
 #ifdef HAVE_PACKET_AUXDATA
 	int			val;
 #endif
@@ -3653,43 +2279,37 @@
 #endif
 
 	/*
-	 * Open a socket with protocol family packet. If the
-	 * "any" device was specified, we open a SOCK_DGRAM
-	 * socket for the cooked interface, otherwise we first
-	 * try a SOCK_RAW socket for the raw interface.
+	 * Open a socket with protocol family packet. If cooked is true,
+	 * we open a SOCK_DGRAM socket for the cooked interface, otherwise
+	 * we open a SOCK_RAW socket for the raw interface.
+	 *
+	 * The protocol is set to 0.  This means we will receive no
+	 * packets until we "bind" the socket with a non-zero
+	 * protocol.  This allows us to setup the ring buffers without
+	 * dropping any packets.
 	 */
 	sock_fd = is_any_device ?
-		socket(PF_PACKET, SOCK_DGRAM, protocol) :
-		socket(PF_PACKET, SOCK_RAW, protocol);
+		socket(PF_PACKET, SOCK_DGRAM, 0) :
+		socket(PF_PACKET, SOCK_RAW, 0);
 
 	if (sock_fd == -1) {
-		if (errno == EINVAL || errno == EAFNOSUPPORT) {
-			/*
-			 * We don't support PF_PACKET/SOCK_whatever
-			 * sockets; try the old mechanism.
-			 */
-			return 0;
-		}
 		if (errno == EPERM || errno == EACCES) {
 			/*
 			 * You don't have permission to open the
 			 * socket.
 			 */
-			ret = PCAP_ERROR_PERM_DENIED;
+			status = PCAP_ERROR_PERM_DENIED;
 		} else {
 			/*
 			 * Other error.
 			 */
-			ret = PCAP_ERROR;
+			status = PCAP_ERROR;
 		}
 		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    errno, "socket");
-		return ret;
+		return status;
 	}
 
-	/* It seems the kernel supports the new interface. */
-	handlep->sock_packet = 0;
-
 	/*
 	 * Get the interface index of the loopback device.
 	 * If the attempt fails, don't fail, just set the
@@ -3754,7 +2374,7 @@
 			close(sock_fd);
 			return arptype;
 		}
-		map_arphrd_to_dlt(handle, sock_fd, arptype, device, 1);
+		map_arphrd_to_dlt(handle, arptype, device, 1);
 		if (handle->linktype == -1 ||
 		    handle->linktype == DLT_LINUX_SLL ||
 		    handle->linktype == DLT_LINUX_IRDA ||
@@ -3771,29 +2391,29 @@
 			 * type we can only determine by using
 			 * APIs that may be different on different
 			 * kernels) - reopen in cooked mode.
+			 *
+			 * If the type is unknown, return a warning;
+			 * map_arphrd_to_dlt() has already set the
+			 * warning message.
 			 */
 			if (close(sock_fd) == -1) {
 				pcap_fmt_errmsg_for_errno(handle->errbuf,
 				    PCAP_ERRBUF_SIZE, errno, "close");
 				return PCAP_ERROR;
 			}
-			sock_fd = socket(PF_PACKET, SOCK_DGRAM, protocol);
-			if (sock_fd == -1) {
-				if (errno == EPERM || errno == EACCES) {
-					/*
-					 * You don't have permission to
-					 * open the socket.
-					 */
-					ret = PCAP_ERROR_PERM_DENIED;
-				} else {
-					/*
-					 * Other error.
-					 */
-					ret = PCAP_ERROR;
-				}
+			sock_fd = socket(PF_PACKET, SOCK_DGRAM, 0);
+			if (sock_fd < 0) {
+				/*
+				 * Fatal error.  We treat this as
+				 * a generic error; we already know
+				 * that we were able to open a
+				 * PF_PACKET/SOCK_RAW socket, so
+				 * any failure is a "this shouldn't
+				 * happen" case.
+				 */
 				pcap_fmt_errmsg_for_errno(handle->errbuf,
 				    PCAP_ERRBUF_SIZE, errno, "socket");
-				return ret;
+				return PCAP_ERROR;
 			}
 			handlep->cooked = 1;
 
@@ -3816,7 +2436,7 @@
 				 * update "map_arphrd_to_dlt()"
 				 * to handle the new type.
 				 */
-				pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 					"arptype %d not "
 					"supported by libpcap - "
 					"falling back to cooked "
@@ -3833,6 +2453,12 @@
 			    handle->linktype != DLT_LINUX_LAPD &&
 			    handle->linktype != DLT_NETLINK)
 				handle->linktype = DLT_LINUX_SLL;
+			if (handle->linktype == -1) {
+				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+				    "unknown arptype %d, defaulting to cooked mode",
+				    arptype);
+				status = PCAP_WARNING;
+			}
 		}
 
 		handlep->ifindex = iface_get_id(sock_fd, device,
@@ -3843,12 +2469,9 @@
 		}
 
 		if ((err = iface_bind(sock_fd, handlep->ifindex,
-		    handle->errbuf, protocol)) != 1) {
-		    	close(sock_fd);
-			if (err < 0)
-				return err;
-			else
-				return 0;	/* try old mechanism */
+		    handle->errbuf, 0)) != 0) {
+			close(sock_fd);
+			return err;
 		}
 	} else {
 		/*
@@ -3916,7 +2539,7 @@
 		}
 	}
 
-	/* Enable auxillary data if supported and reserve room for
+	/* Enable auxiliary data if supported and reserve room for
 	 * reconstructing VLAN headers. */
 #ifdef HAVE_PACKET_AUXDATA
 	val = 1;
@@ -3931,14 +2554,6 @@
 #endif /* HAVE_PACKET_AUXDATA */
 
 	/*
-	 * This is a 2.2[.x] or later kernel (we know that
-	 * because we're not using a SOCK_PACKET socket -
-	 * PF_PACKET is supported only in 2.2 and later
-	 * kernels).
-	 *
-	 * We can safely pass "recvfrom()" a byte count
-	 * based on the snapshot length.
-	 *
 	 * If we're in cooked mode, make the snapshot length
 	 * large enough to hold a "cooked mode" header plus
 	 * 1 byte of packet data (so we don't pass a byte
@@ -3981,17 +2596,15 @@
 		break;
 	}
 
-#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS)
 	if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) {
 		int nsec_tstamps = 1;
 
 		if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, &nsec_tstamps, sizeof(nsec_tstamps)) < 0) {
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: unable to set SO_TIMESTAMPNS");
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: unable to set SO_TIMESTAMPNS");
 			close(sock_fd);
 			return PCAP_ERROR;
 		}
 	}
-#endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */
 
 	/*
 	 * We've succeeded. Save the socket FD in the pcap structure.
@@ -4015,30 +2628,20 @@
 	}
 #endif /* defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) */
 
-	return 1;
-#else /* HAVE_PF_PACKET_SOCKETS */
-	pcap_strlcpy(ebuf,
-		"New packet capturing interface not supported by build "
-		"environment", PCAP_ERRBUF_SIZE);
-	return 0;
-#endif /* HAVE_PF_PACKET_SOCKETS */
+	return status;
 }
 
-#ifdef HAVE_PACKET_RING
 /*
- * Attempt to activate with memory-mapped access.
+ * Attempt to setup memory-mapped access.
  *
  * On success, returns 1, and sets *status to 0 if there are no warnings
  * or to a PCAP_WARNING_ code if there is a warning.
  *
- * On failure due to lack of support for memory-mapped capture, returns
- * 0.
- *
  * On error, returns -1, and sets *status to the appropriate error code;
  * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message.
  */
 static int
-activate_mmap(pcap_t *handle, int *status)
+setup_mmapped(pcap_t *handle, int *status)
 {
 	struct pcap_linux *handlep = handle->priv;
 	int ret;
@@ -4066,14 +2669,6 @@
 		return ret;
 	}
 	ret = create_ring(handle, status);
-	if (ret == 0) {
-		/*
-		 * We don't support memory-mapped capture; our caller
-		 * will fall back on reading from the socket.
-		 */
-		free(handlep->oneshot_buffer);
-		return 0;
-	}
 	if (ret == -1) {
 		/*
 		 * Error attempting to enable memory-mapped capture;
@@ -4087,49 +2682,18 @@
 	 * Success.  *status has been set either to 0 if there are no
 	 * warnings or to a PCAP_WARNING_ value if there is a warning.
 	 *
-	 * Override some defaults and inherit the other fields from
-	 * activate_new.
 	 * handle->offset is used to get the current position into the rx ring.
 	 * handle->cc is used to store the ring size.
 	 */
 
-	switch (handlep->tp_version) {
-	case TPACKET_V1:
-		handle->read_op = pcap_read_linux_mmap_v1;
-		break;
-	case TPACKET_V1_64:
-		handle->read_op = pcap_read_linux_mmap_v1_64;
-		break;
-#ifdef HAVE_TPACKET2
-	case TPACKET_V2:
-		handle->read_op = pcap_read_linux_mmap_v2;
-		break;
-#endif
-#ifdef HAVE_TPACKET3
-	case TPACKET_V3:
-		handle->read_op = pcap_read_linux_mmap_v3;
-		break;
-#endif
-	}
-	handle->cleanup_op = pcap_cleanup_linux_mmap;
-	handle->setfilter_op = pcap_setfilter_linux_mmap;
-	handle->setnonblock_op = pcap_setnonblock_mmap;
-	handle->getnonblock_op = pcap_getnonblock_mmap;
-	handle->oneshot_callback = pcap_oneshot_mmap;
-	handle->selectable_fd = handle->fd;
+	/*
+	 * Set the timeout to use in poll() before returning.
+	 */
+	set_poll_timeout(handlep);
+
 	return 1;
 }
-#else /* HAVE_PACKET_RING */
-static int
-activate_mmap(pcap_t *handle _U_, int *status _U_)
-{
-	return 0;
-}
-#endif /* HAVE_PACKET_RING */
 
-#ifdef HAVE_PACKET_RING
-
-#if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3)
 /*
  * Attempt to set the socket to the specified version of the memory-mapped
  * header.
@@ -4152,20 +2716,36 @@
 	 * also the first release with TPACKET_V2 support.
 	 */
 	if (getsockopt(handle->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) {
-		if (errno == ENOPROTOOPT || errno == EINVAL) {
+		if (errno == EINVAL) {
 			/*
-			 * ENOPROTOOPT means the kernel is too old to
-			 * support PACKET_HDRLEN at all, which means
-			 * it either doesn't support TPACKET at all
-			 * or supports  only TPACKET_V1.
+			 * EINVAL means this specific version of TPACKET
+			 * is not supported. Tell the caller they can try
+			 * with a different one; if they've run out of
+			 * others to try, let them set the error message
+			 * appropriately.
 			 */
-			return 1;	/* no */
+			return 1;
 		}
 
-		/* Failed to even find out; this is a fatal error. */
-		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "can't get %s header len on packet socket",
-		    version_str);
+		/*
+		 * All other errors are fatal.
+		 */
+		if (errno == ENOPROTOOPT) {
+			/*
+			 * PACKET_HDRLEN isn't supported, which means
+			 * that memory-mapped capture isn't supported.
+			 * Indicate that in the message.
+			 */
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+			    "Kernel doesn't support memory-mapped capture; a 2.6.27 or later 2.x kernel is required, with CONFIG_PACKET_MMAP specified for 2.x kernels");
+		} else {
+			/*
+			 * Some unexpected error.
+			 */
+			pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+			    errno, "can't get %s header len on packet socket",
+			    version_str);
+		}
 		return -1;
 	}
 	handlep->tp_hdrlen = val;
@@ -4179,68 +2759,20 @@
 	}
 	handlep->tp_version = version;
 
-	/*
-	 * Reserve space for VLAN tag reconstruction.
-	 * This option was also introduced in 2.6.27.
-	 */
-	val = VLAN_TAG_LEN;
-	if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &val,
-			   sizeof(val)) < 0) {
-		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "can't set up reserve on packet socket");
-		return -1;
-	}
-
 	return 0;
 }
-#endif /* defined HAVE_TPACKET2 || defined HAVE_TPACKET3 */
-
-/*
- * If the instruction set for which we're compiling has both 32-bit
- * and 64-bit versions, and Linux support for the 64-bit version
- * predates TPACKET_V2, define ISA_64_BIT as the .machine value
- * you get from uname() for the 64-bit version.  Otherwise, leave
- * it undefined.  (This includes ARM, which has a 64-bit version,
- * but Linux support for it appeared well after TPACKET_V2 support
- * did, so there should never be a case where 32-bit ARM code is
- * running o a 64-bit kernel that only supports TPACKET_V1.)
- *
- * If we've omitted your favorite such architecture, please contribute
- * a patch.  (No patch is needed for architectures that are 32-bit-only
- * or for which Linux has no support for 32-bit userland - or for which,
- * as noted, 64-bit support appeared in Linux after TPACKET_V2 support
- * did.)
- */
-#if defined(__i386__)
-#define ISA_64_BIT	"x86_64"
-#elif defined(__ppc__)
-#define ISA_64_BIT	"ppc64"
-#elif defined(__sparc__)
-#define ISA_64_BIT	"sparc64"
-#elif defined(__s390__)
-#define ISA_64_BIT	"s390x"
-#elif defined(__mips__)
-#define ISA_64_BIT	"mips64"
-#elif defined(__hppa__)
-#define ISA_64_BIT	"parisc64"
-#endif
 
 /*
  * Attempt to set the socket to version 3 of the memory-mapped header and,
  * if that fails because version 3 isn't supported, attempt to fall
- * back to version 2.  If version 2 isn't supported, just leave it at
- * version 1.
+ * back to version 2.  If version 2 isn't supported, just fail.
  *
- * Return 1 if we succeed or if we fail because neither version 2 nor 3 is
- * supported; return -1 on any other error, and set handle->errbuf.
+ * Return 0 if we succeed and -1 on any other error, and set handle->errbuf.
  */
 static int
 prepare_tpacket_socket(pcap_t *handle)
 {
-	struct pcap_linux *handlep = handle->priv;
-#if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3)
 	int ret;
-#endif
 
 #ifdef HAVE_TPACKET3
 	/*
@@ -4260,7 +2792,7 @@
 			/*
 			 * Success.
 			 */
-			return 1;
+			return 0;
 		}
 		if (ret == -1) {
 			/*
@@ -4269,10 +2801,14 @@
 			 */
 			return -1;
 		}
+
+		/*
+		 * This means it returned 1, which means "the kernel
+		 * doesn't support TPACKET_V3"; try TPACKET_V2.
+		 */
 	}
 #endif /* HAVE_TPACKET3 */
 
-#ifdef HAVE_TPACKET2
 	/*
 	 * Try setting the version to TPACKET_V2.
 	 */
@@ -4281,65 +2817,22 @@
 		/*
 		 * Success.
 		 */
-		return 1;
+		return 0;
 	}
-	if (ret == -1) {
+
+	if (ret == 1) {
 		/*
-		 * We failed for some reason other than "the
-		 * kernel doesn't support TPACKET_V2".
+		 * OK, the kernel supports memory-mapped capture, but
+		 * not TPACKET_V2.  Set the error message appropriately.
 		 */
-		return -1;
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		    "Kernel doesn't support TPACKET_V2; a 2.6.27 or later kernel is required");
 	}
-#endif /* HAVE_TPACKET2 */
 
 	/*
-	 * OK, we're using TPACKET_V1, as either that's all the kernel
-	 * supports or it doesn't support TPACKET at all.  In the latter
-	 * case, create_ring() will fail, and we'll fall back on non-
-	 * memory-mapped capture.
+	 * We failed.
 	 */
-	handlep->tp_version = TPACKET_V1;
-	handlep->tp_hdrlen = sizeof(struct tpacket_hdr);
-
-#ifdef ISA_64_BIT
-	/*
-	 * 32-bit userspace + 64-bit kernel + TPACKET_V1 are not compatible with
-	 * each other due to platform-dependent data type size differences.
-	 *
-	 * If we have a 32-bit userland and a 64-bit kernel, use an
-	 * internally-defined TPACKET_V1_64, with which we use a 64-bit
-	 * version of the data structures.
-	 */
-	if (sizeof(long) == 4) {
-		/*
-		 * This is 32-bit code.
-		 */
-		struct utsname utsname;
-
-		if (uname(&utsname) == -1) {
-			/*
-			 * Failed.
-			 */
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "uname failed");
-			return -1;
-		}
-		if (strcmp(utsname.machine, ISA_64_BIT) == 0) {
-			/*
-			 * uname() tells us the machine is 64-bit,
-			 * so we presumably have a 64-bit kernel.
-			 *
-			 * XXX - this presumes that uname() won't lie
-			 * in 32-bit code and claim that the machine
-			 * has the 32-bit version of the ISA.
-			 */
-			handlep->tp_version = TPACKET_V1_64;
-			handlep->tp_hdrlen = sizeof(struct tpacket_hdr_64);
-		}
-	}
-#endif
-
-	return 1;
+	return -1;
 }
 
 #define MAX(a,b) ((a)>(b)?(a):(b))
@@ -4350,9 +2843,6 @@
  * On success, returns 1, and sets *status to 0 if there are no warnings
  * or to a PCAP_WARNING_ code if there is a warning.
  *
- * On failure due to lack of support for memory-mapped capture, returns
- * 0.
- *
  * On error, returns -1, and sets *status to the appropriate error code;
  * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message.
  */
@@ -4363,9 +2853,9 @@
 	unsigned i, j, frames_per_block;
 #ifdef HAVE_TPACKET3
 	/*
-	 * For sockets using TPACKET_V1 or TPACKET_V2, the extra
-	 * stuff at the end of a struct tpacket_req3 will be
-	 * ignored, so this is OK even for those sockets.
+	 * For sockets using TPACKET_V2, the extra stuff at the end of a
+	 * struct tpacket_req3 will be ignored, so this is OK even for
+	 * those sockets.
 	 */
 	struct tpacket_req3 req;
 #else
@@ -4380,13 +2870,56 @@
 	 */
 	*status = 0;
 
+	/*
+	 * Reserve space for VLAN tag reconstruction.
+	 */
+	tp_reserve = VLAN_TAG_LEN;
+
+	/*
+	 * If we're using DLT_LINUX_SLL2, reserve space for a
+	 * DLT_LINUX_SLL2 header.
+	 *
+	 * XXX - we assume that the kernel is still adding
+	 * 16 bytes of extra space; that happens to
+	 * correspond to SLL_HDR_LEN (whether intentionally
+	 * or not - the kernel code has a raw "16" in
+	 * the expression), so we subtract SLL_HDR_LEN
+	 * from SLL2_HDR_LEN to get the additional space
+	 * needed.  That also means we don't bother reserving
+	 * any additional space if we're using DLT_LINUX_SLL.
+	 *
+	 * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)?
+	 */
+	if (handle->linktype == DLT_LINUX_SLL2)
+		tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN;
+
+	/*
+	 * Try to request that amount of reserve space.
+	 * This must be done before creating the ring buffer.
+	 * If PACKET_RESERVE is supported, creating the ring
+	 * buffer should be, although if creating the ring
+	 * buffer fails, the PACKET_RESERVE call has no effect,
+	 * so falling back on read-from-the-socket capturing
+	 * won't be affected.
+	 */
+	len = sizeof(tp_reserve);
+	if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
+	    &tp_reserve, len) < 0) {
+		/*
+		 * We treat ENOPROTOOPT as an error, as we
+		 * already determined that we support
+		 * TPACKET_V2 and later; see above.
+		 */
+		pcap_fmt_errmsg_for_errno(handle->errbuf,
+		    PCAP_ERRBUF_SIZE, errno,
+		    "setsockopt (PACKET_RESERVE)");
+		*status = PCAP_ERROR;
+		return -1;
+	}
+
 	switch (handlep->tp_version) {
 
-	case TPACKET_V1:
-	case TPACKET_V1_64:
-#ifdef HAVE_TPACKET2
 	case TPACKET_V2:
-#endif
 		/* Note that with large snapshot length (say 256K, which is
 		 * the default for recent versions of tcpdump, Wireshark,
 		 * TShark, dumpcap or 64K, the value that "-s 0" has given for
@@ -4456,62 +2989,6 @@
 			*status = PCAP_ERROR;
 			return -1;
 		}
-#ifdef PACKET_RESERVE
-		len = sizeof(tp_reserve);
-		if (getsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
-		    &tp_reserve, &len) < 0) {
-			if (errno != ENOPROTOOPT) {
-				/*
-				 * ENOPROTOOPT means "kernel doesn't support
-				 * PACKET_RESERVE", in which case we fall back
-				 * as best we can.
-				 */
-				pcap_fmt_errmsg_for_errno(handle->errbuf,
-				    PCAP_ERRBUF_SIZE, errno,
-				    "getsockopt (PACKET_RESERVE)");
-				*status = PCAP_ERROR;
-				return -1;
-			}
-			/*
-			 * Older kernel, so we can't use PACKET_RESERVE;
-			 * this means we can't reserver extra space
-			 * for a DLT_LINUX_SLL2 header.
-			 */
-			tp_reserve = 0;
-		} else {
-			/*
-			 * We can reserve extra space for a DLT_LINUX_SLL2
-			 * header.  Do so.
-			 *
-			 * XXX - we assume that the kernel is still adding
-			 * 16 bytes of extra space; that happens to
-			 * correspond to SLL_HDR_LEN (whether intentionally
-			 * or not - the kernel code has a raw "16" in
-			 * the expression), so we subtract SLL_HDR_LEN
-			 * from SLL2_HDR_LEN to get the additional space
-			 * needed.
-			 *
-			 * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)?
-			 */
-			tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN;
-			len = sizeof(tp_reserve);
-			if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
-			    &tp_reserve, len) < 0) {
-				pcap_fmt_errmsg_for_errno(handle->errbuf,
-				    PCAP_ERRBUF_SIZE, errno,
-				    "setsockopt (PACKET_RESERVE)");
-				*status = PCAP_ERROR;
-				return -1;
-			}
-		}
-#else
-		/*
-		 * Build environment for an older kernel, so we can't
-		 * use PACKET_RESERVE; this means we can't reserve
-		 * extra space for a DLT_LINUX_SLL2 header.
-		 */
-		tp_reserve = 0;
-#endif
 		maclen = (sk_type == SOCK_DGRAM) ? 0 : MAX_LINKHEADER_SIZE;
 			/* XXX: in the kernel maclen is calculated from
 			 * LL_ALLOCATED_SPACE(dev) and vnet_hdr.hdr_len
@@ -4554,49 +3031,6 @@
 
 #ifdef HAVE_TPACKET3
 	case TPACKET_V3:
-		/*
-		 * If we have TPACKET_V3, we have PACKET_RESERVE.
-		 */
-		len = sizeof(tp_reserve);
-		if (getsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
-		    &tp_reserve, &len) < 0) {
-			/*
-			 * Even ENOPROTOOPT is an error - we wouldn't
-			 * be here if the kernel didn't support
-			 * TPACKET_V3, which means it supports
-			 * PACKET_RESERVE.
-			 */
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno,
-			    "getsockopt (PACKET_RESERVE)");
-			*status = PCAP_ERROR;
-			return -1;
-		}
-		/*
-		 * We can reserve extra space for a DLT_LINUX_SLL2
-		 * header.  Do so.
-		 *
-		 * XXX - we assume that the kernel is still adding
-		 * 16 bytes of extra space; that happens to
-		 * correspond to SLL_HDR_LEN (whether intentionally
-		 * or not - the kernel code has a raw "16" in
-		 * the expression), so we subtract SLL_HDR_LEN
-		 * from SLL2_HDR_LEN to get the additional space
-		 * needed.
-		 *
-		 * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)?
-		 */
-		tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN;
-		len = sizeof(tp_reserve);
-		if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
-                    &tp_reserve, len) < 0) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno,
-			    "setsockopt (PACKET_RESERVE)");
-			*status = PCAP_ERROR;
-			return -1;
-		}
-
 		/* The "frames" for this are actually buffers that
 		 * contain multiple variable-sized frames.
 		 *
@@ -4615,14 +3049,14 @@
 		break;
 #endif
 	default:
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    "Internal error: unknown TPACKET_ value %u",
 		    handlep->tp_version);
 		*status = PCAP_ERROR;
 		return -1;
 	}
 
-	/* compute the minumum block size that will handle this frame.
+	/* compute the minimum block size that will handle this frame.
 	 * The block has to be page size aligned.
 	 * The max block size allowed by the kernel is arch-dependent and
 	 * it's not explicitly checked here. */
@@ -4796,12 +3230,6 @@
 				req.tp_frame_nr -= req.tp_frame_nr/20;
 			goto retry;
 		}
-		if (errno == ENOPROTOOPT) {
-			/*
-			 * We don't have ring buffer support in this kernel.
-			 */
-			return 0;
-		}
 		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
 		    errno, "can't create rx ring on packet socket");
 		*status = PCAP_ERROR;
@@ -4837,7 +3265,7 @@
 	/* fill the header ring with proper frame ptr*/
 	handle->offset = 0;
 	for (i=0; i<req.tp_block_nr; ++i) {
-		void *base = &handlep->mmapbuf[i*req.tp_block_size];
+		u_char *base = &handlep->mmapbuf[i*req.tp_block_size];
 		for (j=0; j<frames_per_block; ++j, ++handle->offset) {
 			RING_GET_CURRENT_FRAME(handle) = base;
 			base += req.tp_frame_size;
@@ -4855,10 +3283,14 @@
 {
 	struct pcap_linux *handlep = handle->priv;
 
-	/* tell the kernel to destroy the ring*/
+	/*
+	 * Tell the kernel to destroy the ring.
+	 * We don't check for setsockopt failure, as 1) we can't recover
+	 * from an error and 2) we might not yet have set it up in the
+	 * first place.
+	 */
 	struct tpacket_req req;
 	memset(&req, 0, sizeof(req));
-	/* do not test for setsockopt failure, as we can't recover from any error */
 	(void)setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING,
 				(void *) &req, sizeof(req));
 
@@ -4888,7 +3320,7 @@
  * pcap_next() or pcap_next_ex().
  */
 static void
-pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h,
+pcap_oneshot_linux(u_char *user, const struct pcap_pkthdr *h,
     const u_char *bytes)
 {
 	struct oneshot_userdata *sp = (struct oneshot_userdata *)user;
@@ -4900,22 +3332,8 @@
 	*sp->pkt = handlep->oneshot_buffer;
 }
 
-static void
-pcap_cleanup_linux_mmap( pcap_t *handle )
-{
-	struct pcap_linux *handlep = handle->priv;
-
-	destroy_ring(handle);
-	if (handlep->oneshot_buffer != NULL) {
-		free(handlep->oneshot_buffer);
-		handlep->oneshot_buffer = NULL;
-	}
-	pcap_cleanup_linux(handle);
-}
-
-
 static int
-pcap_getnonblock_mmap(pcap_t *handle)
+pcap_getnonblock_linux(pcap_t *handle)
 {
 	struct pcap_linux *handlep = handle->priv;
 
@@ -4924,7 +3342,7 @@
 }
 
 static int
-pcap_setnonblock_mmap(pcap_t *handle, int nonblock)
+pcap_setnonblock_linux(pcap_t *handle, int nonblock)
 {
 	struct pcap_linux *handlep = handle->priv;
 
@@ -4960,7 +3378,7 @@
 /*
  * Get the status field of the ring buffer frame at a specified offset.
  */
-static inline int
+static inline u_int
 pcap_get_ring_frame_status(pcap_t *handle, int offset)
 {
 	struct pcap_linux *handlep = handle->priv;
@@ -4968,20 +3386,12 @@
 
 	h.raw = RING_GET_FRAME_AT(handle, offset);
 	switch (handlep->tp_version) {
-	case TPACKET_V1:
-		return (h.h1->tp_status);
-		break;
-	case TPACKET_V1_64:
-		return (h.h1_64->tp_status);
-		break;
-#ifdef HAVE_TPACKET2
 	case TPACKET_V2:
-		return (h.h2->tp_status);
+		return __atomic_load_n(&h.h2->tp_status, __ATOMIC_ACQUIRE);
 		break;
-#endif
 #ifdef HAVE_TPACKET3
 	case TPACKET_V3:
-		return (h.h3->hdr.bh1.block_status);
+		return __atomic_load_n(&h.h3->hdr.bh1.block_status, __ATOMIC_ACQUIRE);
 		break;
 #endif
 	}
@@ -4989,25 +3399,62 @@
 	return 0;
 }
 
-#ifndef POLLRDHUP
-#define POLLRDHUP 0
-#endif
-
 /*
  * Block waiting for frames to be available.
  */
 static int pcap_wait_for_frames_mmap(pcap_t *handle)
 {
 	struct pcap_linux *handlep = handle->priv;
-	char c;
-	struct pollfd pollinfo;
+	int timeout;
+	struct ifreq ifr;
 	int ret;
+	struct pollfd pollinfo[2];
+	pollinfo[0].fd = handle->fd;
+	pollinfo[0].events = POLLIN;
+	pollinfo[1].fd = handlep->poll_breakloop_fd;
+	pollinfo[1].events = POLLIN;
 
-	pollinfo.fd = handle->fd;
-	pollinfo.events = POLLIN;
-
-	do {
-		/*
+	/*
+	 * Keep polling until we either get some packets to read, see
+	 * that we got told to break out of the loop, get a fatal error,
+	 * or discover that the device went away.
+	 *
+	 * In non-blocking mode, we must still do one poll() to catch
+	 * any pending error indications, but the poll() has a timeout
+	 * of 0, so that it doesn't block, and we quit after that one
+	 * poll().
+	 *
+	 * If we've seen an ENETDOWN, it might be the first indication
+	 * that the device went away, or it might just be that it was
+	 * configured down.  Unfortunately, there's no guarantee that
+	 * the device has actually been removed as an interface, because:
+	 *
+	 * 1) if, as appears to be the case at least some of the time,
+	 * the PF_PACKET socket code first gets a NETDEV_DOWN indication
+	 * for the device and then gets a NETDEV_UNREGISTER indication
+	 * for it, the first indication will cause a wakeup with ENETDOWN
+	 * but won't set the packet socket's field for the interface index
+	 * to -1, and the second indication won't cause a wakeup (because
+	 * the first indication also caused the protocol hook to be
+	 * unregistered) but will set the packet socket's field for the
+	 * interface index to -1;
+	 *
+	 * 2) even if just a NETDEV_UNREGISTER indication is registered,
+	 * the packet socket's field for the interface index only gets
+	 * set to -1 after the wakeup, so there's a small but non-zero
+	 * risk that a thread blocked waiting for the wakeup will get
+	 * to the "fetch the socket name" code before the interface index
+	 * gets set to -1, so it'll get the old interface index.
+	 *
+	 * Therefore, if we got an ENETDOWN and haven't seen a packet
+	 * since then, we assume that we might be waiting for the interface
+	 * to disappear, and poll with a timeout to try again in a short
+	 * period of time.  If we *do* see a packet, the interface has
+	 * come back up again, and is *definitely* still there, so we
+	 * don't need to poll.
+	 */
+	for (;;) {
+	 	/*
 		 * Yes, we do this even in non-blocking mode, as it's
 		 * the only way to get error indications from a
 		 * tpacket socket.
@@ -5015,67 +3462,281 @@
 		 * The timeout is 0 in non-blocking mode, so poll()
 		 * returns immediately.
 		 */
-		ret = poll(&pollinfo, 1, handlep->poll_timeout);
-		if (ret < 0 && errno != EINTR) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno,
-			    "can't poll on packet socket");
-			return PCAP_ERROR;
-		} else if (ret > 0 &&
-			(pollinfo.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) {
+		timeout = handlep->poll_timeout;
+
+		/*
+		 * If we got an ENETDOWN and haven't gotten an indication
+		 * that the device has gone away or that the device is up,
+		 * we don't yet know for certain whether the device has
+		 * gone away or not, do a poll() with a 1-millisecond timeout,
+		 * as we have to poll indefinitely for "device went away"
+		 * indications until we either get one or see that the
+		 * device is up.
+		 */
+		if (handlep->netdown) {
+			if (timeout != 0)
+				timeout = 1;
+		}
+		ret = poll(pollinfo, 2, timeout);
+		if (ret < 0) {
 			/*
-			 * There's some indication other than
-			 * "you can read on this descriptor" on
-			 * the descriptor.
+			 * Error.  If it's not EINTR, report it.
 			 */
-			if (pollinfo.revents & (POLLHUP | POLLRDHUP)) {
-				pcap_snprintf(handle->errbuf,
-					PCAP_ERRBUF_SIZE,
-					"Hangup on packet socket");
+			if (errno != EINTR) {
+				pcap_fmt_errmsg_for_errno(handle->errbuf,
+				    PCAP_ERRBUF_SIZE, errno,
+				    "can't poll on packet socket");
 				return PCAP_ERROR;
 			}
-			if (pollinfo.revents & POLLERR) {
+
+			/*
+			 * It's EINTR; if we were told to break out of
+			 * the loop, do so.
+			 */
+			if (handle->break_loop) {
+				handle->break_loop = 0;
+				return PCAP_ERROR_BREAK;
+			}
+		} else if (ret > 0) {
+			/*
+			 * OK, some descriptor is ready.
+			 * Check the socket descriptor first.
+			 *
+			 * As I read the Linux man page, pollinfo[0].revents
+			 * will either be POLLIN, POLLERR, POLLHUP, or POLLNVAL.
+			 */
+			if (pollinfo[0].revents == POLLIN) {
 				/*
-				 * A recv() will give us the actual error code.
-				 *
-				 * XXX - make the socket non-blocking?
+				 * OK, we may have packets to
+				 * read.
 				 */
-				if (recv(handle->fd, &c, sizeof c,
-					MSG_PEEK) != -1)
-					continue;	/* what, no error? */
-				if (errno == ENETDOWN) {
+				break;
+			}
+			if (pollinfo[0].revents != 0) {
+				/*
+				 * There's some indication other than
+				 * "you can read on this descriptor" on
+				 * the descriptor.
+				 */
+				if (pollinfo[0].revents & POLLNVAL) {
+					snprintf(handle->errbuf,
+					    PCAP_ERRBUF_SIZE,
+					    "Invalid polling request on packet socket");
+					return PCAP_ERROR;
+				}
+				if (pollinfo[0].revents & (POLLHUP | POLLRDHUP)) {
+					snprintf(handle->errbuf,
+					    PCAP_ERRBUF_SIZE,
+					    "Hangup on packet socket");
+					return PCAP_ERROR;
+				}
+				if (pollinfo[0].revents & POLLERR) {
 					/*
-					 * The device on which we're
-					 * capturing went away.
-					 *
-					 * XXX - we should really return
-					 * PCAP_ERROR_IFACE_NOT_UP, but
-					 * pcap_dispatch() etc. aren't
-					 * defined to return that.
+					 * Get the error.
 					 */
-					pcap_snprintf(handle->errbuf,
-						PCAP_ERRBUF_SIZE,
-						"The interface went down");
+					int err;
+					socklen_t errlen;
+
+					errlen = sizeof(err);
+					if (getsockopt(handle->fd, SOL_SOCKET,
+					    SO_ERROR, &err, &errlen) == -1) {
+						/*
+						 * The call *itself* returned
+						 * an error; make *that*
+						 * the error.
+						 */
+						err = errno;
+					}
+
+					/*
+					 * OK, we have the error.
+					 */
+					if (err == ENETDOWN) {
+						/*
+						 * The device on which we're
+						 * capturing went away or the
+						 * interface was taken down.
+						 *
+						 * We don't know for certain
+						 * which happened, and the
+						 * next poll() may indicate
+						 * that there are packets
+						 * to be read, so just set
+						 * a flag to get us to do
+						 * checks later, and set
+						 * the required select
+						 * timeout to 1 millisecond
+						 * so that event loops that
+						 * check our socket descriptor
+						 * also time out so that
+						 * they can call us and we
+						 * can do the checks.
+						 */
+						handlep->netdown = 1;
+						handle->required_select_timeout = &netdown_timeout;
+					} else if (err == 0) {
+						/*
+						 * This shouldn't happen, so
+						 * report a special indication
+						 * that it did.
+						 */
+						snprintf(handle->errbuf,
+						    PCAP_ERRBUF_SIZE,
+						    "Error condition on packet socket: Reported error was 0");
+						return PCAP_ERROR;
+					} else {
+						pcap_fmt_errmsg_for_errno(handle->errbuf,
+						    PCAP_ERRBUF_SIZE,
+						    err,
+						    "Error condition on packet socket");
+						return PCAP_ERROR;
+					}
+				}
+			}
+			/*
+			 * Now check the event device.
+			 */
+			if (pollinfo[1].revents & POLLIN) {
+				ssize_t nread;
+				uint64_t value;
+
+				/*
+				 * This should never fail, but, just
+				 * in case....
+				 */
+				nread = read(handlep->poll_breakloop_fd, &value,
+				    sizeof(value));
+				if (nread == -1) {
+					pcap_fmt_errmsg_for_errno(handle->errbuf,
+					    PCAP_ERRBUF_SIZE,
+					    errno,
+					    "Error reading from event FD");
+					return PCAP_ERROR;
+				}
+
+				/*
+				 * According to the Linux read(2) man
+				 * page, read() will transfer at most
+				 * 2^31-1 bytes, so the return value is
+				 * either -1 or a value between 0
+				 * and 2^31-1, so it's non-negative.
+				 *
+				 * Cast it to size_t to squelch
+				 * warnings from the compiler; add this
+				 * comment to squelch warnings from
+				 * humans reading the code. :-)
+				 *
+				 * Don't treat an EOF as an error, but
+				 * *do* treat a short read as an error;
+				 * that "shouldn't happen", but....
+				 */
+				if (nread != 0 &&
+				    (size_t)nread < sizeof(value)) {
+					snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+					    "Short read from event FD: expected %zu, got %zd",
+					    sizeof(value), nread);
+					return PCAP_ERROR;
+				}
+
+				/*
+				 * This event gets signaled by a
+				 * pcap_breakloop() call; if we were told
+				 * to break out of the loop, do so.
+				 */
+				if (handle->break_loop) {
+					handle->break_loop = 0;
+					return PCAP_ERROR_BREAK;
+				}
+			}
+		}
+
+		/*
+		 * Either:
+		 *
+		 *   1) we got neither an error from poll() nor any
+		 *      readable descriptors, in which case there
+		 *      are no packets waiting to read
+		 *
+		 * or
+		 *
+		 *   2) We got readable descriptors but the PF_PACKET
+		 *      socket wasn't one of them, in which case there
+		 *      are no packets waiting to read
+		 *
+		 * so, if we got an ENETDOWN, we've drained whatever
+		 * packets were available to read at the point of the
+		 * ENETDOWN.
+		 *
+		 * So, if we got an ENETDOWN and haven't gotten an indication
+		 * that the device has gone away or that the device is up,
+		 * we don't yet know for certain whether the device has
+		 * gone away or not, check whether the device exists and is
+		 * up.
+		 */
+		if (handlep->netdown) {
+			if (!device_still_exists(handle)) {
+				/*
+				 * The device doesn't exist any more;
+				 * report that.
+				 *
+				 * XXX - we should really return an
+				 * appropriate error for that, but
+				 * pcap_dispatch() etc. aren't documented
+				 * as having error returns other than
+				 * PCAP_ERROR or PCAP_ERROR_BREAK.
+				 */
+				snprintf(handle->errbuf,  PCAP_ERRBUF_SIZE,
+				    "The interface disappeared");
+				return PCAP_ERROR;
+			}
+
+			/*
+			 * The device still exists; try to see if it's up.
+			 */
+			memset(&ifr, 0, sizeof(ifr));
+			pcap_strlcpy(ifr.ifr_name, handlep->device,
+			    sizeof(ifr.ifr_name));
+			if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
+				if (errno == ENXIO || errno == ENODEV) {
+					/*
+					 * OK, *now* it's gone.
+					 *
+					 * XXX - see above comment.
+					 */
+					snprintf(handle->errbuf,
+					    PCAP_ERRBUF_SIZE,
+					    "The interface disappeared");
+					return PCAP_ERROR;
 				} else {
 					pcap_fmt_errmsg_for_errno(handle->errbuf,
 					    PCAP_ERRBUF_SIZE, errno,
-					    "Error condition on packet socket");
+					    "%s: Can't get flags",
+					    handlep->device);
+					return PCAP_ERROR;
 				}
-				return PCAP_ERROR;
 			}
-			if (pollinfo.revents & POLLNVAL) {
-				pcap_snprintf(handle->errbuf,
-					PCAP_ERRBUF_SIZE,
-					"Invalid polling request on packet socket");
-				return PCAP_ERROR;
+			if (ifr.ifr_flags & IFF_UP) {
+				/*
+				 * It's up, so it definitely still exists.
+				 * Cancel the ENETDOWN indication - we
+				 * presumably got it due to the interface
+				 * going down rather than the device going
+				 * away - and revert to "no required select
+				 * timeout.
+				 */
+				handlep->netdown = 0;
+				handle->required_select_timeout = NULL;
 			}
 		}
-		/* check for break loop condition on interrupted syscall*/
-		if (handle->break_loop) {
-			handle->break_loop = 0;
-			return PCAP_ERROR_BREAK;
-		}
-	} while (ret < 0);
+
+		/*
+		 * If we're in non-blocking mode, just quit now, rather
+		 * than spinning in a loop doing poll()s that immediately
+		 * time out if there's no indication on any descriptor.
+		 */
+		if (handlep->poll_timeout == 0)
+			break;
+	}
 	return 0;
 }
 
@@ -5107,7 +3768,7 @@
 		 * Report some system information as a debugging aid.
 		 */
 		if (uname(&utsname) != -1) {
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 				"corrupted frame on kernel ring mac "
 				"offset %u + caplen %u > frame len %d "
 				"(kernel %.32s version %s, machine %.16s)",
@@ -5115,7 +3776,7 @@
 				utsname.release, utsname.version,
 				utsname.machine);
 		} else {
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 				"corrupted frame on kernel ring mac "
 				"offset %u + caplen %u > frame len %d",
 				tp_mac, tp_snaplen, handle->bufsize);
@@ -5135,7 +3796,7 @@
 	bp = frame + tp_mac;
 
 	/* if required build in place the sll header*/
-	sll = (void *)frame + TPACKET_ALIGN(handlep->tp_hdrlen);
+	sll = (void *)(frame + TPACKET_ALIGN(handlep->tp_hdrlen));
 	if (handlep->cooked) {
 		if (handle->linktype == DLT_LINUX_SLL2) {
 			struct sll2_header *hdrp;
@@ -5159,7 +3820,7 @@
 			if (bp < (u_char *)frame +
 					   TPACKET_ALIGN(handlep->tp_hdrlen) +
 					   sizeof(struct sockaddr_ll)) {
-				pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 					"cooked-mode frame doesn't have room for sll header");
 				return -1;
 			}
@@ -5199,7 +3860,7 @@
 			if (bp < (u_char *)frame +
 					   TPACKET_ALIGN(handlep->tp_hdrlen) +
 					   sizeof(struct sockaddr_ll)) {
-				pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 					"cooked-mode frame doesn't have room for sll header");
 				return -1;
 			}
@@ -5224,11 +3885,11 @@
 		aux_data.vlan_tag_present = tp_vlan_tci_valid;
 		aux_data.vlan_tag = tp_vlan_tci & 0x0fff;
 
-		if (bpf_filter_with_aux_data(handle->fcode.bf_insns,
-					     bp,
-					     tp_len,
-					     snaplen,
-					     &aux_data) == 0)
+		if (pcap_filter_with_aux_data(handle->fcode.bf_insns,
+					      bp,
+					      tp_len,
+					      snaplen,
+					      &aux_data) == 0)
 			return 0;
 	}
 
@@ -5253,7 +3914,6 @@
 		}
 	}
 
-#if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3)
 	if (tp_vlan_tci_valid &&
 		handlep->vlan_offset != -1 &&
 		tp_snaplen >= (unsigned int) handlep->vlan_offset)
@@ -5281,7 +3941,6 @@
 		pcaphdr.caplen += VLAN_TAG_LEN;
 		pcaphdr.len += VLAN_TAG_LEN;
 	}
-#endif
 
 	/*
 	 * The only way to tell the kernel to cut off the
@@ -5291,6 +3950,13 @@
 	 *
 	 * Trim the snapshot length to be no longer than the
 	 * specified snapshot length.
+	 *
+	 * XXX - an alternative is to put a filter, consisting
+	 * of a "ret <snaplen>" instruction, on the socket
+	 * in the activate routine, so that the truncation is
+	 * done in the kernel even if nobody specified a filter;
+	 * that means that less buffer space is consumed in
+	 * the memory-mapped buffer.
 	 */
 	if (pcaphdr.caplen > (bpf_u_int32)handle->snapshot)
 		pcaphdr.caplen = handle->snapshot;
@@ -5302,175 +3968,6 @@
 }
 
 static int
-pcap_read_linux_mmap_v1(pcap_t *handle, int max_packets, pcap_handler callback,
-		u_char *user)
-{
-	struct pcap_linux *handlep = handle->priv;
-	union thdr h;
-	int pkts = 0;
-	int ret;
-
-	/* wait for frames availability.*/
-	h.raw = RING_GET_CURRENT_FRAME(handle);
-	if (h.h1->tp_status == TP_STATUS_KERNEL) {
-		/*
-		 * The current frame is owned by the kernel; wait for
-		 * a frame to be handed to us.
-		 */
-		ret = pcap_wait_for_frames_mmap(handle);
-		if (ret) {
-			return ret;
-		}
-	}
-
-	/* non-positive values of max_packets are used to require all
-	 * packets currently available in the ring */
-	while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) {
-		/*
-		 * Get the current ring buffer frame, and break if
-		 * it's still owned by the kernel.
-		 */
-		h.raw = RING_GET_CURRENT_FRAME(handle);
-		if (h.h1->tp_status == TP_STATUS_KERNEL)
-			break;
-
-		ret = pcap_handle_packet_mmap(
-				handle,
-				callback,
-				user,
-				h.raw,
-				h.h1->tp_len,
-				h.h1->tp_mac,
-				h.h1->tp_snaplen,
-				h.h1->tp_sec,
-				h.h1->tp_usec,
-				0,
-				0,
-				0);
-		if (ret == 1) {
-			pkts++;
-			handlep->packets_read++;
-		} else if (ret < 0) {
-			return ret;
-		}
-
-		/*
-		 * Hand this block back to the kernel, and, if we're
-		 * counting blocks that need to be filtered in userland
-		 * after having been filtered by the kernel, count
-		 * the one we've just processed.
-		 */
-		h.h1->tp_status = TP_STATUS_KERNEL;
-		if (handlep->blocks_to_filter_in_userland > 0) {
-			handlep->blocks_to_filter_in_userland--;
-			if (handlep->blocks_to_filter_in_userland == 0) {
-				/*
-				 * No more blocks need to be filtered
-				 * in userland.
-				 */
-				handlep->filter_in_userland = 0;
-			}
-		}
-
-		/* next block */
-		if (++handle->offset >= handle->cc)
-			handle->offset = 0;
-
-		/* check for break loop condition*/
-		if (handle->break_loop) {
-			handle->break_loop = 0;
-			return PCAP_ERROR_BREAK;
-		}
-	}
-	return pkts;
-}
-
-static int
-pcap_read_linux_mmap_v1_64(pcap_t *handle, int max_packets, pcap_handler callback,
-		u_char *user)
-{
-	struct pcap_linux *handlep = handle->priv;
-	union thdr h;
-	int pkts = 0;
-	int ret;
-
-	/* wait for frames availability.*/
-	h.raw = RING_GET_CURRENT_FRAME(handle);
-	if (h.h1_64->tp_status == TP_STATUS_KERNEL) {
-		/*
-		 * The current frame is owned by the kernel; wait for
-		 * a frame to be handed to us.
-		 */
-		ret = pcap_wait_for_frames_mmap(handle);
-		if (ret) {
-			return ret;
-		}
-	}
-
-	/* non-positive values of max_packets are used to require all
-	 * packets currently available in the ring */
-	while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) {
-		/*
-		 * Get the current ring buffer frame, and break if
-		 * it's still owned by the kernel.
-		 */
-		h.raw = RING_GET_CURRENT_FRAME(handle);
-		if (h.h1_64->tp_status == TP_STATUS_KERNEL)
-			break;
-
-		ret = pcap_handle_packet_mmap(
-				handle,
-				callback,
-				user,
-				h.raw,
-				h.h1_64->tp_len,
-				h.h1_64->tp_mac,
-				h.h1_64->tp_snaplen,
-				h.h1_64->tp_sec,
-				h.h1_64->tp_usec,
-				0,
-				0,
-				0);
-		if (ret == 1) {
-			pkts++;
-			handlep->packets_read++;
-		} else if (ret < 0) {
-			return ret;
-		}
-
-		/*
-		 * Hand this block back to the kernel, and, if we're
-		 * counting blocks that need to be filtered in userland
-		 * after having been filtered by the kernel, count
-		 * the one we've just processed.
-		 */
-		h.h1_64->tp_status = TP_STATUS_KERNEL;
-		if (handlep->blocks_to_filter_in_userland > 0) {
-			handlep->blocks_to_filter_in_userland--;
-			if (handlep->blocks_to_filter_in_userland == 0) {
-				/*
-				 * No more blocks need to be filtered
-				 * in userland.
-				 */
-				handlep->filter_in_userland = 0;
-			}
-		}
-
-		/* next block */
-		if (++handle->offset >= handle->cc)
-			handle->offset = 0;
-
-		/* check for break loop condition*/
-		if (handle->break_loop) {
-			handle->break_loop = 0;
-			return PCAP_ERROR_BREAK;
-		}
-	}
-	return pkts;
-}
-
-#ifdef HAVE_TPACKET2
-static int
 pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback,
 		u_char *user)
 {
@@ -5481,7 +3978,7 @@
 
 	/* wait for frames availability.*/
 	h.raw = RING_GET_CURRENT_FRAME(handle);
-	if (h.h2->tp_status == TP_STATUS_KERNEL) {
+	if (!packet_mmap_acquire(h.h2)) {
 		/*
 		 * The current frame is owned by the kernel; wait for
 		 * a frame to be handed to us.
@@ -5500,7 +3997,7 @@
 		 * it's still owned by the kernel.
 		 */
 		h.raw = RING_GET_CURRENT_FRAME(handle);
-		if (h.h2->tp_status == TP_STATUS_KERNEL)
+		if (!packet_mmap_acquire(h.h2))
 			break;
 
 		ret = pcap_handle_packet_mmap(
@@ -5518,7 +4015,6 @@
 				VLAN_TPID(h.h2, h.h2));
 		if (ret == 1) {
 			pkts++;
-			handlep->packets_read++;
 		} else if (ret < 0) {
 			return ret;
 		}
@@ -5529,7 +4025,7 @@
 		 * after having been filtered by the kernel, count
 		 * the one we've just processed.
 		 */
-		h.h2->tp_status = TP_STATUS_KERNEL;
+		packet_mmap_release(h.h2);
 		if (handlep->blocks_to_filter_in_userland > 0) {
 			handlep->blocks_to_filter_in_userland--;
 			if (handlep->blocks_to_filter_in_userland == 0) {
@@ -5553,7 +4049,6 @@
 	}
 	return pkts;
 }
-#endif /* HAVE_TPACKET2 */
 
 #ifdef HAVE_TPACKET3
 static int
@@ -5569,7 +4064,7 @@
 	if (handlep->current_packet == NULL) {
 		/* wait for frames availability.*/
 		h.raw = RING_GET_CURRENT_FRAME(handle);
-		if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) {
+		if (!packet_mmap_v3_acquire(h.h3)) {
 			/*
 			 * The current frame is owned by the kernel; wait
 			 * for a frame to be handed to us.
@@ -5581,7 +4076,7 @@
 		}
 	}
 	h.raw = RING_GET_CURRENT_FRAME(handle);
-	if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) {
+	if (!packet_mmap_v3_acquire(h.h3)) {
 		if (pkts == 0 && handlep->timeout == 0) {
 			/* Block until we see a packet. */
 			goto again;
@@ -5596,7 +4091,7 @@
 
 		if (handlep->current_packet == NULL) {
 			h.raw = RING_GET_CURRENT_FRAME(handle);
-			if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL)
+			if (!packet_mmap_v3_acquire(h.h3))
 				break;
 
 			handlep->current_packet = h.raw + h.h3->hdr.bh1.offset_to_first_pkt;
@@ -5632,7 +4127,6 @@
 					VLAN_TPID(tp3_hdr, &tp3_hdr->hv1));
 			if (ret == 1) {
 				pkts++;
-				handlep->packets_read++;
 			} else if (ret < 0) {
 				handlep->current_packet = NULL;
 				return ret;
@@ -5649,7 +4143,7 @@
 			 * filtered by the kernel, count the one we've
 			 * just processed.
 			 */
-			h.h3->hdr.bh1.block_status = TP_STATUS_KERNEL;
+			packet_mmap_v3_release(h.h3);
 			if (handlep->blocks_to_filter_in_userland > 0) {
 				handlep->blocks_to_filter_in_userland--;
 				if (handlep->blocks_to_filter_in_userland == 0) {
@@ -5682,29 +4176,180 @@
 }
 #endif /* HAVE_TPACKET3 */
 
+/*
+ *  Attach the given BPF code to the packet capture device.
+ */
 static int
-pcap_setfilter_linux_mmap(pcap_t *handle, struct bpf_program *filter)
+pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter)
 {
-	struct pcap_linux *handlep = handle->priv;
-	int n, offset;
-	int ret;
+	struct pcap_linux *handlep;
+	struct sock_fprog	fcode;
+	int			can_filter_in_kernel;
+	int			err = 0;
+	int			n, offset;
+
+	if (!handle)
+		return -1;
+	if (!filter) {
+	        pcap_strlcpy(handle->errbuf, "setfilter: No filter specified",
+			PCAP_ERRBUF_SIZE);
+		return -1;
+	}
+
+	handlep = handle->priv;
+
+	/* Make our private copy of the filter */
+
+	if (install_bpf_program(handle, filter) < 0)
+		/* install_bpf_program() filled in errbuf */
+		return -1;
 
 	/*
-	 * Don't rewrite "ret" instructions; we don't need to, as
-	 * we're not reading packets with recvmsg(), and we don't
-	 * want to, as, by not rewriting them, the kernel can avoid
-	 * copying extra data.
+	 * Run user level packet filter by default. Will be overridden if
+	 * installing a kernel filter succeeds.
 	 */
-	ret = pcap_setfilter_linux_common(handle, filter, 1);
-	if (ret < 0)
-		return ret;
+	handlep->filter_in_userland = 1;
+
+	/* Install kernel level filter if possible */
+
+#ifdef USHRT_MAX
+	if (handle->fcode.bf_len > USHRT_MAX) {
+		/*
+		 * fcode.len is an unsigned short for current kernel.
+		 * I have yet to see BPF-Code with that much
+		 * instructions but still it is possible. So for the
+		 * sake of correctness I added this check.
+		 */
+		fprintf(stderr, "Warning: Filter too complex for kernel\n");
+		fcode.len = 0;
+		fcode.filter = NULL;
+		can_filter_in_kernel = 0;
+	} else
+#endif /* USHRT_MAX */
+	{
+		/*
+		 * Oh joy, the Linux kernel uses struct sock_fprog instead
+		 * of struct bpf_program and of course the length field is
+		 * of different size. Pointed out by Sebastian
+		 *
+		 * Oh, and we also need to fix it up so that all "ret"
+		 * instructions with non-zero operands have MAXIMUM_SNAPLEN
+		 * as the operand if we're not capturing in memory-mapped
+		 * mode, and so that, if we're in cooked mode, all memory-
+		 * reference instructions use special magic offsets in
+		 * references to the link-layer header and assume that the
+		 * link-layer payload begins at 0; "fix_program()" will do
+		 * that.
+		 */
+		switch (fix_program(handle, &fcode)) {
+
+		case -1:
+		default:
+			/*
+			 * Fatal error; just quit.
+			 * (The "default" case shouldn't happen; we
+			 * return -1 for that reason.)
+			 */
+			return -1;
+
+		case 0:
+			/*
+			 * The program performed checks that we can't make
+			 * work in the kernel.
+			 */
+			can_filter_in_kernel = 0;
+			break;
+
+		case 1:
+			/*
+			 * We have a filter that'll work in the kernel.
+			 */
+			can_filter_in_kernel = 1;
+			break;
+		}
+	}
+
+	/*
+	 * NOTE: at this point, we've set both the "len" and "filter"
+	 * fields of "fcode".  As of the 2.6.32.4 kernel, at least,
+	 * those are the only members of the "sock_fprog" structure,
+	 * so we initialize every member of that structure.
+	 *
+	 * If there is anything in "fcode" that is not initialized,
+	 * it is either a field added in a later kernel, or it's
+	 * padding.
+	 *
+	 * If a new field is added, this code needs to be updated
+	 * to set it correctly.
+	 *
+	 * If there are no other fields, then:
+	 *
+	 *	if the Linux kernel looks at the padding, it's
+	 *	buggy;
+	 *
+	 *	if the Linux kernel doesn't look at the padding,
+	 *	then if some tool complains that we're passing
+	 *	uninitialized data to the kernel, then the tool
+	 *	is buggy and needs to understand that it's just
+	 *	padding.
+	 */
+	if (can_filter_in_kernel) {
+		if ((err = set_kernel_filter(handle, &fcode)) == 0)
+		{
+			/*
+			 * Installation succeeded - using kernel filter,
+			 * so userland filtering not needed.
+			 */
+			handlep->filter_in_userland = 0;
+		}
+		else if (err == -1)	/* Non-fatal error */
+		{
+			/*
+			 * Print a warning if we weren't able to install
+			 * the filter for a reason other than "this kernel
+			 * isn't configured to support socket filters.
+			 */
+			if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) {
+				fprintf(stderr,
+				    "Warning: Kernel filter failed: %s\n",
+					pcap_strerror(errno));
+			}
+		}
+	}
+
+	/*
+	 * If we're not using the kernel filter, get rid of any kernel
+	 * filter that might've been there before, e.g. because the
+	 * previous filter could work in the kernel, or because some other
+	 * code attached a filter to the socket by some means other than
+	 * calling "pcap_setfilter()".  Otherwise, the kernel filter may
+	 * filter out packets that would pass the new userland filter.
+	 */
+	if (handlep->filter_in_userland) {
+		if (reset_kernel_filter(handle) == -1) {
+			pcap_fmt_errmsg_for_errno(handle->errbuf,
+			    PCAP_ERRBUF_SIZE, errno,
+			    "can't remove kernel filter");
+			err = -2;	/* fatal error */
+		}
+	}
+
+	/*
+	 * Free up the copy of the filter that was made by "fix_program()".
+	 */
+	if (fcode.filter != NULL)
+		free(fcode.filter);
+
+	if (err == -2)
+		/* Fatal error */
+		return -1;
 
 	/*
 	 * If we're filtering in userland, there's nothing to do;
 	 * the new filter will be used for the next packet.
 	 */
 	if (handlep->filter_in_userland)
-		return ret;
+		return 0;
 
 	/*
 	 * We're filtering in the kernel; the packets present in
@@ -5755,13 +4400,10 @@
 	 */
 	handlep->blocks_to_filter_in_userland = handle->cc - n;
 	handlep->filter_in_userland = 1;
-	return ret;
+
+	return 0;
 }
 
-#endif /* HAVE_PACKET_RING */
-
-
-#ifdef HAVE_PF_PACKET_SOCKETS
 /*
  *  Return the index of the given device name. Fill ebuf and return
  *  -1 on failure.
@@ -5785,19 +4427,18 @@
 
 /*
  *  Bind the socket associated with FD to the given device.
- *  Return 1 on success, 0 if we should try a SOCK_PACKET socket,
- *  or a PCAP_ERROR_ value on a hard error.
+ *  Return 0 on success or a PCAP_ERROR_ value on a hard error.
  */
 static int
 iface_bind(int fd, int ifindex, char *ebuf, int protocol)
 {
 	struct sockaddr_ll	sll;
-	int			err;
+	int			ret, err;
 	socklen_t		errlen = sizeof(err);
 
 	memset(&sll, 0, sizeof(sll));
 	sll.sll_family		= AF_PACKET;
-	sll.sll_ifindex		= ifindex;
+	sll.sll_ifindex		= ifindex < 0 ? 0 : ifindex;
 	sll.sll_protocol	= protocol;
 
 	if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) {
@@ -5810,11 +4451,14 @@
 			 * libpcap developers.
 			 */
 			return PCAP_ERROR_IFACE_NOT_UP;
-		} else {
-			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
-			    errno, "bind");
-			return PCAP_ERROR;
 		}
+		if (errno == ENODEV)
+			ret = PCAP_ERROR_NO_SUCH_DEVICE;
+		else
+			ret = PCAP_ERROR;
+		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+		    errno, "bind");
+		return ret;
 	}
 
 	/* Any pending errors, e.g., network is down? */
@@ -5822,7 +4466,7 @@
 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
 		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
 		    errno, "getsockopt (SO_ERROR)");
-		return 0;
+		return PCAP_ERROR;
 	}
 
 	if (err == ENETDOWN) {
@@ -5837,391 +4481,89 @@
 	} else if (err > 0) {
 		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
 		    err, "bind");
-		return 0;
-	}
-
-	return 1;
-}
-
-#ifdef IW_MODE_MONITOR
-/*
- * Check whether the device supports the Wireless Extensions.
- * Returns 1 if it does, 0 if it doesn't, PCAP_ERROR_NO_SUCH_DEVICE
- * if the device doesn't even exist.
- */
-static int
-has_wext(int sock_fd, const char *device, char *ebuf)
-{
-	struct iwreq ireq;
-	int ret;
-
-	if (is_bonding_device(sock_fd, device))
-		return 0;	/* bonding device, so don't even try */
-
-	pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-	    sizeof ireq.ifr_ifrn.ifrn_name);
-	if (ioctl(sock_fd, SIOCGIWNAME, &ireq) >= 0)
-		return 1;	/* yes */
-	if (errno == ENODEV)
-		ret = PCAP_ERROR_NO_SUCH_DEVICE;
-	else
-		ret = 0;
-	pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno,
-	    "%s: SIOCGIWNAME", device);
-	return ret;
-}
-
-/*
- * Per me si va ne la citta dolente,
- * Per me si va ne l'etterno dolore,
- *	...
- * Lasciate ogne speranza, voi ch'intrate.
- *
- * XXX - airmon-ng does special stuff with the Orinoco driver and the
- * wlan-ng driver.
- */
-typedef enum {
-	MONITOR_WEXT,
-	MONITOR_HOSTAP,
-	MONITOR_PRISM,
-	MONITOR_PRISM54,
-	MONITOR_ACX100,
-	MONITOR_RT2500,
-	MONITOR_RT2570,
-	MONITOR_RT73,
-	MONITOR_RTL8XXX
-} monitor_type;
-
-/*
- * Use the Wireless Extensions, if we have them, to try to turn monitor mode
- * on if it's not already on.
- *
- * Returns 1 on success, 0 if we don't support the Wireless Extensions
- * on this device, or a PCAP_ERROR_ value if we do support them but
- * we weren't able to turn monitor mode on.
- */
-static int
-enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device)
-{
-	/*
-	 * XXX - at least some adapters require non-Wireless Extensions
-	 * mechanisms to turn monitor mode on.
-	 *
-	 * Atheros cards might require that a separate "monitor virtual access
-	 * point" be created, with later versions of the madwifi driver.
-	 * airmon-ng does "wlanconfig ath create wlandev {if} wlanmode
-	 * monitor -bssid", which apparently spits out a line "athN"
-	 * where "athN" is the monitor mode device.  To leave monitor
-	 * mode, it destroys the monitor mode device.
-	 *
-	 * Some Intel Centrino adapters might require private ioctls to get
-	 * radio headers; the ipw2200 and ipw3945 drivers allow you to
-	 * configure a separate "rtapN" interface to capture in monitor
-	 * mode without preventing the adapter from operating normally.
-	 * (airmon-ng doesn't appear to use that, though.)
-	 *
-	 * It would be Truly Wonderful if mac80211 and nl80211 cleaned this
-	 * up, and if all drivers were converted to mac80211 drivers.
-	 *
-	 * If interface {if} is a mac80211 driver, the file
-	 * /sys/class/net/{if}/phy80211 is a symlink to
-	 * /sys/class/ieee80211/{phydev}, for some {phydev}.
-	 *
-	 * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at
-	 * least, has a "wmaster0" device and a "wlan0" device; the
-	 * latter is the one with the IP address.  Both show up in
-	 * "tcpdump -D" output.  Capturing on the wmaster0 device
-	 * captures with 802.11 headers.
-	 *
-	 * airmon-ng searches through /sys/class/net for devices named
-	 * monN, starting with mon0; as soon as one *doesn't* exist,
-	 * it chooses that as the monitor device name.  If the "iw"
-	 * command exists, it does "iw dev {if} interface add {monif}
-	 * type monitor", where {monif} is the monitor device.  It
-	 * then (sigh) sleeps .1 second, and then configures the
-	 * device up.  Otherwise, if /sys/class/ieee80211/{phydev}/add_iface
-	 * is a file, it writes {mondev}, without a newline, to that file,
-	 * and again (sigh) sleeps .1 second, and then iwconfig's that
-	 * device into monitor mode and configures it up.  Otherwise,
-	 * you can't do monitor mode.
-	 *
-	 * All these devices are "glued" together by having the
-	 * /sys/class/net/{device}/phy80211 links pointing to the same
-	 * place, so, given a wmaster, wlan, or mon device, you can
-	 * find the other devices by looking for devices with
-	 * the same phy80211 link.
-	 *
-	 * To turn monitor mode off, delete the monitor interface,
-	 * either with "iw dev {monif} interface del" or by sending
-	 * {monif}, with no NL, down /sys/class/ieee80211/{phydev}/remove_iface
-	 *
-	 * Note: if you try to create a monitor device named "monN", and
-	 * there's already a "monN" device, it fails, as least with
-	 * the netlink interface (which is what iw uses), with a return
-	 * value of -ENFILE.  (Return values are negative errnos.)  We
-	 * could probably use that to find an unused device.
-	 */
-	struct pcap_linux *handlep = handle->priv;
-	int err;
-	struct iwreq ireq;
-	struct iw_priv_args *priv;
-	monitor_type montype;
-	int i;
-	__u32 cmd;
-	struct ifreq ifr;
-	int oldflags;
-	int args[2];
-	int channel;
-
-	/*
-	 * Does this device *support* the Wireless Extensions?
-	 */
-	err = has_wext(sock_fd, device, handle->errbuf);
-	if (err <= 0)
-		return err;	/* either it doesn't or the device doesn't even exist */
-	/*
-	 * Start out assuming we have no private extensions to control
-	 * radio metadata.
-	 */
-	montype = MONITOR_WEXT;
-	cmd = 0;
-
-	/*
-	 * Try to get all the Wireless Extensions private ioctls
-	 * supported by this device.
-	 *
-	 * First, get the size of the buffer we need, by supplying no
-	 * buffer and a length of 0.  If the device supports private
-	 * ioctls, it should return E2BIG, with ireq.u.data.length set
-	 * to the length we need.  If it doesn't support them, it should
-	 * return EOPNOTSUPP.
-	 */
-	memset(&ireq, 0, sizeof ireq);
-	pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-	    sizeof ireq.ifr_ifrn.ifrn_name);
-	ireq.u.data.pointer = (void *)args;
-	ireq.u.data.length = 0;
-	ireq.u.data.flags = 0;
-	if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) != -1) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    "%s: SIOCGIWPRIV with a zero-length buffer didn't fail!",
-		    device);
 		return PCAP_ERROR;
 	}
-	if (errno != EOPNOTSUPP) {
+
+	return 0;
+}
+
+/*
+ * Try to enter monitor mode.
+ * If we have libnl, try to create a new monitor-mode device and
+ * capture on that; otherwise, just say "not supported".
+ */
+#ifdef HAVE_LIBNL
+static int
+enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device)
+{
+	struct pcap_linux *handlep = handle->priv;
+	int ret;
+	char phydev_path[PATH_MAX+1];
+	struct nl80211_state nlstate;
+	struct ifreq ifr;
+	u_int n;
+
+	/*
+	 * Is this a mac80211 device?
+	 */
+	ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX);
+	if (ret < 0)
+		return ret;	/* error */
+	if (ret == 0)
+		return 0;	/* no error, but not mac80211 device */
+
+	/*
+	 * XXX - is this already a monN device?
+	 * If so, we're done.
+	 */
+
+	/*
+	 * OK, it's apparently a mac80211 device.
+	 * Try to find an unused monN device for it.
+	 */
+	ret = nl80211_init(handle, &nlstate, device);
+	if (ret != 0)
+		return ret;
+	for (n = 0; n < UINT_MAX; n++) {
 		/*
-		 * OK, it's not as if there are no private ioctls.
+		 * Try mon{n}.
 		 */
-		if (errno != E2BIG) {
+		char mondevice[3+10+1];	/* mon{UINT_MAX}\0 */
+
+		snprintf(mondevice, sizeof mondevice, "mon%u", n);
+		ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice);
+		if (ret == 1) {
 			/*
-			 * Failed.
+			 * Success.  We don't clean up the libnl state
+			 * yet, as we'll be using it later.
 			 */
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWPRIV", device);
-			return PCAP_ERROR;
+			goto added;
 		}
-
-		/*
-		 * OK, try to get the list of private ioctls.
-		 */
-		priv = malloc(ireq.u.data.length * sizeof (struct iw_priv_args));
-		if (priv == NULL) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "malloc");
-			return PCAP_ERROR;
+		if (ret < 0) {
+			/*
+			 * Hard failure.  Just return ret; handle->errbuf
+			 * has already been set.
+			 */
+			nl80211_cleanup(&nlstate);
+			return ret;
 		}
-		ireq.u.data.pointer = (void *)priv;
-		if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWPRIV", device);
-			free(priv);
-			return PCAP_ERROR;
-		}
-
-		/*
-		 * Look for private ioctls to turn monitor mode on or, if
-		 * monitor mode is on, to set the header type.
-		 */
-		for (i = 0; i < ireq.u.data.length; i++) {
-			if (strcmp(priv[i].name, "monitor_type") == 0) {
-				/*
-				 * Hostap driver, use this one.
-				 * Set monitor mode first.
-				 * You can set it to 0 to get DLT_IEEE80211,
-				 * 1 to get DLT_PRISM, 2 to get
-				 * DLT_IEEE80211_RADIO_AVS, and, with more
-				 * recent versions of the driver, 3 to get
-				 * DLT_IEEE80211_RADIO.
-				 */
-				if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
-					break;
-				if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
-					break;
-				if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
-					break;
-				montype = MONITOR_HOSTAP;
-				cmd = priv[i].cmd;
-				break;
-			}
-			if (strcmp(priv[i].name, "set_prismhdr") == 0) {
-				/*
-				 * Prism54 driver, use this one.
-				 * Set monitor mode first.
-				 * You can set it to 2 to get DLT_IEEE80211
-				 * or 3 or get DLT_PRISM.
-				 */
-				if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
-					break;
-				if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
-					break;
-				if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
-					break;
-				montype = MONITOR_PRISM54;
-				cmd = priv[i].cmd;
-				break;
-			}
-			if (strcmp(priv[i].name, "forceprismheader") == 0) {
-				/*
-				 * RT2570 driver, use this one.
-				 * Do this after turning monitor mode on.
-				 * You can set it to 1 to get DLT_PRISM or 2
-				 * to get DLT_IEEE80211.
-				 */
-				if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
-					break;
-				if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
-					break;
-				if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
-					break;
-				montype = MONITOR_RT2570;
-				cmd = priv[i].cmd;
-				break;
-			}
-			if (strcmp(priv[i].name, "forceprism") == 0) {
-				/*
-				 * RT73 driver, use this one.
-				 * Do this after turning monitor mode on.
-				 * Its argument is a *string*; you can
-				 * set it to "1" to get DLT_PRISM or "2"
-				 * to get DLT_IEEE80211.
-				 */
-				if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_CHAR)
-					break;
-				if (priv[i].set_args & IW_PRIV_SIZE_FIXED)
-					break;
-				montype = MONITOR_RT73;
-				cmd = priv[i].cmd;
-				break;
-			}
-			if (strcmp(priv[i].name, "prismhdr") == 0) {
-				/*
-				 * One of the RTL8xxx drivers, use this one.
-				 * It can only be done after monitor mode
-				 * has been turned on.  You can set it to 1
-				 * to get DLT_PRISM or 0 to get DLT_IEEE80211.
-				 */
-				if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
-					break;
-				if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
-					break;
-				if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
-					break;
-				montype = MONITOR_RTL8XXX;
-				cmd = priv[i].cmd;
-				break;
-			}
-			if (strcmp(priv[i].name, "rfmontx") == 0) {
-				/*
-				 * RT2500 or RT61 driver, use this one.
-				 * It has one one-byte parameter; set
-				 * u.data.length to 1 and u.data.pointer to
-				 * point to the parameter.
-				 * It doesn't itself turn monitor mode on.
-				 * You can set it to 1 to allow transmitting
-				 * in monitor mode(?) and get DLT_IEEE80211,
-				 * or set it to 0 to disallow transmitting in
-				 * monitor mode(?) and get DLT_PRISM.
-				 */
-				if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
-					break;
-				if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 2)
-					break;
-				montype = MONITOR_RT2500;
-				cmd = priv[i].cmd;
-				break;
-			}
-			if (strcmp(priv[i].name, "monitor") == 0) {
-				/*
-				 * Either ACX100 or hostap, use this one.
-				 * It turns monitor mode on.
-				 * If it takes two arguments, it's ACX100;
-				 * the first argument is 1 for DLT_PRISM
-				 * or 2 for DLT_IEEE80211, and the second
-				 * argument is the channel on which to
-				 * run.  If it takes one argument, it's
-				 * HostAP, and the argument is 2 for
-				 * DLT_IEEE80211 and 3 for DLT_PRISM.
-				 *
-				 * If we see this, we don't quit, as this
-				 * might be a version of the hostap driver
-				 * that also supports "monitor_type".
-				 */
-				if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
-					break;
-				if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
-					break;
-				switch (priv[i].set_args & IW_PRIV_SIZE_MASK) {
-
-				case 1:
-					montype = MONITOR_PRISM;
-					cmd = priv[i].cmd;
-					break;
-
-				case 2:
-					montype = MONITOR_ACX100;
-					cmd = priv[i].cmd;
-					break;
-
-				default:
-					break;
-				}
-			}
-		}
-		free(priv);
 	}
 
-	/*
-	 * XXX - ipw3945?  islism?
-	 */
+	snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+	    "%s: No free monN interfaces", device);
+	nl80211_cleanup(&nlstate);
+	return PCAP_ERROR;
 
-	/*
-	 * Get the old mode.
-	 */
-	pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-	    sizeof ireq.ifr_ifrn.ifrn_name);
-	if (ioctl(sock_fd, SIOCGIWMODE, &ireq) == -1) {
-		/*
-		 * We probably won't be able to set the mode, either.
-		 */
-		return PCAP_ERROR_RFMON_NOTSUP;
-	}
+added:
 
+#if 0
 	/*
-	 * Is it currently in monitor mode?
+	 * Sleep for .1 seconds.
 	 */
-	if (ireq.u.mode == IW_MODE_MONITOR) {
-		/*
-		 * Yes.  Just leave things as they are.
-		 * We don't offer multiple link-layer types, as
-		 * changing the link-layer type out from under
-		 * somebody else capturing in monitor mode would
-		 * be considered rude.
-		 */
-		return 1;
-	}
-	/*
-	 * No.  We have to put the adapter into rfmon mode.
-	 */
+	delay.tv_sec = 0;
+	delay.tv_nsec = 500000000;
+	nanosleep(&delay, NULL);
+#endif
 
 	/*
 	 * If we haven't already done so, arrange to have
@@ -6232,277 +4574,47 @@
 		 * "atexit()" failed; don't put the interface
 		 * in rfmon mode, just give up.
 		 */
-		return PCAP_ERROR_RFMON_NOTSUP;
-	}
-
-	/*
-	 * Save the old mode.
-	 */
-	handlep->oldmode = ireq.u.mode;
-
-	/*
-	 * Put the adapter in rfmon mode.  How we do this depends
-	 * on whether we have a special private ioctl or not.
-	 */
-	if (montype == MONITOR_PRISM) {
-		/*
-		 * We have the "monitor" private ioctl, but none of
-		 * the other private ioctls.  Use this, and select
-		 * the Prism header.
-		 *
-		 * If it fails, just fall back on SIOCSIWMODE.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		ireq.u.data.length = 1;	/* 1 argument */
-		args[0] = 3;	/* request Prism header */
-		memcpy(ireq.u.name, args, sizeof (int));
-		if (ioctl(sock_fd, cmd, &ireq) != -1) {
-			/*
-			 * Success.
-			 * Note that we have to put the old mode back
-			 * when we close the device.
-			 */
-			handlep->must_do_on_close |= MUST_CLEAR_RFMON;
-
-			/*
-			 * Add this to the list of pcaps to close
-			 * when we exit.
-			 */
-			pcap_add_to_pcaps_to_close(handle);
-
-			return 1;
-		}
-
-		/*
-		 * Failure.  Fall back on SIOCSIWMODE.
-		 */
-	}
-
-	/*
-	 * First, take the interface down if it's up; otherwise, we
-	 * might get EBUSY.
-	 */
-	memset(&ifr, 0, sizeof(ifr));
-	pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
-	if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
-		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    errno, "%s: Can't get flags", device);
+		del_mon_if(handle, sock_fd, &nlstate, device,
+		    handlep->mondevice);
+		nl80211_cleanup(&nlstate);
 		return PCAP_ERROR;
 	}
-	oldflags = 0;
-	if (ifr.ifr_flags & IFF_UP) {
-		oldflags = ifr.ifr_flags;
-		ifr.ifr_flags &= ~IFF_UP;
-		if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags",
-			    device);
-			return PCAP_ERROR;
-		}
+
+	/*
+	 * Now configure the monitor interface up.
+	 */
+	memset(&ifr, 0, sizeof(ifr));
+	pcap_strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name));
+	if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
+		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "%s: Can't get flags for %s", device,
+		    handlep->mondevice);
+		del_mon_if(handle, sock_fd, &nlstate, device,
+		    handlep->mondevice);
+		nl80211_cleanup(&nlstate);
+		return PCAP_ERROR;
+	}
+	ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
+	if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
+		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+		    errno, "%s: Can't set flags for %s", device,
+		    handlep->mondevice);
+		del_mon_if(handle, sock_fd, &nlstate, device,
+		    handlep->mondevice);
+		nl80211_cleanup(&nlstate);
+		return PCAP_ERROR;
 	}
 
 	/*
-	 * Then turn monitor mode on.
+	 * Success.  Clean up the libnl state.
 	 */
-	pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-	    sizeof ireq.ifr_ifrn.ifrn_name);
-	ireq.u.mode = IW_MODE_MONITOR;
-	if (ioctl(sock_fd, SIOCSIWMODE, &ireq) == -1) {
-		/*
-		 * Scientist, you've failed.
-		 * Bring the interface back up if we shut it down.
-		 */
-		ifr.ifr_flags = oldflags;
-		if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags",
-			    device);
-			return PCAP_ERROR;
-		}
-		return PCAP_ERROR_RFMON_NOTSUP;
-	}
+	nl80211_cleanup(&nlstate);
 
 	/*
-	 * XXX - airmon-ng does "iwconfig {if} key off" after setting
-	 * monitor mode and setting the channel, and then does
-	 * "iwconfig up".
+	 * Note that we have to delete the monitor device when we close
+	 * the handle.
 	 */
-
-	/*
-	 * Now select the appropriate radio header.
-	 */
-	switch (montype) {
-
-	case MONITOR_WEXT:
-		/*
-		 * We don't have any private ioctl to set the header.
-		 */
-		break;
-
-	case MONITOR_HOSTAP:
-		/*
-		 * Try to select the radiotap header.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		args[0] = 3;	/* request radiotap header */
-		memcpy(ireq.u.name, args, sizeof (int));
-		if (ioctl(sock_fd, cmd, &ireq) != -1)
-			break;	/* success */
-
-		/*
-		 * That failed.  Try to select the AVS header.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		args[0] = 2;	/* request AVS header */
-		memcpy(ireq.u.name, args, sizeof (int));
-		if (ioctl(sock_fd, cmd, &ireq) != -1)
-			break;	/* success */
-
-		/*
-		 * That failed.  Try to select the Prism header.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		args[0] = 1;	/* request Prism header */
-		memcpy(ireq.u.name, args, sizeof (int));
-		ioctl(sock_fd, cmd, &ireq);
-		break;
-
-	case MONITOR_PRISM:
-		/*
-		 * The private ioctl failed.
-		 */
-		break;
-
-	case MONITOR_PRISM54:
-		/*
-		 * Select the Prism header.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		args[0] = 3;	/* request Prism header */
-		memcpy(ireq.u.name, args, sizeof (int));
-		ioctl(sock_fd, cmd, &ireq);
-		break;
-
-	case MONITOR_ACX100:
-		/*
-		 * Get the current channel.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		if (ioctl(sock_fd, SIOCGIWFREQ, &ireq) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWFREQ", device);
-			return PCAP_ERROR;
-		}
-		channel = ireq.u.freq.m;
-
-		/*
-		 * Select the Prism header, and set the channel to the
-		 * current value.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		args[0] = 1;		/* request Prism header */
-		args[1] = channel;	/* set channel */
-		memcpy(ireq.u.name, args, 2*sizeof (int));
-		ioctl(sock_fd, cmd, &ireq);
-		break;
-
-	case MONITOR_RT2500:
-		/*
-		 * Disallow transmission - that turns on the
-		 * Prism header.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		args[0] = 0;	/* disallow transmitting */
-		memcpy(ireq.u.name, args, sizeof (int));
-		ioctl(sock_fd, cmd, &ireq);
-		break;
-
-	case MONITOR_RT2570:
-		/*
-		 * Force the Prism header.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		args[0] = 1;	/* request Prism header */
-		memcpy(ireq.u.name, args, sizeof (int));
-		ioctl(sock_fd, cmd, &ireq);
-		break;
-
-	case MONITOR_RT73:
-		/*
-		 * Force the Prism header.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		ireq.u.data.length = 1;	/* 1 argument */
-		ireq.u.data.pointer = "1";
-		ireq.u.data.flags = 0;
-		ioctl(sock_fd, cmd, &ireq);
-		break;
-
-	case MONITOR_RTL8XXX:
-		/*
-		 * Force the Prism header.
-		 */
-		memset(&ireq, 0, sizeof ireq);
-		pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
-		    sizeof ireq.ifr_ifrn.ifrn_name);
-		args[0] = 1;	/* request Prism header */
-		memcpy(ireq.u.name, args, sizeof (int));
-		ioctl(sock_fd, cmd, &ireq);
-		break;
-	}
-
-	/*
-	 * Now bring the interface back up if we brought it down.
-	 */
-	if (oldflags != 0) {
-		ifr.ifr_flags = oldflags;
-		if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags",
-			    device);
-
-			/*
-			 * At least try to restore the old mode on the
-			 * interface.
-			 */
-			if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) {
-				/*
-				 * Scientist, you've failed.
-				 */
-				fprintf(stderr,
-				    "Can't restore interface wireless mode (SIOCSIWMODE failed: %s).\n"
-				    "Please adjust manually.\n",
-				    strerror(errno));
-			}
-			return PCAP_ERROR;
-		}
-	}
-
-	/*
-	 * Note that we have to put the old mode back when we
-	 * close the device.
-	 */
-	handlep->must_do_on_close |= MUST_CLEAR_RFMON;
+	handlep->must_do_on_close |= MUST_DELETE_MONIF;
 
 	/*
 	 * Add this to the list of pcaps to close when we exit.
@@ -6511,41 +4623,16 @@
 
 	return 1;
 }
-#endif /* IW_MODE_MONITOR */
-
-/*
- * Try various mechanisms to enter monitor mode.
- */
+#else /* HAVE_LIBNL */
 static int
-enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device)
+enter_rfmon_mode(pcap_t *handle _U_, int sock_fd _U_, const char *device _U_)
 {
-#if defined(HAVE_LIBNL) || defined(IW_MODE_MONITOR)
-	int ret;
-#endif
-
-#ifdef HAVE_LIBNL
-	ret = enter_rfmon_mode_mac80211(handle, sock_fd, device);
-	if (ret < 0)
-		return ret;	/* error attempting to do so */
-	if (ret == 1)
-		return 1;	/* success */
-#endif /* HAVE_LIBNL */
-
-#ifdef IW_MODE_MONITOR
-	ret = enter_rfmon_mode_wext(handle, sock_fd, device);
-	if (ret < 0)
-		return ret;	/* error attempting to do so */
-	if (ret == 1)
-		return 1;	/* success */
-#endif /* IW_MODE_MONITOR */
-
 	/*
-	 * Either none of the mechanisms we know about work or none
-	 * of those mechanisms are available, so we can't do monitor
-	 * mode.
+	 * We don't have libnl, so we can't do monitor mode.
 	 */
 	return 0;
 }
+#endif /* HAVE_LIBNL */
 
 #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
 /*
@@ -6564,15 +4651,21 @@
 /*
  * Set the list of time stamping types to include all types.
  */
-static void
-iface_set_all_ts_types(pcap_t *handle)
+static int
+iface_set_all_ts_types(pcap_t *handle, char *ebuf)
 {
 	u_int i;
 
-	handle->tstamp_type_count = NUM_SOF_TIMESTAMPING_TYPES;
 	handle->tstamp_type_list = malloc(NUM_SOF_TIMESTAMPING_TYPES * sizeof(u_int));
+	if (handle->tstamp_type_list == NULL) {
+		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+		    errno, "malloc");
+		return -1;
+	}
 	for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++)
 		handle->tstamp_type_list[i] = sof_ts_type_map[i].pcap_tstamp_val;
+	handle->tstamp_type_count = NUM_SOF_TIMESTAMPING_TYPES;
+	return 0;
 }
 
 #ifdef ETHTOOL_GET_TS_INFO
@@ -6603,7 +4696,7 @@
 	/*
 	 * Create a socket from which to fetch time stamping capabilities.
 	 */
-	fd = socket(PF_UNIX, SOCK_RAW, 0);
+	fd = get_if_ioctl_socket();
 	if (fd < 0) {
 		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
 		    errno, "socket for SIOCETHTOOL(ETHTOOL_GET_TS_INFO)");
@@ -6628,7 +4721,8 @@
 			 * asking for the time stamping types, so let's
 			 * just return all the possible types.
 			 */
-			iface_set_all_ts_types(handle);
+			if (iface_set_all_ts_types(handle, ebuf) == -1)
+				return -1;
 			return 0;
 
 		case ENODEV:
@@ -6676,15 +4770,20 @@
 		if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val)
 			num_ts_types++;
 	}
-	handle->tstamp_type_count = num_ts_types;
 	if (num_ts_types != 0) {
 		handle->tstamp_type_list = malloc(num_ts_types * sizeof(u_int));
+		if (handle->tstamp_type_list == NULL) {
+			pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+			    errno, "malloc");
+			return -1;
+		}
 		for (i = 0, j = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) {
 			if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) {
 				handle->tstamp_type_list[j] = sof_ts_type_map[i].pcap_tstamp_val;
 				j++;
 			}
 		}
+		handle->tstamp_type_count = num_ts_types;
 	} else
 		handle->tstamp_type_list = NULL;
 
@@ -6692,7 +4791,7 @@
 }
 #else /* ETHTOOL_GET_TS_INFO */
 static int
-iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf _U_)
+iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf)
 {
 	/*
 	 * This doesn't apply to the "any" device; you can't say "turn on
@@ -6710,14 +4809,14 @@
 	 * We don't have an ioctl to use to ask what's supported,
 	 * so say we support everything.
 	 */
-	iface_set_all_ts_types(handle);
+	if (iface_set_all_ts_types(handle, ebuf) == -1)
+		return -1;
 	return 0;
 }
 #endif /* ETHTOOL_GET_TS_INFO */
 
 #endif /* defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) */
 
-#ifdef HAVE_PACKET_RING
 /*
  * Find out if we have any form of fragmentation/reassembly offloading.
  *
@@ -6860,265 +4959,89 @@
 }
 #endif /* SIOCETHTOOL */
 
-#endif /* HAVE_PACKET_RING */
-
-#endif /* HAVE_PF_PACKET_SOCKETS */
-
-/* ===== Functions to interface to the older kernels ================== */
-
-/*
- * Try to open a packet socket using the old kernel interface.
- * Returns 1 on success and a PCAP_ERROR_ value on an error.
- */
-static int
-activate_old(pcap_t *handle)
-{
-	struct pcap_linux *handlep = handle->priv;
-	int		err;
-	int		arptype;
-	struct ifreq	ifr;
-	const char	*device = handle->opt.device;
-	struct utsname	utsname;
-	int		mtu;
-
+static struct dsa_proto {
+	const char *name;
+	bpf_u_int32 linktype;
+} dsa_protos[] = {
 	/*
-	 * PF_INET/SOCK_PACKET sockets must be bound to a device, so we
-	 * can't support the "any" device.
+	 * None is special and indicates that the interface does not have
+	 * any tagging protocol configured, and is therefore a standard
+	 * Ethernet interface.
 	 */
-	if (strcmp(device, "any") == 0) {
-		pcap_strlcpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems",
-			PCAP_ERRBUF_SIZE);
-		return PCAP_ERROR;
-	}
+	{ "none", DLT_EN10MB },
+	{ "brcm", DLT_DSA_TAG_BRCM },
+	{ "brcm-prepend", DLT_DSA_TAG_BRCM_PREPEND },
+	{ "dsa", DLT_DSA_TAG_DSA },
+	{ "edsa", DLT_DSA_TAG_EDSA },
+};
 
-	/* Open the socket */
-	handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
-	if (handle->fd == -1) {
-		err = errno;
+static int
+iface_dsa_get_proto_info(const char *device, pcap_t *handle)
+{
+	char *pathstr;
+	unsigned int i;
+	/*
+	 * Make this significantly smaller than PCAP_ERRBUF_SIZE;
+	 * the tag *shouldn't* have some huge long name, and making
+	 * it smaller keeps newer versions of GCC from whining that
+	 * the error message if we don't support the tag could
+	 * overflow the error message buffer.
+	 */
+	char buf[128];
+	ssize_t r;
+	int fd;
+
+	fd = asprintf(&pathstr, "/sys/class/net/%s/dsa/tagging", device);
+	if (fd < 0) {
 		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    err, "socket");
-		if (err == EPERM || err == EACCES) {
-			/*
-			 * You don't have permission to open the
-			 * socket.
-			 */
-			return PCAP_ERROR_PERM_DENIED;
-		} else {
-			/*
-			 * Other error.
-			 */
-			return PCAP_ERROR;
-		}
-	}
-
-	/* It worked - we are using the old interface */
-	handlep->sock_packet = 1;
-
-	/* ...which means we get the link-layer header. */
-	handlep->cooked = 0;
-
-	/* Bind to the given device */
-	if (iface_bind_old(handle->fd, device, handle->errbuf) == -1)
-		return PCAP_ERROR;
-
-	/*
-	 * Try to get the link-layer type.
-	 */
-	arptype = iface_get_arptype(handle->fd, device, handle->errbuf);
-	if (arptype < 0)
-		return PCAP_ERROR;
-
-	/*
-	 * Try to find the DLT_ type corresponding to that
-	 * link-layer type.
-	 */
-	map_arphrd_to_dlt(handle, handle->fd, arptype, device, 0);
-	if (handle->linktype == -1) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
-			 "unknown arptype %d", arptype);
+					  fd, "asprintf");
 		return PCAP_ERROR;
 	}
 
-	/* Go to promisc mode if requested */
+	fd = open(pathstr, O_RDONLY);
+	free(pathstr);
+	/*
+	 * This is not fatal, kernel >= 4.20 *might* expose this attribute
+	 */
+	if (fd < 0)
+		return 0;
 
-	if (handle->opt.promisc) {
-		memset(&ifr, 0, sizeof(ifr));
-		pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
-		if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
-			pcap_fmt_errmsg_for_errno(handle->errbuf,
-			    PCAP_ERRBUF_SIZE, errno, "SIOCGIFFLAGS");
-			return PCAP_ERROR;
-		}
-		if ((ifr.ifr_flags & IFF_PROMISC) == 0) {
-			/*
-			 * Promiscuous mode isn't currently on,
-			 * so turn it on, and remember that
-			 * we should turn it off when the
-			 * pcap_t is closed.
-			 */
+	r = read(fd, buf, sizeof(buf) - 1);
+	if (r <= 0) {
+		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+					  errno, "read");
+		close(fd);
+		return PCAP_ERROR;
+	}
+	close(fd);
 
-			/*
-			 * If we haven't already done so, arrange
-			 * to have "pcap_close_all()" called when
-			 * we exit.
-			 */
-			if (!pcap_do_addexit(handle)) {
-				/*
-				 * "atexit()" failed; don't put
-				 * the interface in promiscuous
-				 * mode, just give up.
-				 */
-				return PCAP_ERROR;
+	/*
+	 * Buffer should be LF terminated.
+	 */
+	if (buf[r - 1] == '\n')
+		r--;
+	buf[r] = '\0';
+
+	for (i = 0; i < sizeof(dsa_protos) / sizeof(dsa_protos[0]); i++) {
+		if (strlen(dsa_protos[i].name) == (size_t)r &&
+		    strcmp(buf, dsa_protos[i].name) == 0) {
+			handle->linktype = dsa_protos[i].linktype;
+			switch (dsa_protos[i].linktype) {
+			case DLT_EN10MB:
+				return 0;
+			default:
+				return 1;
 			}
-
-			ifr.ifr_flags |= IFF_PROMISC;
-			if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) {
-				pcap_fmt_errmsg_for_errno(handle->errbuf,
-				    PCAP_ERRBUF_SIZE, errno, "SIOCSIFFLAGS");
-				return PCAP_ERROR;
-			}
-			handlep->must_do_on_close |= MUST_CLEAR_PROMISC;
-
-			/*
-			 * Add this to the list of pcaps
-			 * to close when we exit.
-			 */
-			pcap_add_to_pcaps_to_close(handle);
 		}
 	}
 
-	/*
-	 * Compute the buffer size.
-	 *
-	 * We're using SOCK_PACKET, so this might be a 2.0[.x]
-	 * kernel, and might require special handling - check.
-	 */
-	if (uname(&utsname) < 0 ||
-	    strncmp(utsname.release, "2.0", 3) == 0) {
-		/*
-		 * Either we couldn't find out what kernel release
-		 * this is, or it's a 2.0[.x] kernel.
-		 *
-		 * In the 2.0[.x] kernel, a "recvfrom()" on
-		 * a SOCK_PACKET socket, with MSG_TRUNC set, will
-		 * return the number of bytes read, so if we pass
-		 * a length based on the snapshot length, it'll
-		 * return the number of bytes from the packet
-		 * copied to userland, not the actual length
-		 * of the packet.
-		 *
-		 * This means that, for example, the IP dissector
-		 * in tcpdump will get handed a packet length less
-		 * than the length in the IP header, and will
-		 * complain about "truncated-ip".
-		 *
-		 * So we don't bother trying to copy from the
-		 * kernel only the bytes in which we're interested,
-		 * but instead copy them all, just as the older
-		 * versions of libpcap for Linux did.
-		 *
-		 * The buffer therefore needs to be big enough to
-		 * hold the largest packet we can get from this
-		 * device.  Unfortunately, we can't get the MRU
-		 * of the network; we can only get the MTU.  The
-		 * MTU may be too small, in which case a packet larger
-		 * than the buffer size will be truncated *and* we
-		 * won't get the actual packet size.
-		 *
-		 * However, if the snapshot length is larger than
-		 * the buffer size based on the MTU, we use the
-		 * snapshot length as the buffer size, instead;
-		 * this means that with a sufficiently large snapshot
-		 * length we won't artificially truncate packets
-		 * to the MTU-based size.
-		 *
-		 * This mess just one of many problems with packet
-		 * capture on 2.0[.x] kernels; you really want a
-		 * 2.2[.x] or later kernel if you want packet capture
-		 * to work well.
-		 */
-		mtu = iface_get_mtu(handle->fd, device, handle->errbuf);
-		if (mtu == -1)
-			return PCAP_ERROR;
-		handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
-		if (handle->bufsize < (u_int)handle->snapshot)
-			handle->bufsize = (u_int)handle->snapshot;
-	} else {
-		/*
-		 * This is a 2.2[.x] or later kernel.
-		 *
-		 * We can safely pass "recvfrom()" a byte count
-		 * based on the snapshot length.
-		 *
-		 * XXX - this "should not happen", as 2.2[.x]
-		 * kernels all have PF_PACKET sockets, and there's
-		 * no configuration option to disable them without
-		 * disabling SOCK_PACKET sockets, because
-		 * SOCK_PACKET sockets are implemented in the same
-		 * source file, net/packet/af_packet.c.  There *is*
-		 * an option to disable SOCK_PACKET sockets so that
-		 * you only have PF_PACKET sockets, and the kernel
-		 * will log warning messages for code that uses
-		 * "obsolete (PF_INET,SOCK_PACKET)".
-		 */
-		handle->bufsize = (u_int)handle->snapshot;
-	}
+	snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		      "unsupported DSA tag: %s", buf);
 
-	/*
-	 * Default value for offset to align link-layer payload
-	 * on a 4-byte boundary.
-	 */
-	handle->offset	 = 0;
-
-	/*
-	 * SOCK_PACKET sockets don't supply information from
-	 * stripped VLAN tags.
-	 */
-	handlep->vlan_offset = -1; /* unknown */
-
-	return 1;
+	return PCAP_ERROR;
 }
 
 /*
- *  Bind the socket associated with FD to the given device using the
- *  interface of the old kernels.
- */
-static int
-iface_bind_old(int fd, const char *device, char *ebuf)
-{
-	struct sockaddr	saddr;
-	int		err;
-	socklen_t	errlen = sizeof(err);
-
-	memset(&saddr, 0, sizeof(saddr));
-	pcap_strlcpy(saddr.sa_data, device, sizeof(saddr.sa_data));
-	if (bind(fd, &saddr, sizeof(saddr)) == -1) {
-		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
-		    errno, "bind");
-		return -1;
-	}
-
-	/* Any pending errors, e.g., network is down? */
-
-	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
-		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
-		    errno, "getsockopt (SO_ERROR)");
-		return -1;
-	}
-
-	if (err > 0) {
-		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
-		    err, "bind");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/* ===== System calls available on all supported kernels ============== */
-
-/*
  *  Query the kernel for the MTU of the given interface.
  */
 static int
@@ -7169,9 +5092,8 @@
 	return ifr.ifr_hwaddr.sa_family;
 }
 
-#ifdef SO_ATTACH_FILTER
 static int
-fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped)
+fix_program(pcap_t *handle, struct sock_fprog *fcode)
 {
 	struct pcap_linux *handlep = handle->priv;
 	size_t prog_size;
@@ -7203,39 +5125,6 @@
 		 */
 		switch (BPF_CLASS(p->code)) {
 
-		case BPF_RET:
-			/*
-			 * It's a return instruction; are we capturing
-			 * in memory-mapped mode?
-			 */
-			if (!is_mmapped) {
-				/*
-				 * No; is the snapshot length a constant,
-				 * rather than the contents of the
-				 * accumulator?
-				 */
-				if (BPF_MODE(p->code) == BPF_K) {
-					/*
-					 * Yes - if the value to be returned,
-					 * i.e. the snapshot length, is
-					 * anything other than 0, make it
-					 * MAXIMUM_SNAPLEN, so that the packet
-					 * is truncated by "recvfrom()",
-					 * not by the filter.
-					 *
-					 * XXX - there's nothing we can
-					 * easily do if it's getting the
-					 * value from the accumulator; we'd
-					 * have to insert code to force
-					 * non-zero values to be
-					 * MAXIMUM_SNAPLEN.
-					 */
-					if (p->k != 0)
-						p->k = MAXIMUM_SNAPLEN;
-				}
-			}
-			break;
-
 		case BPF_LD:
 		case BPF_LDX:
 			/*
@@ -7301,6 +5190,12 @@
 			 * special magic kernel offset for that field.
 			 */
 			p->k = SKF_AD_OFF + SKF_AD_PROTOCOL;
+		} else if (p->k == 4) {
+			/*
+			 * It's the ifindex field; map it to the
+			 * special magic kernel offset for that field.
+			 */
+			p->k = SKF_AD_OFF + SKF_AD_IFINDEX;
 		} else if (p->k == 10) {
 			/*
 			 * It's the packet type field; map it to the
@@ -7503,7 +5398,6 @@
 		return -1;
 	return 0;
 }
-#endif
 
 int
 pcap_set_protocol_linux(pcap_t *p, int protocol)
@@ -7520,15 +5414,9 @@
 const char *
 pcap_lib_version(void)
 {
-#ifdef HAVE_PACKET_RING
- #if defined(HAVE_TPACKET3)
+#if defined(HAVE_TPACKET3)
 	return (PCAP_VERSION_STRING " (with TPACKET_V3)");
- #elif defined(HAVE_TPACKET2)
-	return (PCAP_VERSION_STRING " (with TPACKET_V2)");
- #else
-	return (PCAP_VERSION_STRING " (with TPACKET_V1)");
- #endif
 #else
-	return (PCAP_VERSION_STRING " (without TPACKET)");
+	return (PCAP_VERSION_STRING " (with TPACKET_V2)");
 #endif
 }
diff --git a/pcap-netfilter-linux.c b/pcap-netfilter-linux.c
index 91bad37..17f528f 100644
--- a/pcap-netfilter-linux.c
+++ b/pcap-netfilter-linux.c
@@ -56,13 +56,13 @@
 #include <linux/netfilter/nfnetlink_log.h>
 #include <linux/netfilter/nfnetlink_queue.h>
 
-/* NOTE: if your program drops privilages after pcap_activate() it WON'T work with nfqueue.
+/* NOTE: if your program drops privileges after pcap_activate() it WON'T work with nfqueue.
  *       It took me quite some time to debug ;/
  *
- *       Sending any data to nfnetlink socket requires CAP_NET_ADMIN privilages,
+ *       Sending any data to nfnetlink socket requires CAP_NET_ADMIN privileges,
  *       and in nfqueue we need to send verdict reply after recving packet.
  *
- *       In tcpdump you can disable dropping privilages with -Z root
+ *       In tcpdump you can disable dropping privileges with -Z root
  */
 
 #include "pcap-netfilter-linux.h"
@@ -91,7 +91,7 @@
 	struct pcap_netfilter *handlep = handle->priv;
 	register u_char *bp, *ep;
 	int count = 0;
-	int len;
+	ssize_t len;
 
 	/*
 	 * Has "pcap_breakloop()" been called?
@@ -152,14 +152,25 @@
 		 */
 		if (handle->break_loop) {
 			handle->bp = bp;
-			handle->cc = ep - bp;
+			handle->cc = (int)(ep - bp);
 			if (count == 0) {
 				handle->break_loop = 0;
 				return PCAP_ERROR_BREAK;
 			} else
 				return count;
 		}
-		if (ep - bp < NLMSG_SPACE(0)) {
+		/*
+		 * NLMSG_SPACE(0) might be signed or might be unsigned,
+		 * depending on whether the kernel defines NLMSG_ALIGNTO
+		 * as 4, which older kernels do, or as 4U, which newer
+		 * kernels do.
+		 *
+		 * ep - bp is of type ptrdiff_t, which is signed.
+		 *
+		 * To squelch warnings, we cast both to size_t, which
+		 * is unsigned; ep >= bp, so the cast is safe.
+		 */
+		if ((size_t)(ep - bp) < (size_t)NLMSG_SPACE(0)) {
 			/*
 			 * There's less than one netlink message left
 			 * in the buffer.  Give up.
@@ -168,7 +179,7 @@
 		}
 
 		if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) {
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len);
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %zd) (nlmsg_len: %u)", len, nlh->nlmsg_len);
 			return -1;
 		}
 
@@ -190,7 +201,7 @@
 				const struct nfattr *payload_attr = NULL;
 
 				if (nlh->nlmsg_len < HDR_LENGTH) {
-					pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len);
+					snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len);
 					return -1;
 				}
 
@@ -240,7 +251,7 @@
 
 				gettimeofday(&pkth.ts, NULL);
 				if (handle->fcode.bf_insns == NULL ||
-						bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
+						pcap_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
 				{
 					handlep->packets_read++;
 					callback(user, &pkth, payload);
@@ -262,14 +273,21 @@
 		 * If the message length would run past the end of the
 		 * buffer, truncate it to the remaining space in the
 		 * buffer.
+		 *
+		 * To squelch warnings, we cast ep - bp to uint32_t, which
+		 * is unsigned and is the type of msg_len; ep >= bp, and
+		 * len should fit in 32 bits (either it's set from an int
+		 * or it's set from a recv() call with a buffer size that's
+		 * an int, and we're assuming either ILP32 or LP64), so
+		 * the cast is safe.
 		 */
-		if (msg_len > ep - bp)
-			msg_len = ep - bp;
+		if (msg_len > (uint32_t)(ep - bp))
+			msg_len = (uint32_t)(ep - bp);
 
 		bp += msg_len;
 		if (count >= max_packets && !PACKET_COUNT_IS_UNLIMITED(max_packets)) {
 			handle->bp = bp;
-			handle->cc = ep - bp;
+			handle->cc = (int)(ep - bp);
 			if (handle->cc < 0)
 				handle->cc = 0;
 			return count;
@@ -299,9 +317,9 @@
 }
 
 static int
-netfilter_inject_linux(pcap_t *handle, const void *buf _U_, size_t size _U_)
+netfilter_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_)
 {
-	pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 	    "Packet injection is not supported on netfilter devices");
 	return (-1);
 }
@@ -363,7 +381,11 @@
 
 		/* ignore interrupt system call error */
 		do {
-			len = recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen);
+			/*
+			 * The buffer is not so big that its size won't
+			 * fit into an int.
+			 */
+			len = (int)recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen);
 		} while ((len == -1) && (errno == EINTR));
 
 		if (len <= 0)
@@ -510,7 +532,7 @@
 			char *end_dev;
 
 			if (group_count == 32) {
-				pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 						"Maximum 32 netfilter groups! dev: %s",
 						handle->opt.device);
 				return PCAP_ERROR;
@@ -519,7 +541,7 @@
 			group_id = strtol(dev, &end_dev, 0);
 			if (end_dev != dev) {
 				if (group_id < 0 || group_id > 65535) {
-					pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+					snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 							"Netfilter group range from 0 to 65535 (got %ld)",
 							group_id);
 					return PCAP_ERROR;
@@ -535,7 +557,7 @@
 	}
 
 	if (type == OTHER || *dev) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 				"Can't get netfilter group(s) index from %s",
 				handle->opt.device);
 		return PCAP_ERROR;
@@ -616,7 +638,7 @@
 			if (nflog_send_config_cmd(handle, groups[i], NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) {
 				pcap_fmt_errmsg_for_errno(handle->errbuf,
 				    PCAP_ERRBUF_SIZE, errno,
-				    "Can't listen on group group index");
+				    "Can't listen on group index");
 				goto close_fail;
 			}
 
@@ -646,7 +668,7 @@
 			if (nfqueue_send_config_cmd(handle, groups[i], NFQNL_CFG_CMD_BIND, AF_UNSPEC) < 0) {
 				pcap_fmt_errmsg_for_errno(handle->errbuf,
 				    PCAP_ERRBUF_SIZE, errno,
-				    "Can't listen on group group index");
+				    "Can't listen on group index");
 				goto close_fail;
 			}
 
@@ -721,7 +743,7 @@
 	/* OK, it's probably ours. */
 	*is_ours = 1;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_netfilter));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_netfilter);
 	if (p == NULL)
 		return (NULL);
 
diff --git a/pcap-netmap.c b/pcap-netmap.c
index b2301a7..27d36e5 100644
--- a/pcap-netmap.c
+++ b/pcap-netmap.c
@@ -29,7 +29,6 @@
 #endif
 
 #include <poll.h>
-#include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
 #include <stdio.h>
@@ -82,7 +81,7 @@
 	const struct bpf_insn *pc = p->fcode.bf_insns;
 
 	++pn->rx_pkts;
-	if (pc == NULL || bpf_filter(pc, buf, h->len, h->caplen))
+	if (pc == NULL || pcap_filter(pc, buf, h->len, h->caplen))
 		pn->cb(pn->cb_arg, h, buf);
 }
 
@@ -117,7 +116,7 @@
 
 /* XXX need to check the NIOCTXSYNC/poll */
 static int
-pcap_netmap_inject(pcap_t *p, const void *buf, size_t size)
+pcap_netmap_inject(pcap_t *p, const void *buf, int size)
 {
 	struct pcap_netmap *pn = p->priv;
 	struct nm_desc *d = pn->d;
@@ -287,7 +286,7 @@
 	*is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4));
 	if (! *is_ours)
 		return NULL;
-	p = pcap_create_common(ebuf, sizeof (struct pcap_netmap));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_netmap);
 	if (p == NULL)
 		return (NULL);
 	p->activate_op = pcap_netmap_activate;
diff --git a/pcap-new.c b/pcap-new.c
index e61cf6a..7c00659 100644
--- a/pcap-new.c
+++ b/pcap-new.c
@@ -88,7 +88,7 @@
 
 	if (strlen(source) > PCAP_BUF_SIZE)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
 		return -1;
 	}
 
@@ -119,7 +119,7 @@
 
 		if (*alldevs == NULL)
 		{
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				"No interfaces found! Make sure libpcap/Npcap is properly installed"
 				" on the local machine.");
 			return -1;
@@ -209,7 +209,7 @@
 		}
 
 		/* Save the path for future reference */
-		pcap_snprintf(path, sizeof(path), "%s", name);
+		snprintf(path, sizeof(path), "%s", name);
 		pathlen = strlen(path);
 
 #ifdef _WIN32
@@ -224,7 +224,7 @@
 
 		if (filehandle == INVALID_HANDLE_VALUE)
 		{
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
+			snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
 			return -1;
 		}
 
@@ -237,7 +237,7 @@
 
 		if (filedata == NULL)
 		{
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
+			snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
 			return -1;
 		}
 #endif
@@ -249,11 +249,11 @@
 			/* Skip the file if the pathname won't fit in the buffer */
 			if (pathlen + strlen(filedata.cFileName) >= sizeof(filename))
 				continue;
-			pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
+			snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
 #else
 			if (pathlen + strlen(filedata->d_name) >= sizeof(filename))
 				continue;
-			pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
+			snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
 #endif
 
 			fp = pcap_open_offline(filename, errbuf);
@@ -370,7 +370,7 @@
 
 	if (strlen(source) > PCAP_BUF_SIZE)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
 		return NULL;
 	}
 
@@ -445,15 +445,15 @@
 
 fail:
 	if (status == PCAP_ERROR)
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
 		    name, fp->errbuf);
 	else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
 	    status == PCAP_ERROR_PERM_DENIED ||
 	    status == PCAP_ERROR_PROMISC_PERM_DENIED)
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
 		    name, pcap_statustostr(status), fp->errbuf);
 	else
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
 		    name, pcap_statustostr(status));
 	pcap_close(fp);
 	return NULL;
diff --git a/pcap-nit.c b/pcap-nit.c
index 6a1a77c..cfd9519 100644
--- a/pcap-nit.c
+++ b/pcap-nit.c
@@ -43,7 +43,6 @@
 #include <netinet/tcp.h>
 #include <netinet/tcpip.h>
 
-#include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 
@@ -168,7 +167,7 @@
 			continue;
 
 		default:
-			pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+			snprintf(p->errbuf, sizeof(p->errbuf),
 			    "bad nit state %d", nh->nh_state);
 			return (-1);
 		}
@@ -179,7 +178,7 @@
 		caplen = nh->nh_wirelen;
 		if (caplen > p->snapshot)
 			caplen = p->snapshot;
-		if (bpf_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) {
+		if (pcap_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) {
 			struct pcap_pkthdr h;
 			h.ts = nh->nh_timestamp;
 			h.len = nh->nh_wirelen;
@@ -197,7 +196,7 @@
 }
 
 static int
-pcap_inject_nit(pcap_t *p, const void *buf, size_t size)
+pcap_inject_nit(pcap_t *p, const void *buf, int size)
 {
 	struct sockaddr sa;
 	int ret;
@@ -371,7 +370,7 @@
 {
 	pcap_t *p;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_nit));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_nit);
 	if (p == NULL)
 		return (NULL);
 
diff --git a/pcap-npf.c b/pcap-npf.c
index da4641f..f12c701 100644
--- a/pcap-npf.c
+++ b/pcap-npf.c
@@ -41,6 +41,17 @@
 #include <pcap-int.h>
 #include <pcap/dlt.h>
 
+/*
+ * XXX - Packet32.h defines bpf_program, so we can't include
+ * <pcap/bpf.h>, which also defines it; that's why we define
+ * PCAP_DONT_INCLUDE_PCAP_BPF_H,
+ *
+ * However, no header in the WinPcap or Npcap SDKs defines the
+ * macros for BPF code, so we have to define them ourselves.
+ */
+#define		BPF_RET		0x06
+#define		BPF_K		0x00
+
 /* Old-school MinGW have these headers in a different place.
  */
 #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
@@ -55,6 +66,10 @@
   #include <dagapi.h>
 #endif /* HAVE_DAG_API */
 
+#include "diag-control.h"
+
+#include "pcap-airpcap.h"
+
 static int pcap_setfilter_npf(pcap_t *, struct bpf_program *);
 static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *);
 static int pcap_getnonblock_npf(pcap_t *);
@@ -155,7 +170,7 @@
 	 */
 	oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp);
 	if (oid_data_arg == NULL) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "Couldn't allocate argument buffer for PacketRequest");
 		return (PCAP_ERROR);
 	}
@@ -240,13 +255,13 @@
  * have an API that returns data in a form like the Options section of a
  * pcapng Interface Statistics Block:
  *
- *    http://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6
+ *    https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6
  *
  * which would let us add new statistics straightforwardly and indicate which
  * statistics we are and are *not* providing, rather than having to provide
  * possibly-bogus values for statistics we can't provide.
  */
-struct pcap_stat *
+static struct pcap_stat *
 pcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size)
 {
 	struct pcap_win *pw = p->priv;
@@ -269,7 +284,12 @@
 	p->stat.ps_recv = bstats.bs_recv;
 	p->stat.ps_drop = bstats.bs_drop;
 	p->stat.ps_ifdrop = bstats.ps_ifdrop;
-#ifdef ENABLE_REMOTE
+	/*
+	 * Just in case this is ever compiled for a target other than
+	 * Windows, which is somewhere between extremely unlikely and
+	 * impossible.
+	 */
+#ifdef _WIN32
 	p->stat.ps_capt = bstats.bs_capt;
 #endif
 	return (&p->stat);
@@ -283,7 +303,7 @@
 
 	if(PacketSetBuff(pw->adapter,dim)==FALSE)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
 		return (-1);
 	}
 	return (0);
@@ -297,7 +317,7 @@
 
 	if(PacketSetMode(pw->adapter,mode)==FALSE)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
 		return (-1);
 	}
 
@@ -312,7 +332,7 @@
 
 	if(PacketSetMinToCopy(pw->adapter, size)==FALSE)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
 		return (-1);
 	}
 	return (0);
@@ -350,7 +370,7 @@
 	 */
 	oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp);
 	if (oid_data_arg == NULL) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "Couldn't allocate argument buffer for PacketRequest");
 		return (PCAP_ERROR);
 	}
@@ -383,12 +403,6 @@
 	struct pcap_win *pw = p->priv;
 	u_int res;
 
-	if (pw->adapter==NULL) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-		    "Cannot transmit a queue to an offline capture or to a TurboCap port");
-		return (0);
-	}
-
 	res = PacketSendPackets(pw->adapter,
 		queue->buffer,
 		queue->len,
@@ -396,7 +410,7 @@
 
 	if(res != queue->len){
 		pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
-		    GetLastError(), "Error opening adapter");
+		    GetLastError(), "Error queueing packets");
 	}
 
 	return (res);
@@ -409,7 +423,7 @@
 
 	if (size<=0) {
 		/* Bogus parameter */
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "Error: invalid size %d",size);
 		return (-1);
 	}
@@ -418,7 +432,7 @@
 	new_buff=(unsigned char*)malloc(sizeof(char)*size);
 
 	if (!new_buff) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "Error: not enough memory");
 		return (-1);
 	}
@@ -440,7 +454,7 @@
 	/* Set the packet driver in dump mode */
 	res = PacketSetMode(pw->adapter, PACKET_MODE_DUMP);
 	if(res == FALSE){
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "Error setting dump mode");
 		return (-1);
 	}
@@ -448,7 +462,7 @@
 	/* Set the name of the dump file */
 	res = PacketSetDumpName(pw->adapter, filename, (int)strlen(filename));
 	if(res == FALSE){
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "Error setting kernel dump file name");
 		return (-1);
 	}
@@ -456,8 +470,8 @@
 	/* Set the limits of the dump file */
 	res = PacketSetDumpLimits(pw->adapter, maxsize, maxpacks);
 	if(res == FALSE) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-		    		"Error setting dump limit");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				"Error setting dump limit");
 		return (-1);
 	}
 
@@ -472,30 +486,34 @@
 	return (PacketIsDumpEnded(pw->adapter, (BOOLEAN)sync));
 }
 
+#ifdef HAVE_AIRPCAP_API
 static PAirpcapHandle
 pcap_get_airpcap_handle_npf(pcap_t *p)
 {
-#ifdef HAVE_AIRPCAP_API
 	struct pcap_win *pw = p->priv;
 
 	return (PacketGetAirPcapHandle(pw->adapter));
-#else
-	return (NULL);
-#endif /* HAVE_AIRPCAP_API */
 }
+#else /* HAVE_AIRPCAP_API */
+static PAirpcapHandle
+pcap_get_airpcap_handle_npf(pcap_t *p _U_)
+{
+	return (NULL);
+}
+#endif /* HAVE_AIRPCAP_API */
 
 static int
 pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
 {
 	PACKET Packet;
 	int cc;
-	int n = 0;
+	int n;
 	register u_char *bp, *ep;
 	u_char *datap;
 	struct pcap_win *pw = p->priv;
 
 	cc = p->cc;
-	if (p->cc == 0) {
+	if (cc == 0) {
 		/*
 		 * Has "pcap_breakloop()" been called?
 		 */
@@ -544,7 +562,7 @@
 				 * documented as having error returns
 				 * other than PCAP_ERROR or PCAP_ERROR_BREAK.
 				 */
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				    "The interface disappeared");
 			} else {
 				pcap_fmt_errmsg_for_win32_err(p->errbuf,
@@ -565,9 +583,10 @@
 	 * Loop through each packet.
 	 */
 #define bhp ((struct bpf_hdr *)bp)
+	n = 0;
 	ep = bp + cc;
 	for (;;) {
-		register int caplen, hdrlen;
+		register u_int caplen, hdrlen;
 
 		/*
 		 * Has "pcap_breakloop()" been called?
@@ -601,13 +620,13 @@
 		 * in kernel, no need to do it now - we already know
 		 * the packet passed the filter.
 		 *
-		 * XXX - bpf_filter() should always return TRUE if
+		 * XXX - pcap_filter() should always return TRUE if
 		 * handed a null pointer for the program, but it might
 		 * just try to "run" the filter, so we check here.
 		 */
 		if (pw->filtering_in_kernel ||
 		    p->fcode.bf_insns == NULL ||
-		    bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
+		    pcap_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
 #ifdef ENABLE_REMOTE
 			switch (p->rmt_samp.method) {
 
@@ -706,7 +725,7 @@
 		 */
 		PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize);
 		if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
 			return (-1);
 		}
 
@@ -814,7 +833,7 @@
 		/* No underlaying filtering system. We need to filter on our own */
 		if (p->fcode.bf_insns)
 		{
-			if (bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0)
+			if (pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0)
 			{
 				/* Move to next packet */
 				header = (dag_record_t*)((char*)header + erf_record_len);
@@ -848,14 +867,14 @@
 
 /* Send a packet to the network */
 static int
-pcap_inject_npf(pcap_t *p, const void *buf, size_t size)
+pcap_inject_npf(pcap_t *p, const void *buf, int size)
 {
 	struct pcap_win *pw = p->priv;
 	PACKET pkt;
 
 	PacketInitPacket(&pkt, (PVOID)buf, size);
 	if(PacketSendPacket(pw->adapter,&pkt,TRUE) == FALSE) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed");
 		return (-1);
 	}
 
@@ -864,7 +883,7 @@
 	 * "pcap_inject()" is expected to return the number of bytes
 	 * sent.
 	 */
-	return ((int)size);
+	return (size);
 }
 
 static void
@@ -883,6 +902,16 @@
 	pcap_cleanup_live_common(p);
 }
 
+static void
+pcap_breakloop_npf(pcap_t *p)
+{
+	pcap_breakloop_common(p);
+	struct pcap_win *pw = p->priv;
+
+	/* XXX - what if this fails? */
+	SetEvent(PacketGetReadEvent(pw->adapter));
+}
+
 static int
 pcap_activate_npf(pcap_t *p)
 {
@@ -890,6 +919,8 @@
 	NetType type;
 	int res;
 	int status = 0;
+	struct bpf_insn total_insn;
+	struct bpf_program total_prog;
 
 	if (p->opt.rfmon) {
 		/*
@@ -921,7 +952,7 @@
 		}
 	}
 
-	/* Init WinSock */
+	/* Init Winsock if it hasn't already been initialized */
 	pcap_wsockinit();
 
 	pw->adapter = PacketOpenAdapter(p->opt.device);
@@ -933,12 +964,22 @@
 		/*
 		 * What error did we get when trying to open the adapter?
 		 */
-		if (errcode == ERROR_BAD_UNIT) {
+		switch (errcode) {
+
+		case ERROR_BAD_UNIT:
 			/*
 			 * There's no such device.
 			 */
 			return (PCAP_ERROR_NO_SUCH_DEVICE);
-		} else {
+
+		case ERROR_ACCESS_DENIED:
+			/*
+			 * There is, but we don't have permission to
+			 * use it.
+			 */
+			return (PCAP_ERROR_PERM_DENIED);
+
+		default:
 			/*
 			 * Unknown - report details.
 			 */
@@ -1034,11 +1075,9 @@
 		p->linktype = DLT_PPI;
 		break;
 
-#ifdef NdisMediumWirelessWan
 	case NdisMediumWirelessWan:
 		p->linktype = DLT_RAW;
 		break;
-#endif
 
 	default:
 		/*
@@ -1053,13 +1092,72 @@
 		 * some programs will report the warning.
 		 */
 		p->linktype = DLT_EN10MB;
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "Unknown NdisMedium value %d, defaulting to DLT_EN10MB",
 		    type.LinkType);
 		status = PCAP_WARNING;
 		break;
 	}
 
+#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
+	/*
+	 * Set the timestamp type.
+	 * (Yes, we require PacketGetTimestampModes(), not just
+	 * PacketSetTimestampMode().  If we have the former, we
+	 * have the latter, unless somebody's using a version
+	 * of Npcap that they've hacked to provide the former
+	 * but not the latter; if they've done that, either
+	 * they're confused or they're trolling us.)
+	 */
+	switch (p->opt.tstamp_type) {
+
+	case PCAP_TSTAMP_HOST_HIPREC_UNSYNCED:
+		/*
+		 * Better than low-res, but *not* synchronized with
+		 * the OS clock.
+		 */
+		if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_SINGLE_SYNCHRONIZATION))
+		{
+			pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+			    GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_SINGLE_SYNCHRONIZATION");
+			goto bad;
+		}
+		break;
+
+	case PCAP_TSTAMP_HOST_LOWPREC:
+		/*
+		 * Low-res, but synchronized with the OS clock.
+		 */
+		if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME))
+		{
+			pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+			    GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME");
+			goto bad;
+		}
+		break;
+
+	case PCAP_TSTAMP_HOST_HIPREC:
+		/*
+		 * High-res, and synchronized with the OS clock.
+		 */
+		if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE))
+		{
+			pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+			    GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE");
+			goto bad;
+		}
+		break;
+
+	case PCAP_TSTAMP_HOST:
+		/*
+		 * XXX - do whatever the default is, for now.
+		 * Set to the highest resolution that's synchronized
+		 * with the system clock?
+		 */
+		break;
+	}
+#endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */
+
 	/*
 	 * Turn a negative snapshot value (invalid), a snapshot value of
 	 * 0 (unspecified), or a value bigger than the normal maximum
@@ -1077,7 +1175,9 @@
 
 		if (PacketSetHwFilter(pw->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE)
 		{
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode");
+			pcap_fmt_errmsg_for_win32_err(p->errbuf,
+			    PCAP_ERRBUF_SIZE, GetLastError(),
+			    "failed to set hardware filter to promiscuous mode");
 			goto bad;
 		}
 	}
@@ -1095,7 +1195,9 @@
 			NDIS_PACKET_TYPE_BROADCAST |
 			NDIS_PACKET_TYPE_MULTICAST) == FALSE)
 		{
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode");
+			pcap_fmt_errmsg_for_win32_err(p->errbuf,
+			    PCAP_ERRBUF_SIZE, GetLastError(),
+			    "failed to set hardware filter to non-promiscuous mode");
 			goto bad;
 		}
 	}
@@ -1112,12 +1214,12 @@
 		 * If the buffer size wasn't explicitly set, default to
 		 * WIN32_DEFAULT_KERNEL_BUFFER_SIZE.
 		 */
-	 	if (p->opt.buffer_size == 0)
-	 		p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE;
+		if (p->opt.buffer_size == 0)
+			p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE;
 
 		if(PacketSetBuff(pw->adapter,p->opt.buffer_size)==FALSE)
 		{
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
 			goto bad;
 		}
 
@@ -1166,7 +1268,7 @@
 		int		postype = 0;
 		char	keyname[512];
 
-		pcap_snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s",
+		snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s",
 			"SYSTEM\\CurrentControlSet\\Services\\DAG",
 			strstr(_strlwr(p->opt.device), "dag"));
 		do
@@ -1205,6 +1307,29 @@
 #endif /* HAVE_DAG_API */
 	}
 
+	/*
+	 * If there's no filter program installed, there's
+	 * no indication to the kernel of what the snapshot
+	 * length should be, so no snapshotting is done.
+	 *
+	 * Therefore, when we open the device, we install
+	 * an "accept everything" filter with the specified
+	 * snapshot length.
+	 */
+	total_insn.code = (u_short)(BPF_RET | BPF_K);
+	total_insn.jt = 0;
+	total_insn.jf = 0;
+	total_insn.k = p->snapshot;
+
+	total_prog.bf_len = 1;
+	total_prog.bf_insns = &total_insn;
+	if (!PacketSetBpf(pw->adapter, &total_prog)) {
+		pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+		    GetLastError(), "PacketSetBpf");
+		status = PCAP_ERROR;
+		goto bad;
+	}
+
 	PacketSetReadTimeout(pw->adapter, p->opt.timeout);
 
 	/* disable loopback capture if requested */
@@ -1212,7 +1337,7 @@
 	{
 		if (!PacketSetLoopbackBehavior(pw->adapter, NPF_DISABLE_LOOPBACK))
 		{
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "Unable to disable the capture of loopback packets.");
 			goto bad;
 		}
@@ -1241,6 +1366,7 @@
 	p->getnonblock_op = pcap_getnonblock_npf;
 	p->setnonblock_op = pcap_setnonblock_npf;
 	p->stats_op = pcap_stats_npf;
+	p->breakloop_op = pcap_breakloop_npf;
 	p->stats_ex_op = pcap_stats_ex_npf;
 	p->setbuff_op = pcap_setbuff_npf;
 	p->setmode_op = pcap_setmode_npf;
@@ -1287,13 +1413,177 @@
 pcap_create_interface(const char *device _U_, char *ebuf)
 {
 	pcap_t *p;
+#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
+	char *device_copy;
+	ADAPTER *adapter;
+	ULONG num_ts_modes;
+	BOOL ret;
+	DWORD error;
+	ULONG *modes;
+#endif
 
-	p = pcap_create_common(ebuf, sizeof(struct pcap_win));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_win);
 	if (p == NULL)
 		return (NULL);
 
 	p->activate_op = pcap_activate_npf;
 	p->can_set_rfmon_op = pcap_can_set_rfmon_npf;
+
+#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
+	/*
+	 * First, find out how many time stamp modes we have.
+	 * To do that, we have to open the adapter.
+	 *
+	 * XXX - PacketOpenAdapter() takes a non-const pointer
+	 * as an argument, so we make a copy of the argument and
+	 * pass that to it.
+	 */
+	device_copy = strdup(device);
+	adapter = PacketOpenAdapter(device_copy);
+	free(device_copy);
+	if (adapter != NULL)
+	{
+		/*
+		 * Get the total number of time stamp modes.
+		 *
+		 * The buffer for PacketGetTimestampModes() is
+		 * a sequence of 1 or more ULONGs.  What's
+		 * passed to PacketGetTimestampModes() should have
+		 * the total number of ULONGs in the first ULONG;
+		 * what's returned *from* PacketGetTimestampModes()
+		 * has the total number of time stamp modes in
+		 * the first ULONG.
+		 *
+		 * Yes, that means if there are N time stamp
+		 * modes, the first ULONG should be set to N+1
+		 * on input, and will be set to N on output.
+		 *
+		 * We first make a call to PacketGetTimestampModes()
+		 * with a pointer to a single ULONG set to 1; the
+		 * call should fail with ERROR_MORE_DATA (unless
+		 * there are *no* modes, but that should never
+		 * happen), and that ULONG should be set to the
+		 * number of modes.
+		 */
+		num_ts_modes = 1;
+		ret = PacketGetTimestampModes(adapter, &num_ts_modes);
+		if (!ret) {
+			/*
+			 * OK, it failed.  Did it fail with
+			 * ERROR_MORE_DATA?
+			 */
+			error = GetLastError();
+			if (error != ERROR_MORE_DATA) {
+				/*
+				 * No, some other error.  Fail.
+				 */
+				pcap_fmt_errmsg_for_win32_err(ebuf,
+				    PCAP_ERRBUF_SIZE, GetLastError(),
+				    "Error calling PacketGetTimestampModes");
+				pcap_close(p);
+				return (NULL);
+			}
+
+			/*
+			 * Yes, so we now know how many types to fetch.
+			 *
+		    	 * The buffer needs to have one ULONG for the
+		    	 * count and num_ts_modes ULONGs for the
+		    	 * num_ts_modes time stamp types.
+		    	 */
+			modes = (ULONG *)malloc((1 + num_ts_modes) * sizeof(ULONG));
+			if (modes == NULL) {
+				/* Out of memory. */
+				/* XXX SET ebuf */
+				pcap_close(p);
+				return (NULL);
+			}
+			modes[0] = 1 + num_ts_modes;
+			if (!PacketGetTimestampModes(adapter, modes)) {
+				pcap_fmt_errmsg_for_win32_err(ebuf,
+				    PCAP_ERRBUF_SIZE, GetLastError(),
+				    "Error calling PacketGetTimestampModes");
+				free(modes);
+				pcap_close(p);
+				return (NULL);
+			}
+			if (modes[0] != num_ts_modes) {
+				snprintf(ebuf, PCAP_ERRBUF_SIZE,
+				    "First PacketGetTimestampModes() call gives %lu modes, second call gives %u modes",
+				    num_ts_modes, modes[0]);
+				free(modes);
+				pcap_close(p);
+				return (NULL);
+			}
+			if (num_ts_modes != 0) {
+				u_int num_ts_types;
+
+				/*
+				 * Allocate a buffer big enough for
+				 * PCAP_TSTAMP_HOST (default) plus
+				 * the explicitly specified modes.
+				 */
+				p->tstamp_type_list = malloc((1 + modes[0]) * sizeof(u_int));
+				if (p->tstamp_type_list == NULL) {
+					/* XXX SET ebuf */
+					free(modes);
+					pcap_close(p);
+					return (NULL);
+				}
+				num_ts_types = 0;
+				p->tstamp_type_list[num_ts_types] =
+				    PCAP_TSTAMP_HOST;
+				num_ts_types++;
+				for (ULONG i = 0; i < modes[0]; i++) {
+					switch (modes[i + 1]) {
+
+					case TIMESTAMPMODE_SINGLE_SYNCHRONIZATION:
+						/*
+						 * Better than low-res,
+						 * but *not* synchronized
+						 * with the OS clock.
+						 */
+						p->tstamp_type_list[num_ts_types] =
+						    PCAP_TSTAMP_HOST_HIPREC_UNSYNCED;
+						num_ts_types++;
+						break;
+
+					case TIMESTAMPMODE_QUERYSYSTEMTIME:
+						/*
+						 * Low-res, but synchronized
+						 * with the OS clock.
+						 */
+						p->tstamp_type_list[num_ts_types] =
+						    PCAP_TSTAMP_HOST_LOWPREC;
+						num_ts_types++;
+						break;
+
+					case TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE:
+						/*
+						 * High-res, and synchronized
+						 * with the OS clock.
+						 */
+						p->tstamp_type_list[num_ts_types] =
+						    PCAP_TSTAMP_HOST_HIPREC;
+						num_ts_types++;
+						break;
+
+					default:
+						/*
+						 * Unknown, so we can't
+						 * report it.
+						 */
+						break;
+					}
+				}
+				p->tstamp_type_count = num_ts_types;
+				free(modes);
+			}
+		}
+		PacketCloseAdapter(adapter);
+	}
+#endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */
+
 	return (p);
 }
 
@@ -1356,7 +1646,7 @@
 }
 
 /*
- * We filter at user level, since the kernel driver does't process the packets
+ * We filter at user level, since the kernel driver doesn't process the packets
  */
 static int
 pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) {
@@ -1596,6 +1886,12 @@
 			 * running.
 			 */
 			break;
+
+		default:
+			/*
+			 * Unknown.
+			 */
+			break;
 		}
 	} else {
 		/*
@@ -1632,7 +1928,13 @@
 	if (status == 0) {
 		/*
 		 * We got the physical medium.
+		 *
+		 * XXX - we might want to check for NdisPhysicalMediumWiMax
+		 * and NdisPhysicalMediumNative802_15_4 being
+		 * part of the enum, and check for those in the "wireless"
+		 * case.
 		 */
+DIAG_OFF_ENUM_SWITCH
 		switch (phys_medium) {
 
 		case NdisPhysicalMediumWirelessLan:
@@ -1649,10 +1951,11 @@
 
 		default:
 			/*
-			 * Not wireless.
+			 * Not wireless or unknown
 			 */
 			break;
 		}
+DIAG_ON_ENUM_SWITCH
 	}
 #endif
 
@@ -1683,6 +1986,13 @@
 			 */
 			*flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
 			break;
+
+		case MediaConnectStateUnknown:
+		default:
+			/*
+			 * It's unknown whether it's connected or not.
+			 */
+			break;
 		}
 	}
 #else
@@ -1765,7 +2075,7 @@
 	AdaptersName = (char*) malloc(NameLength);
 	if (AdaptersName == NULL)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters.");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters.");
 		return (-1);
 	}
 
@@ -1806,6 +2116,20 @@
 	name = &AdaptersName[0];
 	while (*name != '\0') {
 		bpf_u_int32 flags = 0;
+
+#ifdef HAVE_AIRPCAP_API
+		/*
+		 * Is this an AirPcap device?
+		 * If so, ignore it; it'll get added later, by the
+		 * AirPcap code.
+		 */
+		if (device_is_airpcap(name, errbuf) == 1) {
+			name += strlen(name) + 1;
+			desc += strlen(desc) + 1;
+			continue;
+		}
+#endif
+
 #ifdef HAVE_PACKET_IS_LOOPBACK_ADAPTER
 		/*
 		 * Is this a loopback interface?
@@ -1861,10 +2185,26 @@
 	DWORD dwVersion;
 	DWORD dwWindowsMajorVersion;
 
-#pragma warning (push)
-#pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */
+	/*
+	 * 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);
+	}
+
+/* disable MSVC's GetVersion() deprecated warning here */
+DIAG_OFF_DEPRECATION
 	dwVersion = GetVersion();	/* get the OS version */
-#pragma warning (pop)
+DIAG_ON_DEPRECATION
 	dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
 
 	if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
@@ -1895,7 +2235,7 @@
 
 		if(TAdaptersName == NULL)
 		{
-			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
+			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
 			return NULL;
 		}
 
@@ -2056,7 +2396,7 @@
 		/*
 		 * Generate the version string.
 		 */
-		char *packet_version_string = PacketGetVersion();
+		const char *packet_version_string = PacketGetVersion();
 
 		if (strcmp(WINPCAP_VER_STRING, packet_version_string) == 0) {
 			/*
diff --git a/pcap-pf.c b/pcap-pf.c
index fde97ba..4563a22 100644
--- a/pcap-pf.c
+++ b/pcap-pf.c
@@ -48,7 +48,6 @@
 #include <netinet/tcp.h>
 #include <netinet/tcpip.h>
 
-#include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
 #include <stdio.h>
@@ -104,9 +103,7 @@
 	register u_char *p, *bp;
 	register int cc, n, buflen, inc;
 	register struct enstamp *sp;
-#ifdef LBL_ALIGN
 	struct enstamp stamp;
-#endif
 	register u_int pad;
 
  again:
@@ -160,19 +157,17 @@
 			}
 		}
 		if (cc < sizeof(*sp)) {
-			pcap_snprintf(pc->errbuf, sizeof(pc->errbuf),
+			snprintf(pc->errbuf, sizeof(pc->errbuf),
 			    "pf short read (%d)", cc);
 			return (-1);
 		}
-#ifdef LBL_ALIGN
 		if ((long)bp & 3) {
 			sp = &stamp;
 			memcpy((char *)sp, (char *)bp, sizeof(*sp));
 		} else
-#endif
 			sp = (struct enstamp *)bp;
 		if (sp->ens_stamplen != sizeof(*sp)) {
-			pcap_snprintf(pc->errbuf, sizeof(pc->errbuf),
+			snprintf(pc->errbuf, sizeof(pc->errbuf),
 			    "pf short stamplen (%d)",
 			    sp->ens_stamplen);
 			return (-1);
@@ -205,7 +200,7 @@
 		 * skipping that padding.
 		 */
 		if (pf->filtering_in_kernel ||
-		    bpf_filter(pc->fcode.bf_insns, p, sp->ens_count, buflen)) {
+		    pcap_filter(pc->fcode.bf_insns, p, sp->ens_count, buflen)) {
 			struct pcap_pkthdr h;
 			pf->TotAccepted++;
 			h.ts = sp->ens_tstamp;
@@ -226,7 +221,7 @@
 }
 
 static int
-pcap_inject_pf(pcap_t *p, const void *buf, size_t size)
+pcap_inject_pf(pcap_t *p, const void *buf, int size)
 {
 	int ret;
 
@@ -261,7 +256,7 @@
 	 *	full.
 	 *
 	 *	"ps_ifdrop" counts packets dropped by the network
-	 *	inteface (regardless of whether they would have passed
+	 *	interface (regardless of whether they would have passed
 	 *	the input filter, of course).
 	 *
 	 * If packet filtering is not being done in the kernel:
@@ -273,7 +268,7 @@
 	 *	the userland filter.
 	 *
 	 *	"ps_ifdrop" counts packets dropped by the network
-	 *	inteface (regardless of whether they would have passed
+	 *	interface (regardless of whether they would have passed
 	 *	the input filter, of course).
 	 *
 	 * These statistics don't include packets not yet read from
@@ -331,7 +326,7 @@
 		p->fd = pfopen(p->opt.device, O_RDONLY);
 	if (p->fd < 0) {
 		if (errno == EACCES) {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "pf open: %s: Permission denied\n"
 "your system may not be properly configured; see the packetfilter(4) man page",
 			    p->opt.device);
@@ -464,7 +459,7 @@
 		 * framing", there's not much we can do, as that
 		 * doesn't specify a particular type of header.
 		 */
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "unknown data-link type %u", devparams.end_dev_type);
 		err = PCAP_ERROR;
 		goto bad;
@@ -540,7 +535,7 @@
 {
 	pcap_t *p;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_pf));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_pf);
 	if (p == NULL)
 		return (NULL);
 
diff --git a/pcap-rdmasniff.c b/pcap-rdmasniff.c
index c50fe3f..224821d 100644
--- a/pcap-rdmasniff.c
+++ b/pcap-rdmasniff.c
@@ -57,7 +57,7 @@
 	struct ibv_flow *               flow;
 	struct ibv_mr *			mr;
 	u_char *			oneshot_buffer;
-	unsigned			port_num;
+	unsigned long			port_num;
 	int                             cq_event;
 	u_int                           packets_recv;
 };
@@ -156,7 +156,7 @@
 		pktd = (u_char *) handle->buffer + wc.wr_id * RDMASNIFF_RECEIVE_SIZE;
 
 		if (handle->fcode.bf_insns == NULL ||
-		    bpf_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
+		    pcap_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
 			callback(user, &pkth, pktd);
 			++priv->packets_recv;
 			++count;
@@ -197,21 +197,21 @@
 
 	priv->context = ibv_open_device(priv->rdma_device);
 	if (!priv->context) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to open device %s", handle->opt.device);
 		goto error;
 	}
 
 	priv->pd = ibv_alloc_pd(priv->context);
 	if (!priv->pd) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to alloc PD for device %s", handle->opt.device);
 		goto error;
 	}
 
 	priv->channel = ibv_create_comp_channel(priv->context);
 	if (!priv->channel) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to create comp channel for device %s", handle->opt.device);
 		goto error;
 	}
@@ -219,7 +219,7 @@
 	priv->cq = ibv_create_cq(priv->context, RDMASNIFF_NUM_RECEIVES,
 				 NULL, priv->channel, 0);
 	if (!priv->cq) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to create CQ for device %s", handle->opt.device);
 		goto error;
 	}
@@ -233,7 +233,7 @@
 	qp_init_attr.qp_type = IBV_QPT_RAW_PACKET;
 	priv->qp = ibv_create_qp(priv->pd, &qp_init_attr);
 	if (!priv->qp) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to create QP for device %s", handle->opt.device);
 		goto error;
 	}
@@ -242,7 +242,7 @@
 	qp_attr.qp_state = IBV_QPS_INIT;
 	qp_attr.port_num = priv->port_num;
 	if (ibv_modify_qp(priv->qp, &qp_attr, IBV_QP_STATE | IBV_QP_PORT)) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to modify QP to INIT for device %s", handle->opt.device);
 		goto error;
 	}
@@ -250,7 +250,7 @@
 	memset(&qp_attr, 0, sizeof qp_attr);
 	qp_attr.qp_state = IBV_QPS_RTR;
 	if (ibv_modify_qp(priv->qp, &qp_attr, IBV_QP_STATE)) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to modify QP to RTR for device %s", handle->opt.device);
 		goto error;
 	}
@@ -261,7 +261,7 @@
 	flow_attr.port = priv->port_num;
 	priv->flow = ibv_create_flow(priv->qp, &flow_attr);
 	if (!priv->flow) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to create flow for device %s", handle->opt.device);
 		goto error;
 	}
@@ -269,21 +269,21 @@
 	handle->bufsize = RDMASNIFF_NUM_RECEIVES * RDMASNIFF_RECEIVE_SIZE;
 	handle->buffer = malloc(handle->bufsize);
 	if (!handle->buffer) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to allocate receive buffer for device %s", handle->opt.device);
 		goto error;
 	}
 
 	priv->oneshot_buffer = malloc(RDMASNIFF_RECEIVE_SIZE);
 	if (!priv->oneshot_buffer) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to allocate oneshot buffer for device %s", handle->opt.device);
 		goto error;
 	}
 
 	priv->mr = ibv_reg_mr(priv->pd, handle->buffer, handle->bufsize, IBV_ACCESS_LOCAL_WRITE);
 	if (!priv->mr) {
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			      "Failed to register MR for device %s", handle->opt.device);
 		goto error;
 	}
@@ -361,14 +361,18 @@
 	int numdev;
 	size_t namelen;
 	const char *port;
-	unsigned port_num;
+	unsigned long port_num;
 	int i;
 	pcap_t *p = NULL;
 
 	*is_ours = 0;
 
 	dev_list = ibv_get_device_list(&numdev);
-	if (!dev_list || !numdev) {
+	if (!dev_list) {
+		return NULL;
+	}
+	if (!numdev) {
+		ibv_free_device_list(dev_list);
 		return NULL;
 	}
 
@@ -391,7 +395,7 @@
 		    !strncmp(device, dev_list[i]->name, namelen)) {
 			*is_ours = 1;
 
-			p = pcap_create_common(ebuf, sizeof (struct pcap_rdmasniff));
+			p = PCAP_CREATE_COMMON(ebuf, struct pcap_rdmasniff);
 			if (p) {
 				p->activate_op = rdmasniff_activate;
 				priv = p->priv;
@@ -415,7 +419,7 @@
 	int ret = 0;
 
 	dev_list = ibv_get_device_list(&numdev);
-	if (!dev_list || !numdev) {
+	if (!dev_list) {
 		return 0;
 	}
 
@@ -426,11 +430,10 @@
 		 */
 		if (!add_dev(devlistp, dev_list[i]->name, 0, "RDMA sniffer", err_str)) {
 			ret = -1;
-			goto out;
+			break;
 		}
 	}
 
-out:
 	ibv_free_device_list(dev_list);
 	return ret;
 }
diff --git a/pcap-rpcap.c b/pcap-rpcap.c
index 705f06f..a2612e9 100644
--- a/pcap-rpcap.c
+++ b/pcap-rpcap.c
@@ -46,6 +46,14 @@
 #include "rpcap-protocol.h"
 #include "pcap-rpcap.h"
 
+#ifdef _WIN32
+#include "charconv.h"		/* for utf_8_to_acp_truncated() */
+#endif
+
+#ifdef HAVE_OPENSSL
+#include "sslutils.h"
+#endif
+
 /*
  * This file contains the pcap module for capturing from a remote machine's
  * interfaces using the RPCAP protocol.
@@ -83,6 +91,7 @@
 {
 	struct sockaddr_storage host;
 	SOCKET sockctrl;
+	SSL *ssl;
 	uint8 protocol_version;
 	struct activehosts *next;
 };
@@ -97,6 +106,7 @@
  * pcap_remoteact_cleanup() for more details.
  */
 static SOCKET sockmain;
+static SSL *ssl_main;
 
 /*
  * Private data for capturing remotely using the rpcap protocol.
@@ -111,11 +121,13 @@
 
 	SOCKET rmt_sockctrl;		/* socket ID of the socket used for the control connection */
 	SOCKET rmt_sockdata;		/* socket ID of the socket used for the data connection */
+	SSL *ctrl_ssl, *data_ssl;	/* optional transport of rmt_sockctrl and rmt_sockdata via TLS */
 	int rmt_flags;			/* we have to save flags, since they are passed by the pcap_open_live(), but they are used by the pcap_startcapture() */
 	int rmt_capstarted;		/* 'true' if the capture is already started (needed to knoe if we have to call the pcap_startcapture() */
 	char *currentfilter;		/* Pointer to a buffer (allocated at run-time) that stores the current filter. Needed when flag PCAP_OPENFLAG_NOCAPTURE_RPCAP is turned on. */
 
 	uint8 protocol_version;		/* negotiated protocol version */
+	uint8 uses_ssl;				/* User asked for rpcaps scheme */
 
 	unsigned int TotNetDrops;	/* keeps the number of packets that have been dropped by the network */
 
@@ -155,14 +167,14 @@
 static int pcap_setfilter_rpcap(pcap_t *fp, struct bpf_program *prog);
 static int pcap_setsampling_remote(pcap_t *fp);
 static int pcap_startcapture_remote(pcap_t *fp);
-static int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char *errbuf);
-static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_header *header, char *errbuf);
-static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf);
-static int rpcap_process_msg_header(SOCKET sock, uint8 ver, uint8 request_type, struct rpcap_header *header, char *errbuf);
-static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, char *errbuf);
-static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf);
-static int rpcap_discard(SOCKET sock, uint32 len, char *errbuf);
-static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size);
+static int rpcap_recv_msg_header(SOCKET sock, SSL *, struct rpcap_header *header, char *errbuf);
+static int rpcap_check_msg_ver(SOCKET sock, SSL *, uint8 expected_ver, struct rpcap_header *header, char *errbuf);
+static int rpcap_check_msg_type(SOCKET sock, SSL *, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf);
+static int rpcap_process_msg_header(SOCKET sock, SSL *, uint8 ver, uint8 request_type, struct rpcap_header *header, char *errbuf);
+static int rpcap_recv(SOCKET sock, SSL *, void *buffer, size_t toread, uint32 *plen, char *errbuf);
+static void rpcap_msg_err(SOCKET sockctrl, SSL *, uint32 plen, char *remote_errbuf);
+static int rpcap_discard(SOCKET sock, SSL *, uint32 len, char *errbuf);
+static int rpcap_read_packet_msg(struct pcap_rpcap const *, pcap_t *p, size_t size);
 
 /****************************************************
  *                                                  *
@@ -375,7 +387,7 @@
 	struct rpcap_pkthdr *net_pkt_header;	/* header of the packet, from the message */
 	u_char *net_pkt_data;			/* packet data from the message */
 	uint32 plen;
-	int retval;				/* generic return value */
+	int retval = 0;				/* generic return value */
 	int msglen;
 
 	/* Structures needed for the select() call */
@@ -387,29 +399,42 @@
 	 * 'timeout', in pcap_t, is in milliseconds; we have to convert it into sec and microsec
 	 */
 	tv.tv_sec = p->opt.timeout / 1000;
-	tv.tv_usec = (p->opt.timeout - tv.tv_sec * 1000) * 1000;
+	tv.tv_usec = (suseconds_t)((p->opt.timeout - tv.tv_sec * 1000) * 1000);
 
-	/* Watch out sockdata to see if it has input */
-	FD_ZERO(&rfds);
-
-	/*
-	 * 'fp->rmt_sockdata' has always to be set before calling the select(),
-	 * since it is cleared by the select()
-	 */
-	FD_SET(pr->rmt_sockdata, &rfds);
-
-	retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv);
-	if (retval == -1)
-	{
-#ifndef _WIN32
-		if (errno == EINTR)
-		{
-			/* Interrupted. */
-			return 0;
-		}
+#ifdef HAVE_OPENSSL
+	/* Check if we still have bytes available in the last decoded TLS record.
+	 * If that's the case, we know SSL_read will not block. */
+	retval = pr->data_ssl && SSL_pending(pr->data_ssl) > 0;
 #endif
-		sock_geterror("select()", p->errbuf, PCAP_ERRBUF_SIZE);
-		return -1;
+	if (! retval)
+	{
+		/* Watch out sockdata to see if it has input */
+		FD_ZERO(&rfds);
+
+		/*
+		 * 'fp->rmt_sockdata' has always to be set before calling the select(),
+		 * since it is cleared by the select()
+		 */
+		FD_SET(pr->rmt_sockdata, &rfds);
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+		retval = 1;
+#else
+		retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv);
+#endif
+
+		if (retval == -1)
+		{
+#ifndef _WIN32
+			if (errno == EINTR)
+			{
+				/* Interrupted. */
+				return 0;
+			}
+#endif
+			sock_geterror("select()", p->errbuf, PCAP_ERRBUF_SIZE);
+			return -1;
+		}
 	}
 
 	/* There is no data waiting, so return '0' */
@@ -427,7 +452,7 @@
 	if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)
 	{
 		/* Read the entire message from the network */
-		msglen = sock_recv_dgram(pr->rmt_sockdata, p->buffer,
+		msglen = sock_recv_dgram(pr->rmt_sockdata, pr->data_ssl, p->buffer,
 		    p->bufsize, p->errbuf, PCAP_ERRBUF_SIZE);
 		if (msglen == -1)
 		{
@@ -444,7 +469,7 @@
 			/*
 			 * Message is shorter than an rpcap header.
 			 */
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "UDP packet message is shorter than an rpcap header");
 			return -1;
 		}
@@ -455,7 +480,7 @@
 			 * Message is shorter than the header claims it
 			 * is.
 			 */
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "UDP packet message is shorter than its rpcap header claims");
 			return -1;
 		}
@@ -471,8 +496,7 @@
 			 * The size we should get is the size of the
 			 * packet header.
 			 */
-			status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
-			    sizeof(struct rpcap_header));
+			status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header));
 			if (status == -1)
 			{
 				/* Network error. */
@@ -500,12 +524,11 @@
 			 * subtracting in order to avoid an
 			 * overflow.)
 			 */
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "Server sent us a message larger than the largest expected packet message");
 			return -1;
 		}
-		status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
-		    sizeof(struct rpcap_header) + plen);
+		status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header) + plen);
 		if (status == -1)
 		{
 			/* Network error. */
@@ -534,7 +557,7 @@
 	/*
 	 * Did the server specify the version we negotiated?
 	 */
-	if (rpcap_check_msg_ver(pr->rmt_sockdata, pr->protocol_version,
+	if (rpcap_check_msg_ver(pr->rmt_sockdata, pr->data_ssl, pr->protocol_version,
 	    header, p->errbuf) == -1)
 	{
 		return 0;	/* Return 'no packets received' */
@@ -550,7 +573,7 @@
 
 	if (ntohl(net_pkt_header->caplen) > plen)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "Packet's captured data goes past the end of the received packet message.");
 		return -1;
 	}
@@ -678,7 +701,9 @@
 }
 
 /*
- * This function sends a CLOSE command to the capture server.
+ * This function sends a CLOSE command to the capture server if we're in
+ * passive mode and an ENDCAP command to the capture server if we're in
+ * active mode.
  *
  * It is called when the user calls pcap_close().  It sends a command
  * to our peer that says 'ok, let's stop capturing'.
@@ -714,7 +739,7 @@
 		 * we're closing this pcap_t, and have no place to report
 		 * the error.  No reply is sent to this message.
 		 */
-		(void)sock_send(pr->rmt_sockctrl, (char *)&header,
+		(void)sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header,
 		    sizeof(struct rpcap_header), NULL, 0);
 	}
 	else
@@ -727,7 +752,7 @@
 		 * as we're closing this pcap_t, and have no place to
 		 * report the error.
 		 */
-		if (sock_send(pr->rmt_sockctrl, (char *)&header,
+		if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header,
 		    sizeof(struct rpcap_header), NULL, 0) == 0)
 		{
 			/*
@@ -735,11 +760,11 @@
 			 * as we're closing this pcap_t, and have no
 			 * place to report the error.
 			 */
-			if (rpcap_process_msg_header(pr->rmt_sockctrl,
+			if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl,
 			    pr->protocol_version, RPCAP_MSG_ENDCAP_REQ,
 			    &header, NULL) == 0)
 			{
-				(void)rpcap_discard(pr->rmt_sockctrl,
+				(void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl,
 				    header.plen, NULL);
 			}
 		}
@@ -747,14 +772,35 @@
 
 	if (pr->rmt_sockdata)
 	{
+#ifdef HAVE_OPENSSL
+		if (pr->data_ssl)
+		{
+			// Finish using the SSL handle for the data socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(pr->data_ssl);
+			pr->data_ssl = NULL;
+		}
+#endif
 		sock_close(pr->rmt_sockdata, NULL, 0);
 		pr->rmt_sockdata = 0;
 	}
 
 	if ((!active) && (pr->rmt_sockctrl))
+	{
+#ifdef HAVE_OPENSSL
+		if (pr->ctrl_ssl)
+		{
+			// Finish using the SSL handle for the control socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(pr->ctrl_ssl);
+			pr->ctrl_ssl = NULL;
+		}
+#endif
 		sock_close(pr->rmt_sockctrl, NULL, 0);
+	}
 
 	pr->rmt_sockctrl = 0;
+	pr->ctrl_ssl = NULL;
 
 	if (pr->currentfilter)
 	{
@@ -848,7 +894,7 @@
 	if (mode != PCAP_STATS_STANDARD)
 #endif
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "Invalid stats mode %d", mode);
 		return NULL;
 	}
@@ -879,19 +925,19 @@
 	    RPCAP_MSG_STATS_REQ, 0, 0);
 
 	/* Send the PCAP_STATS command */
-	if (sock_send(pr->rmt_sockctrl, (char *)&header,
+	if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header,
 	    sizeof(struct rpcap_header), p->errbuf, PCAP_ERRBUF_SIZE) < 0)
 		return NULL;		/* Unrecoverable network error */
 
 	/* Receive and process the reply message header. */
-	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
 	    RPCAP_MSG_STATS_REQ, &header, p->errbuf) == -1)
 		return NULL;		/* Error */
 
 	plen = header.plen;
 
 	/* Read the reply body */
-	if (rpcap_recv(pr->rmt_sockctrl, (char *)&netstats,
+	if (rpcap_recv(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&netstats,
 	    sizeof(struct rpcap_stats), &plen, p->errbuf) == -1)
 		goto error;
 
@@ -908,7 +954,7 @@
 #endif /* _WIN32 */
 
 	/* Discard the rest of the message. */
-	if (rpcap_discard(pr->rmt_sockctrl, plen, p->errbuf) == -1)
+	if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, p->errbuf) == -1)
 		goto error_nodiscard;
 
 	return ps;
@@ -919,7 +965,7 @@
 	 * We already reported an error; if this gets an error, just
 	 * drive on.
 	 */
-	(void)rpcap_discard(pr->rmt_sockctrl, plen, NULL);
+	(void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, NULL);
 
 error_nodiscard:
 	return NULL;
@@ -960,7 +1006,7 @@
 	retval = getaddrinfo(host, "0", &hints, &addrinfo);
 	if (retval != 0)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s",
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s",
 		    gai_strerror(retval));
 		*error = 1;
 		return NULL;
@@ -1039,6 +1085,10 @@
 	int sockbufsize = 0;
 	uint32 server_sockbufsize;
 
+	// Take the opportunity to clear pr->data_ssl before any goto error,
+	// as it seems pr->priv is not zeroed after its malloced.
+	pr->data_ssl = NULL;
+
 	/*
 	 * Let's check if sampling has been required.
 	 * If so, let's set it first
@@ -1178,18 +1228,18 @@
 	if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, &fp->fcode))
 		goto error_nodiscard;
 
-	if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
+	if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf,
 	    PCAP_ERRBUF_SIZE) < 0)
 		goto error_nodiscard;
 
 	/* Receive and process the reply message header. */
-	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
 	    RPCAP_MSG_STARTCAP_REQ, &header, fp->errbuf) == -1)
 		goto error_nodiscard;
 
 	plen = header.plen;
 
-	if (rpcap_recv(pr->rmt_sockctrl, (char *)&startcapreply,
+	if (rpcap_recv(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&startcapreply,
 	    sizeof(struct rpcap_startcapreply), &plen, fp->errbuf) == -1)
 		goto error;
 
@@ -1211,7 +1261,7 @@
 			memset(&hints, 0, sizeof(struct addrinfo));
 			hints.ai_family = ai_family;		/* Use the same address family of the control socket */
 			hints.ai_socktype = (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM;
-			pcap_snprintf(portdata, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata));
+			snprintf(portdata, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata));
 
 			/* Let's the server pick up a free network port for us */
 			if (sock_initaddress(host, portdata, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
@@ -1248,6 +1298,14 @@
 	/* Let's save the socket of the data connection */
 	pr->rmt_sockdata = sockdata;
 
+#ifdef HAVE_OPENSSL
+	if (pr->uses_ssl)
+	{
+		pr->data_ssl = ssl_promotion(0, sockdata, fp->errbuf, PCAP_ERRBUF_SIZE);
+		if (! pr->data_ssl) goto error;
+	}
+#endif
+
 	/*
 	 * Set the size of the socket buffer for the data socket.
 	 * It has the same size as the local capture buffer used
@@ -1335,7 +1393,7 @@
 	fp->cc = 0;
 
 	/* Discard the rest of the message. */
-	if (rpcap_discard(pr->rmt_sockctrl, plen, fp->errbuf) == -1)
+	if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, fp->errbuf) == -1)
 		goto error_nodiscard;
 
 	/*
@@ -1375,14 +1433,36 @@
 	 * We already reported an error; if this gets an error, just
 	 * drive on.
 	 */
-	(void)rpcap_discard(pr->rmt_sockctrl, plen, NULL);
+	(void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, NULL);
 
 error_nodiscard:
-	if ((sockdata) && (sockdata != -1))		/* we can be here because sockdata said 'error' */
+#ifdef HAVE_OPENSSL
+	if (pr->data_ssl)
+	{
+		// Finish using the SSL handle for the data socket.
+		// This must be done *before* the socket is closed.
+		ssl_finish(pr->data_ssl);
+		pr->data_ssl = NULL;
+	}
+#endif
+
+	/* we can be here because sockdata said 'error' */
+	if ((sockdata != 0) && (sockdata != INVALID_SOCKET))
 		sock_close(sockdata, NULL, 0);
 
 	if (!active)
+	{
+#ifdef HAVE_OPENSSL
+		if (pr->ctrl_ssl)
+		{
+			// Finish using the SSL handle for the control socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(pr->ctrl_ssl);
+			pr->ctrl_ssl = NULL;
+		}
+#endif
 		sock_close(pr->rmt_sockctrl, NULL, 0);
+	}
 
 	if (addrinfo != NULL)
 		freeaddrinfo(addrinfo);
@@ -1408,7 +1488,7 @@
  * This function can be called in two cases:
  * - pcap_startcapture_remote() is called (we have to send the filter
  *   along with the 'start capture' command)
- * - we want to udpate the filter during a capture (i.e. pcap_setfilter()
+ * - we want to update the filter during a capture (i.e. pcap_setfilter()
  *   after the capture has been started)
  *
  * This function serializes the filter into the sending buffer ('sendbuf',
@@ -1515,19 +1595,19 @@
 	if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, prog))
 		return -1;
 
-	if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
+	if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf,
 	    PCAP_ERRBUF_SIZE) < 0)
 		return -1;
 
 	/* Receive and process the reply message header. */
-	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
 	    RPCAP_MSG_UPDATEFILTER_REQ, &header, fp->errbuf) == -1)
 		return -1;
 
 	/*
 	 * It shouldn't have any contents; discard it if it does.
 	 */
-	if (rpcap_discard(pr->rmt_sockctrl, header.plen, fp->errbuf) == -1)
+	if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, header.plen, fp->errbuf) == -1)
 		return -1;
 
 	return 0;
@@ -1672,7 +1752,7 @@
 			    mydataport) == -1)
 			{
 				/* Failed. */
-				pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
 				    "Can't allocate memory for new filter");
 				return -1;
 			}
@@ -1689,7 +1769,7 @@
 			    myaddress, peeraddress, mydataport) == -1)
 			{
 				/* Failed. */
-				pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
 				    "Can't allocate memory for new filter");
 				return -1;
 			}
@@ -1745,12 +1825,12 @@
 	 * that do fit into the message.
 	 */
 	if (fp->rmt_samp.method < 0 || fp->rmt_samp.method > 255) {
-		pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
 		    "Invalid sampling method %d", fp->rmt_samp.method);
 		return -1;
 	}
 	if (fp->rmt_samp.value < 0 || fp->rmt_samp.value > 65535) {
-		pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
 		    "Invalid sampling value %d", fp->rmt_samp.value);
 		return -1;
 	}
@@ -1775,19 +1855,19 @@
 	sampling_pars->method = (uint8)fp->rmt_samp.method;
 	sampling_pars->value = (uint16)htonl(fp->rmt_samp.value);
 
-	if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
+	if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf,
 	    PCAP_ERRBUF_SIZE) < 0)
 		return -1;
 
 	/* Receive and process the reply message header. */
-	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
 	    RPCAP_MSG_SETSAMPLING_REQ, &header, fp->errbuf) == -1)
 		return -1;
 
 	/*
 	 * It shouldn't have any contents; discard it if it does.
 	 */
-	if (rpcap_discard(pr->rmt_sockctrl, header.plen, fp->errbuf) == -1)
+	if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, header.plen, fp->errbuf) == -1)
 		return -1;
 
 	return 0;
@@ -1831,7 +1911,7 @@
  * \return '0' if everything is fine, '-1' for an error.  For errors,
  * an error message string is returned in the 'errbuf' variable.
  */
-static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
+static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
 {
 	char sendbuf[RPCAP_NETBUF_SIZE];	/* temporary buffer in which data that has to be sent is buffered */
 	int sendbufidx = 0;			/* index which keeps the number of bytes currently buffered */
@@ -1859,7 +1939,7 @@
 				str_length = strlen(auth->username);
 				if (str_length > 65535)
 				{
-					pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "User name is too long (> 65535 bytes)");
+					snprintf(errbuf, PCAP_ERRBUF_SIZE, "User name is too long (> 65535 bytes)");
 					return -1;
 				}
 				length += (uint16)str_length;
@@ -1869,7 +1949,7 @@
 				str_length = strlen(auth->password);
 				if (str_length > 65535)
 				{
-					pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Password is too long (> 65535 bytes)");
+					snprintf(errbuf, PCAP_ERRBUF_SIZE, "Password is too long (> 65535 bytes)");
 					return -1;
 				}
 				length += (uint16)str_length;
@@ -1877,7 +1957,7 @@
 			break;
 
 		default:
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized.");
+			snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized.");
 			return -1;
 		}
 
@@ -1930,12 +2010,12 @@
 		rpauth->slen2 = htons(rpauth->slen2);
 	}
 
-	if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf,
+	if (sock_send(sockctrl, ssl, sendbuf, sendbufidx, errbuf,
 	    PCAP_ERRBUF_SIZE) < 0)
 		return -1;
 
 	/* Receive and process the reply message header */
-	if (rpcap_process_msg_header(sockctrl, 0, RPCAP_MSG_AUTH_REQ,
+	if (rpcap_process_msg_header(sockctrl, ssl, 0, RPCAP_MSG_AUTH_REQ,
 	    &header, errbuf) == -1)
 		return -1;
 
@@ -1951,20 +2031,20 @@
 		if (plen < sizeof(struct rpcap_authreply))
 		{
 			/* No - discard it and fail. */
-			(void)rpcap_discard(sockctrl, plen, NULL);
+			(void)rpcap_discard(sockctrl, ssl, plen, NULL);
 			return -1;
 		}
 
 		/* Read the reply body */
-		if (rpcap_recv(sockctrl, (char *)&authreply,
+		if (rpcap_recv(sockctrl, ssl, (char *)&authreply,
 		    sizeof(struct rpcap_authreply), &plen, errbuf) == -1)
 		{
-			(void)rpcap_discard(sockctrl, plen, NULL);
+			(void)rpcap_discard(sockctrl, ssl, plen, NULL);
 			return -1;
 		}
 
 		/* Discard the rest of the message, if there is any. */
-		if (rpcap_discard(sockctrl, plen, errbuf) == -1)
+		if (rpcap_discard(sockctrl, ssl, plen, errbuf) == -1)
 			return -1;
 
 		/*
@@ -1976,7 +2056,7 @@
 			/*
 			 * Bogus - give up on this server.
 			 */
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "The server's minimum supported protocol version is greater than its maximum supported protocol version");
 			return -1;
 		}
@@ -2025,7 +2105,7 @@
 	/*
 	 * There is no version we both support; that is a fatal error.
 	 */
-	pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(errbuf, PCAP_ERRBUF_SIZE,
 	    "The server doesn't support any protocol version that we support");
 	return -1;
 }
@@ -2034,7 +2114,7 @@
 static int
 pcap_getnonblock_rpcap(pcap_t *p)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Non-blocking mode isn't supported for capturing remotely with rpcap");
 	return (-1);
 }
@@ -2042,15 +2122,16 @@
 static int
 pcap_setnonblock_rpcap(pcap_t *p, int nonblock _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Non-blocking mode isn't supported for capturing remotely with rpcap");
 	return (-1);
 }
 
 static int
 rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
-    int *activep, SOCKET *sockctrlp, uint8 *protocol_versionp,
-    char *host, char *port, char *iface, char *errbuf)
+    int *activep, SOCKET *sockctrlp, uint8 *uses_sslp, SSL **sslp,
+    int rmt_flags, uint8 *protocol_versionp, char *host, char *port,
+    char *iface, char *errbuf)
 {
 	int type;
 	struct activehosts *activeconn;		/* active connection, if there is one */
@@ -2061,7 +2142,8 @@
 	 * You must have a valid source string even if we're in active mode,
 	 * because otherwise the call to the following function will fail.
 	 */
-	if (pcap_parsesrcstr(source, &type, host, port, iface, errbuf) == -1)
+	if (pcap_parsesrcstr_ex(source, &type, host, port, iface, uses_sslp,
+	    errbuf) == -1)
 		return -1;
 
 	/*
@@ -2069,13 +2151,25 @@
 	 */
 	if (type != PCAP_SRC_IFREMOTE)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "Non-remote interface passed to remote capture routine");
 		return -1;
 	}
 
+	/*
+	 * We don't yet support DTLS, so if the user asks for a TLS
+	 * connection and asks for data packets to be sent over UDP,
+	 * we have to give up.
+	 */
+	if (*uses_sslp && (rmt_flags & PCAP_OPENFLAG_DATATX_UDP))
+	{
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "TLS not supported with UDP forward of remote packets");
+		return -1;
+	}
+
 	/* Warning: this call can be the first one called by the user. */
-	/* For this reason, we have to initialize the WinSock support. */
+	/* For this reason, we have to initialize the Winsock support. */
 	if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
 		return -1;
 
@@ -2085,6 +2179,7 @@
 	{
 		*activep = 1;
 		*sockctrlp = activeconn->sockctrl;
+		*sslp = activeconn->ssl;
 		*protocol_versionp = activeconn->protocol_version;
 	}
 	else
@@ -2134,9 +2229,36 @@
 		freeaddrinfo(addrinfo);
 		addrinfo = NULL;
 
-		if (rpcap_doauth(*sockctrlp, protocol_versionp, auth,
+		if (*uses_sslp)
+		{
+#ifdef HAVE_OPENSSL
+			*sslp = ssl_promotion(0, *sockctrlp, errbuf,
+			    PCAP_ERRBUF_SIZE);
+			if (!*sslp)
+			{
+				sock_close(*sockctrlp, NULL, 0);
+				return -1;
+			}
+#else
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "No TLS support");
+			sock_close(*sockctrlp, NULL, 0);
+			return -1;
+#endif
+		}
+
+		if (rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, auth,
 		    errbuf) == -1)
 		{
+#ifdef HAVE_OPENSSL
+			if (*sslp)
+			{
+				// Finish using the SSL handle for the socket.
+				// This must be done *before* the socket is
+				// closed.
+				ssl_finish(*sslp);
+			}
+#endif
 			sock_close(*sockctrlp, NULL, 0);
 			return -1;
 		}
@@ -2190,6 +2312,7 @@
 	struct pcap_rpcap *pr;		/* structure used when doing a remote live capture */
 	char host[PCAP_BUF_SIZE], ctrlport[PCAP_BUF_SIZE], iface[PCAP_BUF_SIZE];
 	SOCKET sockctrl;
+	SSL *ssl = NULL;
 	uint8 protocol_version;			/* negotiated protocol version */
 	int active;
 	uint32 plen;
@@ -2200,7 +2323,7 @@
 	struct rpcap_header header;		/* header of the RPCAP packet */
 	struct rpcap_openreply openreply;	/* open reply message */
 
-	fp = pcap_create_common(errbuf, sizeof (struct pcap_rpcap));
+	fp = PCAP_CREATE_COMMON(errbuf, struct pcap_rpcap);
 	if (fp == NULL)
 	{
 		return NULL;
@@ -2236,13 +2359,17 @@
 	 * Attempt to set up the session with the server.
 	 */
 	if (rpcap_setup_session(fp->opt.device, auth, &active, &sockctrl,
-	    &protocol_version, host, ctrlport, iface, errbuf) == -1)
+	    &pr->uses_ssl, &ssl, flags, &protocol_version, host, ctrlport,
+	    iface, errbuf) == -1)
 	{
 		/* Session setup failed. */
 		pcap_close(fp);
 		return NULL;
 	}
 
+	/* All good so far, save the ssl handler */
+	ssl_main = ssl;
+
 	/*
 	 * Now it's time to start playing with the RPCAP protocol
 	 * RPCAP open command: create the request message
@@ -2258,29 +2385,29 @@
 		RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
 		goto error_nodiscard;
 
-	if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf,
+	if (sock_send(sockctrl, ssl, sendbuf, sendbufidx, errbuf,
 	    PCAP_ERRBUF_SIZE) < 0)
 		goto error_nodiscard;
 
 	/* Receive and process the reply message header. */
-	if (rpcap_process_msg_header(sockctrl, protocol_version,
+	if (rpcap_process_msg_header(sockctrl, ssl, protocol_version,
 	    RPCAP_MSG_OPEN_REQ, &header, errbuf) == -1)
 		goto error_nodiscard;
 	plen = header.plen;
 
 	/* Read the reply body */
-	if (rpcap_recv(sockctrl, (char *)&openreply,
+	if (rpcap_recv(sockctrl, ssl, (char *)&openreply,
 	    sizeof(struct rpcap_openreply), &plen, errbuf) == -1)
 		goto error;
 
 	/* Discard the rest of the message, if there is any. */
-	if (rpcap_discard(sockctrl, plen, errbuf) == -1)
+	if (rpcap_discard(sockctrl, ssl, plen, errbuf) == -1)
 		goto error_nodiscard;
 
 	/* Set proper fields into the pcap_t struct */
 	fp->linktype = ntohl(openreply.linktype);
-	fp->tzoff = ntohl(openreply.tzoff);
 	pr->rmt_sockctrl = sockctrl;
+	pr->ctrl_ssl = ssl;
 	pr->protocol_version = protocol_version;
 	pr->rmt_clientside = 1;
 
@@ -2312,11 +2439,21 @@
 	 * We already reported an error; if this gets an error, just
 	 * drive on.
 	 */
-	(void)rpcap_discard(sockctrl, plen, NULL);
+	(void)rpcap_discard(sockctrl, pr->ctrl_ssl, plen, NULL);
 
 error_nodiscard:
 	if (!active)
+	{
+#ifdef HAVE_OPENSSL
+		if (ssl)
+		{
+			// Finish using the SSL handle for the socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(ssl);
+		}
+#endif
 		sock_close(sockctrl, NULL, 0);
+	}
 
 	pcap_close(fp);
 	return NULL;
@@ -2344,11 +2481,13 @@
 {
 	uint8 protocol_version;		/* protocol version */
 	SOCKET sockctrl;		/* socket descriptor of the control connection */
+	SSL *ssl = NULL;		/* optional SSL handler for sockctrl */
 	uint32 plen;
 	struct rpcap_header header;	/* structure that keeps the general header of the rpcap protocol */
 	int i, j;		/* temp variables */
 	int nif;		/* Number of interfaces listed */
 	int active;			/* 'true' if we the other end-party is in active mode */
+	uint8 uses_ssl;
 	char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE];
 	char tmpstring[PCAP_BUF_SIZE + 1];		/* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
 	pcap_if_t *lastdev;	/* Last device in the pcap_if_t list */
@@ -2361,8 +2500,8 @@
 	/*
 	 * Attempt to set up the session with the server.
 	 */
-	if (rpcap_setup_session(source, auth, &active, &sockctrl,
-	    &protocol_version, host, port, NULL, errbuf) == -1)
+	if (rpcap_setup_session(source, auth, &active, &sockctrl, &uses_ssl,
+	    &ssl, 0, &protocol_version, host, port, NULL, errbuf) == -1)
 	{
 		/* Session setup failed. */
 		return -1;
@@ -2372,12 +2511,12 @@
 	rpcap_createhdr(&header, protocol_version, RPCAP_MSG_FINDALLIF_REQ,
 	    0, 0);
 
-	if (sock_send(sockctrl, (char *)&header, sizeof(struct rpcap_header),
+	if (sock_send(sockctrl, ssl, (char *)&header, sizeof(struct rpcap_header),
 	    errbuf, PCAP_ERRBUF_SIZE) < 0)
 		goto error_nodiscard;
 
 	/* Receive and process the reply message header. */
-	if (rpcap_process_msg_header(sockctrl, protocol_version,
+	if (rpcap_process_msg_header(sockctrl, ssl, protocol_version,
 	    RPCAP_MSG_FINDALLIF_REQ, &header, errbuf) == -1)
 		goto error_nodiscard;
 
@@ -2396,7 +2535,7 @@
 		tmpstring2[PCAP_BUF_SIZE] = 0;
 
 		/* receive the findalldevs structure from remote host */
-		if (rpcap_recv(sockctrl, (char *)&findalldevs_if,
+		if (rpcap_recv(sockctrl, ssl, (char *)&findalldevs_if,
 		    sizeof(struct rpcap_findalldevs_if), &plen, errbuf) == -1)
 			goto error;
 
@@ -2440,20 +2579,20 @@
 
 			if (findalldevs_if.namelen >= sizeof(tmpstring))
 			{
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long");
+				snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long");
 				goto error;
 			}
 
 			/* Retrieve adapter name */
-			if (rpcap_recv(sockctrl, tmpstring,
+			if (rpcap_recv(sockctrl, ssl, tmpstring,
 			    findalldevs_if.namelen, &plen, errbuf) == -1)
 				goto error;
 
 			tmpstring[findalldevs_if.namelen] = 0;
 
 			/* Create the new device identifier */
-			if (pcap_createsrcstr(tmpstring2, PCAP_SRC_IFREMOTE,
-			    host, port, tmpstring, errbuf) == -1)
+			if (pcap_createsrcstr_ex(tmpstring2, PCAP_SRC_IFREMOTE,
+			    host, port, tmpstring, uses_ssl, errbuf) == -1)
 				goto error;
 
 			dev->name = strdup(tmpstring2);
@@ -2469,12 +2608,12 @@
 		{
 			if (findalldevs_if.desclen >= sizeof(tmpstring))
 			{
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long");
+				snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long");
 				goto error;
 			}
 
 			/* Retrieve adapter description */
-			if (rpcap_recv(sockctrl, tmpstring,
+			if (rpcap_recv(sockctrl, ssl, tmpstring,
 			    findalldevs_if.desclen, &plen, errbuf) == -1)
 				goto error;
 
@@ -2499,7 +2638,7 @@
 			struct rpcap_findalldevs_ifaddr ifaddr;
 
 			/* Retrieve the interface addresses */
-			if (rpcap_recv(sockctrl, (char *)&ifaddr,
+			if (rpcap_recv(sockctrl, ssl, (char *)&ifaddr,
 			    sizeof(struct rpcap_findalldevs_ifaddr),
 			    &plen, errbuf) == -1)
 				goto error;
@@ -2573,13 +2712,21 @@
 	}
 
 	/* Discard the rest of the message. */
-	if (rpcap_discard(sockctrl, plen, errbuf) == 1)
+	if (rpcap_discard(sockctrl, ssl, plen, errbuf) == 1)
 		goto error_nodiscard;
 
 	/* Control connection has to be closed only in case the remote machine is in passive mode */
 	if (!active)
 	{
 		/* DO not send RPCAP_CLOSE, since we did not open a pcap_t; no need to free resources */
+#ifdef HAVE_OPENSSL
+		if (ssl)
+		{
+			// Finish using the SSL handle for the socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(ssl);
+		}
+#endif
 		if (sock_close(sockctrl, errbuf, PCAP_ERRBUF_SIZE))
 			return -1;
 	}
@@ -2603,12 +2750,22 @@
 	 *
 	 * Checks if all the data has been read; if not, discard the data in excess
 	 */
-	(void) rpcap_discard(sockctrl, plen, NULL);
+	(void) rpcap_discard(sockctrl, ssl, plen, NULL);
 
 error_nodiscard:
 	/* Control connection has to be closed only in case the remote machine is in passive mode */
 	if (!active)
+	{
+#ifdef HAVE_OPENSSL
+		if (ssl)
+		{
+			// Finish using the SSL handle for the socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(ssl);
+		}
+#endif
 		sock_close(sockctrl, NULL, 0);
+	}
 
 	/* To avoid inconsistencies in the number of sock_init() */
 	sock_cleanup();
@@ -2626,7 +2783,7 @@
  * to implement; we provide some APIs for it that work only with rpcap.
  */
 
-SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf)
+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)
 {
 	/* socket-related variables */
 	struct addrinfo hints;			/* temporary struct to keep settings needed to open the new socket */
@@ -2634,6 +2791,7 @@
 	struct sockaddr_storage from;	/* generic sockaddr_storage variable */
 	socklen_t fromlen;				/* keeps the length of the sockaddr_storage variable */
 	SOCKET sockctrl;				/* keeps the main socket identifier */
+	SSL *ssl = NULL;				/* Optional SSL handler for sockctrl */
 	uint8 protocol_version;			/* negotiated protocol version */
 	struct activehosts *temp, *prev;	/* temp var needed to scan he host list chain */
 
@@ -2647,7 +2805,7 @@
 	hints.ai_socktype = SOCK_STREAM;
 
 	/* Warning: this call can be the first one called by the user. */
-	/* For this reason, we have to initialize the WinSock support. */
+	/* For this reason, we have to initialize the Winsock support. */
 	if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
 		return (SOCKET)-1;
 
@@ -2691,11 +2849,36 @@
 		return (SOCKET)-2;
 	}
 
+	/* Promote to SSL early before any error message may be sent */
+	if (uses_ssl)
+	{
+#ifdef HAVE_OPENSSL
+		ssl = ssl_promotion(0, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
+		if (! ssl)
+		{
+			sock_close(sockctrl, NULL, 0);
+			return (SOCKET)-1;
+		}
+#else
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "No TLS support");
+		sock_close(sockctrl, NULL, 0);
+		return (SOCKET)-1;
+#endif
+	}
+
 	/* Get the numeric for of the name of the connecting host */
 	if (getnameinfo((struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST))
 	{
 		sock_geterror("getnameinfo()", errbuf, PCAP_ERRBUF_SIZE);
-		rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+		rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+		if (ssl)
+		{
+			// Finish using the SSL handle for the socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(ssl);
+		}
+#endif
 		sock_close(sockctrl, NULL, 0);
 		return (SOCKET)-1;
 	}
@@ -2703,7 +2886,15 @@
 	/* checks if the connecting host is among the ones allowed */
 	if (sock_check_hostlist((char *)hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0)
 	{
-		rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+		rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+		if (ssl)
+		{
+			// Finish using the SSL handle for the socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(ssl);
+		}
+#endif
 		sock_close(sockctrl, NULL, 0);
 		return (SOCKET)-1;
 	}
@@ -2711,10 +2902,18 @@
 	/*
 	 * Send authentication to the remote machine.
 	 */
-	if (rpcap_doauth(sockctrl, &protocol_version, auth, errbuf) == -1)
+	if (rpcap_doauth(sockctrl, ssl, &protocol_version, auth, errbuf) == -1)
 	{
 		/* Unrecoverable error. */
-		rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+		rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+		if (ssl)
+		{
+			// Finish using the SSL handle for the socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(ssl);
+		}
+#endif
 		sock_close(sockctrl, NULL, 0);
 		return (SOCKET)-3;
 	}
@@ -2751,19 +2950,33 @@
 	{
 		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
 		    errno, "malloc() failed");
-		rpcap_senderror(sockctrl, protocol_version, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+		rpcap_senderror(sockctrl, ssl, protocol_version, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+		if (ssl)
+		{
+			// Finish using the SSL handle for the socket.
+			// This must be done *before* the socket is closed.
+			ssl_finish(ssl);
+		}
+#endif
 		sock_close(sockctrl, NULL, 0);
 		return (SOCKET)-1;
 	}
 
 	memcpy(&temp->host, &from, fromlen);
 	temp->sockctrl = sockctrl;
+	temp->ssl = ssl;
 	temp->protocol_version = protocol_version;
 	temp->next = NULL;
 
 	return sockctrl;
 }
 
+SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf)
+{
+	return pcap_remoteact_accept_ex(address, port, hostlist, connectinghost, auth, 0, errbuf);
+}
+
 int pcap_remoteact_close(const char *host, char *errbuf)
 {
 	struct activehosts *temp, *prev;	/* temp var needed to scan the host list chain */
@@ -2782,7 +2995,7 @@
 	retval = getaddrinfo(host, "0", &hints, &addrinfo);
 	if (retval != 0)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval));
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval));
 		return -1;
 	}
 
@@ -2804,7 +3017,7 @@
 				 * Don't check for errors, since we're
 				 * just cleaning up.
 				 */
-				if (sock_send(temp->sockctrl,
+				if (sock_send(temp->sockctrl, temp->ssl,
 				    (char *)&header,
 				    sizeof(struct rpcap_header), errbuf,
 				    PCAP_ERRBUF_SIZE) < 0)
@@ -2813,12 +3026,32 @@
 					 * Let that error be the one we
 					 * report.
 					 */
+#ifdef HAVE_OPENSSL
+					if (temp->ssl)
+					{
+						// Finish using the SSL handle
+						// for the socket.
+						// This must be done *before*
+						// the socket is closed.
+						ssl_finish(temp->ssl);
+					}
+#endif
 					(void)sock_close(temp->sockctrl, NULL,
 					   0);
 					status = -1;
 				}
 				else
 				{
+#ifdef HAVE_OPENSSL
+					if (temp->ssl)
+					{
+						// Finish using the SSL handle
+						// for the socket.
+						// This must be done *before*
+						// the socket is closed.
+						ssl_finish(temp->ssl);
+					}
+#endif
 					if (sock_close(temp->sockctrl, errbuf,
 					   PCAP_ERRBUF_SIZE) == -1)
 						status = -1;
@@ -2855,12 +3088,22 @@
 	/* To avoid inconsistencies in the number of sock_init() */
 	sock_cleanup();
 
-	pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known");
+	snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known");
 	return -1;
 }
 
 void pcap_remoteact_cleanup(void)
 {
+#	ifdef HAVE_OPENSSL
+	if (ssl_main)
+	{
+		// Finish using the SSL handle for the main active socket.
+		// This must be done *before* the socket is closed.
+		ssl_finish(ssl_main);
+		ssl_main = NULL;
+	}
+#	endif
+
 	/* Very dirty, but it works */
 	if (sockmain)
 	{
@@ -2869,7 +3112,6 @@
 		/* To avoid inconsistencies in the number of sock_init() */
 		sock_cleanup();
 	}
-
 }
 
 int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf)
@@ -2901,7 +3143,7 @@
 
 		if ((size < 0) || (len >= (size_t)size))
 		{
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep "
+			snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep "
 				"the hostnames for all the active connections");
 			return -1;
 		}
@@ -2919,11 +3161,11 @@
 /*
  * Receive the header of a message.
  */
-static int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char *errbuf)
+static int rpcap_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *header, char *errbuf)
 {
 	int nrecv;
 
-	nrecv = sock_recv(sock, (char *) header, sizeof(struct rpcap_header),
+	nrecv = sock_recv(sock, ssl, (char *) header, sizeof(struct rpcap_header),
 	    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
 	    PCAP_ERRBUF_SIZE);
 	if (nrecv == -1)
@@ -2939,7 +3181,7 @@
  * Make sure the protocol version of a received message is what we were
  * expecting.
  */
-static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_header *header, char *errbuf)
+static int rpcap_check_msg_ver(SOCKET sock, SSL *ssl, uint8 expected_ver, struct rpcap_header *header, char *errbuf)
 {
 	/*
 	 * Did the server specify the version we negotiated?
@@ -2949,7 +3191,7 @@
 		/*
 		 * Discard the rest of the message.
 		 */
-		if (rpcap_discard(sock, header->plen, errbuf) == -1)
+		if (rpcap_discard(sock, ssl, header->plen, errbuf) == -1)
 			return -1;
 
 		/*
@@ -2957,7 +3199,7 @@
 		 */
 		if (errbuf != NULL)
 		{
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "Server sent us a message with version %u when we were expecting %u",
 			    header->ver, expected_ver);
 		}
@@ -2970,7 +3212,7 @@
  * Check the message type of a received message, which should either be
  * the expected message type or RPCAP_MSG_ERROR.
  */
-static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf)
+static int rpcap_check_msg_type(SOCKET sock, SSL *ssl, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf)
 {
 	const char *request_type_string;
 	const char *msg_type_string;
@@ -2985,7 +3227,7 @@
 		 * Hand that error back to our caller.
 		 */
 		*errcode = ntohs(header->value);
-		rpcap_msg_err(sock, header->plen, errbuf);
+		rpcap_msg_err(sock, ssl, header->plen, errbuf);
 		return -1;
 	}
 
@@ -3004,7 +3246,7 @@
 		/*
 		 * Discard the rest of the message.
 		 */
-		if (rpcap_discard(sock, header->plen, errbuf) == -1)
+		if (rpcap_discard(sock, ssl, header->plen, errbuf) == -1)
 			return -1;
 
 		/*
@@ -3017,17 +3259,17 @@
 			if (request_type_string == NULL)
 			{
 				/* This should not happen. */
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "rpcap_check_msg_type called for request message with type %u",
 				    request_type);
 				return -1;
 			}
 			if (msg_type_string != NULL)
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "%s message received in response to a %s message",
 				    msg_type_string, request_type_string);
 			else
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "Message of unknown type %u message received in response to a %s request",
 				    header->type, request_type_string);
 		}
@@ -3040,11 +3282,11 @@
 /*
  * Receive and process the header of a message.
  */
-static int rpcap_process_msg_header(SOCKET sock, uint8 expected_ver, uint8 request_type, struct rpcap_header *header, char *errbuf)
+static int rpcap_process_msg_header(SOCKET sock, SSL *ssl, uint8 expected_ver, uint8 request_type, struct rpcap_header *header, char *errbuf)
 {
 	uint16 errcode;
 
-	if (rpcap_recv_msg_header(sock, header, errbuf) == -1)
+	if (rpcap_recv_msg_header(sock, ssl, header, errbuf) == -1)
 	{
 		/* Network error. */
 		return -1;
@@ -3053,13 +3295,13 @@
 	/*
 	 * Did the server specify the version we negotiated?
 	 */
-	if (rpcap_check_msg_ver(sock, expected_ver, header, errbuf) == -1)
+	if (rpcap_check_msg_ver(sock, ssl, expected_ver, header, errbuf) == -1)
 		return -1;
 
 	/*
 	 * Check the message type.
 	 */
-	return rpcap_check_msg_type(sock, request_type, header,
+	return rpcap_check_msg_type(sock, ssl, request_type, header,
 	    &errcode, errbuf);
 }
 
@@ -3072,17 +3314,17 @@
  * Returns 0 on success, logs a message and returns -1 on a network
  * error.
  */
-static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, char *errbuf)
+static int rpcap_recv(SOCKET sock, SSL *ssl, void *buffer, size_t toread, uint32 *plen, char *errbuf)
 {
 	int nread;
 
 	if (toread > *plen)
 	{
 		/* The server sent us a bad message */
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
 		return -1;
 	}
-	nread = sock_recv(sock, buffer, toread,
+	nread = sock_recv(sock, ssl, buffer, toread,
 	    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
 	if (nread == -1)
 	{
@@ -3095,7 +3337,7 @@
 /*
  * This handles the RPCAP_MSG_ERROR message.
  */
-static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
+static void rpcap_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen, char *remote_errbuf)
 {
 	char errbuf[PCAP_ERRBUF_SIZE];
 
@@ -3105,12 +3347,12 @@
 		 * Message is too long; just read as much of it as we
 		 * can into the buffer provided, and discard the rest.
 		 */
-		if (sock_recv(sockctrl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
+		if (sock_recv(sockctrl, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
 		    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
 		    PCAP_ERRBUF_SIZE) == -1)
 		{
 			// Network error.
-			pcap_snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
+			snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
 			return;
 		}
 
@@ -3119,10 +3361,19 @@
 		 */
 		remote_errbuf[PCAP_ERRBUF_SIZE - 1] = '\0';
 
+#ifdef _WIN32
+		/*
+		 * If we're not in UTF-8 mode, convert it to the local
+		 * code page.
+		 */
+		if (!pcap_utf_8_mode)
+			utf_8_to_acp_truncated(remote_errbuf);
+#endif
+
 		/*
 		 * Throw away the rest.
 		 */
-		(void)rpcap_discard(sockctrl, plen - (PCAP_ERRBUF_SIZE - 1), remote_errbuf);
+		(void)rpcap_discard(sockctrl, ssl, plen - (PCAP_ERRBUF_SIZE - 1), remote_errbuf);
 	}
 	else if (plen == 0)
 	{
@@ -3131,12 +3382,12 @@
 	}
 	else
 	{
-		if (sock_recv(sockctrl, remote_errbuf, plen,
+		if (sock_recv(sockctrl, ssl, remote_errbuf, plen,
 		    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
 		    PCAP_ERRBUF_SIZE) == -1)
 		{
 			// Network error.
-			pcap_snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
+			snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
 			return;
 		}
 
@@ -3153,11 +3404,11 @@
  * Returns 0 on success, logs a message and returns -1 on a network
  * error.
  */
-static int rpcap_discard(SOCKET sock, uint32 len, char *errbuf)
+static int rpcap_discard(SOCKET sock, SSL *ssl, uint32 len, char *errbuf)
 {
 	if (len != 0)
 	{
-		if (sock_discard(sock, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
+		if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
 		{
 			// Network error.
 			return -1;
@@ -3170,7 +3421,7 @@
  * Read bytes into the pcap_t's buffer until we have the specified
  * number of bytes read or we get an error or interrupt indication.
  */
-static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size)
+static int rpcap_read_packet_msg(struct pcap_rpcap const *rp, pcap_t *p, size_t size)
 {
 	u_char *bp;
 	int cc;
@@ -3189,9 +3440,10 @@
 		 * We haven't read all of the packet header yet.
 		 * Read what remains, which could be all of it.
 		 */
-		bytes_read = sock_recv(sock, bp, size - cc,
+		bytes_read = sock_recv(rp->rmt_sockdata, rp->data_ssl, bp, size - cc,
 		    SOCK_RECEIVEALL_NO|SOCK_EOF_IS_ERROR, p->errbuf,
 		    PCAP_ERRBUF_SIZE);
+
 		if (bytes_read == -1)
 		{
 			/*
@@ -3220,7 +3472,7 @@
 			 * Update the read pointer and byte count, and
 			 * return an error indication.
 			 */
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "The server terminated the connection.");
 			return -1;
 		}
diff --git a/pcap-savefile.manfile.in b/pcap-savefile.manfile.in
index 748d7af..a7ae9af 100644
--- a/pcap-savefile.manfile.in
+++ b/pcap-savefile.manfile.in
@@ -17,7 +17,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP-SAVEFILE @MAN_FILE_FORMATS@ "8 March 2015"
+.TH PCAP-SAVEFILE @MAN_FILE_FORMATS@ "24 April 2020"
 .SH NAME
 pcap-savefile \- libpcap savefile format
 .SH DESCRIPTION
@@ -51,6 +51,8 @@
 .TE
 .RE
 .PP
+The per-file header length is 24 octets.
+.PP
 All fields in the per-file header are in the byte order of the host
 writing the file.  Normally, the first field in the per-file header is a
 4-byte magic number, with the value 0xa1b2c3d4.  The magic number, when
@@ -117,6 +119,8 @@
 .TE
 .RE
 .PP
+The per-packet header length is 16 octets.
+.PP
 All fields in the per-packet header are in the byte order of the host
 writing the file.  The per-packet header begins with a time stamp giving
 the approximate time the packet was captured; the time stamp consists of
@@ -130,4 +134,4 @@
 will be equal if the number of bytes of packet data are less than or
 equal to the snapshot length.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap-septel.c b/pcap-septel.c
index 24cb47b..e917edd 100644
--- a/pcap-septel.c
+++ b/pcap-septel.c
@@ -17,7 +17,6 @@
 
 #include "pcap-int.h"
 
-#include <ctype.h>
 #include <netinet/in.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
@@ -32,7 +31,6 @@
 
 #include "pcap-septel.h"
 
-static int septel_setfilter(pcap_t *p, struct bpf_program *fp);
 static int septel_stats(pcap_t *p, struct pcap_stat *ps);
 static int septel_getnonblock(pcap_t *p);
 static int septel_setnonblock(pcap_t *p, int nonblock);
@@ -47,7 +45,7 @@
 /*
  *  Read at most max_packets from the capture queue and call the callback
  *  for each of them. Returns the number of packets handled, -1 if an
- *  error occured, or -2 if we were told to break out of the loop.
+ *  error occurred, or -2 if we were told to break out of the loop.
  */
 static int septel_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) {
 
@@ -126,7 +124,7 @@
         caplen = packet_len;
       }
       /* Run the packet filter if there is one. */
-      if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
+      if ((p->fcode.bf_insns == NULL) || pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
 
 
         /*  get a time stamp , consisting of :
@@ -171,7 +169,7 @@
 
 
 static int
-septel_inject(pcap_t *handle, const void *buf _U_, size_t size _U_)
+septel_inject(pcap_t *handle, const void *buf _U_, int size _U_)
 {
   pcap_strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards",
           PCAP_ERRBUF_SIZE);
@@ -209,7 +207,7 @@
 
   handle->read_op = septel_read;
   handle->inject_op = septel_inject;
-  handle->setfilter_op = septel_setfilter;
+  handle->setfilter_op = install_bpf_program;
   handle->set_datalink_op = NULL; /* can't change data link type */
   handle->getnonblock_op = septel_getnonblock;
   handle->setnonblock_op = septel_setnonblock;
@@ -235,7 +233,7 @@
 	/* OK, it's probably ours. */
 	*is_ours = 1;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_septel));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_septel);
 	if (p == NULL)
 		return NULL;
 
@@ -276,28 +274,6 @@
 
 
 /*
- * Installs the given bpf filter program in the given pcap structure.  There is
- * no attempt to store the filter in kernel memory as that is not supported
- * with Septel cards.
- */
-static int septel_setfilter(pcap_t *p, struct bpf_program *fp) {
-  if (!p)
-    return -1;
-  if (!fp) {
-    strncpy(p->errbuf, "setfilter: No filter specified",
-	    sizeof(p->errbuf));
-    return -1;
-  }
-
-  /* Make our private copy of the filter */
-
-  if (install_bpf_program(p, fp) < 0)
-    return -1;
-
-  return (0);
-}
-
-/*
  * We don't support non-blocking mode.  I'm not sure what we'd
  * do to support it and, given that we don't support select()/
  * poll()/epoll_wait()/kevent() etc., it probably doesn't
@@ -338,7 +314,7 @@
 pcap_t *
 pcap_create_interface(const char *device, char *errbuf)
 {
-  pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+  snprintf(errbuf, PCAP_ERRBUF_SIZE,
                 "This version of libpcap only supports Septel cards");
   return (NULL);
 }
diff --git a/pcap-sita.c b/pcap-sita.c
index b9dda9c..c53f323 100644
--- a/pcap-sita.c
+++ b/pcap-sita.c
@@ -72,6 +72,14 @@
 	int			len;		/* the current size of the inbound message */
 } unit_t;
 
+/*
+ * Private data.
+ * Currently contains nothing.
+ */
+struct pcap_sita {
+	int	dummy;
+};
+
 static unit_t		units[MAX_CHASSIS+1][MAX_GEOSLOT+1];	/* we use indexes of 1 through 8, but we reserve/waste index 0 */
 static fd_set		readfds;				/* a place to store the file descriptors for the connections to the IOPs */
 static int		max_fs;
@@ -266,7 +274,7 @@
 
 	empty_unit_table();
 	if ((fp = fopen("/etc/hosts", "r")) == NULL) {										/* try to open the hosts file and if it fails */
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading.");	/* return the nohostsfile error response */
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading.");	/* return the nohostsfile error response */
 		return -1;
 	}
 	while (fgets(buf, MAX_LINE_SIZE-1, fp)) {			/* while looping over the file */
@@ -289,15 +297,15 @@
 		geoslot = *(ptr2 + 5) - '0';					/* and geo-slot number */
 		if (chassis < 1 || chassis > MAX_CHASSIS ||
 			geoslot < 1 || geoslot > MAX_GEOSLOT) {		/* if the chassis and/or slot numbers appear to be bad... */
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'.");	/* warn the user */
+			snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'.");	/* warn the user */
 			continue;																	/* and ignore the entry */
 		}
-		if ((ptr2 = (char *)malloc(strlen(ptr) + 1)) == NULL) {
+		ptr2 = strdup(ptr);					/* copy the IP address into our malloc'ed memory */
+		if (ptr2 == NULL) {
 			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
 			    errno, "malloc");
 			continue;
 		}
-		strcpy(ptr2, ptr);								/* copy the IP address into our malloc'ed memory */
 		u = &units[chassis][geoslot];
 		u->ip = ptr2;									/* and remember the whole shebang */
 		u->chassis = chassis;
@@ -407,19 +415,18 @@
 
 static void nonUnified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u) {
 
-	pcap_snprintf(buf, bufsize, "%s_%d_%d", proto, u->chassis, u->geoslot);
+	snprintf(buf, bufsize, "%s_%d_%d", proto, u->chassis, u->geoslot);
 }
 
 static void unified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u, int IOPportnum) {
 	int			portnum;
 
 	portnum = ((u->chassis - 1) * 64) + ((u->geoslot - 1) * 8) + IOPportnum + 1;
-	pcap_snprintf(buf, bufsize, "%s_%d", proto, portnum);
+	snprintf(buf, bufsize, "%s_%d", proto, portnum);
 }
 
 static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 iftype) {
 	iface_t		*iface_ptr, *iface;
-	char		*name;
 	char		buf[32];
 	char		*proto;
 	char		*port;
@@ -434,15 +441,12 @@
 
 	iface->iftype = iftype;					/* remember the interface type of this interface */
 
-	name = malloc(strlen(IOPname) + 1);		/* get memory for the IOP's name */
-        if (name == NULL) {    /* oops, we didn't get the memory requested     */
+	iface->IOPname = strdup(IOPnam);			/* copy it and stick it into the structure */
+        if (iface->IOPname == NULL) {    /* oops, we didn't get the memory requested     */
                 fprintf(stderr, "Error...couldn't allocate memory for IOPname...value of errno is: %d\n", errno);
                 return NULL;
         }
 
-	strcpy(name, IOPname);					/* and copy it in */
-	iface->IOPname = name;					/* and stick it into the structure */
-
 	if (strncmp(IOPname, "lo", 2) == 0) {
 		IOPportnum = atoi(&IOPname[2]);
 		switch (iftype) {
@@ -478,15 +482,12 @@
 		return NULL;
 	}
 
-	name = malloc(strlen(buf) + 1);			/* get memory for that name */
-        if (name == NULL) {    /* oops, we didn't get the memory requested     */
+	iface->name = strdup(buf);					/* make a copy and stick it into the structure */
+        if (iface->name == NULL) {    /* oops, we didn't get the memory requested     */
                 fprintf(stderr, "Error...couldn't allocate memory for IOP port name...value of errno is: %d\n", errno);
                 return NULL;
         }
 
-	strcpy(name, buf);						/* and copy it in */
-	iface->name = name;						/* and stick it into the structure */
-
 	if (u->iface == 0) {					/* if this is the first name */
 		u->iface = iface;					/* stick this entry at the head of the list */
 	} else {
@@ -703,7 +704,7 @@
 				prev_iff = iff;
 
 				newname = translate_IOP_to_pcap_name(u, iff->name, interfaceType);		/* add a translation entry and get a point to the mangled name */
-				bigger_buffer = realloc(iff->name, strlen(newname) + 1));
+				bigger_buffer = realloc(iff->name, strlen(newname) + 1);
 				if (bigger_buffer == NULL) {	/* we now re-write the name stored in the interface list */
 					pcap_fmt_errmsg_for_errno(errbuf,
 					    PCAP_ERRBUF_SIZE, errno, "realloc");
@@ -754,9 +755,9 @@
 
 		memcpy(&working_set, &readfds, sizeof(readfds));				/* otherwise, we still have to listen for more stuff, till we timeout */
 		retval = select(max_fs + 1, &working_set, NULL, NULL, &tv);
-		if (retval == -1) {												/* an error occured !!!!! */
+		if (retval == -1) {												/* an error occurred !!!!! */
 			return;
-		} else if (retval == 0) {										/* timeout occured, so process what we've got sofar and return */
+		} else if (retval == 0) {										/* timeout occurred, so process what we've got sofar and return */
 			printf("timeout\n");
 			return;
 		} else {
@@ -883,7 +884,7 @@
 	//printf("acn_start_monitor() complete\n");				// fulko
 }
 
-static int pcap_inject_acn(pcap_t *p, const void *buf _U_, size_t size _U_) {
+static int pcap_inject_acn(pcap_t *p, const void *buf _U_, int size _U_) {
 	pcap_strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters",
 	    PCAP_ERRBUF_SIZE);
 	return (-1);
@@ -915,12 +916,6 @@
 	return 0;
 }
 
-static int pcap_setdirection_acn(pcap_t *handle, pcap_direction_t d) {
-	pcap_snprintf(handle->errbuf, sizeof(handle->errbuf),
-	    "Setting direction is not supported on ACN adapters");
-	return -1;
-}
-
 static int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) {
 	struct		timeval tv;
 	int			retval, fd;
@@ -940,10 +935,10 @@
 	bp = handle->bp;
 	while (count) {
 		retval = select(fd + 1, &w_fds, NULL, NULL, &tv);
-		if (retval == -1) {											/* an error occured !!!!! */
+		if (retval == -1) {											/* an error occurred !!!!! */
 //			fprintf(stderr, "error during packet data read\n");
-			return -1;												/* but we need to return a good indication to prevent unneccessary popups */
-		} else if (retval == 0) {									/* timeout occured, so process what we've got sofar and return */
+			return -1;										/* but we need to return a good indication to prevent unnecessary popups */
+		} else if (retval == 0) {									/* timeout occurred, so process what we've got sofar and return */
 //			fprintf(stderr, "timeout during packet data read\n");
 			return -1;
 		} else {
@@ -997,7 +992,7 @@
 
 	handle->inject_op = pcap_inject_acn;
 	handle->setfilter_op = pcap_setfilter_acn;
-	handle->setdirection_op = pcap_setdirection_acn;
+	handle->setdirection_op = NULL; /* Not implemented */
 	handle->set_datalink_op = NULL;	/* can't change data link type */
 	handle->getnonblock_op = pcap_getnonblock_fd;
 	handle->setnonblock_op = pcap_setnonblock_fd;
@@ -1046,7 +1041,7 @@
 pcap_t *pcap_create_interface(const char *device _U_, char *ebuf) {
 	pcap_t *p;
 
-	p = pcap_create_common(ebuf, 0);
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_sita);
 	if (p == NULL)
 		return (NULL);
 
diff --git a/pcap-sita.html b/pcap-sita.html
index 4a8fe1a..33f1e10 100644
--- a/pcap-sita.html
+++ b/pcap-sita.html
@@ -22,7 +22,7 @@
 <UL>
 	<STRONG>Note:</STRONG> This document is part of the libpcap Git and was derived from 'pcap.3' (circa Aug/07).
 	<P>
-	The ACN provides a customized/distributed version of this library that alows SMPs to
+	The ACN provides a customized/distributed version of this library that allows SMPs to
 	interact with the various IOPs within the site providing a standard mechanism
 	to capture LAN and WAN message traffic.
 	<P>
@@ -31,7 +31,7 @@
 			<TR>
 				<TH VALIGN=TOP>SMP</TH>
 				<TD VALIGN=TOP>The Supervisory Management Processor where Wireshark (or equivalent)
-								runs in conjuction with a libpcap front-end.</TD>
+								runs in conjunction with a libpcap front-end.</TD>
 			</TR>
 			<TR>
 				<TH VALIGN=TOP>IOP</TH>
@@ -43,7 +43,7 @@
 	<P>
 	Each IOP will be capable of supporting multiple connections from an SMP
 	enabling monitoring of more than one interface at a time, each through
-	its own seperate connection.  The IOP is responsible to ensure and report
+	its own separate connection.  The IOP is responsible to ensure and report
 	an error if any attempt is made to monitor the same interface more than once.
 	<P>
 	There are three applications that will be supported by the ACN version of libpcap.
@@ -121,8 +121,8 @@
 		<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
 			<TD>
 			After any required processing is complete, the IOP will return a
-			null terminated string containing an error message if one occured.
-			If no error occured, a empty string is still returned.
+			null terminated string containing an error message if one occurred.
+			If no error occurred, a empty string is still returned.
 			Errors are:
 			<UL>
 			<LI>"Interface (xxx) does not exist."
@@ -298,7 +298,7 @@
 			<TD>
 			The SMP reads only the next packet from the reverse channel of the connection
 			between the SMP and the IOP that provides the captured data (via calling pcap_dispatch()
-			with a count of 1) and returns seperate pointers to both the
+			with a count of 1) and returns separate pointers to both the
 			packet header and packet data by invoking an internal callback.
 			</TD>
 		</TR>
@@ -322,7 +322,7 @@
 		<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
 			<TD>
 			The IOP returns a null terminated error string if it failed to accept the filter.
-			If no error occured, then a NULL terminated empty string is returned instead.
+			If no error occurred, then a NULL terminated empty string is returned instead.
 			Errors are:
 			<UL>
 			<LI>"Invalid BPF."
@@ -362,7 +362,7 @@
 		<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
 			<TD>
 			The SMP closes the file descriptor, and if the descriptor is that of
-			the comminucation session with an IOP, it too is terminated.
+			the communication session with an IOP, it too is terminated.
 			</TD>
 		</TR>
 		<TR><TH VALIGN=TOP NOWRAP>IOP</TH>
@@ -370,7 +370,7 @@
 			If the IOP detects that its communication session with an SMP
 			has closed, it will terminate any monitoring in progress,
 			release any resources and close its end of the session.
-			It will not maintain persistance of any information or prior mode of operation.
+			It will not maintain persistence of any information or prior mode of operation.
 			</TD>
 		</TR>
 	</TABLE></TD></TR>
@@ -442,7 +442,7 @@
 			<TD VALIGN=TOP ALIGN=CENTER NOWRAP>IOP -> SMP</TD>
 			<TD VALIGN=TOP>The IOP returns a list of sequences of information as
 				defined by the return parameter of this function call (as shown in the following table).
-				Elements are specified by providing an unsigned byte preceeding the actual data that contains length information.
+				Elements are specified by providing an unsigned byte preceding the actual data that contains length information.
 				<P>
 				<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
 				<TR>
@@ -635,7 +635,7 @@
 						<TD VALIGN=TOP>BPF program</TD>
 						<TD VALIGN=TOP ALIGN=CENTER>'n'</TD>
 						<TD VALIGN=TOP>8 bytes of each command (repeated 'n' times).<BR>
-								 	Each command consists of that C-style structure which contains:
+									Each command consists of that C-style structure which contains:
 							<P>
 							<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
 								<TR>
@@ -719,7 +719,7 @@
 					<TR>
 						<TD VALIGN=TOP>ps_ifdrop</TD>
 						<TD VALIGN=TOP ALIGN=CENTER>4</TD>
-						<TD VALIGN=TOP>The number of packets dropped by the network inteface
+						<TD VALIGN=TOP>The number of packets dropped by the network interface
 							(regardless of whether they would have passed the input filter).</TD>
 					</TR>
 				</TABLE>
@@ -839,7 +839,7 @@
 	<UL>
 	PCAP, Wireshark and Tcpdump enhancements have been added to the ACN to support
 	monitoring of its ports, however each of these facilities were focused on capturing
-	and displaying traffic from LAN interfaces.  The SITA extentions to these facilities
+	and displaying traffic from LAN interfaces.  The SITA extensions to these facilities
 	are used to also provide the ability to capture, filter, and display information from
 	an ACN's WAN ports.
 	<P>
@@ -849,7 +849,7 @@
 	<P>
 	<UL TYPE=DISC>
 		<LI>For Ethernet (like) devices, the packet format is unchanged from the standard Pcap format.
-		<LI>For WAN devices, the packet contains a 5 byte header that preceeds the actual captured data
+		<LI>For WAN devices, the packet contains a 5 byte header that precedes the actual captured data
 			described by the following table:
 	</UL>
 	<P>
diff --git a/pcap-snf.c b/pcap-snf.c
index 50d92cd..a9162eb 100644
--- a/pcap-snf.c
+++ b/pcap-snf.c
@@ -10,7 +10,6 @@
 #include <string.h>
 #include <errno.h>
 
-#include <ctype.h>
 #ifndef _WIN32
 #include <netinet/in.h>
 #include <sys/mman.h>
@@ -177,7 +176,7 @@
 			caplen = p->snapshot;
 
 		if ((p->fcode.bf_insns == NULL) ||
-		     bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) {
+		     pcap_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) {
 			hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision);
 			hdr.caplen = caplen;
 			hdr.len = req.length;
@@ -194,26 +193,7 @@
 }
 
 static int
-snf_setfilter(pcap_t *p, struct bpf_program *fp)
-{
-	if (!p)
-		return -1;
-	if (!fp) {
-		strncpy(p->errbuf, "setfilter: No filter specified",
-			sizeof(p->errbuf));
-		return -1;
-	}
-
-	/* Make our private copy of the filter */
-
-	if (install_bpf_program(p, fp) < 0)
-		return -1;
-
-	return (0);
-}
-
-static int
-snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
+snf_inject(pcap_t *p, const void *buf _U_, int size _U_)
 {
 #ifdef SNF_HAVE_INJECT_API
 	struct pcap_snf *ps = p->priv;
@@ -253,7 +233,7 @@
 	int flags = -1, ring_id = -1;
 
 	if (device == NULL) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
 		return -1;
 	}
 
@@ -327,7 +307,7 @@
 	p->linktype = DLT_EN10MB;
 	p->read_op = snf_read;
 	p->inject_op = snf_inject;
-	p->setfilter_op = snf_setfilter;
+	p->setfilter_op = install_bpf_program;
 	p->setdirection_op = NULL; /* Not implemented.*/
 	p->set_datalink_op = snf_set_datalink;
 	p->getnonblock_op = snf_getnonblock;
@@ -355,7 +335,7 @@
 	const char *nr = NULL;
 
 	if (snf_init(SNF_VERSION_API)) {
-		(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "snf_getifaddrs: snf_init failed");
 		return (-1);
 	}
@@ -370,7 +350,7 @@
 		errno = 0;
 		merge = strtol(nr, NULL, 0);
 		if (errno) {
-			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				"snf_getifaddrs: SNF_FLAGS is not a valid number");
 			return (-1);
 		}
@@ -408,7 +388,7 @@
 		 * entry for the device, if they're not already in the
 		 * list of IP addresses for the device?
  		 */
-		(void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d",
+		(void)snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d",
 			merge ? "Merge Bitmask Port " : "",
 			merge ? 1 << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum);
 		/*
@@ -484,8 +464,8 @@
 		/*
 		 * Add a new entry with all ports bitmask
 		 */
-		(void)pcap_snprintf(name,MAX_DESC_LENGTH,"snf%d",allports);
-		(void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d",
+		(void)snprintf(name,MAX_DESC_LENGTH,"snf%d",allports);
+		(void)snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d",
 			allports);
 		/*
 		 * XXX - is there any notion of "up" and "running" that
@@ -560,7 +540,7 @@
 	/* OK, it's probably ours. */
 	*is_ours = 1;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_snf));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_snf);
 	if (p == NULL)
 		return NULL;
 	ps = p->priv;
@@ -568,7 +548,6 @@
 	/*
 	 * We support microsecond and nanosecond time stamps.
 	 */
-	p->tstamp_precision_count = 2;
 	p->tstamp_precision_list = malloc(2 * sizeof(u_int));
 	if (p->tstamp_precision_list == NULL) {
 		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno,
@@ -578,6 +557,7 @@
 	}
 	p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
 	p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
+	p->tstamp_precision_count = 2;
 
 	p->activate_op = snf_activate;
 	ps->snf_boardnum = boardnum;
@@ -605,7 +585,7 @@
 pcap_t *
 pcap_create_interface(const char *device, char *errbuf)
 {
-	pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(errbuf, PCAP_ERRBUF_SIZE,
 	    "This version of libpcap only supports SNF cards");
 	return NULL;
 }
diff --git a/pcap-snit.c b/pcap-snit.c
index 9c6fbd4..ca6222c 100644
--- a/pcap-snit.c
+++ b/pcap-snit.c
@@ -53,7 +53,6 @@
 #include <netinet/tcp.h>
 #include <netinet/tcpip.h>
 
-#include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
@@ -190,7 +189,7 @@
 		if (caplen > p->snapshot)
 			caplen = p->snapshot;
 
-		if (bpf_filter(p->fcode.bf_insns, cp, nlp->nh_pktlen, caplen)) {
+		if (pcap_filter(p->fcode.bf_insns, cp, nlp->nh_pktlen, caplen)) {
 			struct pcap_pkthdr h;
 			h.ts = ntp->nh_timestamp;
 			h.len = nlp->nh_pktlen;
@@ -208,7 +207,7 @@
 }
 
 static int
-pcap_inject_snit(pcap_t *p, const void *buf, size_t size)
+pcap_inject_snit(pcap_t *p, const void *buf, int size)
 {
 	struct strbuf ctl, data;
 
@@ -460,7 +459,7 @@
 {
 	pcap_t *p;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_snit));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_snit);
 	if (p == NULL)
 		return (NULL);
 
diff --git a/pcap-snoop.c b/pcap-snoop.c
index a598bae..2f44b1d 100644
--- a/pcap-snoop.c
+++ b/pcap-snoop.c
@@ -126,7 +126,7 @@
 	}
 
 	if (p->fcode.bf_insns == NULL ||
-	    bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) {
+	    pcap_filter(p->fcode.bf_insns, cp, datalen, caplen)) {
 		struct pcap_pkthdr h;
 		++psn->stat.ps_recv;
 		h.ts.tv_sec = sh->snoop_timestamp.tv_sec;
@@ -140,7 +140,7 @@
 }
 
 static int
-pcap_inject_snoop(pcap_t *p, const void *buf, size_t size)
+pcap_inject_snoop(pcap_t *p, const void *buf, int size)
 {
 	int ret;
 
@@ -310,7 +310,7 @@
 		p->linktype = DLT_NULL;
 		ll_hdrlen = 4;
 	} else {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "snoop: unknown physical layer type");
 		goto bad;
 	}
@@ -421,7 +421,7 @@
 {
 	pcap_t *p;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_snoop));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_snoop);
 	if (p == NULL)
 		return (NULL);
 
diff --git a/pcap-tc.c b/pcap-tc.c
index 65fb0e2..9902633 100644
--- a/pcap-tc.c
+++ b/pcap-tc.c
@@ -126,7 +126,6 @@
 static int TcInject(pcap_t *p, const void *buf, int size);
 static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
 static int TcStats(pcap_t *p, struct pcap_stat *ps);
-static int TcSetFilter(pcap_t *p, struct bpf_program *fp);
 #ifdef _WIN32
 static struct pcap_stat *TcStatsEx(pcap_t *p, int *pcap_stat_size);
 static int TcSetBuff(pcap_t *p, int dim);
@@ -253,58 +252,6 @@
 #pragma pack(pop)
 
 #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 airpcap.dll from the application folder).
-// This solves the DLL Hijacking issue discovered in August 2010
-// http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html
-//
-HMODULE LoadLibrarySafe(LPCTSTR lpFileName)
-{
-  TCHAR path[MAX_PATH];
-  TCHAR fullFileName[MAX_PATH];
-  UINT res;
-  HMODULE hModule = NULL;
-  do
-  {
-	res = GetSystemDirectory(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 + _tcslen(lpFileName) + 1 < MAX_PATH)
-	{
-		memcpy(fullFileName, path, res * sizeof(TCHAR));
-		fullFileName[res] = _T('\\');
-		memcpy(&fullFileName[res + 1], lpFileName, (_tcslen(lpFileName) + 1) * sizeof(TCHAR));
-
-		hModule = LoadLibrary(fullFileName);
-	}
-	else
-	{
-		SetLastError(ERROR_INSUFFICIENT_BUFFER);
-	}
-
-  }while(FALSE);
-
-  return hModule;
-}
-
 /*
  * NOTE: this function should be called by the pcap functions that can theoretically
  *       deal with the Tc library for the first time, namely listing the adapters and
@@ -341,34 +288,34 @@
 
 		currentStatus = TC_API_CANNOT_LOAD;
 
-		g_TcFunctions.hTcApiDllHandle = LoadLibrarySafe("TcApi.dll");
+		g_TcFunctions.hTcApiDllHandle = pcap_load_code("TcApi.dll");
 		if (g_TcFunctions.hTcApiDllHandle == NULL)	break;
 
-		g_TcFunctions.QueryPortList					= (TcFcnQueryPortList)			GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList");
-		g_TcFunctions.FreePortList					= (TcFcnFreePortList)			GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcFreePortList");
+		g_TcFunctions.QueryPortList			= (TcFcnQueryPortList)			pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList");
+		g_TcFunctions.FreePortList			= (TcFcnFreePortList)			pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcFreePortList");
 
-		g_TcFunctions.StatusGetString				= (TcFcnStatusGetString)		GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString");
+		g_TcFunctions.StatusGetString			= (TcFcnStatusGetString)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString");
 
-		g_TcFunctions.PortGetName					= (TcFcnPortGetName)			GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetName");
-		g_TcFunctions.PortGetDescription			= (TcFcnPortGetDescription)		GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription");
+		g_TcFunctions.PortGetName			= (TcFcnPortGetName)			pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetName");
+		g_TcFunctions.PortGetDescription		= (TcFcnPortGetDescription)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription");
 
-		g_TcFunctions.InstanceOpenByName			= (TcFcnInstanceOpenByName)		GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName");
-		g_TcFunctions.InstanceClose					= (TcFcnInstanceClose)			GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose");
-		g_TcFunctions.InstanceSetFeature			= (TcFcnInstanceSetFeature)		GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature");
-		g_TcFunctions.InstanceQueryFeature			= (TcFcnInstanceQueryFeature)	GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature");
-		g_TcFunctions.InstanceReceivePackets		= (TcFcnInstanceReceivePackets)	GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets");
-		g_TcFunctions.InstanceGetReceiveWaitHandle	= (TcFcnInstanceGetReceiveWaitHandle)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle");
-		g_TcFunctions.InstanceTransmitPackets		= (TcFcnInstanceTransmitPackets)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets");
-		g_TcFunctions.InstanceQueryStatistics		= (TcFcnInstanceQueryStatistics)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics");
+		g_TcFunctions.InstanceOpenByName		= (TcFcnInstanceOpenByName)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName");
+		g_TcFunctions.InstanceClose			= (TcFcnInstanceClose)			pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose");
+		g_TcFunctions.InstanceSetFeature		= (TcFcnInstanceSetFeature)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature");
+		g_TcFunctions.InstanceQueryFeature		= (TcFcnInstanceQueryFeature)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature");
+		g_TcFunctions.InstanceReceivePackets		= (TcFcnInstanceReceivePackets)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets");
+		g_TcFunctions.InstanceGetReceiveWaitHandle	= (TcFcnInstanceGetReceiveWaitHandle)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle");
+		g_TcFunctions.InstanceTransmitPackets		= (TcFcnInstanceTransmitPackets)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets");
+		g_TcFunctions.InstanceQueryStatistics		= (TcFcnInstanceQueryStatistics)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics");
 
-		g_TcFunctions.PacketsBufferCreate			= (TcFcnPacketsBufferCreate)	GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate");
-		g_TcFunctions.PacketsBufferDestroy			= (TcFcnPacketsBufferDestroy)	GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy");
-		g_TcFunctions.PacketsBufferQueryNextPacket	= (TcFcnPacketsBufferQueryNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket");
-		g_TcFunctions.PacketsBufferCommitNextPacket	= (TcFcnPacketsBufferCommitNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket");
+		g_TcFunctions.PacketsBufferCreate		= (TcFcnPacketsBufferCreate)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate");
+		g_TcFunctions.PacketsBufferDestroy		= (TcFcnPacketsBufferDestroy)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy");
+		g_TcFunctions.PacketsBufferQueryNextPacket	= (TcFcnPacketsBufferQueryNextPacket)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket");
+		g_TcFunctions.PacketsBufferCommitNextPacket	= (TcFcnPacketsBufferCommitNextPacket)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket");
 
-		g_TcFunctions.StatisticsDestroy				= (TcFcnStatisticsDestroy)		GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy");
-		g_TcFunctions.StatisticsUpdate				= (TcFcnStatisticsUpdate)		GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate");
-		g_TcFunctions.StatisticsQueryValue			= (TcFcnStatisticsQueryValue)	GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue");
+		g_TcFunctions.StatisticsDestroy			= (TcFcnStatisticsDestroy)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy");
+		g_TcFunctions.StatisticsUpdate			= (TcFcnStatisticsUpdate)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate");
+		g_TcFunctions.StatisticsQueryValue		= (TcFcnStatisticsQueryValue)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue");
 
 		if (   g_TcFunctions.QueryPortList == NULL
 			|| g_TcFunctions.FreePortList == NULL
@@ -552,7 +499,7 @@
 
 	if (pt->PpiPacket == NULL)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory");
 		return PCAP_ERROR;
 	}
 
@@ -587,7 +534,7 @@
 	if (status != TC_SUCCESS)
 	{
 		/* Adapter detected but we are not able to open it. Return failure. */
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status));
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status));
 		return PCAP_ERROR;
 	}
 
@@ -619,7 +566,7 @@
 
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
 		goto bad;
 	}
 
@@ -658,12 +605,12 @@
 
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
 		goto bad;
 	}
 
 	p->read_op = TcRead;
-	p->setfilter_op = TcSetFilter;
+	p->setfilter_op = install_bpf_program;
 	p->setdirection_op = NULL;	/* Not implemented. */
 	p->set_datalink_op = TcSetDatalink;
 	p->getnonblock_op = TcGetNonBlock;
@@ -756,7 +703,7 @@
 	/* OK, it's probably ours. */
 	*is_ours = 1;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_tc));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_tc);
 	if (p == NULL)
 		return NULL;
 
@@ -791,14 +738,14 @@
 
 static int TcGetNonBlock(pcap_t *p)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Non-blocking mode isn't supported for TurboCap ports");
 	return -1;
 }
 
 static int TcSetNonBlock(pcap_t *p, int nonblock)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Non-blocking mode isn't supported for TurboCap ports");
 	return -1;
 }
@@ -840,7 +787,7 @@
 
 	if (size >= 0xFFFF)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k");
 		return -1;
 	}
 
@@ -848,7 +795,7 @@
 
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 		return -1;
 	}
 
@@ -868,12 +815,12 @@
 
 		if (status != TC_SUCCESS)
 		{
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 		}
 	}
 	else
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 	}
 
 	g_TcFunctions.PacketsBufferDestroy(buffer);
@@ -913,7 +860,7 @@
 		status = g_TcFunctions.InstanceReceivePackets(pt->TcInstance, &pt->TcPacketsBuffer);
 		if (status != TC_SUCCESS)
 		{
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 			return -1;
 		}
 	}
@@ -963,14 +910,14 @@
 
 		if (status != TC_SUCCESS)
 		{
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 			return -1;
 		}
 
 		/* No underlaying filtering system. We need to filter on our own */
 		if (p->fcode.bf_insns)
 		{
-			filterResult = bpf_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength);
+			filterResult = pcap_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength);
 
 			if (filterResult == 0)
 			{
@@ -1053,7 +1000,7 @@
 
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 		return -1;
 	}
 
@@ -1062,7 +1009,7 @@
 	status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 		return -1;
 	}
 	if (counter <= (ULONGLONG)0xFFFFFFFF)
@@ -1077,7 +1024,7 @@
 	status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 		return -1;
 	}
 	if (counter <= (ULONGLONG)0xFFFFFFFF)
@@ -1100,27 +1047,6 @@
 }
 
 
-/*
- * We filter at user level, since the kernel driver does't process the packets
- */
-static int
-TcSetFilter(pcap_t *p, struct bpf_program *fp)
-{
-	if(!fp)
-	{
-		strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf));
-		return -1;
-	}
-
-	/* Install a user level filter */
-	if (install_bpf_program(p, fp) < 0)
-	{
-		return -1;
-	}
-
-	return 0;
-}
-
 #ifdef _WIN32
 static struct pcap_stat *
 TcStatsEx(pcap_t *p, int *pcap_stat_size)
@@ -1136,7 +1062,7 @@
 
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 		return NULL;
 	}
 
@@ -1145,7 +1071,7 @@
 	status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 		return NULL;
 	}
 	if (counter <= (ULONGLONG)0xFFFFFFFF)
@@ -1160,7 +1086,7 @@
 	status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 		return NULL;
 	}
 	if (counter <= (ULONGLONG)0xFFFFFFFF)
@@ -1198,7 +1124,7 @@
 {
 	if (mode != MODE_CAPT)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode);
 		return -1;
 	}
 
@@ -1213,7 +1139,7 @@
 
 	if (size < 0)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0.");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0.");
 		return -1;
 	}
 
@@ -1221,7 +1147,7 @@
 
 	if (status != TC_SUCCESS)
 	{
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
 	}
 
 	return 0;
@@ -1238,7 +1164,7 @@
 static int
 TcOidGetRequest(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "An OID get request cannot be performed on a TurboCap device");
 	return PCAP_ERROR;
 }
@@ -1247,7 +1173,7 @@
 TcOidSetRequest(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
     size_t *lenp _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "An OID set request cannot be performed on a TurboCap device");
 	return PCAP_ERROR;
 }
@@ -1255,7 +1181,7 @@
 static u_int
 TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Packets cannot be bulk transmitted on a TurboCap device");
 	return 0;
 }
@@ -1263,7 +1189,7 @@
 static int
 TcSetUserBuffer(pcap_t *p, int size _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "The user buffer cannot be set on a TurboCap device");
 	return -1;
 }
@@ -1271,7 +1197,7 @@
 static int
 TcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Live packet dumping cannot be performed on a TurboCap device");
 	return -1;
 }
@@ -1279,7 +1205,7 @@
 static int
 TcLiveDumpEnded(pcap_t *p, int sync _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Live packet dumping cannot be performed on a TurboCap device");
 	return -1;
 }
diff --git a/pcap-tstamp.manmisc.in b/pcap-tstamp.manmisc.in
index 6437e80..eea8c1d 100644
--- a/pcap-tstamp.manmisc.in
+++ b/pcap-tstamp.manmisc.in
@@ -19,7 +19,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP-TSTAMP @MAN_MISC_INFO@ "8 March 2015"
+.TH PCAP-TSTAMP @MAN_MISC_INFO@ "14 July 2020"
 .SH NAME
 pcap-tstamp \- packet time stamps in libpcap
 .SH DESCRIPTION
@@ -58,7 +58,20 @@
 different CPU cores on a multi-core or multi-processor system might be
 running at different speeds, or might not have time counters all
 synchronized, so packets time-stamped by different cores might not have
-consistent time stamps.
+consistent time stamps;
+.IP
+some time sources, such as those that supply POSIX "seconds since the
+Epoch" time, do not count leap seconds, meaning that the seconds
+portion
+.RB ( tv_sec )
+of the time stamp might not be incremented for a leap second, so that
+the fraction-of-a-second part of the time stamp might roll over past
+zero but the second part would not change, or the clock might run
+slightly more slowly for a period before the leap second.
+.LP
+For these reasons, time differences between packet time stamps will not
+necessarily accurately reflect the time differences between the receipt
+or transmission times of the packets.
 .LP
 In addition, packets time-stamped by different cores might be
 time-stamped in one order and added to the queue of packets for libpcap
@@ -73,6 +86,9 @@
 synchronized with the host operating system's clock, so that, for
 example, the time stamp of a packet might not correspond to the time
 stamp of an event on the host triggered by the arrival of that packet.
+If they are synchronized with the host operating system's clock, some of
+the issues listed above with time stamps supplied by the host operating
+system may also apply to time stamps supplied by the capture device.
 .LP
 Depending on the capture device and the software on the host, libpcap
 might allow different types of time stamp to be used.  The
@@ -87,15 +103,15 @@
 offered for that capture device.  If the list is not empty, the
 .BR pcap_set_tstamp_type (3PCAP)
 routine can be used after a
-.B pcap_create()
+.BR pcap_create ()
 call and before a
-.B pcap_activate()
+.BR pcap_activate ()
 call to specify the type of time stamp to be used on the device.
 The time stamp types are listed here; the first value is the #define to
 use in code, the second value is the value returned by
-.B pcap_tstamp_type_val_to_name(3PCAP)
+.BR pcap_tstamp_type_val_to_name (3PCAP)
 and accepted by
-.BR pcap_tstamp_type_name_to_val(3PCAP) .
+.BR pcap_tstamp_type_name_to_val (3PCAP) .
 .RS 5
 .TP 5
 .BR PCAP_TSTAMP_HOST " - " host
@@ -110,9 +126,14 @@
 .TP 5
 .BR PCAP_TSTAMP_HOST_HIPREC " - " host_hiprec
 Time stamp provided by the host on which the capture is being done.
-This is a high-precision time stamp; it might or might not be
-synchronized with the host operating system's clock.  It might be more
-expensive to fetch than
+This is a high-precision time stamp, synchronized with the host
+operating system's clock. It might be more expensive to fetch than
+.BR PCAP_TSTAMP_HOST_LOWPREC .
+.TP 5
+.BR PCAP_TSTAMP_HOST_HIPREC_UNSYNCED " - " host_hiprec_unsynced
+Time stamp provided by the host on which the capture is being done.
+This is a high-precision time stamp, not synchronized with the host
+operating system's clock. It might be more expensive to fetch than
 .BR PCAP_TSTAMP_HOST_LOWPREC .
 .TP 5
 .BR PCAP_TSTAMP_ADAPTER " - " adapter
@@ -126,6 +147,18 @@
 the host operating system's clock.
 .RE
 .LP
+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.
+.LP
+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..
+.LP
 By default, when performing a live capture or reading from a savefile,
 time stamps are supplied as seconds since January 1, 1970, 00:00:00 UTC,
 and microseconds since that seconds value, even if higher-resolution
@@ -137,15 +170,15 @@
 The
 .BR pcap_set_tstamp_precision (3PCAP)
 routine can be used after a
-.B pcap_create()
+.BR pcap_create ()
 call and after a
-.B pcap_activate()
+.BR pcap_activate ()
 call to specify the resolution of the time stamps to get for the device.
 If the hardware or software cannot supply a higher-resolution time
 stamp, the
-.B pcap_set_tstamp_precision()
+.BR pcap_set_tstamp_precision ()
 call will fail, and the time stamps supplied after the
-.B pcap_activate()
+.BR pcap_activate ()
 call will have microsecond resolution.
 .LP
 When opening a savefile, the
@@ -165,4 +198,4 @@
 reading a savefile, this does not indicate the actual precision of time
 stamps in the file.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap-types.h b/pcap-types.h
index 9614f9f..7d0fe81 100644
--- a/pcap-types.h
+++ b/pcap-types.h
@@ -35,7 +35,6 @@
  * Get u_int defined, by hook or by crook.
  */
 #ifdef _WIN32
-
   /*
    * This defines u_int.
    */
diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c
index b306dca..3596428 100644
--- a/pcap-usb-linux.c
+++ b/pcap-usb-linux.c
@@ -41,11 +41,12 @@
 #include "pcap-usb-linux.h"
 #include "pcap/usb.h"
 
+#include "extract.h"
+
 #ifdef NEED_STRERROR_H
 #include "strerror.h"
 #endif
 
-#include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -136,7 +137,7 @@
 static int usb_read_linux(pcap_t *, int , pcap_handler , u_char *);
 static int usb_read_linux_bin(pcap_t *, int , pcap_handler , u_char *);
 static int usb_read_linux_mmap(pcap_t *, int , pcap_handler , u_char *);
-static int usb_inject_linux(pcap_t *, const void *, size_t);
+static int usb_inject_linux(pcap_t *, const void *, int);
 static int usb_setdirection_linux(pcap_t *, pcap_direction_t);
 static void usb_cleanup_linux_mmap(pcap_t *);
 
@@ -145,7 +146,7 @@
 {
 	struct utsname utsname;
 	char *version_component, *endp;
-	int major, minor, subminor;
+	long major, minor, subminor;
 
 	if (uname(&utsname) == 0) {
 		/*
@@ -230,7 +231,7 @@
 {
 	char dev_name[10];
 	char dev_descr[30];
-	pcap_snprintf(dev_name, 10, USB_IFACE"%d", n);
+	snprintf(dev_name, 10, USB_IFACE"%d", n);
 	/*
 	 * XXX - is there any notion of "up" and "running"?
 	 */
@@ -251,7 +252,7 @@
 		 * PCAP_IF_CONNECTION_STATUS_CONNECTED or
 		 * PCAP_IF_CONNECTION_STATUS_DISCONNECTED?
 		 */
-		pcap_snprintf(dev_descr, 30, "Raw USB traffic, bus number %d", n);
+		snprintf(dev_descr, 30, "Raw USB traffic, bus number %d", n);
 		if (add_dev(devlistp, dev_name, 0, dev_descr, err_str) == NULL)
 			return -1;
 	}
@@ -363,9 +364,9 @@
 				len = strlen(name);
 
 				/* if this file name does not end with a number it's not of our interest */
-				if ((len < 1) || !isdigit(name[--len]))
+				if ((len < 1) || !PCAP_ISDIGIT(name[--len]))
 					continue;
-				while (isdigit(name[--len]));
+				while (PCAP_ISDIGIT(name[--len]));
 				if (sscanf(&name[len+1], "%d", &n) != 1)
 					continue;
 
@@ -490,6 +491,10 @@
 #define USB_REQ_GET_DESCRIPTOR	6
 
 #define USB_DT_DEVICE		1
+#define USB_DT_CONFIG		2
+
+#define USB_DEVICE_DESCRIPTOR_SIZE	18
+#define USB_CONFIG_DESCRIPTOR_SIZE	9
 
 /* probe the descriptors of the devices attached to the bus */
 /* the descriptors will end up in the captured packet stream */
@@ -501,12 +506,14 @@
 	struct usbdevfs_ctrltransfer ctrl;
 	struct dirent* data;
 	int ret = 0;
-	char buf[sizeof("/dev/bus/usb/000/") + NAME_MAX];
+	char busdevpath[sizeof("/dev/bus/usb/000/") + NAME_MAX];
 	DIR* dir;
+	uint8_t descriptor[USB_DEVICE_DESCRIPTOR_SIZE];
+	uint8_t configdesc[USB_CONFIG_DESCRIPTOR_SIZE];
 
 	/* scan usb bus directories for device nodes */
-	pcap_snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d", bus);
-	dir = opendir(buf);
+	snprintf(busdevpath, sizeof(busdevpath), "/dev/bus/usb/%03d", bus);
+	dir = opendir(busdevpath);
 	if (!dir)
 		return;
 
@@ -517,9 +524,9 @@
 		if (name[0] == '.')
 			continue;
 
-		pcap_snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d/%s", bus, data->d_name);
+		snprintf(busdevpath, sizeof(busdevpath), "/dev/bus/usb/%03d/%s", bus, data->d_name);
 
-		fd = open(buf, O_RDWR);
+		fd = open(busdevpath, O_RDWR);
 		if (fd == -1)
 			continue;
 
@@ -532,19 +539,43 @@
 		ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
 		ctrl.wValue = USB_DT_DEVICE << 8;
 		ctrl.wIndex = 0;
- 		ctrl.wLength = sizeof(buf);
+ 		ctrl.wLength = sizeof(descriptor);
 #else
 		ctrl.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
 		ctrl.request = USB_REQ_GET_DESCRIPTOR;
 		ctrl.value = USB_DT_DEVICE << 8;
 		ctrl.index = 0;
- 		ctrl.length = sizeof(buf);
+ 		ctrl.length = sizeof(descriptor);
 #endif
-		ctrl.data = buf;
+		ctrl.data = descriptor;
 		ctrl.timeout = CTRL_TIMEOUT;
 
 		ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
 
+		/* Request CONFIGURATION descriptor alone to know wTotalLength */
+#ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
+		ctrl.wValue = USB_DT_CONFIG << 8;
+		ctrl.wLength = sizeof(configdesc);
+#else
+		ctrl.value = USB_DT_CONFIG << 8;
+		ctrl.length = sizeof(configdesc);
+#endif
+		ctrl.data = configdesc;
+		ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
+		if (ret >= 0) {
+			uint16_t wtotallength;
+			wtotallength = EXTRACT_LE_U_2(&configdesc[2]);
+#ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
+			ctrl.wLength = wtotallength;
+#else
+			ctrl.length = wtotallength;
+#endif
+			ctrl.data = malloc(wtotallength);
+			if (ctrl.data) {
+				ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
+				free(ctrl.data);
+			}
+		}
 		close(fd);
 	}
 	closedir(dir);
@@ -586,7 +617,7 @@
 	/* OK, it's probably ours. */
 	*is_ours = 1;
 
-	p = pcap_create_common(ebuf, sizeof (struct pcap_usb_linux));
+	p = PCAP_CREATE_COMMON(ebuf, struct pcap_usb_linux);
 	if (p == NULL)
 		return (NULL);
 
@@ -627,7 +658,7 @@
 	/*get usb bus index from device name */
 	if (sscanf(handle->opt.device, USB_IFACE"%d", &handlep->bus_index) != 1)
 	{
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			"Can't get USB bus index from %s", handle->opt.device);
 		return PCAP_ERROR;
 	}
@@ -638,7 +669,7 @@
 		 * We have binary-mode support.
 		 * Try to open the binary interface.
 		 */
-		pcap_snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handlep->bus_index);
+		snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handlep->bus_index);
 		handle->fd = open(full_path, O_RDONLY, 0);
 		if (handle->fd < 0)
 		{
@@ -731,7 +762,7 @@
 		 * We don't have binary mode support.
 		 * Try opening the text-mode device.
 		 */
-		pcap_snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handlep->bus_index);
+		snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handlep->bus_index);
 		handle->fd = open(full_path, O_RDONLY, 0);
 		if (handle->fd < 0)
 		{
@@ -741,7 +772,7 @@
 				 * Not found at the new location; try
 				 * the old location.
 				 */
-				pcap_snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%dt", handlep->bus_index);
+				snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%dt", handlep->bus_index);
 				handle->fd = open(full_path, O_RDONLY, 0);
 			}
 			if (handle->fd < 0) {
@@ -832,6 +863,7 @@
 	struct pcap_usb_linux *handlep = handle->priv;
 	unsigned timestamp;
 	int tag, cnt, ep_num, dev_addr, dummy, ret, urb_len, data_len;
+	ssize_t read_ret;
 	char etype, pipeid1, pipeid2, status[16], urb_tag, line[USB_LINE_LEN];
 	char *string = line;
 	u_char * rawdata = handle->buffer;
@@ -842,14 +874,14 @@
 
 	/* ignore interrupt system call errors */
 	do {
-		ret = read(handle->fd, line, USB_LINE_LEN - 1);
+		read_ret = read(handle->fd, line, USB_LINE_LEN - 1);
 		if (handle->break_loop)
 		{
 			handle->break_loop = 0;
 			return -2;
 		}
-	} while ((ret == -1) && (errno == EINTR));
-	if (ret < 0)
+	} while ((read_ret == -1) && (errno == EINTR));
+	if (read_ret < 0)
 	{
 		if (errno == EAGAIN)
 			return 0;	/* no data there */
@@ -861,15 +893,19 @@
 
 	/* read urb header; %n argument may increment return value, but it's
 	* not mandatory, so does not count on it*/
-	string[ret] = 0;
+	string[read_ret] = 0;
 	ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, &timestamp, &etype,
 		&pipeid1, &pipeid2, &dev_addr, &ep_num, status,
 		&cnt);
 	if (ret < 8)
 	{
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
-		    "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)",
-		    string, ret);
+		char string_truncated[181];
+
+		strncpy(string_truncated, string, sizeof(string_truncated));
+		string_truncated[sizeof(string_truncated) - 1] = 0;
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+			 "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)",
+			 string_truncated, ret);
 		return -1;
 	}
 	uhdr->id = tag;
@@ -886,7 +922,7 @@
 		return -1;
 	}
 	uhdr->ts_sec = pkth.ts.tv_sec;
-	uhdr->ts_usec = pkth.ts.tv_usec;
+	uhdr->ts_usec = (int32_t)pkth.ts.tv_usec;
 
 	/* parse endpoint information */
 	if (pipeid1 == 'C')
@@ -932,7 +968,7 @@
 		str5, &cnt);
 		if (ret < 5)
 		{
-			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 				"Can't parse USB bus message '%s', too few tokens (expected 5 got %d)",
 				string, ret);
 			return -1;
@@ -956,7 +992,7 @@
 	ret = sscanf(string, " %d%n", &urb_len, &cnt);
 	if (ret < 1)
 	{
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 		  "Can't parse urb length from '%s'", string);
 		return -1;
 	}
@@ -974,7 +1010,7 @@
 	/* check for data presence; data is present if and only if urb tag is '=' */
 	if (sscanf(string, " %c", &urb_tag) != 1)
 	{
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			"Can't parse urb tag from '%s'", string);
 		return -1;
 	}
@@ -1010,7 +1046,7 @@
 		pkth.caplen = (bpf_u_int32)handle->snapshot;
 
 	if (handle->fcode.bf_insns == NULL ||
-	    bpf_filter(handle->fcode.bf_insns, handle->buffer,
+	    pcap_filter(handle->fcode.bf_insns, handle->buffer,
 	      pkth.len, pkth.caplen)) {
 		handlep->packets_read++;
 		callback(user, &pkth, handle->buffer);
@@ -1020,9 +1056,9 @@
 }
 
 static int
-usb_inject_linux(pcap_t *handle, const void *buf _U_, size_t size _U_)
+usb_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_)
 {
-	pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 	    "Packet injection is not supported on USB devices");
 	return (-1);
 }
@@ -1031,13 +1067,14 @@
 usb_stats_linux(pcap_t *handle, struct pcap_stat *stats)
 {
 	struct pcap_usb_linux *handlep = handle->priv;
-	int dummy, ret, consumed, cnt;
+	int dummy, cnt;
+	ssize_t ret, consumed;
 	char string[USB_LINE_LEN];
 	char token[USB_LINE_LEN];
 	char * ptr = string;
 	int fd;
 
-	pcap_snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handlep->bus_index);
+	snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handlep->bus_index);
 	fd = open(string, O_RDONLY, 0);
 	if (fd < 0)
 	{
@@ -1047,7 +1084,7 @@
 			 * Not found at the new location; try the old
 			 * location.
 			 */
-			pcap_snprintf(string, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%ds", handlep->bus_index);
+			snprintf(string, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%ds", handlep->bus_index);
 			fd = open(string, O_RDONLY, 0);
 		}
 		if (fd < 0) {
@@ -1066,7 +1103,7 @@
 
 	if (ret < 0)
 	{
-		pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
 			"Can't read stats from fd %d ", fd);
 		return -1;
 	}
@@ -1108,6 +1145,10 @@
 static int
 usb_setdirection_linux(pcap_t *p, pcap_direction_t d)
 {
+	/*
+	 * It's guaranteed, at this point, that d is a valid
+	 * direction value.
+	 */
 	p->direction = d;
 	return 0;
 }
@@ -1208,11 +1249,11 @@
 		 */
 		pkth.len = sizeof(pcap_usb_header) + info.hdr->urb_len;
 	}
-	pkth.ts.tv_sec = info.hdr->ts_sec;
+	pkth.ts.tv_sec = (time_t)info.hdr->ts_sec;
 	pkth.ts.tv_usec = info.hdr->ts_usec;
 
 	if (handle->fcode.bf_insns == NULL ||
-	    bpf_filter(handle->fcode.bf_insns, handle->buffer,
+	    pcap_filter(handle->fcode.bf_insns, handle->buffer,
 	      pkth.len, pkth.caplen)) {
 		handlep->packets_read++;
 		callback(user, &pkth, handle->buffer);
@@ -1323,11 +1364,11 @@
 				pkth.len = sizeof(pcap_usb_header_mmapped) +
 				    (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len;
 			}
-			pkth.ts.tv_sec = hdr->ts_sec;
+			pkth.ts.tv_sec = (time_t)hdr->ts_sec;
 			pkth.ts.tv_usec = hdr->ts_usec;
 
 			if (handle->fcode.bf_insns == NULL ||
-			    bpf_filter(handle->fcode.bf_insns, (u_char*) hdr,
+			    pcap_filter(handle->fcode.bf_insns, (u_char*) hdr,
 			      pkth.len, pkth.caplen)) {
 				handlep->packets_read++;
 				callback(user, &pkth, (u_char*) hdr);
@@ -1335,7 +1376,7 @@
 			}
 		}
 
-		/* with max_packets specifying "unlimited" we stop afer the first chunk*/
+		/* with max_packets specifying "unlimited" we stop after the first chunk*/
 		if (PACKET_COUNT_IS_UNLIMITED(max_packets) || (packets == max_packets))
 			break;
 	}
diff --git a/pcap.3pcap.in b/pcap.3pcap.in
index 8010140..492c227 100644
--- a/pcap.3pcap.in
+++ b/pcap.3pcap.in
@@ -17,7 +17,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP 3PCAP "25 July 2018"
+.TH PCAP 3PCAP "9 September 2020"
 .SH NAME
 pcap \- Packet Capture library
 .SH SYNOPSIS
@@ -35,12 +35,69 @@
 through this mechanism.
 It also supports saving captured packets to a ``savefile'', and reading
 packets from a ``savefile''.
+.SS Initializing
+.BR pcap_init ()
+initializes the library.  It takes an argument giving options;
+currently, the options are:
+.TP
+.B PCAP_CHAR_ENC_LOCAL
+Treat all strings supplied as arguments, and return all strings to the
+caller, as being in the local character encoding.
+.TP
+.B PCAP_CHAR_ENC_UTF_8
+Treat all strings supplied as arguments, and return all strings to the
+caller, as being in UTF-8.
+.PP
+On UNIX-like systems, the local character encoding is assumed to be
+UTF-8, so no character encoding transformations are done.
+.PP
+On Windows, the local character encoding is the local ANSI code page.
+.PP
+If
+.BR pcap_init ()
+is called, the deprecated
+.BR pcap_lookupdev ()
+routine always fails, so it should not be used, and, on Windows,
+.BR pcap_create ()
+does not attempt to handle UTF-16LE strings.
+.PP
+If
+.BR pcap_init ()
+is not called, strings are treated as being in the local ANSI code page
+on Windows,
+.BR pcap_lookupdev ()
+will succeed if there is a device on which to capture, and
+.BR pcap_create ()
+makes an attempt to check whether the string passed as an argument is a
+UTF-16LE string - note that this attempt is unsafe, as it may run past
+the end of the string - to handle
+.BR pcap_lookupdev ()
+returning a UTF-16LE string. Programs that don't call
+.BR pcap_init ()
+should, on Windows, call
+.BR pcap_wsockinit ()
+to initialize Winsock; this is not necessary if
+.BR pcap_init ()
+is called, as
+.BR pcap_init ()
+will initialize Winsock itself on Windows.
+.TP
+.B Routines
+.RS
+.TP
+.BR pcap_init (3PCAP)
+initialize the library
+.RE
 .SS Opening a capture handle for reading
 To open a handle for a live capture, given the name of the network or
 other interface on which the capture should be done, call
 .BR pcap_create (),
 set the appropriate options on the handle, and then activate it with
 .BR pcap_activate ().
+If
+.BR pcap_activate ()
+fails, the handle should be closed with
+.BR pcap_close ().
 .PP
 To obtain a list of devices that can be opened for a live capture, call
 .BR pcap_findalldevs ();
@@ -121,7 +178,9 @@
 adapter could well be in promiscuous mode for some other reason.
 .IP
 For now, this doesn't work on the "any" device; if an argument of "any"
-or NULL is supplied, the setting of promiscuous mode is ignored.
+or
+.B NULL
+is supplied, the setting of promiscuous mode is ignored.
 .IP
 Promiscuous mode is set with
 .BR pcap_set_promisc ().
@@ -249,7 +308,7 @@
 that privilege to the user's
 .B defaultpriv
 key with the
-.B usermod (@MAN_ADMIN_COMMANDS@)
+.BR usermod (@MAN_ADMIN_COMMANDS@)
 command.
 .TP
 .B Under HP-UX with DLPI:
@@ -262,14 +321,11 @@
 .TP
 .B Under Linux:
 You must be root or the application capturing packets must be installed
-setuid to root (unless your distribution has a kernel
+setuid to root, unless your distribution has a kernel
 that supports capability bits such as CAP_NET_RAW and code to allow
 those capability bits to be given to particular accounts and to cause
 those bits to be set on a user's initial processes when they log in, in
-which case you  must have CAP_NET_RAW in order to capture and
-CAP_NET_ADMIN to enumerate network devices with, for example, the
-.B \-D
-flag).
+which case you must have CAP_NET_RAW in order to capture.
 .TP
 .B Under ULTRIX and Digital UNIX/Tru64 UNIX:
 Any user may capture network traffic.
@@ -320,6 +376,8 @@
 for Ethernet.  For example, the "any" device on Linux will have a
 link-layer header type of
 .B DLT_LINUX_SLL
+or
+.B DLT_LINUX_SLL2
 even if all devices on the system at the time the "any" device is opened
 have some other data link type, such as
 .B DLT_EN10MB
@@ -515,7 +573,11 @@
 get name for a link-layer header type
 .TP
 .BR pcap_datalink_val_to_description (3PCAP)
+.PD 0
+.TP
+.BR pcap_datalink_val_to_description_or_dlt (3PCAP)
 get description for a link-layer header type
+.PD
 .TP
 .BR pcap_datalink_name_to_val (3PCAP)
 get link-layer header type corresponding to a name
@@ -585,7 +647,9 @@
 .I const u_char
 to the first
 .B caplen
-bytes of the packet on success, and NULL on error.
+bytes of the packet on success, and
+.B NULL
+on error.
 .PP
 .BR pcap_next_ex ()
 is passed two pointer arguments, one of which points to a
@@ -648,7 +712,7 @@
 Not all handles have such a descriptor available;
 .BR pcap_get_selectable_fd ()
 will return
-.B PCAP_ERROR
+.B \-1
 if no such descriptor is available.  If no such
 descriptor is available, this may be because the device must be polled
 periodically for packets; in that case,
@@ -659,7 +723,9 @@
 routine returns, an attmept should be made to read packets from the
 device.  If
 .BR pcap_get_required_select_timeout ()
-returns NULL, no such timeout is available, and those routines cannot be
+returns
+.BR NULL ,
+no such timeout is available, and those routines cannot be
 used with the device.
 .PP
 In addition, for various
@@ -723,13 +789,12 @@
 .BR poll (2)
 .TP
 .BR pcap_get_required_select_timeout (3PCAP)
-if no descriptor usable with
+attempt to get a timeout required for using a
+.B pcap_t
+in calls such as
 .BR select (2)
 and
 .BR poll (2)
-is available for the
-.BR pcap_t ,
-attempt to get a timeout usable with those routines
 .RE
 .SS Filters
 In order to cause only certain packets to be returned when reading
@@ -893,8 +958,9 @@
 .BR pcap_inject ()
 or
 .BR pcap_sendpacket ().
-(The two routines exist for compatibility with both OpenBSD and WinPcap;
-they perform the same function, but have different return values.)
+(The two routines exist for compatibility with both OpenBSD and
+WinPcap/Npcap; they perform the same function, but have different return
+values.)
 .TP
 .B Routines
 .RS
@@ -958,8 +1024,12 @@
 script or some other configuration script to check whether the libpcap
 1.0 APIs are available and use them only if they are.
 .SH SEE ALSO
-autoconf(1), tcpdump(1), tcpslice(1), pcap-filter(@MAN_MISC_INFO@), pfconfig(8),
-usermod(@MAN_ADMIN_COMMANDS@)
+.BR autoconf (1),
+.BR tcpdump (1),
+.BR tcpslice (1),
+.BR pcap-filter (@MAN_MISC_INFO@),
+.BR pfconfig (8),
+.BR usermod (@MAN_ADMIN_COMMANDS@)
 .SH AUTHORS
 The original authors of libpcap are:
 .LP
@@ -978,5 +1048,5 @@
 .LP
 To report bugs and other problems, contribute patches, request a
 feature, provide generic feedback etc please see the file
-.I CONTRIBUTING
+.I CONTRIBUTING.md
 in the libpcap source tree root.
diff --git a/pcap.c b/pcap.c
index 5c8b51a..ed8570a 100644
--- a/pcap.c
+++ b/pcap.c
@@ -53,7 +53,6 @@
 #include <netinet/in.h>
 #endif /* _WIN32 */
 
-#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -62,11 +61,9 @@
 #endif
 #include <fcntl.h>
 #include <errno.h>
-#ifdef HAVE_LIMITS_H
 #include <limits.h>
-#else
-#define INT_MAX		2147483647
-#endif
+
+#include "diag-control.h"
 
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
@@ -96,7 +93,7 @@
 #include "pcap-tc.h"
 #endif /* HAVE_TC_API */
 
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
 #include "pcap-usb-linux.h"
 #endif
 
@@ -124,56 +121,201 @@
 #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,
-  DWORD dwReason,
-  LPVOID lpvReserved
+  HANDLE hinstDLL _U_,
+  DWORD dwReason _U_,
+  LPVOID lpvReserved _U_
 )
 {
 	return (TRUE);
 }
 
 /*
- * Start WinSock.
+ * 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)
 {
-	WORD wVersionRequested;
-	WSADATA wsaData;
-	static int err = -1;
-	static int done = 0;
-
-	if (done)
-		return (err);
-
-	wVersionRequested = MAKEWORD( 1, 1);
-	err = WSAStartup( wVersionRequested, &wsaData );
-	atexit ((void(*)(void))WSACleanup);
-	done = 1;
-
-	if ( err != 0 )
-		err = -1;
-	return (err);
+	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 (wsockinit());
+	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
@@ -191,12 +333,12 @@
 {
 	if (pcap->activated) {
 		/* A module probably forgot to set the function pointer */
-		(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+		(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)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+	(void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
 	    "This handle hasn't been activated yet");
 }
 
@@ -210,7 +352,7 @@
 }
 
 static int
-pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, size_t size _U_)
+pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, int size _U_)
 {
 	pcap_set_not_initialized_message(pcap);
 	/* this means 'not initialized' */
@@ -258,7 +400,7 @@
 }
 
 #ifdef _WIN32
-struct pcap_stat *
+static struct pcap_stat *
 pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_)
 {
 	pcap_set_not_initialized_message(pcap);
@@ -313,7 +455,8 @@
 }
 
 static u_int
-pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync)
+pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue _U_,
+    int sync _U_)
 {
 	pcap_set_not_initialized_message(pcap);
 	return (0);
@@ -534,7 +677,7 @@
 #ifdef PCAP_SUPPORT_BT_MONITOR
 	{ bt_monitor_findalldevs, bt_monitor_create },
 #endif
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
 	{ usb_findalldevs, usb_create },
 #endif
 #ifdef PCAP_SUPPORT_NETFILTER
@@ -549,6 +692,12 @@
 #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 }
 };
 
@@ -628,39 +777,26 @@
  *
  * 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 interface index
- * in the 29 bits below that.  (Yes, we assume u_int is 32 bits.)
+ * 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)
 {
-	const char *cp;
 	u_int n;
 
-	if (strcmp(dev->name, "any") == 0) {
-		/*
-		 * Give the "any" device an artificially high instance
-		 * number, so it shows up after all other non-loopback
-		 * interfaces.
-		 */
-		n = 0x1FFFFFFF;	/* 29 all-1 bits */
-	} else {
-		/*
-		 * A number at the end of the device name string is
-		 * assumed to be an instance number.  Add 1 to the
-		 * instance number, and use 0 for "no instance
-		 * number", so we don't put "no instance number"
-		 * devices and "instance 0" devices together.
-		 */
-		cp = dev->name + strlen(dev->name) - 1;
-		while (cp-1 >= dev->name && *(cp-1) >= '0' && *(cp-1) <= '9')
-			cp--;
-		if (*cp >= '0' && *cp <= '9')
-			n = atoi(cp) + 1;
-		else
-			n = 0;
-	}
+	n = 0;
 	if (!(dev->flags & PCAP_IF_RUNNING))
 		n |= 0x80000000;
 	if (!(dev->flags & PCAP_IF_UP))
@@ -687,6 +823,13 @@
 	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);
 }
 
@@ -887,7 +1030,7 @@
 	 * see if it looks like a loopback device.
 	 */
 	if (name[0] == 'l' && name[1] == 'o' &&
-	    (isdigit((unsigned char)(name[2])) || name[2] == '\0')
+	    (PCAP_ISDIGIT(name[2]) || name[2] == '\0'))
 		pcap_flags |= PCAP_IF_LOOPBACK;
 #endif
 #ifdef IFF_UP
@@ -1368,6 +1511,22 @@
 	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);
 
@@ -1431,7 +1590,7 @@
 #ifdef PCAP_SUPPORT_BT
 	    || strstr(device, "bluetooth") != NULL
 #endif
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
 	    || strstr(device, "usbmon") != NULL
 #endif
 #ifdef HAVE_SNF_API
@@ -1441,6 +1600,9 @@
 	    || 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;
@@ -1460,7 +1622,7 @@
 	(void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
 	if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
 		if (errno == EADDRNOTAVAIL) {
-			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "%s: no IPv4 address assigned", device);
 		} else {
 			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
@@ -1493,7 +1655,7 @@
 		else if (IN_CLASSC(*netp))
 			*maskp = IN_CLASSC_NET;
 		else {
-			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "inet class for 0x%x unknown", *netp);
 			return (-1);
 		}
@@ -1685,7 +1847,8 @@
 	 *
 	 * XXX - %-escaping?
 	 */
-	if (pcap_strcasecmp(scheme, "rpcap") == 0 &&
+	if ((pcap_strcasecmp(scheme, "rpcap") == 0 ||
+	    pcap_strcasecmp(scheme, "rpcaps") == 0) &&
 	    strchr(colonp + 3, '/') == NULL) {
 		/*
 		 * Local device.
@@ -1788,7 +1951,7 @@
 				/*
 				 * There's no closing square bracket.
 				 */
-				pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+				snprintf(ebuf, PCAP_ERRBUF_SIZE,
 				    "IP-literal in URL doesn't end with ]");
 				free(userinfo);
 				free(authority);
@@ -1801,7 +1964,7 @@
 				 * There's extra crud after the
 				 * closing square bracketn.
 				 */
-				pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+				snprintf(ebuf, PCAP_ERRBUF_SIZE,
 				    "Extra text after IP-literal in URL");
 				free(userinfo);
 				free(authority);
@@ -1896,8 +2059,8 @@
 }
 
 int
-pcap_createsrcstr(char *source, int type, const char *host, const char *port,
-    const char *name, char *errbuf)
+pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port,
+    const char *name, unsigned char uses_ssl, char *errbuf)
 {
 	switch (type) {
 
@@ -1907,13 +2070,15 @@
 			pcap_strlcat(source, name, PCAP_BUF_SIZE);
 			return (0);
 		} else {
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "The file name cannot be NULL.");
 			return (-1);
 		}
 
 	case PCAP_SRC_IFREMOTE:
-		pcap_strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
+		pcap_strlcpy(source,
+		    (uses_ssl ? "rpcaps://" : PCAP_SRC_IF_STRING),
+		    PCAP_BUF_SIZE);
 		if (host != NULL && *host != '\0') {
 			if (strchr(host, ':') != NULL) {
 				/*
@@ -1934,7 +2099,7 @@
 
 			pcap_strlcat(source, "/", PCAP_BUF_SIZE);
 		} else {
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "The host name cannot be NULL.");
 			return (-1);
 		}
@@ -1953,15 +2118,23 @@
 		return (0);
 
 	default:
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "The interface type is not valid.");
 		return (-1);
 	}
 }
 
+
 int
-pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
-    char *name, char *errbuf)
+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;
 
@@ -1972,6 +2145,8 @@
 		*port = '\0';
 	if (name)
 		*name = '\0';
+	if (uses_ssl)
+		*uses_ssl = 0;
 
 	/* Parse the source string */
 	if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost,
@@ -1997,16 +2172,24 @@
 		return (0);
 	}
 
-	if (strcmp(scheme, "rpcap") == 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://
+		 * rpcap[s]://
 		 *
 		 * pcap_parse_source() has already handled the case of
-		 * rpcap://device
+		 * rpcap[s]://device
 		 */
 		if (host && tmphost) {
 			if (tmpuserinfo)
-				pcap_snprintf(host, PCAP_BUF_SIZE, "%s@%s",
+				snprintf(host, PCAP_BUF_SIZE, "%s@%s",
 				    tmpuserinfo, tmphost);
 			else
 				pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE);
@@ -2056,6 +2239,13 @@
 	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 *
@@ -2089,19 +2279,31 @@
 		 * 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 strinh and, if
+		 * looks as if it might be a UTF-16LE string and, if
 		 * so, convert it back to the local code page's
 		 * extended ASCII.
 		 *
-		 * XXX - 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.  This particular
-		 * version of this heuristic dates back to WinPcap
-		 * 4.1.1; PacketOpenAdapter() does uses the same
-		 * heuristic, with the exact same vulnerability.
+		 * 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 (device[0] != '\0' && device[1] == '\0') {
+		if (!pcap_new_api && device[0] != '\0' && device[1] == '\0') {
 			size_t length;
 
 			length = wcslen((wchar_t *)device);
@@ -2113,7 +2315,7 @@
 				return (NULL);
 			}
 
-			pcap_snprintf(device_str, length + 1, "%ws",
+			snprintf(device_str, length + 1, "%ws",
 			    (const wchar_t *)device);
 		} else
 #endif
@@ -2225,36 +2427,31 @@
 	 * 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 size)
+pcap_alloc_pcap_t(char *ebuf, size_t total_size, size_t private_offset)
 {
 	char *chunk;
 	pcap_t *p;
 
 	/*
-	 * Allocate a chunk of memory big enough for a pcap_t
-	 * plus a structure following it of size "size".  The
-	 * structure following it is a private data structure
-	 * for the routines that handle this pcap_t.
-	 *
-	 * The structure following it must be aligned on
-	 * the appropriate alignment boundary for this platform.
-	 * We align on an 8-byte boundary as that's probably what
-	 * at least some platforms do, even with 32-bit integers,
-	 * and because we can't be sure that some values won't
-	 * require 8-byte alignment even on platforms with 32-bit
-	 * integers.
+	 * total_size is the size of a structure containing a pcap_t
+	 * followed by a private structure.
 	 */
-#define PCAP_T_ALIGNED_SIZE	((sizeof(pcap_t) + 7U) & ~0x7U)
-	chunk = malloc(PCAP_T_ALIGNED_SIZE + size);
+	chunk = calloc(total_size, 1);
 	if (chunk == NULL) {
 		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
 		    errno, "malloc");
 		return (NULL);
 	}
-	memset(chunk, 0, PCAP_T_ALIGNED_SIZE + size);
 
 	/*
 	 * Get a pointer to the pcap_t at the beginning.
@@ -2271,26 +2468,24 @@
 #endif /* MSDOS */
 #endif /* _WIN32 */
 
-	if (size == 0) {
-		/* No private data was requested. */
-		p->priv = NULL;
-	} else {
-		/*
-		 * Set the pointer to the private data; that's the structure
-		 * of size "size" following the pcap_t.
-		 */
-		p->priv = (void *)(chunk + PCAP_T_ALIGNED_SIZE);
-	}
+	/*
+	 * 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 size)
+pcap_create_common(char *ebuf, size_t total_size, size_t private_offset)
 {
 	pcap_t *p;
 
-	p = pcap_alloc_pcap_t(ebuf, size);
+	p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
 	if (p == NULL)
 		return (NULL);
 
@@ -2342,7 +2537,7 @@
 pcap_check_activated(pcap_t *p)
 {
 	if (p->activated) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
 			" operation on activated capture");
 		return (-1);
 	}
@@ -2550,7 +2745,7 @@
 			 * handle errors other than PCAP_ERROR, return the
 			 * error message corresponding to the status.
 			 */
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",
 			    pcap_statustostr(status));
 		}
 
@@ -2608,7 +2803,7 @@
 		    NULL, errbuf));
 	}
 	if (srctype == PCAP_SRC_FILE) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
 		return (NULL);
 	}
 	if (srctype == PCAP_SRC_IFLOCAL) {
@@ -2655,26 +2850,26 @@
 	return (p);
 fail:
 	if (status == PCAP_ERROR)
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device,
+		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)
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%.*s)", device,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%.*s)", device,
 		    pcap_statustostr(status), PCAP_ERRBUF_SIZE - 6, p->errbuf);
 	else
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
+		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 size)
+pcap_open_offline_common(char *ebuf, size_t total_size, size_t private_offset)
 {
 	pcap_t *p;
 
-	p = pcap_alloc_pcap_t(ebuf, size);
+	p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
 	if (p == NULL)
 		return (NULL);
 
@@ -2725,7 +2920,7 @@
 void
 pcap_breakloop(pcap_t *p)
 {
-	p->break_loop = 1;
+	p->breakloop_op(p);
 }
 
 int
@@ -2848,11 +3043,11 @@
 unsupported:
 	dlt_name = pcap_datalink_val_to_name(dlt);
 	if (dlt_name != NULL) {
-		(void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+		(void) snprintf(p->errbuf, sizeof(p->errbuf),
 		    "%s is not one of the DLTs supported by this device",
 		    dlt_name);
 	} else {
-		(void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+		(void) snprintf(p->errbuf, sizeof(p->errbuf),
 		    "DLT %d is not one of the DLTs supported by this device",
 		    dlt);
 	}
@@ -2965,7 +3160,7 @@
 	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(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"),
@@ -3094,6 +3289,18 @@
 	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
 };
 
@@ -3143,7 +3350,7 @@
         if (description != NULL) {
                 return description;
         } else {
-                (void)pcap_snprintf(unkbuf, sizeof(unkbuf), "DLT %u", dlt);
+                (void)snprintf(unkbuf, sizeof(unkbuf), "DLT %u", dlt);
                 return unkbuf;
         }
 }
@@ -3160,6 +3367,7 @@
 	{ "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 }
 };
 
@@ -3245,18 +3453,33 @@
 	return (p->rfile);
 }
 
+#ifdef _WIN32
 int
 pcap_fileno(pcap_t *p)
 {
-#ifndef _WIN32
-	return (p->fd);
-#else
-	if (p->handle != INVALID_HANDLE_VALUE)
+	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);
-	else
+DIAG_ON_NARROWING
+	} else
 		return (PCAP_ERROR);
-#endif
 }
+#else /* _WIN32 */
+int
+pcap_fileno(pcap_t *p)
+{
+	return (p->fd);
+}
+#endif /* _WIN32 */
 
 #if !defined(_WIN32) && !defined(MSDOS)
 int
@@ -3265,7 +3488,7 @@
 	return (p->selectable_fd);
 }
 
-struct timeval *
+const struct timeval *
 pcap_get_required_select_timeout(pcap_t *p)
 {
 	return (p->required_select_timeout);
@@ -3435,7 +3658,7 @@
 	case PCAP_ERROR_TSTAMP_PRECISION_NOTSUP:
 		return ("That device doesn't support that time stamp precision");
 	}
-	(void)pcap_snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
+	(void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
 	return(ebuf);
 }
 
@@ -3463,7 +3686,7 @@
 
 	if ((unsigned int)errnum < sys_nerr)
 		return ((char *)sys_errlist[errnum]);
-	(void)pcap_snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum);
+	(void)snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum);
 	return (errbuf);
 #endif
 }
@@ -3484,11 +3707,29 @@
 pcap_setdirection(pcap_t *p, pcap_direction_t d)
 {
 	if (p->setdirection_op == NULL) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-		    "Setting direction is not implemented on this platform");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		    "Setting direction is not supported on this device");
 		return (-1);
-	} else
-		return (p->setdirection_op(p, d));
+	} 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
@@ -3620,7 +3861,7 @@
 
 	handle = p->get_airpcap_handle_op(p);
 	if (handle == NULL) {
-		(void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+		(void)snprintf(p->errbuf, sizeof(p->errbuf),
 		    "This isn't an AirPcap device");
 	}
 	return (handle);
@@ -3657,8 +3898,28 @@
 {
 	struct pcap *handle;
 
-	while ((handle = pcaps_to_close) != NULL)
+	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
@@ -3716,6 +3977,13 @@
 }
 
 void
+pcap_breakloop_common(pcap_t *p)
+{
+	p->break_loop = 1;
+}
+
+
+void
 pcap_cleanup_live_common(pcap_t *p)
 {
 	if (p->buffer != NULL) {
@@ -3756,6 +4024,12 @@
 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);
@@ -3768,7 +4042,23 @@
 int
 pcap_inject(pcap_t *p, const void *buf, size_t size)
 {
-	return (p->inject_op(p, buf, 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
@@ -3781,6 +4071,81 @@
 }
 
 /*
+ * 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
@@ -3793,7 +4158,7 @@
 	const struct bpf_insn *fcode = fp->bf_insns;
 
 	if (fcode != NULL)
-		return (bpf_filter(fcode, pkt, h->len, h->caplen));
+		return (pcap_filter(fcode, pkt, h->len, h->caplen));
 	else
 		return (0);
 }
@@ -3801,7 +4166,7 @@
 static int
 pcap_can_set_rfmon_dead(pcap_t *p)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Rfmon mode doesn't apply on a pcap_open_dead pcap_t");
 	return (PCAP_ERROR);
 }
@@ -3810,15 +4175,15 @@
 pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
     u_char *user _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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_, size_t size _U_)
+pcap_inject_dead(pcap_t *p, const void *buf _U_, int size _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Packets can't be sent on a pcap_open_dead pcap_t");
 	return (-1);
 }
@@ -3826,7 +4191,7 @@
 static int
 pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "A filter cannot be set on a pcap_open_dead pcap_t");
 	return (-1);
 }
@@ -3834,7 +4199,7 @@
 static int
 pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "The packet direction cannot be set on a pcap_open_dead pcap_t");
 	return (-1);
 }
@@ -3842,7 +4207,7 @@
 static int
 pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "The link-layer header type cannot be set on a pcap_open_dead pcap_t");
 	return (-1);
 }
@@ -3850,7 +4215,7 @@
 static int
 pcap_getnonblock_dead(pcap_t *p)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
 	return (-1);
 }
@@ -3858,7 +4223,7 @@
 static int
 pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
 	return (-1);
 }
@@ -3866,40 +4231,40 @@
 static int
 pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Statistics aren't available from a pcap_open_dead pcap_t");
 	return (-1);
 }
 
 #ifdef _WIN32
-struct pcap_stat *
+static struct pcap_stat *
 pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+pcap_setbuff_dead(pcap_t *p, int dim _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+pcap_setmode_dead(pcap_t *p, int mode _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+pcap_setmintocopy_dead(pcap_t *p, int size _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
 	return (-1);
 }
@@ -3907,7 +4272,7 @@
 static HANDLE
 pcap_getevent_dead(pcap_t *p)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "A pcap_open_dead pcap_t has no event handle");
 	return (INVALID_HANDLE_VALUE);
 }
@@ -3916,7 +4281,7 @@
 pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
     size_t *lenp _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "An OID get request cannot be performed on a pcap_open_dead pcap_t");
 	return (PCAP_ERROR);
 }
@@ -3925,45 +4290,47 @@
 pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
     size_t *lenp _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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, int sync)
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue _U_,
+    int sync _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+pcap_setuserbuffer_dead(pcap_t *p, int size _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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, int maxsize, int maxpacks)
+pcap_live_dump_dead(pcap_t *p, char *filename _U_, int maxsize _U_,
+    int maxpacks _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+pcap_live_dump_ended_dead(pcap_t *p, int sync _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+pcap_get_airpcap_handle_dead(pcap_t *p _U_)
 {
 	return (NULL);
 }
diff --git a/pcap/bpf.h b/pcap/bpf.h
index 9d74895..ccb93cc 100644
--- a/pcap/bpf.h
+++ b/pcap/bpf.h
@@ -58,10 +58,21 @@
  * 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.
+ * 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.
  */
@@ -108,6 +119,8 @@
 
 #include <pcap/dlt.h>
 
+#ifndef __LINUX_FILTER_H__
+
 /*
  * The instruction encodings.
  *
@@ -228,6 +241,8 @@
 /*				0xf0	reserved */
 /*				0xf8	reserved */
 
+#endif /* __LINUX_FILTER_H__ */
+
 /*
  * The instruction data structure.
  */
@@ -238,14 +253,27 @@
 	bpf_u_int32 k;
 };
 
+#ifndef __LINUX_FILTER_H__
+
 /*
  * Macros for insn array initializers.
  */
 #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
 #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
 
-PCAP_API int bpf_validate(const struct bpf_insn *, int);
-PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+#endif /* __LINUX_FILTER_H__ */
+
+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).
diff --git a/pcap/compiler-tests.h b/pcap/compiler-tests.h
index ea5962c..a69c2b0 100644
--- a/pcap/compiler-tests.h
+++ b/pcap/compiler-tests.h
@@ -38,7 +38,7 @@
 /*
  * This was introduced by Clang:
  *
- *     http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
+ *     https://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
  *
  * in some version (which version?); it has been picked up by GCC 5.0.
  */
diff --git a/pcap/dlt.h b/pcap/dlt.h
index 8dacf02..eaba34f 100644
--- a/pcap/dlt.h
+++ b/pcap/dlt.h
@@ -136,7 +136,7 @@
 #define DLT_PFSYNC	18
 #endif
 
-#define DLT_ATM_CLIP	19	/* Linux Classical-IP over ATM */
+#define DLT_ATM_CLIP	19	/* Linux Classical IP over ATM */
 
 /*
  * Apparently Redback uses this for its SmartEdge 400/800.  I hope
@@ -465,7 +465,7 @@
 #define DLT_DOCSIS		143
 
 /*
- * Linux-IrDA packets. Protocol defined at http://www.irda.org.
+ * 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.
@@ -473,7 +473,7 @@
  * 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 dependant on the direction of the packet (incomming or
+ * 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...
@@ -565,7 +565,7 @@
  * 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 accomodate
+ * The first byte of the PPP header (0xff03) is modified to accommodate
  * the direction - 0x00 = IN, 0x01 = OUT.
  */
 #define DLT_PPP_PPPD		166
@@ -607,7 +607,7 @@
 /*
  * Link types requested by Gregor Maier <gregor@endace.com> of Endace
  * Measurement Systems.  They add an ERF header (see
- * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of
  * the link-layer header.
  */
 #define DLT_ERF_ETH		175	/* Ethernet */
@@ -750,7 +750,7 @@
 
 /*
  * Various link-layer types, with a pseudo-header, for SITA
- * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
  */
 #define DLT_SITA		196
 
@@ -817,8 +817,11 @@
  * 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	/* Don't confuse with DLT_PPP_WITH_DIRECTION */
+#define DLT_PPP_WITH_DIR	204
 
 /*
  * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero
@@ -862,7 +865,7 @@
 
 /*
  * Media Oriented Systems Transport (MOST) bus for multimedia
- * transport - http://www.mostcooperation.com/ - as requested
+ * transport - https://www.mostcooperation.com/ - as requested
  * by Hannes Kaelber <hannes.kaelber@x2e.de>.
  */
 #define DLT_MOST		211
@@ -1048,16 +1051,16 @@
 /*
  * Raw D-Bus:
  *
- *	http://www.freedesktop.org/wiki/Software/dbus
+ *	https://www.freedesktop.org/wiki/Software/dbus
  *
  * messages:
  *
- *	http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-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:
  *
- *	http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ *	https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
  *
  * Requested by Martin Vidner <martin@vidner.net>.
  */
@@ -1075,7 +1078,7 @@
  * DVB-CI (DVB Common Interface for communication between a PC Card
  * module and a DVB receiver).  See
  *
- *	http://www.kaiser.cx/pcap-dvbci.html
+ *	https://www.kaiser.cx/pcap-dvbci.html
  *
  * for the specification.
  *
@@ -1364,9 +1367,9 @@
 
 /*
  * per: Stefanha at gmail.com for
- *   http://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
+ *   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: http://qemu-project.org/Features/VirtioVsock
+ * for: https://qemu-project.org/Features/VirtioVsock
  */
 #define DLT_VSOCK               271
 
@@ -1378,7 +1381,7 @@
 /*
  * Excentis DOCSIS 3.1 RF sniffer (XRA-31)
  *   per: bruno.verstuyft at excentis.com
- *        http://www.xra31.com/xra-header
+ *        https://www.xra31.com/xra-header
  */
 #define DLT_DOCSIS31_XRA31	273
 
@@ -1390,7 +1393,7 @@
 
 /*
  * DisplayPort AUX channel monitoring data as specified by VESA
- * DisplayPort(DP) Standard preceeded by a pseudo-header.
+ * DisplayPort(DP) Standard preceded by a pseudo-header.
  *    per dirk.eibach at gdsys.cc
  */
 #define DLT_DISPLAYPORT_AUX	275
@@ -1401,6 +1404,83 @@
 #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
@@ -1410,7 +1490,7 @@
 #ifdef DLT_MATCHING_MAX
 #undef DLT_MATCHING_MAX
 #endif
-#define DLT_MATCHING_MAX	276	/* highest value in the "matching" range */
+#define DLT_MATCHING_MAX	289	/* highest value in the "matching" range */
 
 /*
  * DLT and savefile link type values are split into a class and
diff --git a/pcap/funcattrs.h b/pcap/funcattrs.h
index e64da93..cdc083d 100644
--- a/pcap/funcattrs.h
+++ b/pcap/funcattrs.h
@@ -147,6 +147,70 @@
 #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 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
+#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
@@ -233,10 +297,10 @@
    * __attribute__((deprecated(msg))).
    */
   #define PCAP_DEPRECATED(func, msg)	__attribute__((deprecated))
-#elif (defined(_MSC_VER) && (_MSC_VER >= 1500)) && !defined(BUILDING_PCAP)
+#elif defined(_MSC_VER) && !defined(BUILDING_PCAP)
   /*
-   * MSVC from Visual Studio 2008 or later, and we're not building
-   * libpcap itself.
+   * 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.
@@ -251,11 +315,7 @@
  */
 #ifdef _MSC_VER
  #include <sal.h>
- #if _MSC_VER > 1400
-  #define PCAP_FORMAT_STRING(p) _Printf_format_string_ p
- #else
-  #define PCAP_FORMAT_STRING(p) __format_string p
- #endif
+ #define PCAP_FORMAT_STRING(p) _Printf_format_string_ p
 #else
  #define PCAP_FORMAT_STRING(p) p
 #endif
diff --git a/pcap/namedb.h b/pcap/namedb.h
index c66846d..34a0ae7 100644
--- a/pcap/namedb.h
+++ b/pcap/namedb.h
@@ -59,7 +59,8 @@
 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_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 *);
 
diff --git a/pcap/pcap-inttypes.h b/pcap/pcap-inttypes.h
index 8b1eb8b..1cfa0bf 100644
--- a/pcap/pcap-inttypes.h
+++ b/pcap/pcap-inttypes.h
@@ -32,97 +32,49 @@
 #define pcap_pcap_inttypes_h
 
 /*
- * Get the integer types and PRi[doux]64 values from C99 <inttypes.h>
- * defined, by hook or by crook.
+ * 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.
+   * Compiler is MSVC.  Make sure we have VS 2015 or later.
    */
-  #if _MSC_VER >= 1800
-    /*
-     * VS 2013 or newer; we have <inttypes.h>.
-     */
-    #include <inttypes.h>
-  #else
-    /*
-     * Earlier VS; we have to define this stuff ourselves.
-     */
-    typedef unsigned char uint8_t;
-    typedef signed char int8_t;
-    typedef unsigned short uint16_t;
-    typedef signed short int16_t;
-    typedef unsigned int uint32_t;
-    typedef signed int int32_t;
-    #ifdef _MSC_EXTENSIONS
-      typedef unsigned _int64 uint64_t;
-      typedef _int64 int64_t;
-    #else /* _MSC_EXTENSIONS */
-      typedef unsigned long long uint64_t;
-      typedef long long int64_t;
-    #endif
+  #if _MSC_VER < 1900
+    #error "Building libpcap requires VS 2015 or later"
   #endif
-
-  /*
-   * These may be defined by <inttypes.h>.
-   *
-   * XXX - for MSVC, we always want the _MSC_EXTENSIONS versions.
-   * What about other compilers?  If, as the MinGW Web site says MinGW
-   * does, the other compilers just use Microsoft's run-time library,
-   * then they should probably use the _MSC_EXTENSIONS even if the
-   * compiler doesn't define _MSC_EXTENSIONS.
-   *
-   * XXX - we currently aren't using any of these, but this allows
-   * their use in the future.
-   */
-  #ifndef PRId64
-    #ifdef _MSC_EXTENSIONS
-      #define PRId64	"I64d"
-    #else
-      #define PRId64	"lld"
-    #endif
-  #endif /* PRId64 */
-
-  #ifndef PRIo64
-    #ifdef _MSC_EXTENSIONS
-      #define PRIo64	"I64o"
-    #else
-      #define PRIo64	"llo"
-    #endif
-  #endif /* PRIo64 */
-
-  #ifndef PRIx64
-    #ifdef _MSC_EXTENSIONS
-      #define PRIx64	"I64x"
-    #else
-      #define PRIx64	"llx"
-    #endif
-  #endif
-
-  #ifndef PRIu64
-    #ifdef _MSC_EXTENSIONS
-      #define PRIu64	"I64u"
-    #else
-      #define PRIu64	"llu"
-    #endif
-  #endif
-
-  /*
-   * MSVC's support library doesn't support %zu to print a size_t until
-   * Visual Studio 2017, but supports %Iu earlier, so use that.
-   */
-  #define PRIsize	"Iu"
-#elif defined(__MINGW32__) || !defined(_WIN32)
-  /*
-   * Compiler is MinGW or target is UN*X or MS-DOS.  Just use
-   * <inttypes.h>.
-   */
-  #include <inttypes.h>
-
-  /*
-   * Assume the support library supports %zu; it's required by C99.
-   */
-  #define PRIsize	"zu"
 #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
index 90614dd..8182bef 100644
--- a/pcap/pcap.h
+++ b/pcap/pcap.h
@@ -69,6 +69,49 @@
 #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>
@@ -127,6 +170,7 @@
  * 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).
@@ -154,7 +198,7 @@
  *
  * Then supply the changes by forking the branch at
  *
- *	https://github.com/the-tcpdump-group/libpcap/issues
+ *	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
@@ -164,8 +208,8 @@
 	bpf_u_int32 magic;
 	u_short version_major;
 	u_short version_minor;
-	bpf_int32 thiszone;	/* gmt to local correction */
-	bpf_u_int32 sigfigs;	/* accuracy of timestamps */
+	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_*) */
 };
@@ -201,7 +245,7 @@
 struct pcap_pkthdr {
 	struct timeval ts;	/* time stamp */
 	bpf_u_int32 caplen;	/* length of portion present */
-	bpf_u_int32 len;	/* length this packet (off wire) */
+	bpf_u_int32 len;	/* length of this packet (off wire) */
 };
 
 /*
@@ -321,35 +365,91 @@
 #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
 
@@ -359,8 +459,7 @@
  *
  * 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;
- * it will not offer any of the PCAP_TSTAMP_HOST_ subtypes.
+ * 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
@@ -368,10 +467,15 @@
  * 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 might
- * or might not be synchronized with the system clock, and might have
+ * 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.
+ * 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.
@@ -391,11 +495,12 @@
  * 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 */
-#define PCAP_TSTAMP_HOST_HIPREC		2	/* host-provided, high precision */
-#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			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.
@@ -406,13 +511,25 @@
 #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,
@@ -434,60 +551,153 @@
 	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.
@@ -506,17 +716,35 @@
 	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 *);
 
 /*
@@ -524,7 +752,7 @@
  * version string directly.
  *
  * On at least some UNIXes, if you import data from a shared library into
- * an program, the data is bound into the program binary, so if the string
+ * 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,
@@ -534,22 +762,9 @@
  *
  * On Windows, the string is constructed at run time.
  */
+PCAP_AVAILABLE_0_8
 PCAP_API const char *pcap_lib_version(void);
 
-/*
- * On at least some versions of NetBSD and QNX, we don't want to declare
- * bpf_filter() here, as it's also be declared in <net/bpf.h>, with a
- * different signature, but, on other BSD-flavored UN*Xes, it's not
- * declared in <net/bpf.h>, so we *do* want to declare it here, so it's
- * declared when we build pcap-bpf.c.
- */
-#if !defined(__NetBSD__) && !defined(__QNX__)
-  PCAP_API u_int	bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
-#endif
-PCAP_API int	bpf_validate(const struct bpf_insn *f, int len);
-PCAP_API char	*bpf_image(const struct bpf_insn *, int);
-PCAP_API void	bpf_dump(const struct bpf_program *, int);
-
 #if defined(_WIN32)
 
   /*
@@ -583,7 +798,10 @@
 
   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);
@@ -626,8 +844,11 @@
    * UN*X definitions
    */
 
+  PCAP_AVAILABLE_0_8
   PCAP_API int	pcap_get_selectable_fd(pcap_t *);
-  PCAP_API struct timeval *pcap_get_required_select_timeout(pcap_t *);
+
+  PCAP_AVAILABLE_1_9
+  PCAP_API const struct timeval *pcap_get_required_select_timeout(pcap_t *);
 
 #endif /* _WIN32/MSDOS/UN*X */
 
@@ -660,14 +881,17 @@
  * - 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 compability, but it is strongly discouraged]
- * - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged]
+ * - 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:
  *
@@ -728,7 +952,7 @@
 #define PCAP_OPENFLAG_DATATX_UDP		0x00000002
 
 /*
- * Specifies wheether the remote probe will capture its own generated
+ * Specifies whether the remote probe will capture its own generated
  * traffic.
  *
  * In case the remote probe uses the same interface to capture traffic
@@ -797,7 +1021,7 @@
 #define RPCAP_RMTAUTH_PWD 1
 
 /*
- * This structure keeps the information needed to autheticate the user
+ * 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
@@ -856,10 +1080,15 @@
  * 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);
 
@@ -882,6 +1111,7 @@
  * 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);
 
@@ -952,6 +1182,7 @@
 /*
  * New functions.
  */
+PCAP_AVAILABLE_1_9
 PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p);
 
 /*
@@ -961,12 +1192,24 @@
 /* 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
diff --git a/pcap/socket.h b/pcap/socket.h
index 6f27cba..ee2e393 100644
--- a/pcap/socket.h
+++ b/pcap/socket.h
@@ -49,15 +49,6 @@
   #include <ws2tcpip.h>
 
   /*
-   * Winsock doesn't have this UN*X type; it's used in the UN*X
-   * sockets API.
-   *
-   * XXX - do we need to worry about UN*Xes so old that *they*
-   * don't have it, either?
-   */
-  typedef int socklen_t;
-
-  /*
    * Winsock doesn't have this POSIX type; it's used for the
    * tv_usec value of struct timeval.
    */
diff --git a/pcap_activate.3pcap b/pcap_activate.3pcap
index 162a929..169a756 100644
--- a/pcap_activate.3pcap
+++ b/pcap_activate.3pcap
@@ -17,7 +17,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_ACTIVATE 3PCAP "31 July 2016"
+.TH PCAP_ACTIVATE 3PCAP "24 November 2019"
 .SH NAME
 pcap_activate \- activate a capture handle
 .SH SYNOPSIS
@@ -31,13 +31,15 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_activate()
+.BR pcap_activate ()
 is used to activate a packet capture handle to look
 at packets on the network, with the options that were set on the handle
 being in effect.
 .SH RETURN VALUE
-.B pcap_activate()
-returns 0 on success without warnings, a non-zero positive value on
+.BR pcap_activate ()
+returns
+.B 0
+on success without warnings, a non-zero positive value on
 success with warnings, and a negative value on error.
 A non-zero return value indicates what warning or error condition
 occurred.
@@ -50,15 +52,15 @@
 .TP
 .B PCAP_WARNING_TSTAMP_TYPE_NOTSUP
 The time stamp type specified in a previous
-.B pcap_set_tstamp_type(3PCAP)
+.BR pcap_set_tstamp_type (3PCAP)
 call isn't supported by the capture source (the time stamp type is
 left as the default),
 .TP
 .B PCAP_WARNING
 Another warning condition occurred;
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display a message describing the warning
@@ -89,9 +91,9 @@
 .TP
 .B PCAP_ERROR
 Another error occurred.
-.B pcap_geterr()
+.BR pcap_geterr ()
 or
-.B pcap_perror()
+.BR pcap_perror ()
 may be called with
 .I p
 as an argument to fetch or display a message describing the error.
@@ -102,9 +104,9 @@
 or
 .B PCAP_ERROR_PERM_DENIED
 is returned,
-.B pcap_geterr()
+.BR pcap_geterr ()
 or
-.B pcap_perror()
+.BR pcap_perror ()
 may be called with
 .I p
 as an argument to fetch or display an message giving additional details
@@ -115,8 +117,15 @@
 should check for positive, negative, and zero return codes, and treat
 all positive return codes as warnings and all negative return
 codes as errors.
-.B pcap_statustostr(3PCAP)
+.BR pcap_statustostr (3PCAP)
 can be called, with a warning or error code as an argument, to fetch a
 message describing the warning or error code.
+.LP
+If
+.BR pcap_activate ()
+fails, the
+.I pcap_t *
+is not closed and freed; it should be closed using
+.BR pcap_close ().
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_breakloop.3pcap b/pcap_breakloop.3pcap
index cc000d2..996290f 100644
--- a/pcap_breakloop.3pcap
+++ b/pcap_breakloop.3pcap
@@ -31,11 +31,11 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_breakloop()
+.BR pcap_breakloop ()
 sets a flag that will force
-.B pcap_dispatch(3PCAP)
+.BR pcap_dispatch (3PCAP)
 or
-.B pcap_loop(3PCAP)
+.BR pcap_loop (3PCAP)
 to return rather than looping; they will return the number of packets
 that have been processed so far, or
 .B PCAP_ERROR_BREAK
@@ -69,9 +69,9 @@
 breaking a thread out of blocking calls in order to unblock the thread,
 such as thread cancellation or thread signalling in systems that support
 POSIX threads, or
-.B SetEvent()
+.BR SetEvent ()
 on the result of
-.B pcap_getevent()
+.BR pcap_getevent ()
 on a
 .B pcap_t
 on which the thread is blocked on Windows.  Asynchronous procedure calls
@@ -81,35 +81,35 @@
 .ft R
 .PP
 Note that
-.B pcap_next()
+.BR pcap_next ()
 and
-.B pcap_next_ex()
+.BR pcap_next_ex ()
 will, on some platforms, loop reading packets from the OS; that loop
 will not necessarily be terminated by a signal, so
-.B pcap_breakloop()
+.BR pcap_breakloop ()
 should be used to terminate packet processing even if
-.B pcap_next()
+.BR pcap_next ()
 or
-.B pcap_next_ex()
+.BR pcap_next_ex ()
 is being used.
 .PP
-.B pcap_breakloop()
+.BR pcap_breakloop ()
 does not guarantee that no further packets will be processed by
-.B pcap_dispatch()
+.BR pcap_dispatch ()
 or
-.B pcap_loop()
+.BR pcap_loop ()
 after it is called; at most one more packet might be processed.
 .PP
 If
 .B PCAP_ERROR_BREAK
 is returned from
-.B pcap_dispatch()
+.BR pcap_dispatch ()
 or
-.BR pcap_loop() ,
+.BR pcap_loop (),
 the flag is cleared, so a subsequent call will resume reading packets.
 If a positive number is returned, the flag is not cleared, so a
 subsequent call will return
 .B PCAP_ERROR_BREAK
 and clear the flag.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_can_set_rfmon.3pcap b/pcap_can_set_rfmon.3pcap
index 0baac7a..be03956 100644
--- a/pcap_can_set_rfmon.3pcap
+++ b/pcap_can_set_rfmon.3pcap
@@ -31,13 +31,16 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_can_set_rfmon()
+.BR pcap_can_set_rfmon ()
 checks whether monitor mode could be set on a capture handle when
 the handle is activated.
 .SH RETURN VALUE
-.B pcap_can_set_rfmon()
-returns 0 if monitor mode could not be set,
-1 if monitor mode could be set, and a negative value on error.
+.BR pcap_can_set_rfmon ()
+returns
+.B 0
+if monitor mode could not be set,
+.B 1
+if monitor mode could be set, and a negative value on error.
 A negative return value indicates what error condition occurred.
 The possible error values are:
 .TP
@@ -54,19 +57,24 @@
 .TP
 .B PCAP_ERROR
 Another error occurred.
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B \%pcap_perror(3PCAP)
+.BR \%pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display a message describing the error.
 .LP
 Additional error codes may be added in the future; a program should
-check for 0, 1, and negative, return codes, and treat all negative
+check for
+.BR 0 ,
+.BR 1 ,
+and negative, return codes, and treat all negative
 return codes as errors.
-.B pcap_statustostr(3PCAP)
+.BR pcap_statustostr (3PCAP)
 can be called, with a warning or error code as an argument, to fetch a
 message describing the warning or error code.
 .SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP),
-pcap_set_rfmon(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP),
+.BR pcap_set_rfmon (3PCAP)
diff --git a/pcap_close.3pcap b/pcap_close.3pcap
index e2316a4..c4ac3fa 100644
--- a/pcap_close.3pcap
+++ b/pcap_close.3pcap
@@ -31,9 +31,9 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_close()
+.BR pcap_close ()
 closes the files associated with
 .I p
 and deallocates resources.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_compile.3pcap.in b/pcap_compile.3pcap.in
index 824f52b..8238e54 100644
--- a/pcap_compile.3pcap.in
+++ b/pcap_compile.3pcap.in
@@ -33,7 +33,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_compile()
+.BR pcap_compile ()
 is used to compile the string
 .I str
 into a filter program.  See
@@ -43,7 +43,7 @@
 is a pointer to a
 .I bpf_program
 struct and is filled in by
-.BR pcap_compile() .
+.BR pcap_compile ().
 .I optimize
 controls whether optimization on the resulting code is performed.
 .I netmask
@@ -59,24 +59,26 @@
 the filter program will be OK.
 .LP
 NOTE: in libpcap 1.8.0 and later,
-.B pcap_compile()
+.BR pcap_compile ()
 can be used in multiple threads within a single process.  However, in
 earlier versions of libpcap, it is
 .I not
 safe to use
-.B pcap_compile()
+.BR pcap_compile ()
 in multiple threads in a single process without some form of mutual
 exclusion allowing only one thread to call it at any given time.
 .SH RETURN VALUE
-.B pcap_compile()
-returns 0 on success and
+.BR pcap_compile ()
+returns
+.B 0
+on success and
 .B PCAP_ERROR
 on failure. If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
@@ -86,4 +88,6 @@
 .B PCAP_NETMASK_UNKNOWN
 constant became available in libpcap release 1.1.0.
 .SH SEE ALSO
-pcap(3PCAP), pcap_setfilter(3PCAP), pcap_freecode(3PCAP),
+.BR pcap (3PCAP),
+.BR pcap_setfilter (3PCAP),
+.BR pcap_freecode (3PCAP)
diff --git a/pcap_create.3pcap b/pcap_create.3pcap
index 5a15007..bd42d73 100644
--- a/pcap_create.3pcap
+++ b/pcap_create.3pcap
@@ -36,7 +36,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_create()
+.BR pcap_create ()
 is used to create a packet capture handle to look
 at packets on the network.
 .I source
@@ -48,12 +48,12 @@
 can be used to capture packets from all interfaces.
 .PP
 The returned handle must be activated with
-.B pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
 before packets can be captured
 with it; options for the capture, such as promiscuous mode, can be set
 on the handle before activating it.
 .SH RETURN VALUE
-.B pcap_create()
+.BR pcap_create ()
 returns a
 .I pcap_t *
 on success and
@@ -69,4 +69,4 @@
 .B PCAP_ERRBUF_SIZE
 chars.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_datalink.3pcap.in b/pcap_datalink.3pcap.in
index 2620368..abb7375 100644
--- a/pcap_datalink.3pcap.in
+++ b/pcap_datalink.3pcap.in
@@ -31,19 +31,19 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_datalink()
+.BR pcap_datalink ()
 returns the link-layer header type for the live capture or ``savefile''
 specified by
 .IR p .
 .PP
 It must not be called on a pcap descriptor created by
-.B \%pcap_create(3PCAP)
+.BR \%pcap_create (3PCAP)
 that has not yet been activated by
-.BR \%pcap_activate(3PCAP) .
+.BR \%pcap_activate (3PCAP).
 .PP
 .I https://www.tcpdump.org/linktypes.html
 lists the values
-.B pcap_datalink()
+.BR pcap_datalink ()
 can return and describes the packet formats that
 correspond to those values.
 .PP
@@ -55,14 +55,17 @@
 for Ethernet.  For example, the "any" device on Linux will have a
 link-layer header type of
 .B DLT_LINUX_SLL
+or
+.B DLT_LINUX_SLL2
 even if all devices on the system at the time the "any" device is opened
 have some other data link type, such as
 .B DLT_EN10MB
 for Ethernet.
 .SH RETURN VALUE
-.B pcap_datalink()
+.BR pcap_datalink ()
 returns the link-layer header type on success and
 .B PCAP_ERROR_NOT_ACTIVATED
 if called on a capture handle that has been created but not activated.
 .SH SEE ALSO
-pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap-linktype (@MAN_MISC_INFO@)
diff --git a/pcap_datalink_name_to_val.3pcap b/pcap_datalink_name_to_val.3pcap
index dd4688f..d2cb103 100644
--- a/pcap_datalink_name_to_val.3pcap
+++ b/pcap_datalink_name_to_val.3pcap
@@ -32,7 +32,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_datalink_name_to_val()
+.BR pcap_datalink_name_to_val ()
 translates a link-layer header type name, which is a
 .B DLT_
 name with the
@@ -40,10 +40,10 @@
 removed, to the corresponding link-layer header type value.  The
 translation is case-insensitive.
 .SH RETURN VALUE
-.B pcap_datalink_name_to_val()
+.BR pcap_datalink_name_to_val ()
 returns the type value on success and
 .B PCAP_ERROR
 if the name is not a known
-type name..
+type name.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_datalink_val_to_name.3pcap b/pcap_datalink_val_to_name.3pcap
index f42165f..bbfa3f8 100644
--- a/pcap_datalink_val_to_name.3pcap
+++ b/pcap_datalink_val_to_name.3pcap
@@ -17,7 +17,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "12 October 2016"
+.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "15 April 2019"
 .SH NAME
 pcap_datalink_val_to_name, pcap_datalink_val_to_description,
 pcap_datalink_val_to_description_or_dlt \- get a
@@ -35,7 +35,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_datalink_val_to_name()
+.BR pcap_datalink_val_to_name ()
 translates a link-layer header type value to the corresponding
 link-layer header type name, which is the
 .B DLT_
@@ -47,7 +47,7 @@
 .B DLT_
 value.
 .PP
-.B pcap_datalink_val_to_description()
+.BR pcap_datalink_val_to_description ()
 translates a link-layer header type value to a short description of that
 link-layer header type.
 .B NULL
@@ -55,12 +55,22 @@
 .B DLT_
 value.
 .PP
-.B pcap_datalink_val_to_description_or_dlt()
+.BR pcap_datalink_val_to_description_or_dlt ()
 translates a link-layer header type value to a short description of that
-link-layer header type just like pcap_datalink_val_to_description.
+link-layer header type just like
+.BR pcap_datalink_val_to_description ().
 If the type value does not correspond to a known
 .B DLT_
 value, the string "DLT n" is returned, where n is the value of
 the dlt argument.
+.SH BACKWARD COMPATIBILITY
+The
+.BR pcap_datalink_val_to_description_or_dlt ()
+function first became available in libpcap release 1.10.0.  In previous
+releases,
+.BR pcap_datalink_val_to_description ()
+would have to be called and, if it returned
+.BR NULL ,
+a default string would have to be constructed.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_dump.3pcap b/pcap_dump.3pcap
index 7f201b7..ba7f75a 100644
--- a/pcap_dump.3pcap
+++ b/pcap_dump.3pcap
@@ -33,18 +33,18 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_dump()
+.BR pcap_dump ()
 outputs a packet to the ``savefile'' opened with
-.BR pcap_dump_open(3PCAP) .
+.BR pcap_dump_open (3PCAP).
 Note that its calling arguments are suitable for use with
-.B pcap_dispatch(3PCAP)
+.BR pcap_dispatch (3PCAP)
 or
-.BR pcap_loop(3PCAP) .
+.BR pcap_loop (3PCAP).
 If called directly, the
 .I user
 parameter is of type
 .B pcap_dumper_t
 as returned by
-.BR pcap_dump_open() .
+.BR pcap_dump_open ().
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_dump_close.3pcap b/pcap_dump_close.3pcap
index bd95a52..a62eb34 100644
--- a/pcap_dump_close.3pcap
+++ b/pcap_dump_close.3pcap
@@ -31,7 +31,9 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_dump_close()
+.BR pcap_dump_close ()
 closes the ``savefile.''
 .SH SEE ALSO
-pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dump(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_dump_open (3PCAP),
+.BR pcap_dump (3PCAP)
diff --git a/pcap_dump_file.3pcap b/pcap_dump_file.3pcap
index d207431..9fd6c7e 100644
--- a/pcap_dump_file.3pcap
+++ b/pcap_dump_file.3pcap
@@ -31,8 +31,8 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_dump_file()
+.BR pcap_dump_file ()
 returns the standard I/O stream of the ``savefile'' opened by
-.BR pcap_dump_open(3PCAP) .
+.BR pcap_dump_open (3PCAP).
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_dump_flush.3pcap b/pcap_dump_flush.3pcap
index 5d17474..c6e0f86 100644
--- a/pcap_dump_flush.3pcap
+++ b/pcap_dump_flush.3pcap
@@ -31,15 +31,18 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_dump_flush()
+.BR pcap_dump_flush ()
 flushes the output buffer to the ``savefile,'' so that any packets
 written with
-.B pcap_dump(3PCAP)
+.BR pcap_dump (3PCAP)
 but not yet written to the ``savefile'' will be written.
 .SH RETURN VALUE
-.B pcap_dump_flush()
-returns 0 on success and
+.BR pcap_dump_flush ()
+returns
+.B 0
+on success and
 .B PCAP_ERROR
 on failure.
 .SH SEE ALSO
-pcap(3PCAP), pcap_dump_open(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_dump_open (3PCAP)
diff --git a/pcap_dump_ftell.3pcap b/pcap_dump_ftell.3pcap
index 20cb995..062d609 100644
--- a/pcap_dump_ftell.3pcap
+++ b/pcap_dump_ftell.3pcap
@@ -33,18 +33,18 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_dump_ftell()
+.BR pcap_dump_ftell ()
 returns the current file position for the ``savefile'', representing the
 number of bytes written by
-.B pcap_dump_open(3PCAP)
+.BR pcap_dump_open (3PCAP)
 and
-.BR pcap_dump(3PCAP) .
+.BR pcap_dump (3PCAP).
 .B PCAP_ERROR
 is returned on error. If the current file position does not fit in a
 .BR long ,
 it will be truncated; this can happen on 32-bit UNIX-like systems with
 large file support and on Windows.
-.B pcap_dump_ftell64()
+.BR pcap_dump_ftell64 ()
 returns the current file position in a
 .BR int64_t ,
 so if file offsets that don't fit in a
@@ -54,5 +54,11 @@
 are supported, this will return the file offset without truncation.
 .B PCAP_ERROR
 is returned on error.
+.SH BACKWARD COMPATIBILITY
+The function
+.BR pcap_dump_ftell64 ()
+became available in libpcap release 1.9.0.  In previous releases, there
+was no mechanism to obtain a file offset that is too large to fit in a
+.BR long .
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_dump_open.3pcap.in b/pcap_dump_open.3pcap.in
index b86696f..fddecb8 100644
--- a/pcap_dump_open.3pcap.in
+++ b/pcap_dump_open.3pcap.in
@@ -17,9 +17,10 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_DUMP_OPEN 3PCAP "22 August 2018"
+.TH PCAP_DUMP_OPEN 3PCAP "3 July 2020"
 .SH NAME
-pcap_dump_open, pcap_dump_fopen \- open a file to which to write packets
+pcap_dump_open, pcap_dump_open_append, pcap_dump_fopen \- open a file to
+which to write packets
 .SH SYNOPSIS
 .nf
 .ft B
@@ -34,7 +35,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_dump_open()
+.BR pcap_dump_open ()
 is called to open a ``savefile'' for writing.
 .I fname
 specifies the name of the file to open. The file will have
@@ -42,62 +43,66 @@
 .BR tcpdump (1)
 and
 .BR tcpslice (1).
+If the file does not exist, it will be created; if the file exists, it
+will be truncated and overwritten.
 The name "-" is a synonym
 for
 .BR stdout .
 .PP
-.B pcap_dump_fopen()
+.BR pcap_dump_fopen ()
 is called to write data to an existing open stream
 .IR fp ;
 this stream will be closed by a subsequent call to
-.BR pcap_dump_close(3PCAP) .
+.BR pcap_dump_close (3PCAP).
+The stream is assumed to be at the beginning of a file that has been
+newly created or truncated, so that writes will start at the beginning
+of the file.
 Note that on Windows, that stream should be opened in binary mode.
 .PP
 .I p
 is a capture or ``savefile'' handle returned by an earlier call to
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
 and activated by an earlier call to
-.BR \%pcap_activate(3PCAP) ,
+.BR \%pcap_activate (3PCAP),
 or returned by an earlier call to
-.BR \%pcap_open_offline(3PCAP) ,
-.BR pcap_open_live(3PCAP) ,
+.BR \%pcap_open_offline (3PCAP),
+.BR pcap_open_live (3PCAP),
 or
-.BR pcap_open_dead(3PCAP) .
+.BR pcap_open_dead (3PCAP).
 The time stamp precision, link-layer type, and snapshot length from
 .I p
 are used as the link-layer type and snapshot length of the output file.
 .PP
-.B pcap_dump_open_append()
+.BR pcap_dump_open_append ()
 is like
-.B pcap_dump_open()
-but does not create the file if it does not exist and, if it does
-already exist, and is a pcap file with the same byte order as the host
-opening the file, and has the same time stamp precision, link-layer
-header type, and snapshot length as
+.BR pcap_dump_open ()
+but, if the file already exists, and is a pcap file with the same byte
+order as the host opening the file, and has the same time stamp
+precision, link-layer header type, and snapshot length as
 .IR p ,
 it will write new packets at the end of the file.
 .SH RETURN VALUES
 A pointer to a
 .B pcap_dumper_t
 structure to use in subsequent
-.B pcap_dump(3PCAP)
+.BR pcap_dump (3PCAP)
 and
-.B pcap_dump_close(3PCAP)
+.BR pcap_dump_close (3PCAP)
 calls is returned on success.
 .B NULL
 is returned on failure.
 If
 .B NULL
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 can be used to get the error text.
 .SH BACKWARD COMPATIBILITY
 .PP
 The
-.B pcap_dump_open_append()
+.BR pcap_dump_open_append ()
 function became available in libpcap release 1.7.2.  In previous
 releases, there is no support for appending packets to an existing
 savefile.
 .SH SEE ALSO
-pcap(3PCAP),
-\%pcap-savefile(@MAN_FILE_FORMATS@)
+.BR pcap (3PCAP),
+.BR \%pcap-savefile (@MAN_FILE_FORMATS@)
diff --git a/pcap_file.3pcap b/pcap_file.3pcap
index 981451b..7402973 100644
--- a/pcap_file.3pcap
+++ b/pcap_file.3pcap
@@ -31,29 +31,29 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_file()
+.BR pcap_file ()
 returns the standard I/O stream of the ``savefile,'' if a ``savefile''
 was opened with
-.BR pcap_open_offline(3PCAP) ,
+.BR pcap_open_offline (3PCAP),
 or
 .BR NULL ,
 if a network device was opened with
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
 and
-.BR \%pcap_activate(3PCAP) ,
+.BR \%pcap_activate (3PCAP),
 or with
-.BR pcap_open_live(3PCAP) .
+.BR pcap_open_live (3PCAP).
 .PP
 Note that the Packet Capture library is usually built with large file
 support, so the standard I/O stream of the ``savefile'' might refer to
 a file larger than 2 gigabytes; applications that use
-.B pcap_file()
+.BR pcap_file ()
 should, if possible, use calls that support large files on the return
 value of
-.B pcap_file()
+.BR pcap_file ()
 or the value returned by
-.B fileno(3)
+.BR fileno (3)
 when passed the return value of
-.BR pcap_file() .
+.BR pcap_file ().
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_fileno.3pcap b/pcap_fileno.3pcap
index 60ac129..6d0edf8 100644
--- a/pcap_fileno.3pcap
+++ b/pcap_fileno.3pcap
@@ -35,31 +35,31 @@
 .I p
 refers to a network device that was opened for a live capture using
 a combination of
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
 and
-.BR pcap_activate(3PCAP) ,
+.BR pcap_activate (3PCAP),
 or using
-.BR pcap_open_live(3PCAP) ,
-.B pcap_fileno()
+.BR pcap_open_live (3PCAP),
+.BR pcap_fileno ()
 returns the file descriptor from which captured packets are read.
 .LP
 If
 .I p
 refers to a ``savefile'' that was opened using functions such as
-.BR pcap_open_offline(3PCAP)
+.BR pcap_open_offline (3PCAP)
 or
-.BR pcap_fopen_offline(3PCAP) ,
+.BR pcap_fopen_offline (3PCAP),
 a ``dead''
 .B pcap_t
 opened using
-.BR pcap_open_dead(3PCAP) ,
+.BR pcap_open_dead (3PCAP),
 or a
 .B pcap_t
 that was created with
-.B pcap_create()
+.BR pcap_create ()
 but that has not yet been activated with
-.BR pcap_activate() ,
+.BR pcap_activate (),
 it returns
 .BR PCAP_ERROR .
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_findalldevs.3pcap b/pcap_findalldevs.3pcap
index 712e255..41c98fe 100644
--- a/pcap_findalldevs.3pcap
+++ b/pcap_findalldevs.3pcap
@@ -17,7 +17,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_FINDALLDEVS 3PCAP "22 August 2018"
+.TH PCAP_FINDALLDEVS 3PCAP "23 August 2018"
 .SH NAME
 pcap_findalldevs, pcap_freealldevs \- get a list of capture devices, and
 free that list
@@ -38,21 +38,21 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_findalldevs()
+.BR pcap_findalldevs ()
 constructs a list of network devices that can be opened with
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
 and
-.B pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
 or with
-.BR pcap_open_live(3PCAP) .
+.BR pcap_open_live (3PCAP).
 (Note that there may be network devices that cannot be opened by the
 process calling
-.BR pcap_findalldevs() ,
+.BR pcap_findalldevs (),
 because, for example, that process does not have sufficient privileges
 to open them for capturing; if so, those devices will not appear on the
 list.)
 If
-.B pcap_findalldevs()
+.BR pcap_findalldevs ()
 succeeds, the pointer pointed to by
 .I alldevsp
 is set to point to the first element of the list, or to
@@ -72,7 +72,7 @@
 .TP
 .B name
 a pointer to a string giving a name for the device to pass to
-.B pcap_open_live()
+.BR pcap_open_live ()
 .TP
 .B description
 if not
@@ -194,12 +194,14 @@
 .BR "struct sockaddr_in6".
 .PP
 The list of devices must be freed with
-.BR pcap_freealldevs(3PCAP) ,
+.BR pcap_freealldevs (3PCAP),
 which frees the list pointed to by
 .IR alldevs .
 .SH RETURN VALUE
-.B pcap_findalldevs()
-returns 0 on success and
+.BR pcap_findalldevs ()
+returns
+.B 0
+on success and
 .B PCAP_ERROR
 on failure; as indicated, finding no
 devices is considered success, rather than failure, so 0 will be
@@ -228,4 +230,4 @@
 .B PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
 constants became available in libpcap release 1.9.0.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_freecode.3pcap b/pcap_freecode.3pcap
index 4e71efa..65915fa 100644
--- a/pcap_freecode.3pcap
+++ b/pcap_freecode.3pcap
@@ -31,13 +31,13 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_freecode()
+.BR pcap_freecode ()
 is used to free up allocated memory pointed to by a
 .I bpf_program
 struct generated by
-.B pcap_compile(3PCAP)
+.BR pcap_compile (3PCAP)
 when that BPF program is no longer needed, for example after it
 has been made the filter program for a pcap structure by a call to
-.BR pcap_setfilter(3PCAP) .
+.BR pcap_setfilter (3PCAP).
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_get_required_select_timeout.3pcap b/pcap_get_required_select_timeout.3pcap
index e58cb4e..0256a6a 100644
--- a/pcap_get_required_select_timeout.3pcap
+++ b/pcap_get_required_select_timeout.3pcap
@@ -17,10 +17,10 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_GET_REQUIRED_SELECT_TIMEOUT 3PCAP "25 July 2018"
+.TH PCAP_GET_REQUIRED_SELECT_TIMEOUT 3PCAP "29 January 2020"
 .SH NAME
-pcap_get_required_select_timeout \- get a file descriptor on which a
-select() can be done for a live capture
+pcap_get_required_select_timeout \- get a timeout to be used when doing
+select() for a live capture
 .SH SYNOPSIS
 .nf
 .ft B
@@ -28,53 +28,98 @@
 .ft
 .LP
 .ft B
-struct timeval *pcap_get_required_select_timeout(pcap_t *p);
+const struct timeval *pcap_get_required_select_timeout(pcap_t *p);
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_get_required_select_timeout()
+.BR pcap_get_required_select_timeout ()
 returns, on UNIX, a pointer to a
 .B struct timeval
 containing a value that must be used as the minimum timeout in
-.BR select(2) ,
-.BR poll(2) ,
-.BR epoll_wait(2) ,
+.BR select (2),
+.BR poll (2),
+.BR epoll_wait (2),
 and
-.B kevent()
-calls if
-.B pcap_get_selectable_fd(3PCAP)
+.BR kevent (2)
+calls, or
+.B NULL
+if there is no such timeout.
+If a
+.RB non- NULL
+value is returned, it must be used regardless of whether
+.BR pcap_get_selectable_fd (3PCAP)
 returns
-.BR PCAP_ERROR .
-.PP
-The timeout that should be used in those calls must be no larger than
-the smallest of all timeouts returned by
-.B \%pcap_get_required_select_timeout()
-for devices from which packets will be captured.
-.PP
-The device for which
-.B pcap_get_selectable_fd()
-returned
-.B PCAP_ERROR
-must be put in non-blocking mode with
-.BR pcap_setnonblock(3PCAP) ,
-and an attempt must always be made to read packets from the device
-when the
-.BR select() ,
-.BR poll() ,
-.BR epoll_wait() ,
+.B \-1
+for any descriptor on which those calls are being done.
+.BR pcap_get_required_select_timeout ()
+should be called for all
+.BR pcap_t s
+before a call to
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
 or
-.B kevent()
-call returns.
+.BR kevent (),
+and any timeouts used for those calls should be updated as appropriate
+given the new value of the timeout.
+.PP
+For
+.BR kevent (),
+one
+.B EVFILT_TIMER
+filter per selectable descriptor can be used, rather than using the
+timeout argument to
+.BR kevent ();
+if the
+.B EVFILT_TIMER
+event for a particular selectable descriptor signals an event,
+.BR pcap_dispatch (3PCAP)
+should be called for the corresponding
+.BR pcap_t .
+.PP
+On Linux systems with
+.BR timerfd_create (2),
+one timer object created by
+.BR timerfd_create ()
+per selectable descriptor can be used, rather than using the timeout
+argument to
+.BR epoll_wait ();
+if the
+timer object for a particular selectable descriptor signals an event,
+.BR pcap_dispatch (3PCAP)
+should be called for the corresponding
+.BR pcap_t .
+.PP
+Otherwise, a timeout value no larger than
+the smallest of all timeouts returned by
+.BR \%pcap_get_required_select_timeout ()
+for devices from which packets will be captured and any other timeouts
+to be used in the call should be used as the timeout for the call, and,
+when the call returns,
+.BR pcap_dispatch (3PCAP)
+should be called for all
+.BR pcap_t s
+for which a
+.RB non- NULL
+timeout was returned, regardless of whether it's indicated as having
+anything to read from it or not.
+.PP
+All devices with a
+.RB non- NULL
+timeout must be put in non-blocking mode with
+.BR pcap_setnonblock (3PCAP).
 .PP
 Note that a device on which a read can be done without blocking may,
 on some platforms, not have any packets to read if the packet buffer
 timeout has expired.  A call to
-.B pcap_dispatch(3PCAP)
+.BR pcap_dispatch ()
 or
-.B pcap_next_ex(3PCAP)
-will return 0 in this case, but will not block.
+.BR pcap_next_ex (3PCAP)
+will return
+.B 0
+in this case, but will not block.
 .PP
-.B pcap_get_required_select_timeout()
+.BR pcap_get_required_select_timeout ()
 is not available on Windows.
 .SH RETURN VALUE
 A pointer to a
@@ -85,14 +130,50 @@
 .SH BACKWARD COMPATIBILITY
 This function became available in libpcap release 1.9.0.  In previous
 releases,
-.BR select() ,
-.BR poll() ,
-.BR epoll_wait() ,
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
 and
-.B kevent()
+.BR kevent ()
 cannot be used on any capture source for which
-.B pcap_get_selectable_fd
-returns \-1.
+.BR pcap_get_selectable_fd ()
+returns
+.BR \-1 .
+.PP
+In libpcap release 1.10.0 and later, the timeout value can change from
+call to call, so
+.BR pcap_get_required_select_timeout ()
+must be called before each call to
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
+or
+.BR kevent (),
+and the new value must be used to calculate timeouts for the call.  Code
+that does that will also work with libpcap 1.9.x releases, so code
+using
+.BR pcap_get_required_select_timeout ()
+should be changed to call it for each call to
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
+or
+.BR kevent ()
+even if the code must also work with libpcap 1.9.x.
+.SH BACKWARD COMPATIBILITY
+This function became available in libpcap release 1.9.0.  In previous
+releases,
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
+and
+.BR kevent ()
+could not be used for devices that don't provide a selectable file
+descriptor.
 .SH SEE ALSO
-pcap(3PCAP), pcap_get_selectable_fd(3PCAP), select(2), poll(2),
-epoll_wait(2), kqueue(2)
+.BR pcap (3PCAP),
+.BR pcap_get_selectable_fd (3PCAP),
+.BR select (2),
+.BR poll (2),
+.BR epoll_wait (2),
+.BR kqueue (2)
diff --git a/pcap_get_selectable_fd.3pcap b/pcap_get_selectable_fd.3pcap
index 7f43db3..ed33303 100644
--- a/pcap_get_selectable_fd.3pcap
+++ b/pcap_get_selectable_fd.3pcap
@@ -17,7 +17,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_GET_SELECTABLE_FD 3PCAP "25 July 2018"
+.TH PCAP_GET_SELECTABLE_FD 3PCAP "29 January 2020"
 .SH NAME
 pcap_get_selectable_fd \- get a file descriptor on which a select() can
 be done for a live capture
@@ -32,42 +32,42 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_get_selectable_fd()
+.BR pcap_get_selectable_fd ()
 returns, on UNIX, a file descriptor number for a file descriptor on
 which one can
 do a
-.BR select(2) ,
-.BR poll(2) ,
-.BR epoll_wait(2) ,
-.BR kevent() ,
+.BR select (2),
+.BR poll (2),
+.BR epoll_wait (2),
+.BR kevent (2),
 or other such call
 to wait for it to be possible to read packets without blocking, if such
 a descriptor exists, or
-.BR PCAP_ERROR ,
+.BR \-1 ,
 if no such descriptor exists.
 .PP
 Some network devices opened with
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
 and
-.BR pcap_activate(3PCAP) ,
+.BR pcap_activate (3PCAP),
 or with
-.BR pcap_open_live(3PCAP) ,
+.BR pcap_open_live (3PCAP),
 do not support those calls (for example, regular network devices on
 FreeBSD 4.3 and 4.4, and Endace DAG devices), so
-.B PCAP_ERROR
+.B \-1
 is returned for
 those devices.  In that case, those calls must be given a timeout less
 than or equal to the timeout returned by
-.B pcap_get_required_select_timeout(3PCAP)
+.BR pcap_get_required_select_timeout (3PCAP)
 for the device for which
-.B pcap_get_selectable_fd()
+.BR pcap_get_selectable_fd ()
 returned
-.BR PCAP_ERROR ,
+.BR \-1 ,
 the device must be put in non-blocking mode with a call to
-.BR \%pcap_setnonblock(3PCAP) ,
+.BR \%pcap_setnonblock (3PCAP),
 and an attempt must always be made to read packets from the device
 when the call returns.  If
-.B \%pcap_get_required_select_timeout()
+.BR \%pcap_get_required_select_timeout ()
 returns
 .BR NULL ,
 it is not possible to wait for packets to arrive on the device in an
@@ -76,9 +76,9 @@
 Note that a device on which a read can be done without blocking may,
 on some platforms, not have any packets to read if the packet buffer
 timeout has expired.  A call to
-.B pcap_dispatch(3PCAP)
+.BR pcap_dispatch (3PCAP)
 or
-.B pcap_next_ex(3PCAP)
+.BR pcap_next_ex (3PCAP)
 will return 0 in this case, but will not block.
 .PP
 Note that in:
@@ -91,18 +91,18 @@
 .IP
 Mac OS X prior to Mac OS X 10.7;
 .PP
-.BR select() ,
-.BR poll() ,
+.BR select (),
+.BR poll (),
 and
-.B kevent()
+.BR kevent ()
 do not work correctly on BPF devices;
-.B pcap_get_selectable_fd()
+.BR pcap_get_selectable_fd ()
 will return a file descriptor on most of those versions (the exceptions
 being FreeBSD 4.3 and 4.4), but a simple
-.BR select() ,
-.BR poll() ,
+.BR select (),
+.BR poll (),
 or
-.B kevent()
+.BR kevent ()
 call will not indicate that the descriptor is readable until a full
 buffer's worth of packets is received, even if the packet timeout
 expires before then.  To work around this, code that uses
@@ -119,33 +119,34 @@
 although it does no harm.)
 .PP
 Note also that
-.B poll()
+.BR poll ()
 and
-.B kevent()
+.BR kevent ()
 doesn't work on character special files, including BPF devices, in Mac
 OS X 10.4 and 10.5, so, while
-.B select()
+.BR select ()
 can be used on the descriptor returned by
-.BR pcap_get_selectable_fd() ,
-.B poll()
+.BR pcap_get_selectable_fd (),
+.BR poll ()
 and
-.B kevent()
+.BR kevent ()
 cannot be used on it those versions of Mac OS X.
-.BR poll() ,
+.BR poll (),
 but not
-.BR kevent() ,
+.BR kevent (),
 works on that descriptor in Mac OS X releases prior to
 10.4;
-.B poll()
+.BR poll ()
 and
-.B kevent()
+.BR kevent ()
 work on that descriptor in Mac OS X 10.6 and later.
 .PP
-.B pcap_get_selectable_fd()
+.BR pcap_get_selectable_fd ()
 is not available on Windows.
 .SH RETURN VALUE
 A selectable file descriptor is returned if one exists; otherwise,
-.B PCAP_ERROR
+.B \-1
 is returned.
 .SH SEE ALSO
-pcap(3PCAP), kqueue(2)
+.BR pcap (3PCAP),
+.BR kqueue (2)
diff --git a/pcap_get_tstamp_precision.3pcap.in b/pcap_get_tstamp_precision.3pcap.in
index 2e72e0b..7dbb569 100644
--- a/pcap_get_tstamp_precision.3pcap.in
+++ b/pcap_get_tstamp_precision.3pcap.in
@@ -19,7 +19,7 @@
 .\"IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 .\"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
-.TH PCAP_GET_TSTAMP_PRECISION 3PCAP "18 December 2013"
+.TH PCAP_GET_TSTAMP_PRECISION 3PCAP "23 August 2018"
 .SH NAME
 pcap_get_tstamp_precision \- get the time stamp precision returned in
 captures
@@ -34,11 +34,11 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_get_tstamp_precision()
+.BR pcap_get_tstamp_precision ()
 returns the precision of the time stamp returned in packet captures on the pcap
 descriptor.
 .SH RETURN VALUE
-.B pcap_get_tstamp_precision()
+.BR pcap_get_tstamp_precision ()
 returns
 .B PCAP_TSTAMP_PRECISION_MICRO
 or
@@ -51,6 +51,6 @@
 releases, time stamps from a capture device or savefile are always given
 in seconds and microseconds.
 .SH SEE ALSO
-pcap(3PCAP),
-pcap_set_tstamp_precision(3PCAP),
-pcap-tstamp(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap_set_tstamp_precision (3PCAP),
+.BR pcap-tstamp (@MAN_MISC_INFO@)
diff --git a/pcap_geterr.3pcap b/pcap_geterr.3pcap
index ee681c8..72e23e3 100644
--- a/pcap_geterr.3pcap
+++ b/pcap_geterr.3pcap
@@ -32,7 +32,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_geterr()
+.BR pcap_geterr ()
 returns the error text pertaining to the last pcap library error.
 .BR NOTE :
 the pointer it returns will no longer point to a valid error message
@@ -42,10 +42,10 @@
 the
 .BR pcap_t .
 .PP
-.B pcap_perror()
+.BR pcap_perror ()
 prints the text of the last pcap library error on
 .BR stderr ,
 prefixed by
 .IR prefix .
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_init.3pcap b/pcap_init.3pcap
new file mode 100644
index 0000000..543f083
--- /dev/null
+++ b/pcap_init.3pcap
@@ -0,0 +1,99 @@
+.\" Copyright (c) 1994, 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.
+.\"
+.TH PCAP_INIT 3PCAP "11 April 2020"
+.SH NAME
+pcap_init \- initialize the library
+.SH SYNOPSIS
+.nf
+.ft B
+#include <pcap/pcap.h>
+.ft
+.LP
+.nf
+.ft B
+char errbuf[PCAP_ERRBUF_SIZE];
+.ft
+.LP
+.ft B
+int pcap_init(unsigned int opts, char *errbuf);
+.ft
+.fi
+.SH DESCRIPTION
+.BR pcap_init ()
+is used to initialize the Packet Capture library.
+.I opts
+specifies options for the library;
+currently, the options are:
+.TP
+.B PCAP_CHAR_ENC_LOCAL
+Treat all strings supplied as arguments, and return all strings to the
+caller, as being in the local character encoding.
+.TP
+.B PCAP_CHAR_ENC_UTF_8
+Treat all strings supplied as arguments, and return all strings to the
+caller, as being in UTF-8.
+.PP
+On UNIX-like systems, the local character encoding is assumed to be
+UTF-8, so no character encoding transformations are done.
+.PP
+On Windows, the local character encoding is the local ANSI code page.
+.PP
+If
+.BR pcap_init ()
+is not called, strings are treated as being in the local ANSI code page
+on Windows,
+.BR pcap_lookupdev (3PCAP)
+will succeed if there is a device on which to capture, and
+.BR pcap_create (3PCAP)
+makes an attempt to check whether the string passed as an argument is a
+UTF-16LE string - note that this attempt is unsafe, as it may run past
+the end of the string - to handle
+.BR pcap_lookupdev ()
+returning a UTF-16LE string. Programs that don't call
+.BR pcap_init ()
+should, on Windows, call
+.BR pcap_wsockinit ()
+to initialize Winsock; this is not necessary if
+.BR pcap_init ()
+is called, as
+.BR pcap_init ()
+will initialize Winsock itself on Windows.
+.SH RETURN VALUE
+.BR pcap_init ()
+returns
+.B 0
+on success and
+.B \-1
+on failure.
+If
+.B \-1
+is returned,
+.I errbuf
+is filled in with an appropriate error message.
+.I errbuf
+is assumed to be able to hold at least
+.B PCAP_ERRBUF_SIZE
+chars.
+.SH BACKWARD COMPATIBILITY
+This function became available in libpcap release 1.10.0.  In previous
+releases, on Windows, all strings supplied as arguments, and all strings
+returned to the caller, are in the local character encoding.
+.SH SEE ALSO
+.BR pcap (3PCAP)
diff --git a/pcap_inject.3pcap b/pcap_inject.3pcap
index 92a9263..6b4554e 100644
--- a/pcap_inject.3pcap
+++ b/pcap_inject.3pcap
@@ -32,7 +32,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_inject()
+.BR pcap_inject ()
 sends a raw packet through the network interface;
 .I buf
 points to the data of the packet, including the link-layer header, and
@@ -42,7 +42,7 @@
 Note that, even if you successfully open the network interface, you
 might not have permission to send packets on it, or it might not support
 sending packets; as
-.B pcap_open_live(3PCAP)
+.BR pcap_open_live (3PCAP)
 doesn't have a flag to indicate whether to open for capturing, sending,
 or capturing and sending, you cannot request an open that supports
 sending and be notified at open time whether sending will be possible.
@@ -51,7 +51,7 @@
 Note that, on some platforms, the link-layer header of the packet that's
 sent might not be the same as the link-layer header of the packet
 supplied to
-.BR pcap_inject() ,
+.BR pcap_inject (),
 as the source link-layer address, if the header contains such an
 address, might be changed to be the address assigned to the interface on
 which the packet it sent, if the platform doesn't support sending
@@ -61,34 +61,38 @@
 .I do
 nominally support sending completely raw and unchanged packets.
 .PP
-.B pcap_sendpacket()
+.BR pcap_sendpacket ()
 is like
-.BR pcap_inject() ,
-but it returns 0 on success, rather than returning the number of bytes
+.BR pcap_inject (),
+but it returns
+.B 0
+on success, rather than returning the number of bytes
 written.
-.RB ( pcap_inject()
+.RB ( pcap_inject ()
 comes from OpenBSD;
-.B pcap_sendpacket()
-comes from WinPcap.  Both are provided for compatibility.)
+.BR pcap_sendpacket ()
+comes from WinPcap/Npcap.  Both are provided for compatibility.)
 .SH RETURN VALUE
-.B pcap_inject()
+.BR pcap_inject ()
 returns the number of bytes written on success and
 .B PCAP_ERROR
 on failure.
 .PP
-.B pcap_sendpacket()
-returns 0 on success and
+.BR pcap_sendpacket ()
+returns
+.B 0
+on success and
 .B PCAP_ERROR
 on failure.
 .PP
 If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_is_swapped.3pcap b/pcap_is_swapped.3pcap
index 67f762f..260601a 100644
--- a/pcap_is_swapped.3pcap
+++ b/pcap_is_swapped.3pcap
@@ -31,21 +31,21 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_is_swapped()
-returns true (1) if
+.BR pcap_is_swapped ()
+returns true (\fB1\fP) if
 .I p
 refers to a ``savefile'' that uses a different byte order
 than the current system.  For a live capture, it always returns false
-(0).
+(\fB0\fP).
 .PP
 It must not be called on a pcap descriptor created by
-.B \%pcap_create(3PCAP)
+.BR \%pcap_create (3PCAP)
 that has not yet been activated by
-.BR \%pcap_activate(3PCAP) .
+.BR \%pcap_activate (3PCAP).
 .SH RETURN VALUE
-.B pcap_is_swapped()
-returns true (1) or false (0) on success and
+.BR pcap_is_swapped ()
+returns true (\fB1\fP) or false (\fB0\fP) on success and
 .B PCAP_ERROR_NOT_ACTIVATED
 if called on a capture handle that has been created but not activated.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_lib_version.3pcap b/pcap_lib_version.3pcap
index 4b86b2d..73ed2b8 100644
--- a/pcap_lib_version.3pcap
+++ b/pcap_lib_version.3pcap
@@ -31,9 +31,9 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_lib_version()
+.BR pcap_lib_version ()
 returns a pointer to a string giving information about the version of
 the libpcap library being used; note that it contains more information
 than just a version number.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_list_datalinks.3pcap.in b/pcap_list_datalinks.3pcap.in
index 60ba478..d6e3149 100644
--- a/pcap_list_datalinks.3pcap.in
+++ b/pcap_list_datalinks.3pcap.in
@@ -33,25 +33,25 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_list_datalinks()
+.BR pcap_list_datalinks ()
 is used to get a list of the supported link-layer header types of the
 interface associated with the pcap descriptor.
-.B pcap_list_datalinks()
+.BR pcap_list_datalinks ()
 allocates an array to hold the list and sets
 .IR *dlt_buf
 to point to that array.
 .LP
 The caller is responsible for freeing the array with
-.BR pcap_free_datalinks() ,
+.BR pcap_free_datalinks (),
 which frees the list of link-layer header types pointed to by
 .IR dlt_list .
 .LP
 It must not be called on a pcap descriptor created by
-.B \%pcap_create(3PCAP)
+.BR \%pcap_create (3PCAP)
 that has not yet been activated by
-.BR \%pcap_activate(3PCAP) .
+.BR \%pcap_activate (3PCAP).
 .SH RETURN VALUE
-.B pcap_list_datalinks()
+.BR pcap_list_datalinks ()
 returns the number of link-layer header types in the array on success,
 .B PCAP_ERROR_NOT_ACTIVATED
 if called on a capture handle that has been created but not activated,
@@ -61,13 +61,13 @@
 If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B \%pcap_perror(3PCAP)
+.BR \%pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
 .SH SEE ALSO
-pcap(3PCAP),
-pcap_datalink_val_to_name(3PCAP),
-pcap-linktype(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap_datalink_val_to_name (3PCAP),
+.BR pcap-linktype (@MAN_MISC_INFO@)
diff --git a/pcap_list_tstamp_types.3pcap.in b/pcap_list_tstamp_types.3pcap.in
index e2487f7..74ef00a 100644
--- a/pcap_list_tstamp_types.3pcap.in
+++ b/pcap_list_tstamp_types.3pcap.in
@@ -18,7 +18,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "22 August 2018"
+.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "8 September 2019"
 .SH NAME
 pcap_list_tstamp_types, pcap_free_tstamp_types \- get a list of time
 stamp types supported by a capture device, and free that list
@@ -34,10 +34,10 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_list_tstamp_types()
+.BR pcap_list_tstamp_types ()
 is used to get a list of the supported time stamp types of the interface
 associated with the pcap descriptor.
-.B pcap_list_tstamp_types()
+.BR pcap_list_tstamp_types ()
 allocates an array to hold the list and sets
 .I *tstamp_typesp
 to point to the array.
@@ -46,11 +46,11 @@
 for a list of all the time stamp types.
 .PP
 The caller is responsible for freeing the array with
-.BR pcap_free_tstamp_types() ,
+.BR pcap_free_tstamp_types (),
 which frees the list pointed to by
 .IR tstamp_types .
 .SH RETURN VALUE
-.B pcap_list_tstamp_types()
+.BR pcap_list_tstamp_types ()
 returns the number of time stamp types in the array on success and
 .B PCAP_ERROR
 on failure.
@@ -65,9 +65,9 @@
 If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
@@ -77,5 +77,6 @@
 releases, the time stamp type cannot be set; only the default time stamp
 type offered by a capture source is available.
 .SH SEE ALSO
-pcap(3PCAP), pcap_tstamp_type_val_to_name(3PCAP),
-pcap-tstamp(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap_tstamp_type_val_to_name (3PCAP),
+.BR pcap-tstamp (@MAN_MISC_INFO@)
diff --git a/pcap_lookupdev.3pcap b/pcap_lookupdev.3pcap
index 29f09e3..b5d548f 100644
--- a/pcap_lookupdev.3pcap
+++ b/pcap_lookupdev.3pcap
@@ -39,22 +39,30 @@
 .B This interface is obsoleted by
 .BR pcap_findalldevs (3PCAP).
 To find a default device on which to capture, call
-.B pcap_findalldevs()
+.BR pcap_findalldevs ()
 and, if the list it returns is not empty, use the first device in the
 list.  (If the list is empty, there are no devices on which capture is
 possible.)
 .LP
-.B pcap_lookupdev()
+.B If
+.BR pcap_init (3PCAP)
+.B has been called, this interface always returns
+.BR NULL .
+.LP
+.BR pcap_lookupdev ()
 returns a pointer to a string giving the name of a network device
 suitable for use with
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
 and
-.BR \%pcap_activate(3PCAP) ,
+.BR \%pcap_activate (3PCAP),
 or with
-.BR pcap_open_live(3PCAP) ,
+.BR pcap_open_live (3PCAP),
 and with
-.BR pcap_lookupnet(3PCAP) .
+.BR pcap_lookupnet (3PCAP).
 If there is an error,
+or if
+.BR pcap_init (3PCAP)
+has been called,
 .B NULL
 is returned and
 .I errbuf
@@ -64,16 +72,15 @@
 .B PCAP_ERRBUF_SIZE
 chars.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
 .SH BUGS
 The pointer returned by
-.B pcap_lookupdev()
+.BR pcap_lookupdev ()
 points to a static buffer; subsequent calls to
-.B pcap_lookupdev()
+.BR pcap_lookupdev ()
 in the same thread, or calls to
-.B pcap_lookupdev()
+.BR pcap_lookupdev ()
 in another thread, may overwrite that buffer.
 .LP
-In WinPcap, this function may return a UTF-16 string rather than an
-ASCII or UTF-8 string.
-
+In WinPcap and Npcap, this function may return a UTF-16 string rather
+than an ASCII or UTF-8 string.
diff --git a/pcap_lookupnet.3pcap b/pcap_lookupnet.3pcap
index f609445..c12fa55 100644
--- a/pcap_lookupnet.3pcap
+++ b/pcap_lookupnet.3pcap
@@ -38,7 +38,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_lookupnet()
+.BR pcap_lookupnet ()
 is used to determine the IPv4 network number and mask
 associated with the network device
 .IR device .
@@ -50,8 +50,10 @@
 .I bpf_u_int32
 pointers.
 .SH RETURN VALUE
-.B pcap_lookupnet()
-returns 0 on success and
+.BR pcap_lookupnet ()
+returns
+.B 0
+on success and
 .B PCAP_ERROR
 on failure. If
 .B PCAP_ERROR
@@ -63,4 +65,4 @@
 .B PCAP_ERRBUF_SIZE
 chars.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_loop.3pcap b/pcap_loop.3pcap
index 0193714..3d741ef 100644
--- a/pcap_loop.3pcap
+++ b/pcap_loop.3pcap
@@ -17,7 +17,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_LOOP 3PCAP "25 July 2018"
+.TH PCAP_LOOP 3PCAP "22 August 2020"
 .SH NAME
 pcap_loop, pcap_dispatch \- process packets from a live capture or savefile
 .SH SYNOPSIS
@@ -42,28 +42,32 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_loop()
+.BR pcap_loop ()
 processes packets from a live capture or ``savefile'' until
 .I cnt
 packets are processed, the end of the ``savefile'' is
 reached when reading from a ``savefile'',
-.B pcap_breakloop(3PCAP)
+.BR pcap_breakloop (3PCAP)
 is called, or an error occurs.
 It does
 .B not
 return when live packet buffer timeouts occur.
-A value of \-1 or 0 for
+A value of
+.B \-1
+or
+.B 0
+for
 .I cnt
 is equivalent to infinity, so that packets are processed until another
 ending condition occurs.
 .PP
-.B pcap_dispatch()
+.BR pcap_dispatch ()
 processes packets from a live capture or ``savefile'' until
 .I cnt
 packets are processed, the end of the current bufferful of packets is
 reached when doing a live capture, the end of the ``savefile'' is
 reached when reading from a ``savefile'',
-.B pcap_breakloop()
+.BR pcap_breakloop ()
 is called, or an error occurs.
 Thus, when doing a live capture,
 .I cnt
@@ -71,7 +75,11 @@
 a minimum number; when reading a live capture, only one
 bufferful of packets is read at a time, so fewer than
 .I cnt
-packets may be processed. A value of \-1 or 0 for
+packets may be processed. A value of
+.B \-1
+or
+.B 0
+for
 .I cnt
 causes all the packets received in one buffer to be processed when
 reading a live capture, and causes all the packets in the file to be
@@ -79,20 +87,11 @@
 .PP
 Note that, when doing a live capture on some platforms, if the read
 timeout expires when there are no packets available,
-.B pcap_dispatch()
+.BR pcap_dispatch ()
 will return 0, even when not in non-blocking mode, as there are no
 packets to process.  Applications should be prepared for this to happen,
 but must not rely on it happening.
 .PP
-.ft B
-(In older versions of libpcap, the behavior when
-\fIcnt\fP
-was 0 was undefined; different platforms and devices behaved
-differently, so code that must work with older versions of libpcap
-should use \-1, not 0, as the value of
-\fIcnt\fP.)
-.ft R
-.PP
 .I callback
 specifies a
 .I pcap_handler
@@ -102,9 +101,9 @@
 pointer which is passed in the
 .I user
 argument to
-.B pcap_loop()
+.BR pcap_loop ()
 or
-.BR pcap_dispatch() ,
+.BR pcap_dispatch (),
 a
 .I const struct pcap_pkthdr
 pointer pointing to the packet time stamp and lengths, and a
@@ -123,25 +122,25 @@
 .PP
 The bytes of data from the packet begin with a link-layer header.  The
 format of the link-layer header is indicated by the return value of the
-.B pcap_datalink(3PCAP)
+.BR pcap_datalink (3PCAP)
 routine when handed the
 .B pcap_t
 value also passed to
-.B pcap_loop()
+.BR pcap_loop ()
 or
-.BR pcap_dispatch() .
+.BR pcap_dispatch ().
 .I https://www.tcpdump.org/linktypes.html
 lists the values
-.B pcap_datalink()
+.BR pcap_datalink ()
 can return and describes the packet formats that
 correspond to those values.  The value it returns will be valid for all
 packets received unless and until
-.B pcap_set_datalink(3PCAP)
+.BR pcap_set_datalink (3PCAP)
 is called; after a successful call to
-.BR pcap_set_datalink() ,
+.BR pcap_set_datalink (),
 all subsequent packets will have a link-layer header of the type
 specified by the link-layer header type value passed to
-.BR pcap_set_datalink() .
+.BR pcap_set_datalink ().
 .PP
 Do
 .B NOT
@@ -151,13 +150,17 @@
 for Ethernet.  For example, the "any" device on Linux will have a
 link-layer header type of
 .B DLT_LINUX_SLL
+or
+.B DLT_LINUX_SLL2
 even if all devices on the system at the time the "any" device is opened
 have some other data link type, such as
 .B DLT_EN10MB
 for Ethernet.
 .SH RETURN VALUE
-.B pcap_loop()
-returns 0 if
+.BR pcap_loop ()
+returns
+.B 0
+if
 .I cnt
 is exhausted or if, when reading from a ``savefile'', no more packets
 are available.  It returns
@@ -165,14 +168,14 @@
 if an error occurs or
 .B PCAP_ERROR_BREAK
 if the loop terminated due to a call to
-.B pcap_breakloop()
+.BR pcap_breakloop ()
 before any packets were processed.
 It does
 .B not
 return when live packet buffer timeouts occur; instead, it attempts to
 read more packets.
 .PP
-.B pcap_dispatch()
+.BR pcap_dispatch ()
 returns the number of packets processed on success; this can be 0 if no
 packets were read from a live capture (if, for example, they were
 discarded because they didn't pass the packet filter, or if, on
@@ -185,7 +188,7 @@
 if an error occurs or
 .B PCAP_ERROR_BREAK
 if the loop terminated due to a call to
-.B pcap_breakloop()
+.BR pcap_breakloop ()
 before any packets were processed.
 .ft B
 If your application uses pcap_breakloop(),
@@ -196,11 +199,24 @@
 If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
+.SH BACKWARD COMPATIBILITY
+.PP
+In libpcap versions before 1.5.0, the behavior when
+.I cnt
+was
+.B 0
+was undefined; different platforms and devices behaved differently,
+so code that must work with these versions of libpcap should use
+.BR \-1 ,
+not
+.BR 0 ,
+as the value of
+.IR cnt .
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_major_version.3pcap b/pcap_major_version.3pcap
index 2fedfd2..393705b 100644
--- a/pcap_major_version.3pcap
+++ b/pcap_major_version.3pcap
@@ -35,9 +35,9 @@
 If
 .I p
 refers to a ``savefile'',
-.B pcap_major_version()
+.BR pcap_major_version ()
 returns the major number of the file format of the ``savefile'' and
-.B pcap_minor_version()
+.BR pcap_minor_version ()
 returns the minor number of the file format of the ``savefile''.  The
 version number is stored in the ``savefile''; note that the meaning of
 its values depends on the type of ``savefile'' (for example, pcap or
@@ -46,9 +46,9 @@
 If
 .I p
 refers to a live capture, the values returned by
-.B pcap_major_version()
+.BR pcap_major_version ()
 and
-.B pcap_minor_version()
+.BR pcap_minor_version ()
 are not meaningful.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_next_ex.3pcap b/pcap_next_ex.3pcap
index f0eb82d..2bd1a42 100644
--- a/pcap_next_ex.3pcap
+++ b/pcap_next_ex.3pcap
@@ -34,7 +34,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_next_ex()
+.BR pcap_next_ex ()
 reads the next packet and returns a success/failure indication.
 If the packet was read without problems, the pointer pointed to by the
 .I pkt_header
@@ -47,16 +47,16 @@
 .I struct pcap_pkthdr
 and the packet data are not to be freed by the caller, and are not
 guaranteed to be valid after the next call to
-.BR pcap_next_ex() ,
-.BR pcap_next() ,
-.BR pcap_loop(3PCAP) ,
+.BR pcap_next_ex (),
+.BR pcap_next (),
+.BR pcap_loop (3PCAP),
 or
-.BR pcap_dispatch(3PCAP) ;
+.BR pcap_dispatch (3PCAP);
 if the code needs them to remain valid, it must make a copy of them.
 .PP
-.B pcap_next()
+.BR pcap_next ()
 reads the next packet (by calling
-.B pcap_dispatch()
+.BR pcap_dispatch ()
 with a
 .I cnt
 of 1) and returns a
@@ -64,11 +64,11 @@
 pointer to the data in that packet.  The
 packet data is not to be freed by the caller, and is not
 guaranteed to be valid after the next call to
-.BR pcap_next_ex() ,
-.BR pcap_next() ,
-.BR pcap_loop() ,
+.BR pcap_next_ex (),
+.BR pcap_next (),
+.BR pcap_loop (),
 or
-.BR pcap_dispatch() ;
+.BR pcap_dispatch ();
 if the code needs it to remain valid, it must make a copy of it.
 The
 .I pcap_pkthdr
@@ -78,25 +78,25 @@
 .PP
 The bytes of data from the packet begin with a link-layer header.  The
 format of the link-layer header is indicated by the return value of the
-.B pcap_datalink(PCAP)
+.BR pcap_datalink (3PCAP)
 routine when handed the
 .B pcap_t
 value also passed to
-.B pcap_loop()
+.BR pcap_loop ()
 or
-.BR pcap_dispatch() .
+.BR pcap_dispatch ().
 .I https://www.tcpdump.org/linktypes.html
 lists the values
-.B pcap_datalink()
+.BR pcap_datalink ()
 can return and describes the packet formats that
 correspond to those values.  The value it returns will be valid for all
 packets received unless and until
-.B pcap_set_datalink(3PCAP)
+.BR pcap_set_datalink (3PCAP)
 is called; after a successful call to
-.BR pcap_set_datalink() ,
+.BR pcap_set_datalink (),
 all subsequent packets will have a link-layer header of the type
 specified by the link-layer header type value passed to
-.BR pcap_set_datalink() .
+.BR pcap_set_datalink ().
 .PP
 Do
 .B NOT
@@ -106,13 +106,19 @@
 for Ethernet.  For example, the "any" device on Linux will have a
 link-layer header type of
 .B DLT_LINUX_SLL
+or
+.B DLT_LINUX_SLL2
 even if all devices on the system at the time the "any" device is opened
 have some other data link type, such as
 .B DLT_EN10MB
 for Ethernet.
 .SH RETURN VALUE
-.B pcap_next_ex()
-returns 1 if the packet was read without problems, 0 if packets are
+.BR pcap_next_ex ()
+returns
+.B 1
+if the packet was read without problems,
+.B 0
+if packets are
 being read from a live capture and the packet buffer timeout expired,
 .B PCAP_ERROR
 if an error occurred while reading the packet, and
@@ -122,14 +128,14 @@
 from the savefile.  If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
 .PP
-.B pcap_next()
+.BR pcap_next ()
 returns a pointer to the packet data on success, and returns
 .B NULL
 if an error occurred, or if no packets were read from a live capture
@@ -141,4 +147,4 @@
 more packets are available in a ``savefile.'' Unfortunately, there is no
 way to determine whether an error occurred or not.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_offline_filter.3pcap b/pcap_offline_filter.3pcap
index 724f836..dbb6e96 100644
--- a/pcap_offline_filter.3pcap
+++ b/pcap_offline_filter.3pcap
@@ -33,13 +33,13 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_offline_filter()
+.BR pcap_offline_filter ()
 checks whether a filter matches a packet.
 .I fp
 is a pointer to a
 .I bpf_program
 struct, usually the result of a call to
-.BR pcap_compile(3PCAP) .
+.BR pcap_compile (3PCAP).
 .I h
 points to the
 .I pcap_pkthdr
@@ -47,9 +47,9 @@
 .I pkt
 points to the data in the packet.
 .SH RETURN VALUE
-.B pcap_offline_filter()
+.BR pcap_offline_filter ()
 returns the return value of the filter program.  This will be zero if
 the packet doesn't match the filter and non-zero if the packet matches
 the filter.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_open_dead.3pcap.in b/pcap_open_dead.3pcap.in
index 97a97f3..ced7d6c 100644
--- a/pcap_open_dead.3pcap.in
+++ b/pcap_open_dead.3pcap.in
@@ -35,18 +35,18 @@
 .fi
 .SH DESCRIPTION
 .PP
-.B pcap_open_dead()
+.BR pcap_open_dead ()
 and
-.B pcap_open_dead_with_tstamp_precision()
+.BR pcap_open_dead_with_tstamp_precision ()
 are used for creating a
 .B pcap_t
 structure to use when calling the other functions in libpcap.  It is
 typically used when just using libpcap for compiling BPF code; it can
 also be used if using
-.BR pcap_dump_open(3PCAP) ,
-.BR pcap_dump(3PCAP) ,
+.BR pcap_dump_open (3PCAP),
+.BR pcap_dump (3PCAP),
 and
-.B pcap_dump_close(3PCAP)
+.BR pcap_dump_close (3PCAP)
 to write a savefile if there is no
 .B pcap_t
 that supplies the packets to be written.
@@ -60,11 +60,11 @@
 .BR pcap_t .
 .PP
 When
-.BR pcap_open_dead_with_tstamp_precision() ,
+.BR pcap_open_dead_with_tstamp_precision (),
 is used to create a
 .B pcap_t
 for use with
-.BR pcap_dump_open() ,
+.BR pcap_dump_open (),
 .I precision
 specifies the time stamp precision for packets;
 .B PCAP_TSTAMP_PRECISION_MICRO
@@ -73,6 +73,13 @@
 .B PCAP_TSTAMP_PRECISION_NANO
 should be specified if the packets to be written have time stamps in
 seconds and nanoseconds.  Its value does not affect
-.BR pcap_compile(3PCAP) .
+.BR pcap_compile (3PCAP).
+.SH BACKWARD COMPATIBILITY
+The
+.BR pcap_open_dead_with_tstamp_precision ()
+function became available in libpcap release 1.5.1.  In previous
+releases, there was no mechanism to open a savefile for writing with
+time stamps given in seconds and nanoseconds.
 .SH SEE ALSO
-pcap(3PCAP), \%pcap-linktype(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR \%pcap-linktype (@MAN_MISC_INFO@)
diff --git a/pcap_open_live.3pcap b/pcap_open_live.3pcap
index 3286e29..b8c1729 100644
--- a/pcap_open_live.3pcap
+++ b/pcap_open_live.3pcap
@@ -38,7 +38,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_open_live()
+.BR pcap_open_live ()
 is used to obtain a packet capture handle to look
 at packets on the network.
 .I device
@@ -53,7 +53,10 @@
 specifies the snapshot length to be set on the handle.
 .PP
 .I promisc
-specifies if the interface is to be put into promiscuous mode.
+specifies whether the interface is to be put into promiscuous mode.
+If
+.I promisc
+is non-zero, promiscuous mode will be set, otherwise it will not be set.
 .PP
 .I to_ms
 specifies the packet buffer timeout, as a non-negative value, in
@@ -61,7 +64,7 @@
 .BR pcap (3PCAP)
 for an explanation of the packet buffer timeout.)
 .SH RETURN VALUE
-.B pcap_open_live()
+.BR pcap_open_live ()
 returns a
 .I pcap_t *
 on success and
@@ -74,11 +77,11 @@
 is filled in with an appropriate error message.
 .I errbuf
 may also be set to warning text when
-.B pcap_open_live()
+.BR pcap_open_live ()
 succeeds; to detect this case the caller should store a zero-length string in
 .I errbuf
 before calling
-.B pcap_open_live()
+.BR pcap_open_live ()
 and display the warning to the user if
 .I errbuf
 is no longer a zero-length string.
@@ -87,4 +90,5 @@
 .B PCAP_ERRBUF_SIZE
 chars.
 .SH SEE ALSO
-pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_open_offline.3pcap.in b/pcap_open_offline.3pcap.in
index 2bfbbac..5e878fe 100644
--- a/pcap_open_offline.3pcap.in
+++ b/pcap_open_offline.3pcap.in
@@ -17,7 +17,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_OPEN_OFFLINE 3PCAP "8 January 2018 "
+.TH PCAP_OPEN_OFFLINE 3PCAP "23 August 2018"
 .SH NAME
 pcap_open_offline, pcap_open_offline_with_tstamp_precision,
 pcap_fopen_offline, pcap_fopen_offline_with_tstamp_precision \- open a saved capture file for reading
@@ -42,9 +42,9 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_open_offline()
+.BR pcap_open_offline ()
 and
-.B pcap_open_offline_with_tstamp_precision()
+.BR pcap_open_offline_with_tstamp_precision ()
 are called to open a ``savefile'' for reading.
 .PP
 .I fname
@@ -60,7 +60,7 @@
 The name "-" is a synonym for
 .BR stdin .
 .PP
-.B pcap_open_offline_with_tstamp_precision()
+.BR pcap_open_offline_with_tstamp_precision ()
 takes an additional
 .I precision
 argument specifying the time stamp precision desired;
@@ -76,22 +76,22 @@
 necessary before being supplied.
 .PP
 Alternatively, you may call
-.B pcap_fopen_offline()
+.BR pcap_fopen_offline ()
 or
-.B pcap_fopen_offline_with_tstamp_precision()
+.BR pcap_fopen_offline_with_tstamp_precision ()
 to read dumped data from an existing open stream
 .IR fp .
-.B pcap_fopen_offline_with_tstamp_precision()
+.BR pcap_fopen_offline_with_tstamp_precision ()
 takes an additional
 .I precision
 argument as described above.
 Note that on Windows, that stream should be opened in binary mode.
 .SH RETURN VALUE
-.BR pcap_open_offline() ,
-.BR pcap_open_offline_with_tstamp_precision() ,
-.BR pcap_fopen_offline() ,
+.BR pcap_open_offline (),
+.BR pcap_open_offline_with_tstamp_precision (),
+.BR pcap_fopen_offline (),
 and
-.B pcap_fopen_offline_with_tstamp_precision()
+.BR pcap_fopen_offline_with_tstamp_precision ()
 return a
 .I pcap_t *
 on success and
@@ -107,10 +107,11 @@
 .B PCAP_ERRBUF_SIZE
 chars.
 .SH BACKWARD COMPATIBILITY
-.B pcap_open_offline_with_tstamp_precision
+.BR pcap_open_offline_with_tstamp_precision ()
 and
-.B pcap_fopen_offline_with_tstamp_precision
+.BR pcap_fopen_offline_with_tstamp_precision ()
 became available in libpcap release 1.5.1.  In previous releases, time
 stamps from a savefile are always given in seconds and microseconds.
 .SH SEE ALSO
-pcap(3PCAP), pcap-savefile(@MAN_FILE_FORMATS@)
+.BR pcap (3PCAP),
+.BR pcap-savefile (@MAN_FILE_FORMATS@)
diff --git a/pcap_set_buffer_size.3pcap b/pcap_set_buffer_size.3pcap
index 684f739..49492c0 100644
--- a/pcap_set_buffer_size.3pcap
+++ b/pcap_set_buffer_size.3pcap
@@ -31,15 +31,19 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_set_buffer_size()
+.BR pcap_set_buffer_size ()
 sets the buffer size that will be used on a capture handle when
 the handle is activated to
 .IR buffer_size ,
 which is in units of bytes.
 .SH RETURN VALUE
-.B pcap_set_buffer_size()
-returns 0 on success or
+.BR pcap_set_buffer_size ()
+returns
+.B 0
+on success or
 .B PCAP_ERROR_ACTIVATED
 if called on a capture handle that has been activated.
 .SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_datalink.3pcap b/pcap_set_datalink.3pcap
index 66cfdb1..14e9d20 100644
--- a/pcap_set_datalink.3pcap
+++ b/pcap_set_datalink.3pcap
@@ -32,22 +32,25 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_set_datalink()
+.BR pcap_set_datalink ()
 is used to set the current link-layer header type of the pcap descriptor
 to the type specified by
 .IR dlt .
 .SH RETURN VALUE
-.B pcap_set_datalink()
-returns 0 on success and
+.BR pcap_set_datalink ()
+returns
+.B 0
+on success and
 .B PCAP_ERROR
 on failure. If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
 .SH SEE ALSO
-pcap(3PCAP), pcap_datalink_name_to_val(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_datalink_name_to_val (3PCAP)
diff --git a/pcap_set_immediate_mode.3pcap.in b/pcap_set_immediate_mode.3pcap.in
index 2fe45c5..e493d55 100644
--- a/pcap_set_immediate_mode.3pcap.in
+++ b/pcap_set_immediate_mode.3pcap.in
@@ -18,7 +18,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_SET_IMMEDIATE_MODE 3PCAP "22 August 2018"
+.TH PCAP_SET_IMMEDIATE_MODE 3PCAP "23 August 2018"
 .SH NAME
 pcap_set_immediate_mode \- set immediate mode for a not-yet-activated capture
 handle
@@ -32,7 +32,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_set_immediate_mode()
+.BR pcap_set_immediate_mode ()
 sets whether immediate mode should be set on a capture handle when
 the handle is activated.  In immediate mode, packets are always
 delivered as soon as they arrive, with no buffering.
@@ -40,8 +40,10 @@
 .I immediate_mode
 is non-zero, immediate mode will be set, otherwise it will not be set.
 .SH RETURN VALUE
-.B pcap_set_immediate_mode()
-returns 0 on success or
+.BR pcap_set_immediate_mode ()
+returns
+.B 0
+on success or
 .B PCAP_ERROR_ACTIVATED
 if called on a capture handle that has been activated.
 .SH BACKWARD COMPATIBILITY
@@ -54,11 +56,11 @@
 .B BIOCIMMEDIATE
 .BR ioctl (2),
 as documented in
-.BR bpf(@MAN_DEVICES@) ,
+.BR bpf (@MAN_DEVICES@),
 on the descriptor returned by
-.B pcap_fileno(3PCAP),
+.BR pcap_fileno (3PCAP),
 after
-.BR pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
 is called;
 .IP
 on Solaris 10 and earlier versions of Solaris, immediate mode must be
@@ -70,26 +72,28 @@
 .B BIOCMBIC
 .BR ioctl ,
 as documented in
-.BR packetfilter(7) ,
+.BR packetfilter (7),
 to clear the
 .B ENBATCH
 flag on the descriptor returned by
-.B pcap_fileno(3PCAP),
+.BR pcap_fileno (3PCAP),
 after
-.BR pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
 is called;
 .IP
 on Windows, immediate mode must be turned on by calling
-.B pcap_setmintocopy()
+.BR pcap_setmintocopy ()
 with a size of 0.
 .PP
 On Linux, with previous releases of libpcap, capture devices are always
 in immediate mode; however, in 1.5.0 and later, they are, by default,
 .B not
 in immediate mode, so if
-.B pcap_set_immediate_mode()
+.BR pcap_set_immediate_mode ()
 is available, it should be used.
 .PP
 On other platforms, capture devices are always in immediate mode.
 .SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_promisc.3pcap b/pcap_set_promisc.3pcap
index fcd797a..cfc6cdd 100644
--- a/pcap_set_promisc.3pcap
+++ b/pcap_set_promisc.3pcap
@@ -31,16 +31,20 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_set_promisc()
+.BR pcap_set_promisc ()
 sets whether promiscuous mode should be set on a capture handle when
 the handle is activated.
 If
 .I promisc
 is non-zero, promiscuous mode will be set, otherwise it will not be set.
 .SH RETURN VALUE
-.B pcap_set_promisc()
-returns 0 on success or
+.BR pcap_set_promisc ()
+returns
+.B 0
+on success or
 .B PCAP_ERROR_ACTIVATED
 if called on a capture handle that has been activated.
 .SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_protocol_linux.3pcap b/pcap_set_protocol_linux.3pcap
index 873017b..a891d74 100644
--- a/pcap_set_protocol_linux.3pcap
+++ b/pcap_set_protocol_linux.3pcap
@@ -17,7 +17,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_SET_PROTOCOL_LINUX 3PCAP "24 August 2017"
+.TH PCAP_SET_PROTOCOL_LINUX 3PCAP "22 August 2018"
 .SH NAME
 pcap_set_protocol_linux \- set capture protocol for a not-yet-activated
 capture handle
@@ -32,7 +32,7 @@
 .fi
 .SH DESCRIPTION
 On network interface devices on Linux,
-.B pcap_set_protocol_linux()
+.BR pcap_set_protocol_linux ()
 sets the protocol to be used in the
 .BR socket (2)
 call to create a capture socket when the handle is activated.  The
@@ -48,21 +48,25 @@
 .LP
 It should not be used in portable code; instead, a filter should be
 specified with
-.BR pcap_setfilter(3PCAP) .
+.BR pcap_setfilter (3PCAP).
 .LP
 If a given network interface provides a standard link-layer header, with
 a standard packet type, but provides some packet types with a different
 socket-layer protocol type from the one in the link-layer header, that
 packet type cannot be filtered with a filter specified with
-.B pcap_setfilter()
+.BR pcap_setfilter ()
 but can be filtered by specifying the socket-layer protocol type using
-.BR pcap_set_protocol_linux() .
+.BR pcap_set_protocol_linux ().
 .SH RETURN VALUE
-.B pcap_set_protocol_linux()
-returns 0 on success or
+.BR pcap_set_protocol_linux ()
+returns
+.B 0
+on success or
 .B PCAP_ERROR_ACTIVATED
 if called on a capture handle that has been activated.
 .SH BACKWARD COMPATIBILITY
 This function became available in libpcap release 1.9.0.
 .SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_rfmon.3pcap b/pcap_set_rfmon.3pcap
index 691518a..2b104c2 100644
--- a/pcap_set_rfmon.3pcap
+++ b/pcap_set_rfmon.3pcap
@@ -31,17 +31,21 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_set_rfmon()
+.BR pcap_set_rfmon ()
 sets whether monitor mode should be set on a capture handle when
 the handle is activated.
 If
 .I rfmon
 is non-zero, monitor mode will be set, otherwise it will not be set.
 .SH RETURN VALUE
-.B pcap_set_rfmon()
-returns 0 on success or
+.BR pcap_set_rfmon ()
+returns
+.B 0
+on success or
 .B PCAP_ERROR_ACTIVATED
 if called on a capture handle that has been activated.
 .SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP),
-pcap_can_set_rfmon(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP),
+.BR pcap_can_set_rfmon (3PCAP)
diff --git a/pcap_set_snaplen.3pcap b/pcap_set_snaplen.3pcap
index 44eb154..e3acff1 100644
--- a/pcap_set_snaplen.3pcap
+++ b/pcap_set_snaplen.3pcap
@@ -31,14 +31,18 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_set_snaplen()
+.BR pcap_set_snaplen ()
 sets the snapshot length to be used on a capture handle when the handle
 is activated to
 .IR snaplen .
 .SH RETURN VALUE
-.B pcap_set_snaplen()
-returns 0 on success or
+.BR pcap_set_snaplen ()
+returns
+.B 0
+on success or
 .B PCAP_ERROR_ACTIVATED
 if called on a capture handle that has been activated.
 .SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_timeout.3pcap b/pcap_set_timeout.3pcap
index e67b813..d909b2c 100644
--- a/pcap_set_timeout.3pcap
+++ b/pcap_set_timeout.3pcap
@@ -31,7 +31,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_set_timeout()
+.BR pcap_set_timeout ()
 sets the packet buffer timeout that will be used on a capture handle
 when the handle is activated to
 .IR to_ms ,
@@ -44,10 +44,13 @@
 recommend always setting the timeout to a non-zero value unless
 immediate mode is set, in which case the timeout has no effect.
 .SH RETURN VALUE
-.B pcap_set_timeout()
-returns 0 on success or
+.BR pcap_set_timeout ()
+returns
+.B 0
+on success or
 .B PCAP_ERROR_ACTIVATED
 if called on a capture handle that has been activated.
 .SH SEE ALSO
-pcap_create(3PCAP), pcap_activate(3PCAP),
-\%pcap_set_immediate_mode(3PCAP)
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP),
+.BR \%pcap_set_immediate_mode (3PCAP)
diff --git a/pcap_set_tstamp_precision.3pcap.in b/pcap_set_tstamp_precision.3pcap.in
index dc2b4b3..eb449d5 100644
--- a/pcap_set_tstamp_precision.3pcap.in
+++ b/pcap_set_tstamp_precision.3pcap.in
@@ -19,7 +19,7 @@
 .\"IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 .\"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
-.TH PCAP_SET_TSTAMP_PRECISION 3PCAP "5 February 2015"
+.TH PCAP_SET_TSTAMP_PRECISION 3PCAP "23 August 2018"
 .SH NAME
 pcap_set_tstamp_precision \- set the time stamp precision returned in
 captures
@@ -34,22 +34,24 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_set_tstamp_precision()
+.BR pcap_set_tstamp_precision ()
 sets the precision of the time stamp desired for packets captured on the pcap
 descriptor to the type specified by
 .IR tstamp_precision .
 It must be called on a pcap descriptor created by
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
 that has not yet been activated by
-.BR pcap_activate(3PCAP) .
+.BR pcap_activate (3PCAP).
 Two time stamp precisions are supported, microseconds and nanoseconds. One can
 use options
 .B PCAP_TSTAMP_PRECISION_MICRO and
 .B PCAP_TSTAMP_PRECISION_NANO
 to request desired precision. By default, time stamps are in microseconds.
 .SH RETURN VALUE
-.B pcap_set_tstamp_precision()
-returns 0 on success if the specified time stamp precision is expected to be
+.BR pcap_set_tstamp_precision ()
+returns
+.B 0
+on success if the specified time stamp precision is expected to be
 supported by the capture device,
 .B PCAP_ERROR_TSTAMP_PRECISION_NOTSUP
 if the capture device does not support the requested time stamp
@@ -61,6 +63,6 @@
 releases, time stamps from a capture device or savefile are always given
 in seconds and microseconds.
 .SH SEE ALSO
-pcap(3PCAP),
-pcap_get_tstamp_precision(3PCAP),
-pcap-tstamp(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap_get_tstamp_precision (3PCAP),
+.BR pcap-tstamp (@MAN_MISC_INFO@)
diff --git a/pcap_set_tstamp_type.3pcap.in b/pcap_set_tstamp_type.3pcap.in
index 9833f46..e19d6e5 100644
--- a/pcap_set_tstamp_type.3pcap.in
+++ b/pcap_set_tstamp_type.3pcap.in
@@ -18,7 +18,7 @@
 .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 .\"
-.TH PCAP_SET_TSTAMP_TYPE 3PCAP "22 August 2018"
+.TH PCAP_SET_TSTAMP_TYPE 3PCAP "8 September 2019"
 .SH NAME
 pcap_set_tstamp_type \- set the time stamp type to be used by a
 capture device
@@ -33,23 +33,25 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_set_tstamp_type()
+.BR pcap_set_tstamp_type ()
 sets the type of time stamp desired for packets captured on the pcap
 descriptor to the type specified by
 .IR tstamp_type .
 It must be called on a pcap descriptor created by
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
 that has not yet been activated by
-.BR pcap_activate(3PCAP) .
-.B pcap_list_tstamp_types(3PCAP)
+.BR pcap_activate (3PCAP).
+.BR pcap_list_tstamp_types (3PCAP)
 will give a list of the time stamp types supported by a given capture
 device.
 See
 .BR pcap-tstamp (@MAN_MISC_INFO@)
 for a list of all the time stamp types.
 .SH RETURN VALUE
-.B pcap_set_tstamp_type()
-returns 0 on success if the specified time stamp type is expected to be
+.BR pcap_set_tstamp_type ()
+returns
+.B 0
+on success if the specified time stamp type is expected to be
 supported by the capture device,
 .B PCAP_WARNING_TSTAMP_TYPE_NOTSUP
 if the specified time stamp type is not supported by the
@@ -66,5 +68,5 @@
 releases, the time stamp type cannot be set; only the default time stamp
 type offered by a capture source is available.
 .SH SEE ALSO
-pcap(3PCAP),
-pcap_tstamp_type_name_to_val(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_tstamp_type_name_to_val (3PCAP)
diff --git a/pcap_setdirection.3pcap b/pcap_setdirection.3pcap
index f174b98..7b38845 100644
--- a/pcap_setdirection.3pcap
+++ b/pcap_setdirection.3pcap
@@ -31,7 +31,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_setdirection()
+.BR pcap_setdirection ()
 is used to specify a direction that packets will be captured.
 .I d
 is one of the constants
@@ -48,7 +48,7 @@
 .B PCAP_D_INOUT
 is the default setting if this function is not called.
 .PP
-.B pcap_setdirection()
+.BR pcap_setdirection ()
 isn't necessarily fully supported on all platforms; some platforms might
 return an error for all values, and some other platforms might not
 support
@@ -56,17 +56,19 @@
 .PP
 This operation is not supported if a ``savefile'' is being read.
 .SH RETURN VALUE
-.B pcap_setdirection()
-returns 0 on success and
+.BR pcap_setdirection ()
+returns
+.B 0
+on success and
 .B PCAP_ERROR
 on failure. If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_setfilter.3pcap b/pcap_setfilter.3pcap
index 8729693..1e3c5a5 100644
--- a/pcap_setfilter.3pcap
+++ b/pcap_setfilter.3pcap
@@ -31,25 +31,27 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_setfilter()
+.BR pcap_setfilter ()
 is used to specify a filter program.
 .I fp
 is a pointer to a
 .I bpf_program
 struct, usually the result of a call to
-.BR \%pcap_compile(3PCAP) .
+.BR \%pcap_compile (3PCAP).
 .SH RETURN VALUE
-.B pcap_setfilter()
-returns 0 on success and
+.BR pcap_setfilter ()
+returns
+.B 0
+on success and
 .B PCAP_ERROR
 on failure. If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_setnonblock.3pcap b/pcap_setnonblock.3pcap
index e8adebe..65cfea2 100644
--- a/pcap_setnonblock.3pcap
+++ b/pcap_setnonblock.3pcap
@@ -38,7 +38,7 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_setnonblock()
+.BR pcap_setnonblock ()
 puts a capture handle into ``non-blocking'' mode, or takes it out
 of ``non-blocking'' mode, depending on whether the
 .I nonblock
@@ -47,30 +47,46 @@
 .B PCAP_ERROR
 is returned and
 .I errbuf
-is filled in with an appropriate error message; otherwise, 0 is
-returned.
+is filled in with an appropriate error message; otherwise,
+.B 0
+is returned.
+.PP
 In
 ``non-blocking'' mode, an attempt to read from the capture descriptor
 with
-.B pcap_dispatch(3PCAP)
-will, if no packets are currently available to be read, return 0
-immediately rather than blocking waiting for packets to arrive.
-.B pcap_loop(3PCAP)
+.BR pcap_dispatch (3PCAP)
 and
-.B pcap_next(3PCAP)
-will not work in ``non-blocking'' mode.
+.BR pcap_next_ex (3PCAP)
+will, if no packets are currently available to be read, return
+.B 0
+immediately rather than blocking waiting for packets to arrive.
+.PP
+.BR pcap_loop (3PCAP)
+will loop forever, consuming CPU time when no packets are currently
+available;
+.BR pacp_dispatch ()
+should be used instead.
+.BR pcap_next (3PCAP)
+will return
+.B NULL
+if there are no packets currently available to read;
+this is indistinguishable from an error, so
+.BR pcap_next_ex ()
+should be used instead.
 .PP
 When first activated with
-.B pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
 or opened with
-.B pcap_open_live(3PCAP) ,
+.BR pcap_open_live (3PCAP) ,
 a capture handle is not in ``non-blocking mode''; a call to
-.B pcap_setnonblock()
+.BR pcap_setnonblock ()
 is required in order to put it into ``non-blocking'' mode.
 .SH RETURN VALUE
-.B pcap_getnonblock()
+.BR pcap_getnonblock ()
 returns the current ``non-blocking'' state of the capture descriptor; it
-always returns 0 on ``savefiles''.
+always returns
+.B 0
+on ``savefiles''.
 If there is an error,
 .B PCAP_ERROR
 is returned and
@@ -82,4 +98,6 @@
 .B PCAP_ERRBUF_SIZE
 chars.
 .SH SEE ALSO
-pcap(3PCAP), pcap_next_ex(3PCAP), pcap_geterr(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_next_ex (3PCAP),
+.BR pcap_geterr (3PCAP)
diff --git a/pcap_snapshot.3pcap b/pcap_snapshot.3pcap
index ee54bb0..25f6e03 100644
--- a/pcap_snapshot.3pcap
+++ b/pcap_snapshot.3pcap
@@ -31,22 +31,22 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_snapshot()
+.BR pcap_snapshot ()
 returns the snapshot length specified when
-.B pcap_set_snaplen(3PCAP)
+.BR pcap_set_snaplen (3PCAP)
 or
-.B pcap_open_live(3PCAP)
+.BR pcap_open_live (3PCAP)
 was called, for a live capture, or the snapshot length from the capture
 file, for a ``savefile''.
 .PP
 It must not be called on a pcap descriptor created by
-.B \%pcap_create(3PCAP)
+.BR \%pcap_create (3PCAP)
 that has not yet been activated by
-.BR \%pcap_activate(3PCAP) .
+.BR \%pcap_activate (3PCAP).
 .SH RETURN VALUE
-.B pcap_snapshot()
+.BR pcap_snapshot ()
 returns the snapshot length on success and
 .B PCAP_ERROR_NOT_ACTIVATED
 if called on a capture handle that has been created but not activated.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_stats.3pcap b/pcap_stats.3pcap
index 465dada..aa03013 100644
--- a/pcap_stats.3pcap
+++ b/pcap_stats.3pcap
@@ -31,13 +31,13 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_stats()
+.BR pcap_stats ()
 fills in the
 .B struct pcap_stat
 pointed to by its second argument.  The values represent
 packet statistics from the start of the run to the time of the call.
 .PP
-.B pcap_stats()
+.BR pcap_stats ()
 is supported only on live captures, not on ``savefiles''; no statistics
 are stored in ``savefiles'', so no statistics are available when reading
 from a ``savefile''.
@@ -82,19 +82,21 @@
 statistic is unavailable, so it should not be treated as an indication
 that the interface did not drop any packets.
 .SH RETURN VALUE
-.B pcap_stats()
-returns 0 on success and returns
+.BR pcap_stats ()
+returns
+.B 0
+on success and returns
 .B PCAP_ERROR
 if there is an error or if
 .I p
 doesn't support packet statistics. If
 .B PCAP_ERROR
 is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
 or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
 may be called with
 .I p
 as an argument to fetch or display the error text.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_statustostr.3pcap b/pcap_statustostr.3pcap
index 9c2057a..c679e36 100644
--- a/pcap_statustostr.3pcap
+++ b/pcap_statustostr.3pcap
@@ -31,11 +31,11 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_statustostr()
+.BR pcap_statustostr ()
 converts a
 .B PCAP_ERROR_
 or
 .B PCAP_WARNING_
 value returned by a libpcap routine to an error string.
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_strerror.3pcap b/pcap_strerror.3pcap
index a5775f4..dedfa40 100644
--- a/pcap_strerror.3pcap
+++ b/pcap_strerror.3pcap
@@ -31,10 +31,10 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_strerror()
+.BR pcap_strerror ()
 is provided in case
 .BR strerror (3)
 isn't available.  It returns an error message string corresponding to
 .IR error .
 .SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_tstamp_type_name_to_val.3pcap b/pcap_tstamp_type_name_to_val.3pcap
index fdcc6c6..f60516e 100644
--- a/pcap_tstamp_type_name_to_val.3pcap
+++ b/pcap_tstamp_type_name_to_val.3pcap
@@ -33,11 +33,11 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_tstamp_type_name_to_val()
+.BR pcap_tstamp_type_name_to_val ()
 translates a time stamp type name to the corresponding time stamp type
 value.  The translation is case-insensitive.
 .SH RETURN VALUE
-.B pcap_tstamp_type_name_to_val()
+.BR pcap_tstamp_type_name_to_val ()
 returns time stamp type value on success and
 .B PCAP_ERROR
 on failure.
@@ -45,4 +45,5 @@
 .PP
 This function became available in libpcap release 1.2.1.
 .SH SEE ALSO
-pcap(3PCAP), pcap_tstamp_type_val_to_name(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_tstamp_type_val_to_name (3PCAP)
diff --git a/pcap_tstamp_type_val_to_name.3pcap b/pcap_tstamp_type_val_to_name.3pcap
index 9374f48..5958e81 100644
--- a/pcap_tstamp_type_val_to_name.3pcap
+++ b/pcap_tstamp_type_val_to_name.3pcap
@@ -34,13 +34,13 @@
 .ft
 .fi
 .SH DESCRIPTION
-.B pcap_tstamp_type_val_to_name()
+.BR pcap_tstamp_type_val_to_name ()
 translates a time stamp type value to the corresponding time stamp type
 name.
 .B NULL
 is returned on failure.
 .PP
-.B pcap_tstamp_type_val_to_description()
+.BR pcap_tstamp_type_val_to_description ()
 translates a time stamp type value to a short description of that time
 stamp type.
 .B NULL
@@ -49,4 +49,5 @@
 .PP
 These functions became available in libpcap release 1.2.1.
 .SH SEE ALSO
-pcap(3PCAP), pcap_tstamp_type_name_to_val(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_tstamp_type_name_to_val (3PCAP)
diff --git a/portability.h b/portability.h
index 543846e..d606368 100644
--- a/portability.h
+++ b/portability.h
@@ -52,7 +52,7 @@
   #if defined(_MSC_VER) || defined(__MINGW32__)
     /*
      * strncat_s() is supported at least back to Visual
-     * Studio 2005.
+     * Studio 2005; we require Visual Studio 2015 or later.
      */
     #define pcap_strlcat(x, y, z) \
 	strncat_s((x), (z), (y), _TRUNCATE)
@@ -70,7 +70,7 @@
   #if defined(_MSC_VER) || defined(__MINGW32__)
     /*
      * strncpy_s() is supported at least back to Visual
-     * Studio 2005.
+     * Studio 2005; we require Visual Studio 2015 or later.
      */
     #define pcap_strlcpy(x, y, z) \
 	strncpy_s((x), (z), (y), _TRUNCATE)
@@ -83,8 +83,6 @@
 #endif
 
 #ifdef _MSC_VER
-  #define isascii	__isascii
-
   /*
    * If <crtdbg.h> has been included, and _DEBUG is defined, and
    * __STDC__ is zero, <crtdbg.h> will define strdup() to call
@@ -97,43 +95,9 @@
 #endif
 
 /*
- * On Windows, snprintf(), with that name and with C99 behavior - i.e.,
- * guaranteeing that the formatted string is null-terminated - didn't
- * appear until Visual Studio 2015.  Prior to that, the C runtime had
- * only _snprintf(), which *doesn't* guarantee that the string is
- * null-terminated if it is truncated due to the buffer being too
- * small.  We therefore can't just define snprintf to be _snprintf
- * and define vsnprintf to be _vsnprintf, as we're relying on null-
- * termination of strings in all cases.
- *
- * We also want to allow this to be built with versions of Visual Studio
- * prior to VS 2015, so we can't rely on snprintf() being present.
- *
- * And we want to make sure that, if we support plugins in the future,
- * a routine with C99 snprintf() behavior will be available to them.
- * We also don't want it to collide with the C library snprintf() if
- * there is one.
- *
- * So we make pcap_snprintf() and pcap_vsnprintf() available, either by
- * #defining them to be snprintf or vsnprintf, respectively, or by
- * defining our own versions and exporting them.
- */
-#ifdef HAVE_SNPRINTF
-#define pcap_snprintf snprintf
-#else
-extern int pcap_snprintf(char *, size_t, PCAP_FORMAT_STRING(const char *), ...)
-    PCAP_PRINTFLIKE(3, 4);
-#endif
-
-#ifdef HAVE_VSNPRINTF
-#define pcap_vsnprintf vsnprintf
-#else
-extern int pcap_vsnprintf(char *, size_t, const char *, va_list ap);
-#endif
-
-/*
- * We also want asprintf(), for some cases where we use it to construct
- * dynamically-allocated variable-length strings.
+ * 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
diff --git a/rpcap-protocol.c b/rpcap-protocol.c
index 692f7c5..0cdc0ba 100644
--- a/rpcap-protocol.c
+++ b/rpcap-protocol.c
@@ -61,6 +61,8 @@
  *
  * \param sock: the socket we are currently using.
  *
+ * \param ssl: if compiled with openssl, the optional ssl handler to use with the above socket.
+ *
  * \param ver: the protocol version we want to put in the reply.
  *
  * \param errcode: a integer which tells the other party the type of error
@@ -78,7 +80,7 @@
  * error message is returned in the 'errbuf' variable.
  */
 int
-rpcap_senderror(SOCKET sock, uint8 ver, unsigned short errcode, const char *error, char *errbuf)
+rpcap_senderror(SOCKET sock, SSL *ssl, uint8 ver, unsigned short errcode, const char *error, char *errbuf)
 {
 	char sendbuf[RPCAP_NETBUF_SIZE];	/* temporary buffer in which data to be sent is buffered */
 	int sendbufidx = 0;			/* index which keeps the number of bytes currently buffered */
@@ -99,7 +101,7 @@
 		RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
 		return -1;
 
-	if (sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0)
+	if (sock_send(sock, ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0)
 		return -1;
 
 	return 0;
diff --git a/rpcap-protocol.h b/rpcap-protocol.h
index 8ae8b62..a69cf80 100644
--- a/rpcap-protocol.h
+++ b/rpcap-protocol.h
@@ -259,7 +259,7 @@
 struct rpcap_openreply
 {
 	int32 linktype;	/* Link type */
-	int32 tzoff;	/* Timezone offset */
+	int32 tzoff;	/* Timezone offset - not used by newer clients */
 };
 
 /* Format of the message that starts a remote capture (startcap command) */
@@ -287,10 +287,14 @@
  */
 struct rpcap_pkthdr
 {
+	/*
+	 * This protocol needs to be updated with a new version before
+	 * 2038-01-19 03:14:07 UTC.
+	 */
 	uint32 timestamp_sec;	/* 'struct timeval' compatible, it represents the 'tv_sec' field */
 	uint32 timestamp_usec;	/* 'struct timeval' compatible, it represents the 'tv_usec' field */
 	uint32 caplen;		/* Length of portion present in the capture */
-	uint32 len;		/* Real length this packet (off wire) */
+	uint32 len;		/* Real length of this packet (off wire) */
 	uint32 npkt;		/* Ordinal number of the packet (i.e. the first one captured has '1', the second one '2', etc) */
 };
 
@@ -302,7 +306,7 @@
 	uint32 nitems;		/* Number of items contained into the filter (e.g. BPF instructions for BPF filters) */
 };
 
-/* Structure that keeps a single BPF instuction; it is repeated 'ninsn' times according to the 'rpcap_filterbpf' header */
+/* Structure that keeps a single BPF instruction; it is repeated 'ninsn' times according to the 'rpcap_filterbpf' header */
 struct rpcap_filterbpf_insn
 {
 	uint16 code;	/* opcode of the instruction */
@@ -346,17 +350,17 @@
  */
 #define RPCAP_MSG_IS_REPLY		0x080	/* Flag indicating a reply */
 
-#define RPCAP_MSG_ERROR			1	/* Message that keeps an error notification */
-#define RPCAP_MSG_FINDALLIF_REQ		2	/* Request to list all the remote interfaces */
-#define RPCAP_MSG_OPEN_REQ		3	/* Request to open a remote device */
-#define RPCAP_MSG_STARTCAP_REQ		4	/* Request to start a capture on a remote device */
-#define RPCAP_MSG_UPDATEFILTER_REQ	5	/* Send a compiled filter into the remote device */
-#define RPCAP_MSG_CLOSE			6	/* Close the connection with the remote peer */
-#define RPCAP_MSG_PACKET		7	/* This is a 'data' message, which carries a network packet */
-#define RPCAP_MSG_AUTH_REQ		8	/* Message that keeps the authentication parameters */
-#define RPCAP_MSG_STATS_REQ		9	/* It requires to have network statistics */
-#define RPCAP_MSG_ENDCAP_REQ		10	/* Stops the current capture, keeping the device open */
-#define RPCAP_MSG_SETSAMPLING_REQ	11	/* Set sampling parameters */
+#define RPCAP_MSG_ERROR			0x01	/* Message that keeps an error notification */
+#define RPCAP_MSG_FINDALLIF_REQ		0x02	/* Request to list all the remote interfaces */
+#define RPCAP_MSG_OPEN_REQ		0x03	/* Request to open a remote device */
+#define RPCAP_MSG_STARTCAP_REQ		0x04	/* Request to start a capture on a remote device */
+#define RPCAP_MSG_UPDATEFILTER_REQ	0x05	/* Send a compiled filter into the remote device */
+#define RPCAP_MSG_CLOSE			0x06	/* Close the connection with the remote peer */
+#define RPCAP_MSG_PACKET		0x07	/* This is a 'data' message, which carries a network packet */
+#define RPCAP_MSG_AUTH_REQ		0x08	/* Message that keeps the authentication parameters */
+#define RPCAP_MSG_STATS_REQ		0x09	/* It requires to have network statistics */
+#define RPCAP_MSG_ENDCAP_REQ		0x0A	/* Stops the current capture, keeping the device open */
+#define RPCAP_MSG_SETSAMPLING_REQ	0x0B	/* Set sampling parameters */
 
 #define RPCAP_MSG_FINDALLIF_REPLY	(RPCAP_MSG_FINDALLIF_REQ | RPCAP_MSG_IS_REPLY)		/* Keeps the list of all the remote interfaces */
 #define RPCAP_MSG_OPEN_REPLY		(RPCAP_MSG_OPEN_REQ | RPCAP_MSG_IS_REPLY)		/* The remote device has been opened correctly */
@@ -415,9 +419,10 @@
  *********************************************************/
 
 #include "sockutils.h"
+#include "sslutils.h"
 
 extern void rpcap_createhdr(struct rpcap_header *header, uint8 ver, uint8 type, uint16 value, uint32 length);
 extern const char *rpcap_msg_type_string(uint8 type);
-extern int rpcap_senderror(SOCKET sock, uint8 ver, uint16 errcode, const char *error, char *errbuf);
+extern int rpcap_senderror(SOCKET sock, SSL *ssl, uint8 ver, uint16 errcode, const char *error, char *errbuf);
 
 #endif
diff --git a/rpcapd/CMakeLists.txt b/rpcapd/CMakeLists.txt
index 1821c85..f2bd12d 100644
--- a/rpcapd/CMakeLists.txt
+++ b/rpcapd/CMakeLists.txt
@@ -50,8 +50,8 @@
   if(WIN32)
     set(RPCAPD_EXTRA_SOURCES
         win32-svc.c
+        ${pcap_SOURCE_DIR}/charconv.c
         ${pcap_SOURCE_DIR}/missing/getopt.c
-        ${pcap_SOURCE_DIR}/missing/win_snprintf.c
         rpcapd.rc)
     include_directories(${pcap_SOURCE_DIR}/rpcapd ${pcap_SOURCE_DIR}/missing)
   endif(WIN32)
@@ -63,6 +63,7 @@
     rpcapd.c
     ${pcap_SOURCE_DIR}/rpcap-protocol.c
     ${pcap_SOURCE_DIR}/sockutils.c
+    ${pcap_SOURCE_DIR}/sslutils.c
     ${pcap_SOURCE_DIR}/fmtutils.c
     ${RPCAPD_EXTRA_SOURCES}
   )
@@ -71,6 +72,11 @@
     set_target_properties(rpcapd PROPERTIES COMPILE_FLAGS ${C_ADDITIONAL_FLAGS})
   endif()
 
+  if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+    set_target_properties(rpcapd PROPERTIES
+        LINK_FLAGS "${SANITIZER_FLAGS}")
+  endif()
+
   #
   # By default, build rpcapd universal with the appropriate set of
   # architectures for the OS on which we're doing the build.
@@ -129,11 +135,15 @@
 
   set(MANFILE_EXPAND rpcapd-config.manfile.in)
 
-  if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
-    install(TARGETS rpcapd DESTINATION bin/amd64)
-  else(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
-    install(TARGETS rpcapd DESTINATION bin)
-  endif(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+  if(NOT MSVC)
+    install(TARGETS rpcapd DESTINATION sbin)
+  else(NOT MSVC)
+    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+      install(TARGETS rpcapd DESTINATION bin/amd64)
+    else(CMAKE_SIZEOF_VOID_P EQUAL 8)
+      install(TARGETS rpcapd DESTINATION bin)
+    endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
+  endif(NOT MSVC)
 
   # On UN*X, and on Windows when not using MSVC, generate process man
   # pages and arrange that they be installed.
diff --git a/rpcapd/Makefile.in b/rpcapd/Makefile.in
index 88e632a..3290679 100644
--- a/rpcapd/Makefile.in
+++ b/rpcapd/Makefile.in
@@ -38,6 +38,7 @@
 
 # VPATH
 srcdir = @srcdir@
+top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 
 #
@@ -84,7 +85,7 @@
 	log.c \
 	rpcapd.c
 
-OBJ =	$(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o
+OBJ =	$(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o ../sslutils.o
 PUBHDR =
 
 HDR = $(PUBHDR) log.h
@@ -138,4 +139,4 @@
 	ctags -wtd $(TAGFILES)
 
 depend:
-	../$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
+	$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c
index 209dba2..620dec3 100644
--- a/rpcapd/daemon.c
+++ b/rpcapd/daemon.c
@@ -39,6 +39,7 @@
 #include <errno.h>		// for the errno variable
 #include <stdlib.h>		// for malloc(), free(), ...
 #include <string.h>		// for strlen(), ...
+#include <limits.h>		// for INT_MAX
 
 #ifdef _WIN32
   #include <process.h>		// for threads
@@ -64,6 +65,11 @@
 #include "daemon.h"
 #include "log.h"
 
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#include "sslutils.h"
+#endif
+
 //
 // Timeout, in seconds, when we're waiting for a client to send us an
 // authentication request; if they don't send us a request within that
@@ -90,6 +96,7 @@
 struct daemon_slpars
 {
 	SOCKET sockctrl;	//!< SOCKET ID of the control connection
+	SSL *ssl;		//!< Optional SSL handler for the controlling sockets
 	int isactive;		//!< Not null if the daemon has to run in active mode
 	int nullAuthAllowed;	//!< '1' if we permit NULL authentication, '0' otherwise
 };
@@ -105,6 +112,7 @@
 struct session {
 	SOCKET sockctrl;
 	SOCKET sockdata;
+	SSL *ctrl_ssl, *data_ssl; // optional SSL handlers for sockctrl and sockdata.
 	uint8 protocol_version;
 	pcap_t *fp;
 	unsigned int TotCapt;
@@ -117,7 +125,7 @@
 };
 
 // Locally defined functions
-static int daemon_msg_err(SOCKET sockctrl, uint32 plen);
+static int daemon_msg_err(SOCKET sockctrl, SSL *, uint32 plen);
 static int daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen);
 static int daemon_AuthUserPwd(char *username, char *password, char *errbuf);
 
@@ -128,13 +136,13 @@
     uint32 plen, char *source, size_t sourcelen);
 static int daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars,
     uint32 plen, char *source, struct session **sessionp,
-    struct rpcap_sampling *samp_param);
+    struct rpcap_sampling *samp_param, int uses_ssl);
 static int daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars,
     struct session *session);
 
 static int daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
     struct session *session, uint32 plen);
-static int daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp, char *errbuf);
+static int daemon_unpackapplyfilter(SOCKET sockctrl, SSL *, struct session *session, uint32 *plenp, char *errbuf);
 
 static int daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
     struct session *session, uint32 plen, struct pcap_stat *stats,
@@ -151,21 +159,69 @@
 static void noop_handler(int sign);
 #endif
 
-static int rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp);
-static int rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf);
-static int rpcapd_discard(SOCKET sock, uint32 len);
+static int rpcapd_recv_msg_header(SOCKET sock, SSL *, struct rpcap_header *headerp);
+static int rpcapd_recv(SOCKET sock, SSL *, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf);
+static int rpcapd_discard(SOCKET sock, SSL *, uint32 len);
 static void session_close(struct session *);
 
+//
+// TLS record layer header; used when processing the first message from
+// the client, in case we aren't doing TLS but they are.
+//
+struct tls_record_header {
+	uint8 type;		// ContentType - will be 22, for Handshake
+	uint8 version_major;	// TLS protocol major version
+	uint8 version_injor;	// TLS protocol minor version
+	// This is *not* aligned on a 2-byte boundary; we just
+	// declare it as two bytes.  Don't assume any particular
+	// compiler's mechanism for saying "packed"!
+	uint8 length_hi;	// Upper 8 bits of payload length
+	uint8 length_lo;	// Low 8 bits of payload length
+};
+
+#define TLS_RECORD_HEADER_LEN	5	// Don't use sizeof in case it's padded
+
+#define TLS_RECORD_TYPE_ALERT		21
+#define TLS_RECORD_TYPE_HANDSHAKE	22
+
+//
+// TLS alert message.
+//
+struct tls_alert {
+	uint8 alert_level;
+	uint8 alert_description;
+};
+
+#define TLS_ALERT_LEN			2
+
+#define TLS_ALERT_LEVEL_FATAL		2
+#define TLS_ALERT_HANDSHAKE_FAILURE	40
+
 static int is_url(const char *source);
 
+/*
+ * Maximum sizes for fixed-bit-width values.
+ */
+#ifndef UINT16_MAX
+#define UINT16_MAX	65535U
+#endif
+
+#ifndef UINT32_MAX
+#define UINT32_MAX	4294967295U
+#endif
+
 int
 daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
-    int nullAuthAllowed)
+    int nullAuthAllowed, int uses_ssl)
 {
+	uint8 first_octet;
+	struct tls_record_header tls_header;
+	struct tls_alert tls_alert;
 	struct daemon_slpars pars;		// service loop parameters
 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
 	char errmsgbuf[PCAP_ERRBUF_SIZE + 1];	// buffer for errors to send to the client
 	int host_port_check_status;
+	SSL *ssl = NULL;
 	int nrecv;
 	struct rpcap_header header;		// RPCAP message general header
 	uint32 plen;				// payload length from header
@@ -192,8 +248,177 @@
 
 	*errbuf = 0;	// Initialize errbuf
 
+	//
+	// Peek into the socket to determine whether the client sent us
+	// a TLS handshake message or a non-TLS rpcapd message.
+	//
+	// The first byte of an rpcapd request is the version number;
+	// the first byte of a TLS handshake message is 22.  The
+	// first request to an rpcapd server must be an authentication
+	// request or a close request, and must have a version number
+	// of 0, so it will be possible to distinguish between an
+	// initial plaintext request to a server and an initial TLS
+	// handshake message.
+	//
+	nrecv = sock_recv(sockctrl, NULL, (char *)&first_octet, 1,
+	    SOCK_EOF_ISNT_ERROR|SOCK_MSG_PEEK, errbuf, PCAP_ERRBUF_SIZE);
+	if (nrecv == -1)
+	{
+		// Fatal error.
+		rpcapd_log(LOGPRIO_ERROR, "Peek from client failed: %s", errbuf);
+		goto end;
+	}
+	if (nrecv == 0)
+	{
+		// Client closed the connection.
+		goto end;
+	}
+
+#ifdef HAVE_OPENSSL
+	//
+	// We have to upgrade to TLS as soon as possible, so that the
+	// whole protocol goes through the encrypted tunnel, including
+	// early error messages.
+	//
+	// Even in active mode, the other end has to initiate the TLS
+	// handshake as we still are the server as far as TLS is concerned,
+	// so we don't check isactive.
+	//
+	if (uses_ssl)
+	{
+		//
+		// We're expecting a TLS handshake message.  If this
+		// isn't one, assume it's a non-TLS rpcapd message.
+		//
+		// The first octet of a TLS handshake is
+		// TLS_RECORD_TYPE_HANDSHAKE.
+		//
+		if (first_octet != TLS_RECORD_TYPE_HANDSHAKE)
+		{
+			//
+			// We assume this is a non-TLS rpcapd message.
+			//
+			// Read the message header from the client.
+			//
+			nrecv = rpcapd_recv_msg_header(sockctrl, NULL, &header);
+			if (nrecv == -1)
+			{
+				// Fatal error.
+				goto end;
+			}
+			if (nrecv == -2)
+			{
+				// Client closed the connection.
+				goto end;
+			}
+			plen = header.plen;
+
+			// Discard the rest of the message.
+			if (rpcapd_discard(sockctrl, NULL, plen) == -1)
+			{
+				// Network error.
+				goto end;
+			}
+
+			//
+			// Send an authentication error, indicating
+			// that we require TLS.
+			//
+			if (rpcap_senderror(sockctrl, NULL, header.ver,
+			    PCAP_ERR_TLS_REQUIRED,
+			    "TLS is required by this server", errbuf) == -1)
+			{
+				// That failed; log a message and give up.
+				rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
+				goto end;
+			}
+
+			// Shut the session down.
+			goto end;
+		}
+		ssl = ssl_promotion(1, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
+		if (! ssl)
+		{
+			rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s",
+			    errbuf);
+			goto end;
+		}
+	}
+	else
+#endif
+	{
+		//
+		// We're expecting a non-TLS rpcapd message.  If this
+		// looks, instead, like a TLS handshake message, send
+		// a TLS handshake_failed alert.
+		//
+		// The first octet of a TLS handshake is
+		// TLS_RECORD_TYPE_HANDSHAKE.
+		//
+		if (first_octet == TLS_RECORD_TYPE_HANDSHAKE)
+		{
+			//
+			// TLS handshake.
+			// Read the record header.
+			//
+			nrecv = sock_recv(sockctrl, ssl, (char *) &tls_header,
+			    sizeof tls_header, SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR,
+			    errbuf, PCAP_ERRBUF_SIZE);
+			if (nrecv == -1)
+			{
+				// Network error.
+				rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
+				goto end;
+			}
+			if (nrecv == 0)
+			{
+				// Immediate EOF
+				goto end;
+			}
+			plen = (tls_header.length_hi << 8) | tls_header.length_lo;
+
+			// Discard the rest of the message.
+			if (rpcapd_discard(sockctrl, NULL, plen) == -1)
+			{
+				// Network error.
+				goto end;
+			}
+
+			//
+			// Send a TLS handshake failure alert.
+			// Use the same version the client sent us.
+			//
+			tls_header.type = TLS_RECORD_TYPE_ALERT;
+			tls_header.length_hi = 0;
+			tls_header.length_lo = TLS_ALERT_LEN;
+
+			if (sock_send(sockctrl, NULL, (char *) &tls_header,
+			    TLS_RECORD_HEADER_LEN, errbuf, PCAP_ERRBUF_SIZE) == -1)
+			{
+				// That failed; log a message and give up.
+				rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
+				goto end;
+			}
+
+			tls_alert.alert_level = TLS_ALERT_LEVEL_FATAL;
+			tls_alert.alert_description = TLS_ALERT_HANDSHAKE_FAILURE;
+			if (sock_send(sockctrl, NULL, (char *) &tls_alert,
+			    TLS_ALERT_LEN, errbuf, PCAP_ERRBUF_SIZE) == -1)
+			{
+				// That failed; log a message and give up.
+				rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
+				goto end;
+			}
+			//
+			// Give up anyway.
+			//
+			goto end;
+		}
+	}
+
 	// Set parameters structure
 	pars.sockctrl = sockctrl;
+	pars.ssl = ssl;
 	pars.isactive = isactive;		// active mode
 	pars.nullAuthAllowed = nullAuthAllowed;
 
@@ -225,7 +450,7 @@
 		    &fromlen) == -1)
 		{
 			sock_geterror("getpeername()", errmsgbuf, PCAP_ERRBUF_SIZE);
-			if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
+			if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
 				rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 			goto end;
 		}
@@ -248,7 +473,7 @@
 			//
 			// Sorry, we can't let you in.
 			//
-			if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_HOSTNOAUTH, errmsgbuf, errbuf) == -1)
+			if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_HOSTNOAUTH, errmsgbuf, errbuf) == -1)
 				rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 			goto end;
 		}
@@ -295,11 +520,11 @@
 
 			FD_SET(pars.sockctrl, &rfds);
 
-			retval = select(pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
+			retval = select((int)pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
 			if (retval == -1)
 			{
 				sock_geterror("select() failed", errmsgbuf, PCAP_ERRBUF_SIZE);
-				if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
+				if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 				goto end;
 			}
@@ -308,7 +533,7 @@
 			// So, this was a fake connection. Drop it down
 			if (retval == 0)
 			{
-				if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1)
+				if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1)
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 				goto end;
 			}
@@ -317,7 +542,7 @@
 		//
 		// Read the message header from the client.
 		//
-		nrecv = rpcapd_recv_msg_header(pars.sockctrl, &header);
+		nrecv = rpcapd_recv_msg_header(pars.sockctrl, pars.ssl, &header);
 		if (nrecv == -1)
 		{
 			// Fatal error.
@@ -340,7 +565,7 @@
 			//
 			// Send it back to them with their version.
 			//
-			if (rpcap_senderror(pars.sockctrl, header.ver,
+			if (rpcap_senderror(pars.sockctrl, pars.ssl, header.ver,
 			    PCAP_ERR_WRONGVER,
 			    "RPCAP version in requests in the authentication phase must be 0",
 			    errbuf) == -1)
@@ -352,7 +577,7 @@
 
 			// Discard the rest of the message and drop the
 			// connection.
-			(void)rpcapd_discard(pars.sockctrl, plen);
+			(void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
 			goto end;
 		}
 
@@ -385,7 +610,7 @@
 				// Discard the rest of the message, if
 				// there is anything more.
 				//
-				(void)rpcapd_discard(pars.sockctrl, plen);
+				(void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
 				// We're done with this client.
 				goto end;
 
@@ -397,7 +622,7 @@
 				// an error message rather than a "let
 				// me log in" message, indicating that
 				// we're not allowed to connect to them?
-				(void)daemon_msg_err(pars.sockctrl, plen);
+				(void)daemon_msg_err(pars.sockctrl, pars.ssl, plen);
 				goto end;
 
 			case RPCAP_MSG_FINDALLIF_REQ:
@@ -414,20 +639,21 @@
 				msg_type_string = rpcap_msg_type_string(header.type);
 				if (msg_type_string != NULL)
 				{
-					pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s request sent before authentication was completed", msg_type_string);
+					snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s request sent before authentication was completed", msg_type_string);
 				}
 				else
 				{
-					pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type);
+					snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type);
 				}
-				if (rpcap_senderror(pars.sockctrl, header.ver,
-				    PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1)
+				if (rpcap_senderror(pars.sockctrl, pars.ssl,
+				    header.ver, PCAP_ERR_WRONGMSG,
+				    errmsgbuf, errbuf) == -1)
 				{
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 					goto end;
 				}
 				// Discard the rest of the message.
-				if (rpcapd_discard(pars.sockctrl, plen) == -1)
+				if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
 				{
 					// Network error.
 					goto end;
@@ -449,20 +675,21 @@
 				msg_type_string = rpcap_msg_type_string(header.type);
 				if (msg_type_string != NULL)
 				{
-					pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
+					snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
 				}
 				else
 				{
-					pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
+					snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
 				}
-				if (rpcap_senderror(pars.sockctrl, header.ver,
-				    PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1)
+				if (rpcap_senderror(pars.sockctrl, pars.ssl,
+				    header.ver, PCAP_ERR_WRONGMSG,
+				    errmsgbuf, errbuf) == -1)
 				{
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 					goto end;
 				}
 				// Discard the rest of the message.
-				if (rpcapd_discard(pars.sockctrl, plen) == -1)
+				if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
 				{
 					// Fatal error.
 					goto end;
@@ -473,15 +700,16 @@
 				//
 				// Unknown message type.
 				//
-				pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
-				if (rpcap_senderror(pars.sockctrl, header.ver,
-				    PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1)
+				snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
+				if (rpcap_senderror(pars.sockctrl, pars.ssl,
+				    header.ver, PCAP_ERR_WRONGMSG,
+				    errmsgbuf, errbuf) == -1)
 				{
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 					goto end;
 				}
 				// Discard the rest of the message.
-				if (rpcapd_discard(pars.sockctrl, plen) == -1)
+				if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
 				{
 					// Fatal error.
 					goto end;
@@ -519,7 +747,7 @@
 		//
 		// Be carefully: the capture can have been started, but an error occurred (so session != NULL, but
 		//  sockdata is 0
-		if ((!pars.isactive) &&  ((session == NULL) || ((session != NULL) && (session->sockdata == 0))))
+		if ((!pars.isactive) && (session == NULL || session->sockdata == 0))
 		{
 			// Check for the initial timeout
 			FD_ZERO(&rfds);
@@ -528,13 +756,17 @@
 			tv.tv_usec = 0;
 
 			FD_SET(pars.sockctrl, &rfds);
-
-			retval = select(pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+			retval = 1;
+#else
+			retval = select((int)pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
+#endif
 			if (retval == -1)
 			{
 				sock_geterror("select() failed", errmsgbuf, PCAP_ERRBUF_SIZE);
-				if (rpcap_senderror(pars.sockctrl, 0,
-				    PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
+				if (rpcap_senderror(pars.sockctrl, pars.ssl,
+				    0, PCAP_ERR_NETW,
+				    errmsgbuf, errbuf) == -1)
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 				goto end;
 			}
@@ -543,8 +775,8 @@
 			// So, this was a fake connection. Drop it down
 			if (retval == 0)
 			{
-				if (rpcap_senderror(pars.sockctrl, 0,
-				    PCAP_ERR_INITTIMEOUT,
+				if (rpcap_senderror(pars.sockctrl, pars.ssl,
+				    0, PCAP_ERR_INITTIMEOUT,
 				    "The RPCAP initial timeout has expired",
 				    errbuf) == -1)
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -555,7 +787,7 @@
 		//
 		// Read the message header from the client.
 		//
-		nrecv = rpcapd_recv_msg_header(pars.sockctrl, &header);
+		nrecv = rpcapd_recv_msg_header(pars.sockctrl, pars.ssl, &header);
 		if (nrecv == -1)
 		{
 			// Fatal error.
@@ -581,7 +813,7 @@
 			// so they don't reject it as having the wrong
 			// version.
 			//
-			if (rpcap_senderror(pars.sockctrl,
+			if (rpcap_senderror(pars.sockctrl, pars.ssl,
 			    header.ver, PCAP_ERR_WRONGVER,
 			    "RPCAP version in message isn't supported by the server",
 			    errbuf) == -1)
@@ -592,7 +824,7 @@
 			}
 
 			// Discard the rest of the message.
-			(void)rpcapd_discard(pars.sockctrl, plen);
+			(void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
 			// Give up on them.
 			goto end;
 		}
@@ -601,7 +833,7 @@
 		{
 			case RPCAP_MSG_ERROR:		// The other endpoint reported an error
 			{
-				(void)daemon_msg_err(pars.sockctrl, plen);
+				(void)daemon_msg_err(pars.sockctrl, pars.ssl, plen);
 				// Do nothing; just exit; the error code is already into the errbuf
 				// XXX - actually exit....
 				break;
@@ -647,7 +879,7 @@
 				{
 					// They never told us what device
 					// to capture on!
-					if (rpcap_senderror(pars.sockctrl,
+					if (rpcap_senderror(pars.sockctrl, pars.ssl,
 					    header.ver,
 					    PCAP_ERR_STARTCAPTURE,
 					    "No capture device was specified",
@@ -658,7 +890,7 @@
 						rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 						goto end;
 					}
-					if (rpcapd_discard(pars.sockctrl, plen) == -1)
+					if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
 					{
 						goto end;
 					}
@@ -666,7 +898,8 @@
 				}
 
 				if (daemon_msg_startcap_req(header.ver, &pars,
-				    plen, source, &session, &samp_param) == -1)
+				    plen, source, &session, &samp_param,
+				    uses_ssl) == -1)
 				{
 					// Fatal error; a message has
 					// been logged, so just give up.
@@ -689,8 +922,9 @@
 				}
 				else
 				{
-					if (rpcap_senderror(pars.sockctrl,
-					    header.ver, PCAP_ERR_UPDATEFILTER,
+					if (rpcap_senderror(pars.sockctrl, pars.ssl,
+					    header.ver,
+					    PCAP_ERR_UPDATEFILTER,
 					    "Device not opened. Cannot update filter",
 					    errbuf) == -1)
 					{
@@ -757,8 +991,9 @@
 				}
 				else
 				{
-					rpcap_senderror(pars.sockctrl,
-					    header.ver, PCAP_ERR_ENDCAPTURE,
+					rpcap_senderror(pars.sockctrl, pars.ssl,
+					    header.ver,
+					    PCAP_ERR_ENDCAPTURE,
 					    "Device not opened. Cannot close the capture",
 					    errbuf);
 				}
@@ -784,7 +1019,8 @@
 				// get to reauthenticate.
 				//
 				rpcapd_log(LOGPRIO_INFO, "The client sent an RPCAP_MSG_AUTH_REQ message after authentication was completed");
-				if (rpcap_senderror(pars.sockctrl, header.ver,
+				if (rpcap_senderror(pars.sockctrl, pars.ssl,
+				    header.ver,
 				    PCAP_ERR_WRONGMSG,
 				    "RPCAP_MSG_AUTH_REQ request sent after authentication was completed",
 				    errbuf) == -1)
@@ -793,7 +1029,7 @@
 					goto end;
 				}
 				// Discard the rest of the message.
-				if (rpcapd_discard(pars.sockctrl, plen) == -1)
+				if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
 				{
 					// Fatal error.
 					goto end;
@@ -816,21 +1052,22 @@
 				if (msg_type_string != NULL)
 				{
 					rpcapd_log(LOGPRIO_INFO, "The client sent a %s server-to-client message", msg_type_string);
-					pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
+					snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
 				}
 				else
 				{
 					rpcapd_log(LOGPRIO_INFO, "The client sent a server-to-client message of type %u", header.type);
-					pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
+					snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
 				}
-				if (rpcap_senderror(pars.sockctrl, header.ver,
-				    PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1)
+				if (rpcap_senderror(pars.sockctrl, pars.ssl,
+				    header.ver, PCAP_ERR_WRONGMSG,
+				    errmsgbuf, errbuf) == -1)
 				{
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 					goto end;
 				}
 				// Discard the rest of the message.
-				if (rpcapd_discard(pars.sockctrl, plen) == -1)
+				if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
 				{
 					// Fatal error.
 					goto end;
@@ -842,15 +1079,16 @@
 				// Unknown message type.
 				//
 				rpcapd_log(LOGPRIO_INFO, "The client sent a message of type %u", header.type);
-				pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
-				if (rpcap_senderror(pars.sockctrl, header.ver,
-				    PCAP_ERR_WRONGMSG, errbuf, errmsgbuf) == -1)
+				snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
+				if (rpcap_senderror(pars.sockctrl, pars.ssl,
+				    header.ver, PCAP_ERR_WRONGMSG,
+				    errbuf, errmsgbuf) == -1)
 				{
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 					goto end;
 				}
 				// Discard the rest of the message.
-				if (rpcapd_discard(pars.sockctrl, plen) == -1)
+				if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
 				{
 					// Fatal error.
 					goto end;
@@ -870,6 +1108,21 @@
 		session = NULL;
 	}
 
+	if (passiveClients) {
+		free(passiveClients);
+	}
+	//
+	// Finish using the SSL handle for the control socket, if we
+	// have an SSL connection, and close the control socket.
+	//
+#ifdef HAVE_OPENSSL
+	if (ssl)
+	{
+		// Finish using the SSL handle for the socket.
+		// This must be done *before* the socket is closed.
+		ssl_finish(ssl);
+	}
+#endif
 	sock_close(sockctrl, NULL, 0);
 
 	// Print message and return
@@ -882,7 +1135,7 @@
  * This handles the RPCAP_MSG_ERR message.
  */
 static int
-daemon_msg_err(SOCKET sockctrl, uint32 plen)
+daemon_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen)
 {
 	char errbuf[PCAP_ERRBUF_SIZE];
 	char remote_errbuf[PCAP_ERRBUF_SIZE];
@@ -893,7 +1146,7 @@
 		 * Message is too long; just read as much of it as we
 		 * can into the buffer provided, and discard the rest.
 		 */
-		if (sock_recv(sockctrl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
+		if (sock_recv(sockctrl, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
 		    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
 		    PCAP_ERRBUF_SIZE) == -1)
 		{
@@ -901,7 +1154,7 @@
 			rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
 			return -1;
 		}
-		if (rpcapd_discard(sockctrl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1)
+		if (rpcapd_discard(sockctrl, ssl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1)
 		{
 			// Network error.
 			return -1;
@@ -919,7 +1172,7 @@
 	}
 	else
 	{
-		if (sock_recv(sockctrl, remote_errbuf, plen,
+		if (sock_recv(sockctrl, ssl, remote_errbuf, plen,
 		    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
 		    PCAP_ERRBUF_SIZE) == -1)
 		{
@@ -971,7 +1224,7 @@
 	int sendbufidx = 0;			// index which keeps the number of bytes currently buffered
 	struct rpcap_authreply *authreply;	// authentication reply message
 
-	status = rpcapd_recv(pars->sockctrl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
+	status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
 	if (status == -1)
 	{
 		return -1;
@@ -988,10 +1241,10 @@
 			if (!pars->nullAuthAllowed)
 			{
 				// Send the client an error reply.
-				pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
 				    "Authentication failed; NULL authentication not permitted.");
-				if (rpcap_senderror(pars->sockctrl, 0,
-				    PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
+				if (rpcap_senderror(pars->sockctrl, pars->ssl,
+				    0, PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
 				{
 					// That failed; log a message and give up.
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1015,7 +1268,7 @@
 				    PCAP_ERRBUF_SIZE, errno, "malloc() failed");
 				goto error;
 			}
-			status = rpcapd_recv(pars->sockctrl, username, usernamelen, &plen, errmsgbuf);
+			status = rpcapd_recv(pars->sockctrl, pars->ssl, username, usernamelen, &plen, errmsgbuf);
 			if (status == -1)
 			{
 				free(username);
@@ -1037,7 +1290,7 @@
 				free(username);
 				goto error;
 			}
-			status = rpcapd_recv(pars->sockctrl, passwd, passwdlen, &plen, errmsgbuf);
+			status = rpcapd_recv(pars->sockctrl, pars->ssl, passwd, passwdlen, &plen, errmsgbuf);
 			if (status == -1)
 			{
 				free(username);
@@ -1060,8 +1313,8 @@
 				//
 				free(username);
 				free(passwd);
-				if (rpcap_senderror(pars->sockctrl, 0,
-				    PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
+				if (rpcap_senderror(pars->sockctrl, pars->ssl,
+				    0, PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
 				{
 					// That failed; log a message and give up.
 					rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1088,10 +1341,10 @@
 			}
 
 		default:
-			pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
 			    "Authentication type not recognized.");
-			if (rpcap_senderror(pars->sockctrl, 0,
-			    PCAP_ERR_AUTH_TYPE_NOTSUP, errmsgbuf, errbuf) == -1)
+			if (rpcap_senderror(pars->sockctrl, pars->ssl,
+			    0, PCAP_ERR_AUTH_TYPE_NOTSUP, errmsgbuf, errbuf) == -1)
 			{
 				// That failed; log a message and give up.
 				rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1122,15 +1375,15 @@
 	authreply->maxvers = RPCAP_MAX_VERSION;
 
 	// Send the reply.
-	if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+	if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
 	{
-		// That failed; log a messsage and give up.
+		// That failed; log a message and give up.
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 		return -1;
 	}
 
 	// Check if all the data has been read; if not, discard the data in excess
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		return -1;
 	}
@@ -1138,8 +1391,8 @@
 	return 0;
 
 error:
-	if (rpcap_senderror(pars->sockctrl, 0, PCAP_ERR_AUTH, errmsgbuf,
-	    errbuf) == -1)
+	if (rpcap_senderror(pars->sockctrl, pars->ssl, 0, PCAP_ERR_AUTH,
+	    errmsgbuf, errbuf) == -1)
 	{
 		// That failed; log a message and give up.
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1148,7 +1401,7 @@
 
 error_noreply:
 	// Check if all the data has been read; if not, discard the data in excess
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		return -1;
 	}
@@ -1184,7 +1437,7 @@
 
 	if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
 		error = GetLastError();
 		if (error != ERROR_LOGON_FAILURE)
 		{
@@ -1201,7 +1454,7 @@
 	// I didn't test it.
 	if (ImpersonateLoggedOnUser(Token) == 0)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
 		pcap_fmt_errmsg_for_win32_err(errmsgbuf, PCAP_ERRBUF_SIZE,
 		    GetLastError(), "ImpersonateLoggedOnUser() failed");
 		rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf);
@@ -1216,7 +1469,7 @@
 	/*
 	 * See
 	 *
-	 *	http://www.unixpapa.com/incnote/passwd.html
+	 *	https://www.unixpapa.com/incnote/passwd.html
 	 *
 	 * We use the Solaris/Linux shadow password authentication if
 	 * we have getspnam(), otherwise we just do traditional
@@ -1243,7 +1496,7 @@
 	// This call is needed to get the uid
 	if ((user = getpwnam(username)) == NULL)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
 		return -1;
 	}
 
@@ -1251,7 +1504,7 @@
 	// This call is needed to get the password; otherwise 'x' is returned
 	if ((usersp = getspnam(username)) == NULL)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
 		return -1;
 	}
 	user_password = usersp->sp_pwdp;
@@ -1279,7 +1532,7 @@
 	if (crypt_password == NULL)
 	{
 		error = errno;
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
 		if (error == 0)
 		{
 			// It didn't set errno.
@@ -1294,7 +1547,7 @@
 	}
 	if (strcmp(user_password, crypt_password) != 0)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
 		return -1;
 	}
 
@@ -1324,6 +1577,21 @@
 
 }
 
+/*
+ * Make sure that the reply length won't overflow 32 bits if we add the
+ * specified amount to it.  If it won't, add that amount to it.
+ *
+ * We check whether replylen + itemlen > UINT32_MAX, but subtract itemlen
+ * from both sides, to prevent overflow.
+ */
+#define CHECK_AND_INCREASE_REPLY_LEN(itemlen) \
+	if (replylen > UINT32_MAX - (itemlen)) { \
+		pcap_strlcpy(errmsgbuf, "Reply length doesn't fit in 32 bits", \
+		    sizeof (errmsgbuf)); \
+		goto error; \
+	} \
+	replylen += (uint32)(itemlen)
+
 static int
 daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
 {
@@ -1339,7 +1607,7 @@
 	uint16 nif = 0;				// counts the number of interface listed
 
 	// Discard the rest of the message; there shouldn't be any payload.
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		// Network error.
 		return -1;
@@ -1351,7 +1619,8 @@
 
 	if (alldevs == NULL)
 	{
-		if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_NOREMOTEIF,
+		if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
+			PCAP_ERR_NOREMOTEIF,
 			"No interfaces found! Make sure libpcap/WinPcap is properly installed"
 			" and you have the right to access to the remote device.",
 			errbuf) == -1)
@@ -1369,13 +1638,30 @@
 	{
 		nif++;
 
-		if (d->description)
-			replylen += strlen(d->description);
-		if (d->name)
-			replylen += strlen(d->name);
+		if (d->description) {
+			size_t stringlen = strlen(d->description);
+			if (stringlen > UINT16_MAX) {
+				pcap_strlcpy(errmsgbuf,
+				    "Description length doesn't fit in 16 bits",
+				    sizeof (errmsgbuf));
+				goto error;
+			}
+			CHECK_AND_INCREASE_REPLY_LEN(stringlen);
+		}
+		if (d->name) {
+			size_t stringlen = strlen(d->name);
+			if (stringlen > UINT16_MAX) {
+				pcap_strlcpy(errmsgbuf,
+				    "Name length doesn't fit in 16 bits",
+				    sizeof (errmsgbuf));
+				goto error;
+			}
+			CHECK_AND_INCREASE_REPLY_LEN(stringlen);
+		}
 
-		replylen += sizeof(struct rpcap_findalldevs_if);
+		CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_findalldevs_if));
 
+		uint16_t naddrs = 0;
 		for (address = d->addresses; address != NULL; address = address->next)
 		{
 			/*
@@ -1387,7 +1673,14 @@
 #ifdef AF_INET6
 			case AF_INET6:
 #endif
-				replylen += (sizeof(struct rpcap_sockaddr) * 4);
+				CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_sockaddr) * 4);
+				if (naddrs == UINT16_MAX) {
+					pcap_strlcpy(errmsgbuf,
+					    "Number of interfaces doesn't fit in 16 bits",
+					    sizeof (errmsgbuf));
+					goto error;
+				}
+				naddrs++;
 				break;
 
 			default:
@@ -1396,7 +1689,7 @@
 		}
 	}
 
-	// RPCAP findalldevs command
+	// RPCAP findalldevs reply
 	if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
 	    &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf,
 	    PCAP_ERRBUF_SIZE) == -1)
@@ -1418,10 +1711,18 @@
 
 		memset(findalldevs_if, 0, sizeof(struct rpcap_findalldevs_if));
 
-		if (d->description) ldescr = (short) strlen(d->description);
-		else ldescr = 0;
-		if (d->name) lname = (short) strlen(d->name);
-		else lname = 0;
+		/*
+		 * We've already established that the string lengths
+		 * fit in 16 bits.
+		 */
+		if (d->description)
+			ldescr = (uint16) strlen(d->description);
+		else
+			ldescr = 0;
+		if (d->name)
+			lname = (uint16) strlen(d->name);
+		else
+			lname = 0;
 
 		findalldevs_if->desclen = htons(ldescr);
 		findalldevs_if->namelen = htons(lname);
@@ -1506,7 +1807,7 @@
 	pcap_freealldevs(alldevs);
 
 	// Send a final command that says "now send it!"
-	if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+	if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
 	{
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 		return -1;
@@ -1518,8 +1819,8 @@
 	if (alldevs)
 		pcap_freealldevs(alldevs);
 
-	if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_FINDALLIF,
-	    errmsgbuf, errbuf) == -1)
+	if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
+	    PCAP_ERR_FINDALLIF, errmsgbuf, errbuf) == -1)
 	{
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 		return -1;
@@ -1545,11 +1846,11 @@
 
 	if (plen > sourcelen - 1)
 	{
-		pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string too long");
+		snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string too long");
 		goto error;
 	}
 
-	nread = sock_recv(pars->sockctrl, source, plen,
+	nread = sock_recv(pars->sockctrl, pars->ssl, source, plen,
 	    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
 	if (nread == -1)
 	{
@@ -1563,7 +1864,7 @@
 	// If so, reject it.
 	if (is_url(source))
 	{
-		pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string refers to a remote device");
+		snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string refers to a remote device");
 		goto error;
 	}
 
@@ -1592,13 +1893,20 @@
 
 	memset(openreply, 0, sizeof(struct rpcap_openreply));
 	openreply->linktype = htonl(pcap_datalink(fp));
-	openreply->tzoff = 0; /* This is always 0 for live captures */
+	/*
+	 * This is always 0 for live captures; we no longer support it
+	 * as something we read from capture files and supply to
+	 * clients, but we have to send it over the wire, as open
+	 * replies are expected to have 8 bytes of payload by
+	 * existing clients.
+	 */
+	openreply->tzoff = 0;
 
 	// We're done with the pcap_t.
 	pcap_close(fp);
 
 	// Send the reply.
-	if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+	if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
 	{
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 		return -1;
@@ -1606,7 +1914,7 @@
 	return 0;
 
 error:
-	if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_OPEN,
+	if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_OPEN,
 	    errmsgbuf, errbuf) == -1)
 	{
 		// That failed; log a message and give up.
@@ -1615,7 +1923,7 @@
 	}
 
 	// Check if all the data has been read; if not, discard the data in excess
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		return -1;
 	}
@@ -1629,7 +1937,7 @@
 static int
 daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
     char *source, struct session **sessionp,
-    struct rpcap_sampling *samp_param _U_)
+    struct rpcap_sampling *samp_param _U_, int uses_ssl)
 {
 	char errbuf[PCAP_ERRBUF_SIZE];		// buffer for network errors
 	char errmsgbuf[PCAP_ERRBUF_SIZE];	// buffer for errors to send to the client
@@ -1654,7 +1962,7 @@
 
 	addrinfo = NULL;
 
-	status = rpcapd_recv(pars->sockctrl, (char *) &startcapreq,
+	status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &startcapreq,
 	    sizeof(struct rpcap_startcapreq), &plen, errmsgbuf);
 	if (status == -1)
 	{
@@ -1667,15 +1975,25 @@
 
 	startcapreq.flags = ntohs(startcapreq.flags);
 
+	// Check that the client does not ask for UDP is the server has been asked
+	// to enforce encryption, as SSL is not supported yet with UDP:
+	if (uses_ssl && (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM))
+	{
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		    "SSL not supported with UDP forward of remote packets");
+		goto error;
+	}
+
 	// Create a session structure
 	session = malloc(sizeof(struct session));
 	if (session == NULL)
 	{
-		pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Can't allocate session structure");
+		snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Can't allocate session structure");
 		goto error;
 	}
 
 	session->sockdata = INVALID_SOCKET;
+	session->ctrl_ssl = session->data_ssl = NULL;
 	// We don't have a thread yet.
 	session->have_thread = 0;
 	//
@@ -1737,7 +2055,7 @@
 	// Now we have to create a new socket to send packets
 	if (serveropen_dp)		// Data connection is opened by the server toward the client
 	{
-		pcap_snprintf(portdata, sizeof portdata, "%d", ntohs(startcapreq.portdata));
+		snprintf(portdata, sizeof portdata, "%d", ntohs(startcapreq.portdata));
 
 		// Get the name of the other peer (needed to connect to that specific network address)
 		if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peerhost,
@@ -1787,10 +2105,11 @@
 
 	// Needed to send an error on the ctrl connection
 	session->sockctrl = pars->sockctrl;
+	session->ctrl_ssl = pars->ssl;
 	session->protocol_version = ver;
 
 	// Now I can set the filter
-	ret = daemon_unpackapplyfilter(pars->sockctrl, session, &plen, errmsgbuf);
+	ret = daemon_unpackapplyfilter(pars->sockctrl, pars->ssl, session, &plen, errmsgbuf);
 	if (ret == -1)
 	{
 		// Fatal error.  A message has been logged; just give up.
@@ -1825,7 +2144,7 @@
 		startcapreply->portdata = htons(port);
 	}
 
-	if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+	if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
 	{
 		// That failed; log a message and give up.
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1854,13 +2173,30 @@
 		session->sockdata = socktemp;
 	}
 
+	SSL *ssl = NULL;
+	if (uses_ssl)
+	{
+#ifdef HAVE_OPENSSL
+		/* In both active or passive cases, wait for the client to initiate the
+		 * TLS handshake. Yes during that time the control socket will not be
+		 * served, but the same was true from the above call to accept(). */
+		ssl = ssl_promotion(1, session->sockdata, errbuf, PCAP_ERRBUF_SIZE);
+		if (! ssl)
+		{
+			rpcapd_log(LOGPRIO_ERROR, "TLS handshake failed: %s", errbuf);
+			goto error;
+		}
+#endif
+	}
+	session->data_ssl = ssl;
+
 	// Now we have to create a new thread to receive packets
 #ifdef _WIN32
 	session->thread = (HANDLE)_beginthreadex(NULL, 0, daemon_thrdatamain,
 	    (void *) session, 0, NULL);
 	if (session->thread == 0)
 	{
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread");
 		goto error;
 	}
 #else
@@ -1876,7 +2212,7 @@
 	session->have_thread = 1;
 
 	// Check if all the data has been read; if not, discard the data in excess
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 		goto fatal_error;
 
 	*sessionp = session;
@@ -1898,8 +2234,8 @@
 		free(session);
 	}
 
-	if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_STARTCAPTURE,
-	    errmsgbuf, errbuf) == -1)
+	if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
+	    PCAP_ERR_STARTCAPTURE, errmsgbuf, errbuf) == -1)
 	{
 		// That failed; log a message and give up.
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1907,7 +2243,7 @@
 	}
 
 	// Check if all the data has been read; if not, discard the data in excess
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		// Network error.
 		return -1;
@@ -1942,7 +2278,7 @@
 
 	rpcap_createhdr(&header, ver, RPCAP_MSG_ENDCAP_REPLY, 0, 0);
 
-	if (sock_send(pars->sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+	if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
 	{
 		// That failed; log a message and give up.
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1970,7 +2306,7 @@
 #define RPCAP_BPF_MAXINSNS	8192
 
 static int
-daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp, char *errmsgbuf)
+daemon_unpackapplyfilter(SOCKET sockctrl, SSL *ctrl_ssl, struct session *session, uint32 *plenp, char *errmsgbuf)
 {
 	int status;
 	struct rpcap_filter filter;
@@ -1979,7 +2315,7 @@
 	struct bpf_program bf_prog;
 	unsigned int i;
 
-	status = rpcapd_recv(sockctrl, (char *) &filter,
+	status = rpcapd_recv(sockctrl, ctrl_ssl, (char *) &filter,
 	    sizeof(struct rpcap_filter), plenp, errmsgbuf);
 	if (status == -1)
 	{
@@ -1994,13 +2330,13 @@
 
 	if (ntohs(filter.filtertype) != RPCAP_UPDATEFILTER_BPF)
 	{
-		pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported");
+		snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported");
 		return -2;
 	}
 
 	if (bf_prog.bf_len > RPCAP_BPF_MAXINSNS)
 	{
-		pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
 		    "Filter program is larger than the maximum size of %u instructions",
 		    RPCAP_BPF_MAXINSNS);
 		return -2;
@@ -2017,7 +2353,7 @@
 
 	for (i = 0; i < bf_prog.bf_len; i++)
 	{
-		status = rpcapd_recv(sockctrl, (char *) &insn,
+		status = rpcapd_recv(sockctrl, ctrl_ssl, (char *) &insn,
 		    sizeof(struct rpcap_filterbpf_insn), plenp, errmsgbuf);
 		if (status == -1)
 		{
@@ -2036,15 +2372,18 @@
 		bf_insn++;
 	}
 
+	//
+	// XXX - pcap_setfilter() should do the validation for us.
+	//
 	if (bpf_validate(bf_prog.bf_insns, bf_prog.bf_len) == 0)
 	{
-		pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions");
+		snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions");
 		return -2;
 	}
 
 	if (pcap_setfilter(session->fp, &bf_prog))
 	{
-		pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", pcap_geterr(session->fp));
+		snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", pcap_geterr(session->fp));
 		return -2;
 	}
 
@@ -2060,7 +2399,7 @@
 	int ret;				// status of daemon_unpackapplyfilter()
 	struct rpcap_header header;		// keeps the answer to the updatefilter command
 
-	ret = daemon_unpackapplyfilter(pars->sockctrl, session, &plen, errmsgbuf);
+	ret = daemon_unpackapplyfilter(pars->sockctrl, pars->ssl, session, &plen, errmsgbuf);
 	if (ret == -1)
 	{
 		// Fatal error.  A message has been logged; just give up.
@@ -2073,7 +2412,7 @@
 	}
 
 	// Check if all the data has been read; if not, discard the data in excess
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		// Network error.
 		return -1;
@@ -2082,9 +2421,9 @@
 	// A response is needed, otherwise the other host does not know that everything went well
 	rpcap_createhdr(&header, ver, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
 
-	if (sock_send(pars->sockctrl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
+	if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
 	{
-		// That failed; log a messsage and give up.
+		// That failed; log a message and give up.
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 		return -1;
 	}
@@ -2092,11 +2431,11 @@
 	return 0;
 
 error:
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		return -1;
 	}
-	rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_UPDATEFILTER,
+	rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_UPDATEFILTER,
 	    errmsgbuf, NULL);
 
 	return 0;
@@ -2115,7 +2454,7 @@
 	struct rpcap_sampling rpcap_samp;
 	int status;
 
-	status = rpcapd_recv(pars->sockctrl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf);
+	status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf);
 	if (status == -1)
 	{
 		return -1;
@@ -2132,14 +2471,14 @@
 	// A response is needed, otherwise the other host does not know that everything went well
 	rpcap_createhdr(&header, ver, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0);
 
-	if (sock_send(pars->sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+	if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
 	{
-		// That failed; log a messsage and give up.
+		// That failed; log a message and give up.
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 		return -1;
 	}
 
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		return -1;
 	}
@@ -2147,7 +2486,7 @@
 	return 0;
 
 error:
-	if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_SETSAMPLING,
+	if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_SETSAMPLING,
 	    errmsgbuf, errbuf) == -1)
 	{
 		// That failed; log a message and give up.
@@ -2156,7 +2495,7 @@
 	}
 
 	// Check if all the data has been read; if not, discard the data in excess
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		return -1;
 	}
@@ -2176,7 +2515,7 @@
 	struct rpcap_stats *netstats;		// statistics sent on the network
 
 	// Checks that the header does not contain other data; if so, discard it
-	if (rpcapd_discard(pars->sockctrl, plen) == -1)
+	if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
 	{
 		// Network error.
 		return -1;
@@ -2199,7 +2538,7 @@
 	{
 		if (pcap_stats(session->fp, stats) == -1)
 		{
-			pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s", pcap_geterr(session->fp));
+			snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s", pcap_geterr(session->fp));
 			goto error;
 		}
 
@@ -2220,7 +2559,7 @@
 	}
 
 	// Send the packet
-	if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+	if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
 	{
 		rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
 		return -1;
@@ -2229,7 +2568,7 @@
 	return 0;
 
 error:
-	rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_GETSTATS,
+	rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_GETSTATS,
 	    errmsgbuf, NULL);
 	return 0;
 }
@@ -2288,7 +2627,21 @@
 	//
 	// So we don't need to make sure that sendbufsize will overflow.
 	//
+	// However, we *do* need to make sure its value fits in an int,
+	// because sock_send() can't send more than INT_MAX bytes (it could
+	// do so on 64-bit UN*Xes, but can't do so on Windows, not even
+	// 64-bit Windows, as the send() buffer size argument is an int
+	// in Winsock).
+	//
 	sendbufsize = sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr) + pcap_snapshot(session->fp);
+	if (sendbufsize > INT_MAX)
+	{
+		rpcapd_log(LOGPRIO_ERROR,
+		    "Buffer size for this child thread would be larger than %d",
+		    INT_MAX);
+		sendbuf = NULL;	// we haven't allocated a buffer, so nothing to free
+		goto error;
+	}
 	sendbuf = (char *) malloc (sendbufsize);
 	if (sendbuf == NULL)
 	{
@@ -2335,7 +2688,7 @@
 
 		// Bufferize the general header
 		if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
-		    &sendbufidx, sendbufsize, SOCKBUF_CHECKONLY, errbuf,
+		    &sendbufidx, (int)sendbufsize, SOCKBUF_CHECKONLY, errbuf,
 		    PCAP_ERRBUF_SIZE) == -1)
 		{
 			rpcapd_log(LOGPRIO_ERROR,
@@ -2352,7 +2705,7 @@
 
 		// Bufferize the pkt header
 		if (sock_bufferize(NULL, sizeof(struct rpcap_pkthdr), NULL,
-		    &sendbufidx, sendbufsize, SOCKBUF_CHECKONLY, errbuf,
+		    &sendbufidx, (int)sendbufsize, SOCKBUF_CHECKONLY, errbuf,
 		    PCAP_ERRBUF_SIZE) == -1)
 		{
 			rpcapd_log(LOGPRIO_ERROR,
@@ -2364,12 +2717,16 @@
 		net_pkt_header->caplen = htonl(pkt_header->caplen);
 		net_pkt_header->len = htonl(pkt_header->len);
 		net_pkt_header->npkt = htonl(++(session->TotCapt));
-		net_pkt_header->timestamp_sec = htonl(pkt_header->ts.tv_sec);
-		net_pkt_header->timestamp_usec = htonl(pkt_header->ts.tv_usec);
+		//
+		// This protocol needs to be updated with a new version
+		// before 2038-01-19 03:14:07 UTC.
+		//
+		net_pkt_header->timestamp_sec = htonl((uint32)pkt_header->ts.tv_sec);
+		net_pkt_header->timestamp_usec = htonl((uint32)pkt_header->ts.tv_usec);
 
 		// Bufferize the pkt data
 		if (sock_bufferize((char *) pkt_data, pkt_header->caplen,
-		    sendbuf, &sendbufidx, sendbufsize, SOCKBUF_BUFFERIZE,
+		    sendbuf, &sendbufidx, (int)sendbufsize, SOCKBUF_BUFFERIZE,
 		    errbuf, PCAP_ERRBUF_SIZE) == -1)
 		{
 			rpcapd_log(LOGPRIO_ERROR,
@@ -2381,7 +2738,7 @@
 		// Send the packet
 		// If the client dropped the connection, don't report an
 		// error, just quit.
-		status = sock_send(session->sockdata, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE);
+		status = sock_send(session->sockdata, session->data_ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE);
 		if (status < 0)
 		{
 			if (status == -1)
@@ -2412,8 +2769,8 @@
 		// The latter just means that the client told us to stop
 		// capturing, so there's no error to report.
 		//
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp));
-		rpcap_senderror(session->sockctrl, session->protocol_version,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp));
+		rpcap_senderror(session->sockctrl, session->ctrl_ssl, session->protocol_version,
 		    PCAP_ERR_READEX, errbuf, NULL);
 	}
 
@@ -2502,6 +2859,7 @@
 */
 void sleep_secs(int secs)
 {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
 #ifdef _WIN32
 	Sleep(secs*1000);
 #else
@@ -2513,18 +2871,19 @@
 	while (secs_remaining != 0)
 		secs_remaining = sleep(secs_remaining);
 #endif
+#endif
 }
 
 /*
  * Read the header of a message.
  */
 static int
-rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp)
+rpcapd_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *headerp)
 {
 	int nread;
 	char errbuf[PCAP_ERRBUF_SIZE];		// buffer for network errors
 
-	nread = sock_recv(sock, (char *) headerp, sizeof(struct rpcap_header),
+	nread = sock_recv(sock, ssl, (char *) headerp, sizeof(struct rpcap_header),
 	    SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR, errbuf, PCAP_ERRBUF_SIZE);
 	if (nread == -1)
 	{
@@ -2551,7 +2910,7 @@
  * error.
  */
 static int
-rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf)
+rpcapd_recv(SOCKET sock, SSL *ssl, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf)
 {
 	int nread;
 	char errbuf[PCAP_ERRBUF_SIZE];		// buffer for network errors
@@ -2559,10 +2918,10 @@
 	if (toread > *plen)
 	{
 		// Tell the client and continue.
-		pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
+		snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
 		return -2;
 	}
-	nread = sock_recv(sock, buffer, toread,
+	nread = sock_recv(sock, ssl, buffer, toread,
 	    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
 	if (nread == -1)
 	{
@@ -2580,13 +2939,13 @@
  * error.
  */
 static int
-rpcapd_discard(SOCKET sock, uint32 len)
+rpcapd_discard(SOCKET sock, SSL *ssl, uint32 len)
 {
 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
 
 	if (len != 0)
 	{
-		if (sock_discard(sock, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
+		if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
 		{
 			// Network error.
 			rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
@@ -2669,6 +3028,16 @@
 #endif
 	}
 
+#ifdef HAVE_OPENSSL
+	if (session->data_ssl)
+	{
+		// Finish using the SSL handle for the socket.
+		// This must be done *before* the socket is closed.
+		ssl_finish(session->data_ssl);
+		session->data_ssl = NULL;
+	}
+#endif
+
 	if (session->sockdata != INVALID_SOCKET)
 	{
 		sock_close(session->sockdata, NULL, 0);
diff --git a/rpcapd/daemon.h b/rpcapd/daemon.h
index 74e17da..dbbdb62 100644
--- a/rpcapd/daemon.h
+++ b/rpcapd/daemon.h
@@ -33,13 +33,19 @@
 #ifndef __DAEMON_H__
 #define __DAEMON_H__
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "sslutils.h"
+
 //
 // Returns 1 if the client closed the control connection explicitly, 0
 // otherwise; the return value is used only by callers that call us
 // for active mode.
 //
 int daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
-    int nullAuthAllowed);
+    int nullAuthAllowed, int uses_ssl);
 
 void sleep_secs(int secs);
 
diff --git a/rpcapd/fileconf.c b/rpcapd/fileconf.c
index 2f15c01..b79dda1 100644
--- a/rpcapd/fileconf.c
+++ b/rpcapd/fileconf.c
@@ -39,7 +39,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <ctype.h>
 #include <signal.h>
 #include <pcap.h>		// for PCAP_ERRBUF_SIZE
 
@@ -59,6 +58,16 @@
 
 static char *skipws(char *ptr);
 
+/*
+ * Locale-independent version checks for alphabetical and alphanumerical
+ * characters that also can handle being handed a char value that might
+ * be negative.
+ */
+#define FILECONF_ISALPHA(c) \
+	(((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
+#define FILECONF_ISALNUM(c) \
+	(FILECONF_ISALPHA(c) || ((c) >= '0' && (c) <= '9'))
+
 void fileconf_read(void)
 {
 	FILE *fp;
@@ -135,8 +144,7 @@
 			// Is the next character alphabetic?  If not,
 			// this isn't a valid parameter name.
 			//
-			if (!isascii((unsigned char)*ptr) ||
-			    !isalpha((unsigned char)*ptr))
+			if (FILECONF_ISALPHA(*ptr))
 			{
 				rpcapd_log(LOGPRIO_ERROR,
 				    "%s, line %u doesn't have a valid parameter name",
@@ -150,8 +158,7 @@
 			// That's the name of the parameter being set.
 			//
 			param = ptr;
-			while (isascii((unsigned char)*ptr) &&
-			    (isalnum((unsigned char)*ptr) || *ptr == '-' || *ptr == '_'))
+			while (FILECONF_ISALNUM(*ptr) || *ptr == '-' || *ptr == '_')
 				ptr++;
 
 			//
@@ -234,13 +241,15 @@
 				ptr += toklen;	// skip to the terminator
 				if (toklen == 0)
 				{
-					if (isascii((unsigned char)*ptr) &&
-					    (isspace((unsigned char)*ptr) || *ptr == '#' || *ptr == '\0'))
+					if (*ptr == ' ' || *ptr == '\t' ||
+					    *ptr == '\r' || *ptr == '\n' ||
+					    *ptr == '#' || *ptr == '\0')
 					{
 						//
 						// The first character it saw
 						// was a whitespace character
-						// or a comment character.
+						// or a comment character,
+						// or we ran out of characters.
 						// This means that there's
 						// no value.
 						//
@@ -498,8 +507,7 @@
 		fprintf(fp, "# Hosts which are allowed to connect to this server (passive mode)\n");
 		fprintf(fp, "# Format: PassiveClient = <name or address>\n\n");
 
-		strncpy(temphostlist, hostlist, MAX_HOST_LIST);
-		temphostlist[MAX_HOST_LIST] = 0;
+		pcap_strlcpy(temphostlist, hostlist, sizeof (temphostlist));
 
 		token = pcap_strtok_r(temphostlist, RPCAP_HOSTLIST_SEP, &lasts);
 		while(token != NULL)
@@ -548,7 +556,7 @@
 //
 static char *skipws(char *ptr)
 {
-	while (isascii((unsigned char)*ptr) && isspace((unsigned char)*ptr)) {
+	while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n') {
 		if (*ptr == '\r' || *ptr == '\n')
 			return NULL;
 		*ptr++ = '\0';
diff --git a/rpcapd/log.c b/rpcapd/log.c
index 7b5fee5..f26c145 100644
--- a/rpcapd/log.c
+++ b/rpcapd/log.c
@@ -229,7 +229,7 @@
 	 */
 	char logbuf[1024+1];
 
-	pcap_vsnprintf(logbuf, sizeof logbuf, message, ap);
+	vsnprintf(logbuf, sizeof logbuf, message, ap);
 	syslog(syslog_priority, "%s", logbuf);
 #endif
 }
diff --git a/rpcapd/org.tcpdump.rpcapd.plist b/rpcapd/org.tcpdump.rpcapd.plist
index db3223a..b0e2439 100644
--- a/rpcapd/org.tcpdump.rpcapd.plist
+++ b/rpcapd/org.tcpdump.rpcapd.plist
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
 	<key>Disabled</key>
diff --git a/rpcapd/rpcapd-config.manfile.in b/rpcapd/rpcapd-config.manfile.in
index 1a87529..267b48e 100644
--- a/rpcapd/rpcapd-config.manfile.in
+++ b/rpcapd/rpcapd-config.manfile.in
@@ -21,7 +21,7 @@
 .SH NAME
 rpcapd-config \- rpcapd configuration file format
 .SH DESCRIPTION
-An 
+An
 .B rpcapd
 configuration file allows parameters to be set for
 .BR rpcapd (@MAN_ADMIN_COMMANDS@).
@@ -42,7 +42,7 @@
 .TP
 .B ActiveClient
 .I value
-is a host name or IP addresse, followed by a comma,
+is a host name or IP address, followed by a comma,
 semicolon, or space, followed by a port name and address or
 .BR DEFAULT .
 .B DEFAULT
@@ -54,7 +54,7 @@
 .TP
 .B PassiveClient
 .I value
-is a host name or IP addresse, followed by a comma,
+is a host name or IP address, followed by a comma,
 semicolon, or space, followed by a port name and address or
 .BR DEFAULT .
 .B DEFAULT
@@ -75,4 +75,4 @@
 .B No
 means that it is not permitted.
 .SH SEE ALSO
-rpcapd(@MAN_ADMIN_COMMANDS@)
+.BR rpcapd (@MAN_ADMIN_COMMANDS@)
diff --git a/rpcapd/rpcapd.c b/rpcapd/rpcapd.c
index 430acdc..b91a401 100644
--- a/rpcapd/rpcapd.c
+++ b/rpcapd/rpcapd.c
@@ -39,6 +39,7 @@
 #include <errno.h>		// for the errno variable
 #include <string.h>		// for strtok, etc
 #include <stdlib.h>		// for malloc(), free(), ...
+#include <stdio.h>		// for fprintf(), stderr, FILE etc
 #include <pcap.h>		// for PCAP_ERRBUF_SIZE
 #include <signal.h>		// for signal()
 
@@ -53,6 +54,10 @@
 #include "daemon.h"		// the true main() method of this daemon
 #include "log.h"
 
+#ifdef HAVE_OPENSSL
+#include "sslutils.h"
+#endif
+
 #ifdef _WIN32
   #include <process.h>		// for thread stuff
   #include "win32-svc.h"	// for Win32 service stuff
@@ -86,6 +91,7 @@
 #endif
 static volatile sig_atomic_t shutdown_server;	//!< '1' if the server is to shut down
 static volatile sig_atomic_t reread_config;	//!< '1' if the server is to re-read its configuration
+static int uses_ssl; //!< '1' to use TLS over the data socket
 
 extern char *optarg;	// for getopt()
 
@@ -112,7 +118,7 @@
 /*!
 	\brief Prints the usage screen if it is launched in console mode.
 */
-static void printusage(void)
+static void printusage(FILE * f)
 {
 	const char *usagetext =
 	"USAGE:"
@@ -145,14 +151,23 @@
 	"  -i              run in inetd mode (UNIX only)\n\n"
 #endif
 	"  -D              log debugging messages\n\n"
+#ifdef HAVE_OPENSSL
+	"  -S              encrypt all communication with SSL (implements rpcaps://)\n"
+	"  -C              enable compression\n"
+	"  -K <pem_file>   uses the SSL private key in this file (default: key.pem)\n"
+	"  -X <pem_file>   uses the certificate from this file (default: cert.pem)\n"
+#endif
 	"  -s <config_file> save the current configuration to file\n\n"
 	"  -f <config_file> load the current configuration from file; all switches\n"
 	"                  specified from the command line are ignored\n\n"
 	"  -h              print this help screen\n\n";
 
-	(void)fprintf(stderr, "RPCAPD, a remote packet capture daemon.\n"
-	"Compiled with %s\n\n", pcap_lib_version());
-	printf("%s", usagetext);
+	(void)fprintf(f, "RPCAPD, a remote packet capture daemon.\n"
+	"Compiled with %s\n", pcap_lib_version());
+#if defined(HAVE_OPENSSL) && defined(SSLEAY_VERSION)
+	(void)fprintf(f, "Compiled with %s\n", SSLeay_version(SSLEAY_VERSION));
+#endif
+	(void)fprintf(f, "\n%s", usagetext);
 }
 
 
@@ -172,6 +187,9 @@
 #ifndef _WIN32
 	struct sigaction action;
 #endif
+#ifdef HAVE_OPENSSL
+	int enable_compression = 0;
+#endif
 
 	savefile[0] = 0;
 	loadfile[0] = 0;
@@ -180,8 +198,8 @@
 	// Initialize errbuf
 	memset(errbuf, 0, sizeof(errbuf));
 
-	strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE);
-	strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE);
+	pcap_strlcpy(address, RPCAP_DEFAULT_NETADDR, sizeof (address));
+	pcap_strlcpy(port, RPCAP_DEFAULT_NETPORT, sizeof (port));
 
 	// Prepare to open a new server socket
 	memset(&mainhints, 0, sizeof(struct addrinfo));
@@ -191,7 +209,15 @@
 	mainhints.ai_socktype = SOCK_STREAM;
 
 	// Getting the proper command line options
-	while ((retval = getopt(argc, argv, "b:dDhip:4l:na:s:f:v")) != -1)
+#	ifdef HAVE_OPENSSL
+#		define SSL_CLOPTS  "SK:X:C"
+#	else
+#		define SSL_CLOPTS ""
+#	endif
+
+#	define CLOPTS "b:dDhip:4l:na:s:f:v" SSL_CLOPTS
+
+	while ((retval = getopt(argc, argv, CLOPTS)) != -1)
 	{
 		switch (retval)
 		{
@@ -200,10 +226,10 @@
 				rpcapd_log_set(log_to_systemlog, log_debug_messages);
 				break;
 			case 'b':
-				strncpy(address, optarg, MAX_LINE);
+				pcap_strlcpy(address, optarg, sizeof (address));
 				break;
 			case 'p':
-				strncpy(port, optarg, MAX_LINE);
+				pcap_strlcpy(port, optarg, sizeof (port));
 				break;
 			case '4':
 				mainhints.ai_family = PF_INET;		// IPv4 server only
@@ -215,7 +241,7 @@
 				break;
 			case 'i':
 #ifdef _WIN32
-				printusage();
+				printusage(stderr);
 				exit(1);
 #else
 				isrunbyinetd = 1;
@@ -231,7 +257,7 @@
 				break;
 			case 'l':
 			{
-				strncpy(hostlist, optarg, sizeof(hostlist));
+				pcap_strlcpy(hostlist, optarg, sizeof(hostlist));
 				break;
 			}
 			case 'a':
@@ -246,12 +272,12 @@
 				{
 					tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
 
-					pcap_strlcpy(activelist[i].address, tmpaddress, MAX_LINE);
+					pcap_strlcpy(activelist[i].address, tmpaddress, sizeof (activelist[i].address));
 
 					if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
-						pcap_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE);
+						pcap_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof (activelist[i].port));
 					else
-						pcap_strlcpy(activelist[i].port, tmpport, MAX_LINE);
+						pcap_strlcpy(activelist[i].port, tmpport, sizeof (activelist[i].port));
 
 					tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
 
@@ -266,13 +292,27 @@
 				break;
 			}
 			case 'f':
-				pcap_strlcpy(loadfile, optarg, MAX_LINE);
+				pcap_strlcpy(loadfile, optarg, sizeof (loadfile));
 				break;
 			case 's':
-				pcap_strlcpy(savefile, optarg, MAX_LINE);
+				pcap_strlcpy(savefile, optarg, sizeof (savefile));
 				break;
+#ifdef HAVE_OPENSSL
+			case 'S':
+				uses_ssl = 1;
+				break;
+			case 'C':
+				enable_compression = 1;
+				break;
+			case 'K':
+				ssl_set_keyfile(optarg);
+				break;
+			case 'X':
+				ssl_set_certfile(optarg);
+				break;
+#endif
 			case 'h':
-				printusage();
+				printusage(stdout);
 				exit(0);
 				/*NOTREACHED*/
 			default:
@@ -289,6 +329,16 @@
 	}
 #endif
 
+	//
+	// We want UTF-8 error messages.
+	//
+	if (pcap_init(PCAP_CHAR_ENC_UTF_8, errbuf) == -1)
+	{
+		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
+		exit(-1);
+	}
+	pcap_fmt_set_encoding(PCAP_CHAR_ENC_UTF_8);
+
 	if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
 	{
 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
@@ -302,7 +352,7 @@
 	if (loadfile[0])
 		fileconf_read();
 
-#ifdef WIN32
+#ifdef _WIN32
 	//
 	// Create a handle to signal the main loop to tell it to do
 	// something.
@@ -342,6 +392,17 @@
 	signal(SIGPIPE, SIG_IGN);
 #endif
 
+# ifdef HAVE_OPENSSL
+	if (uses_ssl) {
+		if (ssl_init_once(1, enable_compression, errbuf, PCAP_ERRBUF_SIZE) < 0)
+		{
+			rpcapd_log(LOGPRIO_ERROR, "Can't initialize SSL: %s",
+			    errbuf);
+			exit(2);
+		}
+	}
+# endif
+
 #ifndef _WIN32
 	if (isrunbyinetd)
 	{
@@ -399,7 +460,7 @@
 			exit(0);
 		}
 		(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
-		    nullAuthAllowed);
+		    nullAuthAllowed, uses_ssl);
 
 		//
 		// Nothing more to do.
@@ -454,7 +515,7 @@
 		//
 		// If this call succeeds, it is blocking on Win32
 		//
-		if (svc_start() != 1)
+		if (!svc_start())
 			rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service");
 
 		// When the previous call returns, the entire application has to be stopped.
@@ -918,8 +979,8 @@
 				//
 				// Did an error occur?
 				//
-			 	if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
-			 	{
+				if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
+				{
 					//
 					// Yes - report it and keep going.
 					//
@@ -1100,7 +1161,7 @@
 			break;
 		}
 
-		// The accept() call can return this error when a signal is catched
+		// The accept() call can return this error when a signal is caught
 		// In this case, we have simply to ignore this error code
 		// Stevens, pg 124
 #ifdef _WIN32
@@ -1236,7 +1297,7 @@
 			exit(0);
 		}
 		(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
-		    nullAuthAllowed);
+		    nullAuthAllowed, uses_ssl);
 
 		exit(0);
 	}
@@ -1300,7 +1361,7 @@
 		{
 			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
 
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
+			snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
 					activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
 					(hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
 
@@ -1324,10 +1385,10 @@
 			// daemon_serviceloop() will free the copy.
 			//
 			activeclose = daemon_serviceloop(sockctrl, 1,
-			    hostlist_copy, nullAuthAllowed);
+			    hostlist_copy, nullAuthAllowed, uses_ssl);
 		}
 
-		// If the connection is closed by the user explicitely, don't try to connect to it again
+		// If the connection is closed by the user explicitly, don't try to connect to it again
 		// just exit the program
 		if (activeclose == 1)
 			break;
@@ -1352,7 +1413,7 @@
 	// told by the client to close.
 	//
 	(void)daemon_serviceloop(params.sockctrl, 0, params.hostlist,
-	    nullAuthAllowed);
+	    nullAuthAllowed, uses_ssl);
 
 	return 0;
 }
diff --git a/rpcapd/rpcapd.manadmin.in b/rpcapd/rpcapd.manadmin.in
index 0a9d4e0..ea6046e 100644
--- a/rpcapd/rpcapd.manadmin.in
+++ b/rpcapd/rpcapd.manadmin.in
@@ -30,7 +30,7 @@
 .\"  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 .\"  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.TH RPCAPD @MAN_ADMIN_COMMANDS@ "April 20, 2018"
+.TH RPCAPD @MAN_ADMIN_COMMANDS@ "13 January 2019"
 .SH NAME
 rpcapd \- capture daemon to be controlled by a remote libpcap application
 .SH SYNOPSIS
@@ -69,10 +69,25 @@
 ] [
 .B \-s
 .I config_file
-] [
+]
+[
 .B \-f
 .I config_file
 ]
+[
+.B \-S
+]
+.br
+.ti +8
+[
+.B \-K
+.I ssl_keyfile
+] [
+.B \-X
+.I ssl_certfile
+] [
+.B \-C
+]
 .br
 .ad
 .SH DESCRIPTION
@@ -84,7 +99,9 @@
 .LP
 In passive mode, the client (e.g., a network sniffer) connects to
 .BR rpcapd .
-It then sends hem the appropriate commands to start the capture.
+The client then sends the appropriate commands to
+.B rpcapd
+to start the capture.
 .LP
 In active mode,
 .B rpcapd
@@ -103,26 +120,34 @@
 the same way in both active and passive mode.
 .SH Configuration file
 .LP
-The user can create a configuration file in the same folder of the
+The user can create a configuration file in the same directory as the
 executable, and put the configuration commands in there. In order for
-rpcapd to execute the commands, you have to restart it on Win32, i.e.
-the initialization file is parsed only at the beginning). The UNIX
-version of rpcapd will reread the configuration file when receiving a
-HUP signel. In that case, all the existing connections remain in place,
+.B rpcapd
+to execute the commands, it needs to be restarted on Win32, i.e.
+the configuration file is parsed only at the beginning. The UNIX
+version of
+.B rpcapd
+will reread the configuration file upon receiving a
+HUP signal. In that case, all the existing connections remain in place,
 while the new connections will be created according to the new parameters.
 .LP
 In case a user does not want to create the configuration file manually,
-they can launch rpcapd with the requested parameters plus "-s filename".
+they can launch
+.B rpcapd
+with the desired flags plus
+.BR "-s filename" .
 Rpcapd will parse all the parameters and save them into the specified
 configuration file.
 .SH Installing rpcapd on Win32
 .LP
 The remote daemon is installed automatically when installing WinPcap.
-The installation process places the rpcapd file into the WinPcap folder.
+The installation process places the
+.B rpcapd
+executable file into the WinPcap folder.
 This file can be executed either from the command line, or as a service.
 For instance, the installation process updates the list of available
 services list and it creates a new item (Remote Packet Capture Protocol
-v.0 (experimental) ).  To avoid security problems, the service is
+v.0 (experimental)).  To avoid security problems, the service is
 inactive and it has to be started manually (control panel -
 administrative tools - services - start).
 .LP
@@ -134,7 +159,9 @@
 flag.
 .SH Starting rpcapd on Win32
 .LP
-The rpcapd executable can be launched directly, i.e.  it can run in the
+The
+.B rpcapd
+executable can be launched directly, i.e.  it can run in the
 foreground as well (not as a daemon/service).  The procedure is quite
 simple: you have to invoke the executable from the command line with all
 the requested parameters except for the
@@ -178,7 +205,7 @@
 argument to connect to this server.
 .I host_list
 is a list of host names or IP addresses, separated by commas.
-We suggest that you use use host names rather than literal IP addresses
+We suggest that you use host names rather than literal IP addresses
 in order to avoid problems with different address families.
 .TP
 .B \-n
@@ -202,8 +229,8 @@
 it accepts passive connections as well.
 .TP
 .B \-d
-Run in daemon mode (UNIX only) or as a service (Win32 only)
-Warning (Win32): this switch is provided automatically when
+Run in daemon mode (UNIX only) or as a service (Win32 only).
+Warning (Win32): this flag is specified automatically when
 the service is started from the control panel.
 .TP
 .B \-i
@@ -222,12 +249,37 @@
 Load the current configuration from
 .I config_file
 in the format specified by
-.BR rpcapd-config (@MAN_FILE_FORMATS@);
-all switches specified from the command line are ignored.
+.BR rpcapd-config (@MAN_FILE_FORMATS@)
+and ignore all flags specified on the command line.
 .TP
 .B \-h
 Print this help screen.
+.LP
+If
+.B rpcapd
+was compiled with SSL support, the following options are also
+available:
+.TP
+.B \-S
+Require that SSL be used on connections.
+.TP
+.B \-C
+With SSL enabled, XXX - I'm not sure how *fetching* the list of
+compression mechanisms does anything to compression.
+.TP
+.B \-S
+.I ssl_keyfile
+With SSL enabled, use
+.I ssl_keyfile
+as the SSL key file.
+.TP
+.B \-X
+.I ssl_certfile
+With SSL enabled, use
+.I ssl_certfile
+as the SSL certificate file.
 .br
 .ad
 .SH "SEE ALSO"
-pcap(3PCAP), rpcapd-config(@MAN_FILE_FORMATS@)
+.BR pcap (3PCAP),
+.BR rpcapd-config (@MAN_FILE_FORMATS@)
diff --git a/rpcapd/win32-svc.c b/rpcapd/win32-svc.c
index 3a19910..49b6804 100644
--- a/rpcapd/win32-svc.c
+++ b/rpcapd/win32-svc.c
@@ -38,15 +38,18 @@
 #include "fileconf.h"
 #include "log.h"
 
+#include "win32-svc.h"	// for Win32 service stuff
+
 static SERVICE_STATUS_HANDLE service_status_handle;
 static SERVICE_STATUS service_status;
 
 static void WINAPI svc_main(DWORD argc, char **argv);
+static void WINAPI svc_control_handler(DWORD Opcode);
 static void update_svc_status(DWORD state, DWORD progress_indicator);
 
-int svc_start(void)
+BOOL svc_start(void)
 {
-	int rc;
+	BOOL rc;
 	SERVICE_TABLE_ENTRY ste[] =
 	{
 		{ PROGRAM_NAME, svc_main },
@@ -65,7 +68,8 @@
 	return rc; // FALSE if this is not started as a service
 }
 
-void WINAPI svc_control_handler(DWORD Opcode)
+static void WINAPI
+svc_control_handler(DWORD Opcode)
 {
 	switch(Opcode)
 	{
@@ -130,7 +134,8 @@
 	return;
 }
 
-void WINAPI svc_main(DWORD argc, char **argv)
+static void WINAPI
+svc_main(DWORD argc, char **argv)
 {
 	service_status_handle = RegisterServiceCtrlHandler(PROGRAM_NAME, svc_control_handler);
 
diff --git a/rpcapd/win32-svc.h b/rpcapd/win32-svc.h
index 3f511d2..60b25ec 100644
--- a/rpcapd/win32-svc.h
+++ b/rpcapd/win32-svc.h
@@ -30,4 +30,4 @@
  *
  */
 
-int svc_start(void);
+BOOL svc_start(void);
diff --git a/savefile.c b/savefile.c
index 5b1e14c..d04b917 100644
--- a/savefile.c
+++ b/savefile.c
@@ -54,22 +54,22 @@
 #include "sf-pcap.h"
 #include "sf-pcapng.h"
 #include "pcap-common.h"
+#include "charconv.h"
 
 #ifdef _WIN32
 /*
- * These aren't exported on Windows, because they would only work if both
+ * 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 them as macros that wrap the hopen versions,
- * with the wrappers calling _fileno() and _get_osfhandle() themselves,
- * so that they convert the appropriate CRT version's FILE structure to
+ * 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 *);
-static pcap_t *pcap_fopen_offline(FILE *, char *);
 #endif
 
 /*
@@ -106,7 +106,7 @@
 	 * as it would have to handle reading partial packets and
 	 * keeping the state of the read.)
 	 */
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Savefiles cannot be put into non-blocking mode");
 	return (-1);
 }
@@ -114,40 +114,40 @@
 static int
 sf_stats(pcap_t *p, struct pcap_stat *ps _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+sf_stats_ex(pcap_t *p, int *size _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "Statistics aren't available from savefiles");
 	return (NULL);
 }
 
 static int
-sf_setbuff(pcap_t *p, int dim)
+sf_setbuff(pcap_t *p, int dim _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+sf_setmode(pcap_t *p, int mode _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+sf_setmintocopy(pcap_t *p, int size _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "The mintocopy parameter cannot be set while reading from a file");
 	return (-1);
 }
@@ -155,7 +155,7 @@
 static HANDLE
 sf_getevent(pcap_t *pcap)
 {
-	(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+	(void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
 	    "The read event cannot be retrieved while reading from a file");
 	return (INVALID_HANDLE_VALUE);
 }
@@ -164,7 +164,7 @@
 sf_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
     size_t *lenp _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 	    "An OID get request cannot be performed on a file");
 	return (PCAP_ERROR);
 }
@@ -173,13 +173,13 @@
 sf_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
     size_t *lenp _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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, int sync)
+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);
@@ -187,38 +187,38 @@
 }
 
 static int
-sf_setuserbuffer(pcap_t *p, int size)
+sf_setuserbuffer(pcap_t *p, int size _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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, int maxsize, int maxpacks)
+sf_live_dump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+sf_live_dump_ended(pcap_t *p, int sync _U_)
 {
-	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+	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)
+sf_get_airpcap_handle(pcap_t *pcap _U_)
 {
 	return (NULL);
 }
 #endif
 
 static int
-sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
+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);
@@ -232,7 +232,7 @@
 static int
 sf_setdirection(pcap_t *p, pcap_direction_t d _U_)
 {
-	pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+	snprintf(p->errbuf, sizeof(p->errbuf),
 	    "Setting direction is not supported on savefiles");
 	return (-1);
 }
@@ -247,6 +247,94 @@
 	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)
@@ -255,13 +343,18 @@
 	pcap_t *p;
 
 	if (fname == NULL) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		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
@@ -272,12 +365,16 @@
 	}
 	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.  It's
-		 * required on Windows, as the file is a binary file
-		 * and must be read in binary mode.
+		 * support it, even though it does nothing.  For MS-DOS,
+		 * we again need it.
 		 */
-		fp = fopen(fname, "rb");
+		fp = charset_fopen(fname, "rb");
 		if (fp == NULL) {
 			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
 			    errno, "%s", fname);
@@ -382,6 +479,19 @@
 	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
@@ -394,8 +504,8 @@
 			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
 			    errno, "error reading dump file");
 		} else {
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-			    "truncated dump file; tried to read %" PRIsize " file header bytes, only got %" PRIsize,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "truncated dump file; tried to read %zu file header bytes, only got %zu",
 			    sizeof(magic), amt_read);
 		}
 		return (NULL);
@@ -421,7 +531,7 @@
 	/*
 	 * Well, who knows what this mess is....
 	 */
-	pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
+	snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
 	return (NULL);
 
 found:
@@ -471,6 +581,11 @@
 	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;
@@ -480,15 +595,19 @@
 	return (p);
 }
 
-#ifdef _WIN32
-static
-#endif
+/*
+ * 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
@@ -531,7 +650,7 @@
 		}
 
 		if ((fcode = p->fcode.bf_insns) == NULL ||
-		    bpf_filter(fcode, data, h.len, h.caplen)) {
+		    pcap_filter(fcode, data, h.len, h.caplen)) {
 			(*callback)(user, &h, data);
 			if (++n >= cnt && cnt > 0)
 				break;
diff --git a/scanner.l b/scanner.l
index effcf81..06b9acc 100644
--- a/scanner.l
+++ b/scanner.l
@@ -85,7 +85,6 @@
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#include <ctype.h>
 #include <string.h>
 
 #include "pcap-int.h"
@@ -147,8 +146,7 @@
 #include "os-proto.h"
 #endif
 
-static int stoi(char *);
-static inline int xdtoi(int);
+static int stou(char *, YYSTYPE *, compiler_state_t *);
 
 /*
  * Disable diagnostics in the code generated by Flex.
@@ -339,6 +337,8 @@
 inbound		return INBOUND;
 outbound	return OUTBOUND;
 
+ifindex		return IFINDEX;
+
 vlan		return VLAN;
 mpls		return MPLS;
 pppoed		return PPPOED;
@@ -393,7 +393,7 @@
 ">>"			return RSH;
 ${B}			{ yylval->s = sdup(yyextra, yytext); return AID; }
 {MAC}			{ yylval->s = sdup(yyextra, yytext); return EID; }
-{N}			{ yylval->i = stoi((char *)yytext); return NUM; }
+{N}			{ return stou(yytext, yylval, yyextra); }
 ({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N})	{
 			yylval->s = sdup(yyextra, (char *)yytext); return HID; }
 {V6}			{
@@ -416,62 +416,66 @@
 			  return HID6;
 			}
 {B}:+({B}:+)+		{ bpf_set_error(yyextra, "bogus ethernet address %s", yytext); yylval->s = NULL; return EID; }
-icmptype		{ yylval->i = 0; return NUM; }
-icmpcode		{ yylval->i = 1; return NUM; }
-icmp-echoreply		{ yylval->i = 0; return NUM; }
-icmp-unreach		{ yylval->i = 3; return NUM; }
-icmp-sourcequench	{ yylval->i = 4; return NUM; }
-icmp-redirect		{ yylval->i = 5; return NUM; }
-icmp-echo		{ yylval->i = 8; return NUM; }
-icmp-routeradvert	{ yylval->i = 9; return NUM; }
-icmp-routersolicit	{ yylval->i = 10; return NUM; }
-icmp-timxceed		{ yylval->i = 11; return NUM; }
-icmp-paramprob		{ yylval->i = 12; return NUM; }
-icmp-tstamp		{ yylval->i = 13; return NUM; }
-icmp-tstampreply	{ yylval->i = 14; return NUM; }
-icmp-ireq		{ yylval->i = 15; return NUM; }
-icmp-ireqreply		{ yylval->i = 16; return NUM; }
-icmp-maskreq		{ yylval->i = 17; return NUM; }
-icmp-maskreply		{ yylval->i = 18; return NUM; }
+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->i = 0; return NUM; }
-icmp6code       { yylval->i = 1; return NUM; }
+icmp6type       { yylval->h = 0; return NUM; }
+icmp6code       { yylval->h = 1; return NUM; }
 
-icmp6-echo      { yylval->i = 128; return NUM; }
-icmp6-echoreply { yylval->i = 129; return NUM; }
-icmp6-multicastlistenerquery    { yylval->i = 130; return NUM; }
-icmp6-multicastlistenerreportv1 { yylval->i = 131; return NUM; }
-icmp6-multicastlistenerdone     { yylval->i = 132; return NUM; }
-icmp6-routersolicit   { yylval->i = 133; return NUM; }
-icmp6-routeradvert    { yylval->i = 134; return NUM; }
-icmp6-neighborsolicit { yylval->i = 135; return NUM; }
-icmp6-neighboradvert  { yylval->i = 136; return NUM; }
-icmp6-redirect    { yylval->i = 137; return NUM; }
-icmp6-routerrenum { yylval->i = 138; return NUM; }
-icmp6-nodeinformationquery      { yylval->i = 139; return NUM; }
-icmp6-nodeinformationresponse   { yylval->i = 140; return NUM; }
-icmp6-ineighbordiscoverysolicit { yylval->i = 141; return NUM; }
-icmp6-ineighbordiscoveryadvert  { yylval->i = 142; return NUM; }
-icmp6-multicastlistenerreportv2 { yylval->i = 143; return NUM; }
-icmp6-homeagentdiscoveryrequest { yylval->i = 144; return NUM; }
-icmp6-homeagentdiscoveryreply   { yylval->i = 145; return NUM; }
-icmp6-mobileprefixsolicit       { yylval->i = 146; return NUM; }
-icmp6-mobileprefixadvert        { yylval->i = 147; return NUM; }
-icmp6-certpathsolicit           { yylval->i = 148; return NUM; }
-icmp6-certpathadvert            { yylval->i = 149; return NUM; }
-icmp6-multicastrouteradvert     { yylval->i = 151; return NUM; }
-icmp6-multicastroutersolicit    { yylval->i = 152; return NUM; }
-icmp6-multicastrouterterm       { yylval->i = 153; 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->i = 13; return NUM; }
-tcp-fin			{ yylval->i = 0x01; return NUM; }
-tcp-syn			{ yylval->i = 0x02; return NUM; }
-tcp-rst			{ yylval->i = 0x04; return NUM; }
-tcp-push		{ yylval->i = 0x08; return NUM; }
-tcp-ack			{ yylval->i = 0x10; return NUM; }
-tcp-urg			{ yylval->i = 0x20; return NUM; }
-tcp-ece			{ yylval->i = 0x40; return NUM; }
-tcp-cwr			{ yylval->i = 0x80; 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; }
@@ -483,40 +487,110 @@
  */
 DIAG_ON_FLEX
 
-/* Hex digit to integer. */
-static inline int
-xdtoi(int c)
-{
-	if (isdigit(c))
-		return c - '0';
-	else if (islower(c))
-		return c - 'a' + 10;
-	else
-		return c - 'A' + 10;
-}
-
 /*
- * Convert string to integer.  Just like atoi(), but checks for
+ * 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
-stoi(char *s)
+stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
 {
-	int base = 10;
-	int n = 0;
+	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') {
-			s += 2;
-			base = 16;
-		}
-		else {
-			base = 8;
+			/*
+			 * 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;
 		}
 	}
-	while (*s)
-		n = n * base + xdtoi(*s++);
 
-	return n;
+	yylval_arg->h = n;
+	return NUM;
 }
diff --git a/sf-pcap.c b/sf-pcap.c
index 60c73a8..d8443e9 100644
--- a/sf-pcap.c
+++ b/sf-pcap.c
@@ -194,8 +194,8 @@
 			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
 			    errno, "error reading dump file");
 		} else {
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-			    "truncated dump file; tried to read %" PRIsize " file header bytes, only got %" PRIsize,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "truncated dump file; tried to read %zu file header bytes, only got %zu",
 			    sizeof(hdr), amt_read);
 		}
 		*err = 1;
@@ -215,7 +215,7 @@
 	}
 
 	if (hdr.version_major < PCAP_VERSION_MAJOR) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "archaic pcap savefile format");
 		*err = 1;
 		return (NULL);
@@ -229,7 +229,7 @@
 		hdr.version_minor <= PCAP_VERSION_MINOR) ||
 	       (hdr.version_major == 543 &&
 		hdr.version_minor == 0))) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			 "unsupported pcap savefile version %u.%u",
 			 hdr.version_major, hdr.version_minor);
 		*err = 1;
@@ -240,7 +240,7 @@
 	 * OK, this is a good pcap file.
 	 * Allocate a pcap_t for it.
 	 */
-	p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf));
+	p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_sf);
 	if (p == NULL) {
 		/* Allocation failed. */
 		*err = 1;
@@ -249,7 +249,6 @@
 	p->swapped = swapped;
 	p->version_major = hdr.version_major;
 	p->version_minor = hdr.version_minor;
-	p->tzoff = hdr.thiszone;
 	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);
@@ -292,7 +291,7 @@
 			ps->scale_type = PASS_THROUGH;
 		} else {
 			/*
-			 * The file has microoseconds, the user
+			 * The file has microseconds, the user
 			 * wants nanoseconds; scale the
 			 * precision up.
 			 */
@@ -301,7 +300,7 @@
 		break;
 
 	default:
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "unknown time stamp resolution %u", precision);
 		free(p);
 		*err = 1;
@@ -404,7 +403,7 @@
 		p->bufsize = 2048;
 	p->buffer = malloc(p->bufsize);
 	if (p->buffer == NULL) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
 		free(p);
 		*err = 1;
 		return (NULL);
@@ -425,7 +424,7 @@
 
 	bigger_buffer = realloc(p->buffer, bufsize);
 	if (bigger_buffer == NULL) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "out of memory");
 		return (0);
 	}
 	p->buffer = bigger_buffer;
@@ -462,8 +461,8 @@
 			return (-1);
 		} else {
 			if (amt_read != 0) {
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-				    "truncated dump file; tried to read %" PRIsize " header bytes, only got %" PRIsize,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "truncated dump file; tried to read %zu header bytes, only got %zu",
 				    ps->hdrsize, amt_read);
 				return (-1);
 			}
@@ -546,11 +545,11 @@
 		 * below.)
 		 */
 		if (hdr->caplen > (bpf_u_int32)p->snapshot) {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "invalid packet capture length %u, bigger than "
 			    "snaplen of %d", hdr->caplen, p->snapshot);
 		} else {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "invalid packet capture length %u, bigger than "
 			    "maximum of %u", hdr->caplen,
 			    max_snaplen_for_dlt(p->linktype));
@@ -622,8 +621,8 @@
 				 * that would fail because we got EOF before
 				 * the read finished.
 				 */
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-				    "truncated dump file; tried to read %u captured bytes, only got %" PRIsize,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "truncated dump file; tried to read %u captured bytes, only got %zu",
 				    p->snapshot, amt_read);
 			}
 			return (-1);
@@ -646,8 +645,8 @@
 					    PCAP_ERRBUF_SIZE, errno,
 					    "error reading dump file");
 				} else {
-					pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-					    "truncated dump file; tried to read %u captured bytes, only got %" PRIsize,
+					snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+					    "truncated dump file; tried to read %u captured bytes, only got %zu",
 					    hdr->caplen, bytes_read);
 				}
 				return (-1);
@@ -673,7 +672,7 @@
 
 			new_bufsize = hdr->caplen;
 			/*
-			 * http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+			 * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
 			 */
 			new_bufsize--;
 			new_bufsize |= new_bufsize >> 1;
@@ -698,8 +697,8 @@
 				    PCAP_ERRBUF_SIZE, errno,
 				    "error reading dump file");
 			} else {
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-				    "truncated dump file; tried to read %u captured bytes, only got %" PRIsize,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				    "truncated dump file; tried to read %u captured bytes, only got %zu",
 				    hdr->caplen, amt_read);
 			}
 			return (-1);
@@ -714,7 +713,7 @@
 }
 
 static int
-sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen)
+sf_write_header(pcap_t *p, FILE *fp, int linktype, int snaplen)
 {
 	struct pcap_file_header hdr;
 
@@ -722,9 +721,15 @@
 	hdr.version_major = PCAP_VERSION_MAJOR;
 	hdr.version_minor = PCAP_VERSION_MINOR;
 
-	hdr.thiszone = thiszone;
-	hdr.snaplen = snaplen;
+	/*
+	 * 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)
@@ -743,8 +748,12 @@
 	struct pcap_sf_pkthdr sf_hdr;
 
 	f = (FILE *)user;
-	sf_hdr.ts.tv_sec  = h->ts.tv_sec;
-	sf_hdr.ts.tv_usec = h->ts.tv_usec;
+	/*
+	 * 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 */
@@ -769,7 +778,7 @@
 	else
 		setvbuf(f, NULL, _IONBF, 0);
 #endif
-	if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) {
+	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)
@@ -793,14 +802,14 @@
 	 * link-layer type, so we can't use it.
 	 */
 	if (!p->activated) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		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) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: link-layer type %d isn't supported in savefiles",
 		    fname, p->linktype);
 		return (NULL);
@@ -808,7 +817,7 @@
 	linktype |= p->linktype_ext;
 
 	if (fname == NULL) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "A null pointer was supplied as the file name");
 		return NULL;
 	}
@@ -822,7 +831,7 @@
 		 * required on Windows, as the file is a binary file
 		 * and must be written in binary mode.
 		 */
-		f = fopen(fname, "wb");
+		f = charset_fopen(fname, "wb");
 		if (f == NULL) {
 			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
 			    errno, "%s", fname);
@@ -875,7 +884,7 @@
 
 	linktype = dlt_to_linktype(p->linktype);
 	if (linktype == -1) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "stream: link-layer type %d isn't supported in savefiles",
 		    p->linktype);
 		return (NULL);
@@ -895,14 +904,14 @@
 
 	linktype = dlt_to_linktype(p->linktype);
 	if (linktype == -1) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "%s: link-layer type %d isn't supported in savefiles",
 		    fname, linktype);
 		return (NULL);
 	}
 
 	if (fname == NULL) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "A null pointer was supplied as the file name");
 		return NULL;
 	}
@@ -922,7 +931,7 @@
 	 * 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 = fopen(fname, "ab+");
+	f = charset_fopen(fname, "ab+");
 	if (f == NULL) {
 		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
 		    errno, "%s", fname);
@@ -955,7 +964,7 @@
 			(void)fclose(f);
 			return (NULL);
 		} else if (feof(f) && amt_read > 0) {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "%s: truncated pcap file header", fname);
 			(void)fclose(f);
 			return (NULL);
@@ -991,7 +1000,7 @@
 
 		case TCPDUMP_MAGIC:
 			if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) {
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				    "%s: different time stamp precision, cannot append to file", fname);
 				(void)fclose(f);
 				return (NULL);
@@ -1000,7 +1009,7 @@
 
 		case NSEC_TCPDUMP_MAGIC:
 			if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) {
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				    "%s: different time stamp precision, cannot append to file", fname);
 				(void)fclose(f);
 				return (NULL);
@@ -1009,7 +1018,7 @@
 
 		case SWAPLONG(TCPDUMP_MAGIC):
 		case SWAPLONG(NSEC_TCPDUMP_MAGIC):
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "%s: different byte order, cannot append to file", fname);
 			(void)fclose(f);
 			return (NULL);
@@ -1018,13 +1027,13 @@
 		case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC):
 		case NAVTEL_TCPDUMP_MAGIC:
 		case SWAPLONG(NAVTEL_TCPDUMP_MAGIC):
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "%s: not a pcap file to which we can append", fname);
 			(void)fclose(f);
 			return (NULL);
 
 		default:
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "%s: not a pcap file", fname);
 			(void)fclose(f);
 			return (NULL);
@@ -1035,20 +1044,20 @@
 		 */
 		if (ph.version_major != PCAP_VERSION_MAJOR ||
 		    ph.version_minor != PCAP_VERSION_MINOR) {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			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) {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			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) {
-			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 			    "%s: different snaplen, cannot append to file", fname);
 			(void)fclose(f);
 			return (NULL);
@@ -1057,7 +1066,7 @@
 		/*
 		 * A header isn't present; attempt to write it.
 		 */
-		if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) {
+		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);
diff --git a/sf-pcapng.c b/sf-pcapng.c
index afaeb05..f7f413d 100644
--- a/sf-pcapng.c
+++ b/sf-pcapng.c
@@ -197,6 +197,7 @@
  * 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 */
@@ -265,8 +266,8 @@
 		} else {
 			if (amt_read == 0 && !fail_on_eof)
 				return (0);	/* EOF */
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-			    "truncated pcapng dump file; tried to read %" PRIsize " bytes, only got %" PRIsize,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			    "truncated pcapng dump file; tried to read %zu bytes, only got %zu",
 			    bytes_to_read, amt_read);
 		}
 		return (-1);
@@ -301,8 +302,8 @@
 	 */
 	if (bhdr.total_length < sizeof(struct block_header) +
 	    sizeof(struct block_trailer)) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-		    "block in pcapng dump file has a length of %u < %" PRIsize,
+		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);
@@ -315,8 +316,8 @@
 		/*
 		 * No.  Report that as an error.
 		 */
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-		    "block in pcapng dump file has a length of %u that is not a multiple of 4" PRIsize,
+		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);
 	}
@@ -332,13 +333,13 @@
 		void *bigger_buffer;
 
 		if (bhdr.total_length > ps->max_blocksize) {
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcapng block size %u > maximum %u", bhdr.total_length,
+			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) {
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+			snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
 			return (-1);
 		}
 		p->buffer = bigger_buffer;
@@ -369,7 +370,7 @@
 		/*
 		 * No.
 		 */
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "block total length in header and trailer don't match");
 		return (-1);
 	}
@@ -394,7 +395,7 @@
 	 * the block data.
 	 */
 	if (cursor->data_remaining < chunk_size) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "block of type %u in pcapng dump file is too short",
 		    cursor->block_type);
 		return (NULL);
@@ -495,7 +496,7 @@
 
 		case OPT_ENDOFOPT:
 			if (opthdr->option_length != 0) {
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "Interface Description Block has opt_endofopt option with length %u != 0",
 				    opthdr->option_length);
 				return (-1);
@@ -504,13 +505,13 @@
 
 		case IF_TSRESOL:
 			if (opthdr->option_length != 1) {
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "Interface Description Block has if_tsresol option with length %u != 1",
 				    opthdr->option_length);
 				return (-1);
 			}
 			if (saw_tsresol) {
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "Interface Description Block has more than one if_tsresol option");
 				return (-1);
 			}
@@ -527,7 +528,7 @@
 					 * Resolution is too high; 2^-{res}
 					 * won't fit in a 64-bit value.
 					 */
-					pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+					snprintf(errbuf, PCAP_ERRBUF_SIZE,
 					    "Interface Description Block if_tsresol option resolution 2^-%u is too high",
 					    tsresol_shift);
 					return (-1);
@@ -547,7 +548,7 @@
 					 * the largest 64-bit unsigned
 					 * value is ~1.8*10^19).
 					 */
-					pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+					snprintf(errbuf, PCAP_ERRBUF_SIZE,
 					    "Interface Description Block if_tsresol option resolution 10^-%u is too high",
 					    tsresol_opt);
 					return (-1);
@@ -561,13 +562,13 @@
 
 		case IF_TSOFFSET:
 			if (opthdr->option_length != 8) {
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "Interface Description Block has if_tsoffset option with length %u != 8",
 				    opthdr->option_length);
 				return (-1);
 			}
 			if (saw_tsoffset) {
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "Interface Description Block has more than one if_tsoffset option");
 				return (-1);
 			}
@@ -587,7 +588,8 @@
 }
 
 static int
-add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
+add_interface(pcap_t *p, struct interface_description_block *idbp,
+    struct block_cursor *cursor, char *errbuf)
 {
 	struct pcap_ng_sf *ps;
 	uint64_t tsresol;
@@ -644,7 +646,7 @@
 				 * possible 32-bit power of 2, as we do
 				 * size doubling.
 				 */
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "more than %u interfaces in the file",
 				    0x80000000U);
 				return (0);
@@ -675,7 +677,7 @@
 				 * (unsigned) value divided by
 				 * sizeof (struct pcap_ng_if).
 				 */
-				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(errbuf, PCAP_ERRBUF_SIZE,
 				    "more than %u interfaces in the file",
 				    0xFFFFFFFFU / ((u_int)sizeof (struct pcap_ng_if)));
 				return (0);
@@ -687,7 +689,7 @@
 			 * We ran out of memory.
 			 * Give up.
 			 */
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "out of memory for per-interface information (%u interfaces)",
 			    ps->ifcount);
 			return (0);
@@ -696,6 +698,8 @@
 		ps->ifaces = new_ifaces;
 	}
 
+	ps->ifaces[ps->ifcount - 1].snaplen = idbp->snaplen;
+
 	/*
 	 * Set the default time stamp resolution and offset.
 	 */
@@ -858,8 +862,8 @@
 	 */
 	if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer) ||
             (total_length > BT_SHB_INSANE_MAX)) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-		    "Section Header Block in pcapng dump file has invalid length %" PRIsize " < _%u_ < %u (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);
@@ -872,7 +876,7 @@
 	 * OK, this is a good pcapng file.
 	 * Allocate a pcap_t for it.
 	 */
-	p = pcap_open_offline_common(errbuf, sizeof (struct pcap_ng_sf));
+	p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_ng_sf);
 	if (p == NULL) {
 		/* Allocation failed. */
 		*err = 1;
@@ -895,7 +899,7 @@
 		break;
 
 	default:
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "unknown time stamp resolution %u", precision);
 		free(p);
 		*err = 1;
@@ -925,7 +929,7 @@
 		p->bufsize = total_length;
 	p->buffer = malloc(p->bufsize);
 	if (p->buffer == NULL) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+		snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
 		free(p);
 		*err = 1;
 		return (NULL);
@@ -961,7 +965,7 @@
 	/* currently only SHB version 1.0 is supported */
 	if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR &&
 	       shbp->minor_version == PCAP_NG_VERSION_MINOR)) {
-		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(errbuf, PCAP_ERRBUF_SIZE,
 		    "unsupported pcapng savefile version %u.%u",
 		    shbp->major_version, shbp->minor_version);
 		goto fail;
@@ -984,7 +988,7 @@
 		status = read_block(fp, p, &cursor, errbuf);
 		if (status == 0) {
 			/* EOF - no IDB in this file */
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "the capture file has no Interface Description Blocks");
 			goto fail;
 		}
@@ -1013,7 +1017,7 @@
 			/*
 			 * Try to add this interface.
 			 */
-			if (!add_interface(p, &cursor, errbuf))
+			if (!add_interface(p, idbp, &cursor, errbuf))
 				goto fail;
 
 			goto done;
@@ -1026,7 +1030,7 @@
 			 * not valid, as we don't know what link-layer
 			 * encapsulation the packet has.
 			 */
-			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+			snprintf(errbuf, PCAP_ERRBUF_SIZE,
 			    "the capture file has a packet block before any Interface Description Blocks");
 			goto fail;
 
@@ -1039,7 +1043,6 @@
 	}
 
 done:
-	p->tzoff = 0;	/* XXX - not used in pcap */
 	p->linktype = linktype_to_dlt(idbp->linktype);
 	p->snapshot = pcap_adjust_snapshot(p->linktype, idbp->snaplen);
 	p->linktype_ext = 0;
@@ -1231,7 +1234,7 @@
 			 * interfaces?
 			 */
 			if (p->linktype != idbp->linktype) {
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				    "an interface has a type %u different from the type of the first interface",
 				    idbp->linktype);
 				return (-1);
@@ -1243,8 +1246,8 @@
 			 */
 			if ((bpf_u_int32)p->snapshot !=
 			    pcap_adjust_snapshot(p->linktype, idbp->snaplen)) {
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-				    "an interface has a snapshot length %u different from the type of the first interface",
+				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);
 			}
@@ -1252,7 +1255,7 @@
 			/*
 			 * Try to add this interface.
 			 */
-			if (!add_interface(p, &cursor, p->errbuf))
+			if (!add_interface(p, idbp, &cursor, p->errbuf))
 				return (-1);
 			break;
 
@@ -1295,7 +1298,7 @@
 				/*
 				 * Byte order changes.
 				 */
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				    "the file has sections with different byte orders");
 				return (-1);
 
@@ -1303,7 +1306,7 @@
 				/*
 				 * Not a valid SHB.
 				 */
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				    "the file has a section with a bad byte order magic field");
 				return (-1);
 			}
@@ -1313,7 +1316,7 @@
 			 * we handle.
 			 */
 			if (shbp->major_version != PCAP_NG_VERSION_MAJOR) {
-				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 				    "unknown pcapng savefile major version number %u",
 				    shbp->major_version);
 				return (-1);
@@ -1347,14 +1350,14 @@
 		/*
 		 * Yes.  Fail.
 		 */
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		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) {
-		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
 		    "invalid packet capture length %u, bigger than "
 		    "snaplen of %d", hdr->caplen, p->snapshot);
 		return (-1);
diff --git a/sockutils.c b/sockutils.c
index d3e9464..c1ec9a5 100644
--- a/sockutils.c
+++ b/sockutils.c
@@ -56,11 +56,7 @@
 #include <errno.h>	/* for the errno variable */
 #include <stdio.h>	/* for the stderr file */
 #include <stdlib.h>	/* for malloc() and free() */
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#else
-#define INT_MAX		2147483647
-#endif
+#include <limits.h>	/* for INT_MAX */
 
 #include "pcap-int.h"
 
@@ -71,7 +67,7 @@
   /*
    * Winsock initialization.
    *
-   * Ask for WinSock 2.2.
+   * Ask for Winsock 2.2.
    */
   #define WINSOCK_MAJOR_VERSION 2
   #define WINSOCK_MINOR_VERSION 2
@@ -124,8 +120,31 @@
  *                                                  *
  ****************************************************/
 
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+const uint8_t *fuzzBuffer;
+size_t fuzzSize;
+size_t fuzzPos;
+
+void sock_initfuzz(const uint8_t *Data, size_t Size) {
+	fuzzPos = 0;
+	fuzzSize = Size;
+	fuzzBuffer = Data;
+}
+
+static int fuzz_recv(char *bufp, int remaining) {
+	if (remaining > fuzzSize - fuzzPos) {
+		remaining = fuzzSize - fuzzPos;
+	}
+	if (fuzzPos < fuzzSize) {
+		memcpy(bufp, fuzzBuffer + fuzzPos, remaining);
+	}
+	fuzzPos += remaining;
+	return remaining;
+}
+#endif
+
 /*
- * Format an error message given an errno value (UN*X) or a WinSock error
+ * Format an error message given an errno value (UN*X) or a Winsock error
  * (Windows).
  */
 void sock_fmterror(const char *caller, int errcode, char *errbuf, int errbuflen)
@@ -201,7 +220,7 @@
 		    WINSOCK_MINOR_VERSION), &wsaData) != 0)
 		{
 			if (errbuf)
-				pcap_snprintf(errbuf, errbuflen, "Failed to initialize Winsock\n");
+				snprintf(errbuf, errbuflen, "Failed to initialize Winsock\n");
 
 			WSACleanup();
 
@@ -271,7 +290,7 @@
  *
  * In case of a server socket, the function calls socket(), bind() and listen().
  *
- * This function is usually preceeded by the sock_initaddress().
+ * This function is usually preceded by the sock_initaddress().
  *
  * \param addrinfo: pointer to an addrinfo variable which will be used to
  * open the socket and such. This variable is the one returned by the previous call to
@@ -375,7 +394,7 @@
 			    (char *)&on, sizeof (int)) == -1)
 			{
 				if (errbuf)
-					pcap_snprintf(errbuf, errbuflen, "setsockopt(IPV6_V6ONLY)");
+					snprintf(errbuf, errbuflen, "setsockopt(IPV6_V6ONLY)");
 				closesocket(sock);
 				return INVALID_SOCKET;
 			}
@@ -419,7 +438,9 @@
 		 */
 		while (tempaddrinfo)
 		{
-
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+			break;
+#endif
 			if (connect(sock, tempaddrinfo->ai_addr, (int) tempaddrinfo->ai_addrlen) == -1)
 			{
 				size_t msglen;
@@ -436,7 +457,7 @@
 				/* Returns the numeric address of the host that triggered the error */
 				sock_getascii_addrport((struct sockaddr_storage *) tempaddrinfo->ai_addr, TmpBuffer, sizeof(TmpBuffer), NULL, 0, NI_NUMERICHOST, TmpBuffer, sizeof(TmpBuffer));
 
-				pcap_snprintf(errbufptr, bufspaceleft,
+				snprintf(errbufptr, bufspaceleft,
 				    "Is the server properly installed on %s?  %s", TmpBuffer, SocketErrorMessage);
 
 				/* In case more then one 'connect' fails, we manage to keep all the error messages */
@@ -527,52 +548,52 @@
 	char hostport[PCAP_ERRBUF_SIZE];
 
 	if (hostname != NULL && portname != NULL)
-		pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "%s:%s",
+		snprintf(hostport, PCAP_ERRBUF_SIZE, "%s:%s",
 		    hostname, portname);
 	else if (hostname != NULL)
-		pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "%s",
+		snprintf(hostport, PCAP_ERRBUF_SIZE, "%s",
 		    hostname);
 	else if (portname != NULL)
-		pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, ":%s",
+		snprintf(hostport, PCAP_ERRBUF_SIZE, ":%s",
 		    portname);
 	else
-		pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "<no host or port!>");
+		snprintf(hostport, PCAP_ERRBUF_SIZE, "<no host or port!>");
 	switch (err)
 	{
 #ifdef EAI_ADDRFAMILY
 		case EAI_ADDRFAMILY:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sAddress family for %s not supported",
 			    prefix, hostport);
 			break;
 #endif
 
 		case EAI_AGAIN:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%s%s could not be resolved at this time",
 			    prefix, hostport);
 			break;
 
 		case EAI_BADFLAGS:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sThe ai_flags parameter for looking up %s had an invalid value",
 			    prefix, hostport);
 			break;
 
 		case EAI_FAIL:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sA non-recoverable error occurred when attempting to resolve %s",
 			    prefix, hostport);
 			break;
 
 		case EAI_FAMILY:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sThe address family for looking up %s was not recognized",
 			    prefix, hostport);
 			break;
 
 		case EAI_MEMORY:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sOut of memory trying to allocate storage when looking up %s",
 			    prefix, hostport);
 			break;
@@ -589,26 +610,26 @@
 		 */
 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
 		case EAI_NODATA:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sNo address associated with %s",
 			    prefix, hostport);
 			break;
 #endif
 
 		case EAI_NONAME:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sThe host name %s couldn't be resolved",
 			    prefix, hostport);
 			break;
 
 		case EAI_SERVICE:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sThe service value specified when looking up %s as not recognized for the socket type",
 			    prefix, hostport);
 			break;
 
 		case EAI_SOCKTYPE:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sThe socket type specified when looking up %s as not recognized",
 			    prefix, hostport);
 			break;
@@ -618,15 +639,15 @@
 			/*
 			 * Assumed to be UN*X.
 			 */
-			pcap_snprintf(errbuf, errbuflen,
-			    "%sAn error occurred when looking up %s: %s",
-			    prefix, hostport, pcap_strerror(errno));
+			pcap_fmt_errmsg_for_errno(errbuf, errbuflen, errno,
+			    "%sAn error occurred when looking up %s",
+			    prefix, hostport);
 			break;
 #endif
 
 #ifdef EAI_BADHINTS
 		case EAI_BADHINTS:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sInvalid value for hints when looking up %s",
 			    prefix, hostport);
 			break;
@@ -634,7 +655,7 @@
 
 #ifdef EAI_PROTOCOL
 		case EAI_PROTOCOL:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sResolved protocol when looking up %s is unknown",
 			    prefix, hostport);
 			break;
@@ -642,14 +663,14 @@
 
 #ifdef EAI_OVERFLOW
 		case EAI_OVERFLOW:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sArgument buffer overflow when looking up %s",
 			    prefix, hostport);
 			break;
 #endif
 
 		default:
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "%sgetaddrinfo() error %d when looking up %s",
 			    prefix, err, hostport);
 			break;
@@ -726,7 +747,7 @@
 	    ((*addrinfo)->ai_family != PF_INET6))
 	{
 		if (errbuf)
-			pcap_snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported");
+			snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported");
 		freeaddrinfo(*addrinfo);
 		*addrinfo = NULL;
 		return -1;
@@ -739,7 +760,7 @@
 	    (sock_ismcastaddr((*addrinfo)->ai_addr) == 0))
 	{
 		if (errbuf)
-			pcap_snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams");
+			snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams");
 		freeaddrinfo(*addrinfo);
 		*addrinfo = NULL;
 		return -1;
@@ -775,7 +796,7 @@
  * '-2' if we got one of those errors.
  * For errors, an error message is returned in the 'errbuf' variable.
  */
-int sock_send(SOCKET sock, const char *buffer, size_t size,
+int sock_send(SOCKET sock, SSL *ssl _U_NOSSL_, const char *buffer, size_t size,
     char *errbuf, int errbuflen)
 {
 	int remaining;
@@ -785,7 +806,7 @@
 	{
 		if (errbuf)
 		{
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "Can't send more than %u bytes with sock_send",
 			    INT_MAX);
 		}
@@ -794,6 +815,13 @@
 	remaining = (int)size;
 
 	do {
+#ifdef HAVE_OPENSSL
+		if (ssl) return ssl_send(ssl, buffer, remaining, errbuf, errbuflen);
+#endif
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+		nsent = remaining;
+#else
 #ifdef MSG_NOSIGNAL
 		/*
 		 * Send with MSG_NOSIGNAL, so that we don't get SIGPIPE
@@ -805,6 +833,7 @@
 #else
 		nsent = send(sock, buffer, remaining, 0);
 #endif
+#endif //FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
 
 		if (nsent == -1)
 		{
@@ -912,7 +941,7 @@
 	if ((*offset + size) > totsize)
 	{
 		if (errbuf)
-			pcap_snprintf(errbuf, errbuflen, "Not enough space in the temporary send buffer.");
+			snprintf(errbuf, errbuflen, "Not enough space in the temporary send buffer.");
 		return -1;
 	}
 
@@ -970,9 +999,10 @@
  * The error message is returned in the 'errbuf' variable.
  */
 
-int sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
-    char *errbuf, int errbuflen)
+int sock_recv(SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, size_t size,
+    int flags, char *errbuf, int errbuflen)
 {
+	int recv_flags = 0;
 	char *bufp = buffer;
 	int remaining;
 	ssize_t nread;
@@ -985,13 +1015,16 @@
 	{
 		if (errbuf)
 		{
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "Can't read more than %u bytes with sock_recv",
 			    INT_MAX);
 		}
 		return -1;
 	}
 
+	if (flags & SOCK_MSG_PEEK)
+		recv_flags |= MSG_PEEK;
+
 	bufp = (char *) buffer;
 	remaining = (int) size;
 
@@ -1000,7 +1033,22 @@
 	 * Win32.
 	 */
 	for (;;) {
-		nread = recv(sock, bufp, remaining, 0);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+		nread = fuzz_recv(bufp, remaining);
+#elif defined(HAVE_OPENSSL)
+		if (ssl)
+		{
+			/*
+			 * XXX - what about MSG_PEEK?
+			 */
+			nread = ssl_recv(ssl, bufp, remaining, errbuf, errbuflen);
+			if (nread == -2) return -1;
+		}
+		else
+			nread = recv(sock, bufp, remaining, recv_flags);
+#else
+		nread = recv(sock, bufp, remaining, recv_flags);
+#endif
 
 		if (nread == -1)
 		{
@@ -1024,7 +1072,7 @@
 				 */
 				if (errbuf)
 				{
-					pcap_snprintf(errbuf, errbuflen,
+					snprintf(errbuf, errbuflen,
 					    "The other host terminated the connection.");
 				}
 				return -1;
@@ -1058,7 +1106,7 @@
  *
  * Returns the size of the datagram on success or -1 on error.
  */
-int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
+int sock_recv_dgram(SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, size_t size,
     char *errbuf, int errbuflen)
 {
 	ssize_t nread;
@@ -1075,20 +1123,29 @@
 	{
 		if (errbuf)
 		{
-			pcap_snprintf(errbuf, errbuflen,
+			snprintf(errbuf, errbuflen,
 			    "Can't read more than %u bytes with sock_recv_dgram",
 			    INT_MAX);
 		}
 		return -1;
 	}
 
+#ifdef HAVE_OPENSSL
+	// TODO: DTLS
+	if (ssl)
+	{
+		snprintf(errbuf, errbuflen, "DTLS not implemented yet");
+		return -1;
+	}
+#endif
+
 	/*
 	 * This should be a datagram socket, so we should get the
 	 * entire datagram in one recv() or recvmsg() call, and
 	 * don't need to loop.
 	 */
 #ifdef _WIN32
-	nread = recv(sock, buffer, size, 0);
+	nread = recv(sock, buffer, (int)size, 0);
 	if (nread == SOCKET_ERROR)
 	{
 		/*
@@ -1132,7 +1189,11 @@
 #ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS
 	message.msg_flags = 0;
 #endif
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+	nread = fuzz_recv(buffer, size);
+#else
 	nread = recvmsg(sock, &message, 0);
+#endif
 	if (nread == -1)
 	{
 		if (errno == EINTR)
@@ -1154,7 +1215,7 @@
 		 * Report this as an error, as the Microsoft documentation
 		 * implies we'd do in a similar case on Windows.
 		 */
-		pcap_snprintf(errbuf, errbuflen, "recv(): Message too long");
+		snprintf(errbuf, errbuflen, "recv(): Message too long");
 		return -1;
 	}
 #endif /* HAVE_STRUCT_MSGHDR_MSG_FLAGS */
@@ -1192,7 +1253,7 @@
  * \return '0' if everything is fine, '-1' if some errors occurred.
  * The error message is returned in the 'errbuf' variable.
  */
-int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen)
+int sock_discard(SOCKET sock, SSL *ssl, int size, char *errbuf, int errbuflen)
 {
 #define TEMP_BUF_SIZE 32768
 
@@ -1208,7 +1269,7 @@
 	 */
 	while (size > TEMP_BUF_SIZE)
 	{
-		if (sock_recv(sock, buffer, TEMP_BUF_SIZE, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
+		if (sock_recv(sock, ssl, buffer, TEMP_BUF_SIZE, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
 			return -1;
 
 		size -= TEMP_BUF_SIZE;
@@ -1220,7 +1281,7 @@
 	 */
 	if (size)
 	{
-		if (sock_recv(sock, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
+		if (sock_recv(sock, ssl, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
 			return -1;
 	}
 
@@ -1358,7 +1419,7 @@
 			 * the host wasn't in the list.
 			 */
 			if (errbuf)
-				pcap_snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused.");
+				snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused.");
 			return -1;
 		}
 	}
@@ -1628,7 +1689,7 @@
 		freeaddrinfo(addrinfo);
 
 		if (errbuf)
-			pcap_snprintf(errbuf, errbuflen, "More than one socket requested; using the first one returned");
+			snprintf(errbuf, errbuflen, "More than one socket requested; using the first one returned");
 		return -2;
 	}
 
diff --git a/sockutils.h b/sockutils.h
index 8a45b3d..e748662 100644
--- a/sockutils.h
+++ b/sockutils.h
@@ -52,6 +52,8 @@
   #define closesocket(a) close(a)
 #endif
 
+#include "sslutils.h"  // for SSL type, whatever that turns out to be
+
 /*
  * MingW headers include this definition, but only for Windows XP and above.
  * MSDN states that this function is available for most versions on Windows.
@@ -104,6 +106,8 @@
 #define SOCK_EOF_ISNT_ERROR	0x00000000	/* Return 0 on EOF */
 #define SOCK_EOF_IS_ERROR	0x00000002	/* Return an error on EOF */
 
+#define SOCK_MSG_PEEK		0x00000004	/* Return data but leave it in the socket queue */
+
 /*
  * \}
  */
@@ -128,17 +132,17 @@
 int sock_initaddress(const char *address, const char *port,
     struct addrinfo *hints, struct addrinfo **addrinfo,
     char *errbuf, int errbuflen);
-int sock_recv(SOCKET sock, void *buffer, size_t size, int receiveall,
+int sock_recv(SOCKET sock, SSL *, void *buffer, size_t size, int receiveall,
     char *errbuf, int errbuflen);
-int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
+int sock_recv_dgram(SOCKET sock, SSL *, void *buffer, size_t size,
     char *errbuf, int errbuflen);
 SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen);
 int sock_close(SOCKET sock, char *errbuf, int errbuflen);
 
-int sock_send(SOCKET sock, const char *buffer, size_t size,
+int sock_send(SOCKET sock, SSL *, const char *buffer, size_t size,
     char *errbuf, int errbuflen);
 int sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen);
-int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen);
+int sock_discard(SOCKET sock, SSL *, int size, char *errbuf, int errbuflen);
 int	sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen);
 int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second);
 
diff --git a/sslutils.c b/sslutils.c
new file mode 100644
index 0000000..7274cc3
--- /dev/null
+++ b/sslutils.c
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_OPENSSL
+#include <stdlib.h>
+
+#include "portability.h"
+
+#include "sslutils.h"
+
+static const char *ssl_keyfile = "";   //!< file containing the private key in PEM format
+static const char *ssl_certfile = "";  //!< file containing the server's certificate in PEM format
+static const char *ssl_rootfile = "";  //!< file containing the list of CAs trusted by the client
+// TODO: a way to set ssl_rootfile from the command line, or an envvar?
+
+// TODO: lock?
+static SSL_CTX *ctx;
+
+void ssl_set_certfile(const char *certfile)
+{
+	ssl_certfile = certfile;
+}
+
+void ssl_set_keyfile(const char *keyfile)
+{
+	ssl_keyfile = keyfile;
+}
+
+int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen)
+{
+	static int inited = 0;
+	if (inited) return 0;
+
+	SSL_library_init();
+	SSL_load_error_strings();
+	OpenSSL_add_ssl_algorithms();
+	if (enable_compression)
+		SSL_COMP_get_compression_methods();
+
+	SSL_METHOD const *meth =
+	    is_server ? SSLv23_server_method() : SSLv23_client_method();
+	ctx = SSL_CTX_new(meth);
+	if (! ctx)
+	{
+		snprintf(errbuf, errbuflen, "Cannot get a new SSL context: %s", ERR_error_string(ERR_get_error(), NULL));
+		goto die;
+	}
+
+	SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+
+	if (is_server)
+	{
+		char const *certfile = ssl_certfile[0] ? ssl_certfile : "cert.pem";
+		if (1 != SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
+		{
+			snprintf(errbuf, errbuflen, "Cannot read certificate file %s: %s", certfile, ERR_error_string(ERR_get_error(), NULL));
+			goto die;
+		}
+
+		char const *keyfile = ssl_keyfile[0] ? ssl_keyfile : "key.pem";
+		if (1 != SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
+		{
+			snprintf(errbuf, errbuflen, "Cannot read private key file %s: %s", keyfile, ERR_error_string(ERR_get_error(), NULL));
+			goto die;
+		}
+	}
+	else
+	{
+		if (ssl_rootfile[0])
+		{
+			if (! SSL_CTX_load_verify_locations(ctx, ssl_rootfile, 0))
+			{
+				snprintf(errbuf, errbuflen, "Cannot read CA list from %s", ssl_rootfile);
+				goto die;
+			}
+		}
+		else
+		{
+			SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+		}
+	}
+
+#if 0
+	if (! RAND_load_file(RANDOM, 1024*1024))
+	{
+		snprintf(errbuf, errbuflen, "Cannot init random");
+		goto die;
+	}
+
+	if (is_server)
+	{
+		SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, sizeof(s_server_session_id_context));
+	}
+#endif
+
+	inited = 1;
+	return 0;
+
+die:
+	return -1;
+}
+
+SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen)
+{
+	if (ssl_init_once(is_server, 1, errbuf, errbuflen) < 0) {
+		return NULL;
+	}
+
+	SSL *ssl = SSL_new(ctx); // TODO: also a DTLS context
+	SSL_set_fd(ssl, (int)s);
+
+	if (is_server) {
+		if (SSL_accept(ssl) <= 0) {
+			snprintf(errbuf, errbuflen, "SSL_accept(): %s",
+					ERR_error_string(ERR_get_error(), NULL));
+			return NULL;
+		}
+	} else {
+		if (SSL_connect(ssl) <= 0) {
+			snprintf(errbuf, errbuflen, "SSL_connect(): %s",
+					ERR_error_string(ERR_get_error(), NULL));
+			return NULL;
+		}
+	}
+
+	return ssl;
+}
+
+// Finish using an SSL handle; shut down the connection and free the
+// handle.
+void ssl_finish(SSL *ssl)
+{
+	//
+	// We won't be using this again, so we can just send the
+	// shutdown alert and free up the handle, and have our
+	// caller close the socket.
+	//
+	// XXX - presumably, if the connection is shut down on
+	// our side, either our peer won't have a problem sending
+	// their shutdown alert or will not treat such a problem
+	// as an error.  If this causes errors to be reported,
+	// fix that as appropriate.
+	//
+	SSL_shutdown(ssl);
+	SSL_free(ssl);
+}
+
+// Same return value as sock_send:
+// 0 on OK, -1 on error but closed connection (-2).
+int ssl_send(SSL *ssl, char const *buffer, int size, char *errbuf, size_t errbuflen)
+{
+	int status = SSL_write(ssl, buffer, size);
+	if (status > 0)
+	{
+		// "SSL_write() will only return with success, when the complete contents (...) has been written."
+		return 0;
+	}
+	else
+	{
+		int ssl_err = SSL_get_error(ssl, status); // TODO: does it pop the error?
+		if (ssl_err == SSL_ERROR_ZERO_RETURN)
+		{
+			return -2;
+		}
+		else if (ssl_err == SSL_ERROR_SYSCALL)
+		{
+#ifndef _WIN32
+			if (errno == ECONNRESET || errno == EPIPE) return -2;
+#endif
+		}
+		snprintf(errbuf, errbuflen, "SSL_write(): %s",
+		    ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+}
+
+// Returns the number of bytes read, or -1 on syserror, or -2 on SSL error.
+int ssl_recv(SSL *ssl, char *buffer, int size, char *errbuf, size_t errbuflen)
+{
+	int status = SSL_read(ssl, buffer, size);
+	if (status <= 0)
+	{
+		int ssl_err = SSL_get_error(ssl, status);
+		if (ssl_err == SSL_ERROR_ZERO_RETURN)
+		{
+			return 0;
+		}
+		else if (ssl_err == SSL_ERROR_SYSCALL)
+		{
+			return -1;
+		}
+		else
+		{
+			// Should not happen
+			snprintf(errbuf, errbuflen, "SSL_read(): %s",
+			    ERR_error_string(ERR_get_error(), NULL));
+			return -2;
+		}
+	}
+	else
+	{
+		return status;
+	}
+}
+
+#endif // HAVE_OPENSSL
diff --git a/sslutils.h b/sslutils.h
new file mode 100644
index 0000000..6316364
--- /dev/null
+++ b/sslutils.h
@@ -0,0 +1,66 @@
+/*
+ * 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 __SSLUTILS_H__
+#define __SSLUTILS_H__
+
+#ifdef HAVE_OPENSSL
+#include "pcap/socket.h"  // for SOCKET
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+/*
+ * Utility functions
+ */
+
+void ssl_set_certfile(const char *certfile);
+void ssl_set_keyfile(const char *keyfile);
+int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen);
+SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen);
+void ssl_finish(SSL *ssl);
+int ssl_send(SSL *, char const *buffer, int size, char *errbuf, size_t errbuflen);
+int ssl_recv(SSL *, char *buffer, int size, char *errbuf, size_t errbuflen);
+
+// The SSL parameters are used
+#define _U_NOSSL_
+
+#else   // HAVE_OPENSSL
+
+// This saves us from a lot of ifdefs:
+#define SSL void const
+
+// The SSL parameters are unused
+#define _U_NOSSL_	_U_
+
+#endif  // HAVE_OPENSSL
+
+#endif  // __SSLUTILS_H__
diff --git a/testprogs/.gitignore b/testprogs/.gitignore
index b9178b4..b57c7bb 100644
--- a/testprogs/.gitignore
+++ b/testprogs/.gitignore
@@ -7,7 +7,9 @@
 can_set_rfmon_test
 filtertest
 findalldevstest
+findalldevstest-perf
 opentest
 reactivatetest
 selpolltest
 threadsignaltest
+writecaptest
diff --git a/testprogs/BPF/1.txt b/testprogs/BPF/1.txt
index 6608695..733651e 100644
--- a/testprogs/BPF/1.txt
+++ b/testprogs/BPF/1.txt
@@ -1,2 +1,2 @@
-# common block merging, same block elimination, result propogation
+# common block merging, same block elimination, result propagation
 host 192.168.1.1
diff --git a/testprogs/CMakeLists.txt b/testprogs/CMakeLists.txt
index b8ef9b7..bf57361 100644
--- a/testprogs/CMakeLists.txt
+++ b/testprogs/CMakeLists.txt
@@ -19,6 +19,10 @@
     target_link_libraries(${_executable}
       ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
   endif(WIN32)
+  if(NOT "${LINKER_FLAGS}" STREQUAL "")
+    set_target_properties(${_executable} PROPERTIES
+      LINK_FLAGS "${LINKER_FLAGS}")
+  endif()
   add_dependencies(testprogs ${_executable})
 endmacro()
 
@@ -26,8 +30,10 @@
 add_test_executable(capturetest)
 add_test_executable(filtertest)
 add_test_executable(findalldevstest)
+add_test_executable(findalldevstest-perf)
 add_test_executable(opentest)
 add_test_executable(reactivatetest)
+add_test_executable(writecaptest)
 
 if(NOT WIN32)
   add_test_executable(selpolltest)
@@ -38,3 +44,5 @@
 if(NOT WIN32)
   add_test_executable(valgrindtest)
 endif()
+
+add_subdirectory(fuzz)
diff --git a/testprogs/Makefile.in b/testprogs/Makefile.in
index ec0a472..43af561 100644
--- a/testprogs/Makefile.in
+++ b/testprogs/Makefile.in
@@ -38,6 +38,7 @@
 
 # VPATH
 srcdir = @srcdir@
+top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 
 #
@@ -79,14 +80,16 @@
 	$(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c
 
 SRC = @VALGRINDTEST_SRC@ \
-	capturetest.c \
 	can_set_rfmon_test.c \
+	capturetest.c \
 	filtertest.c \
+	findalldevstest-perf.c \
 	findalldevstest.c \
 	opentest.c \
 	reactivatetest.c \
 	selpolltest.c \
-	threadsignaltest.c
+	threadsignaltest.c \
+	writecaptest.c
 
 TESTS = $(SRC:.c=)
 
@@ -109,6 +112,9 @@
 findalldevstest: $(srcdir)/findalldevstest.c ../libpcap.a
 	$(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest $(srcdir)/findalldevstest.c ../libpcap.a $(EXTRA_NETWORK_LIBS) $(LIBS)
 
+findalldevstest-perf: $(srcdir)/findalldevstest-perf.c ../libpcap.a
+	$(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest-perf $(srcdir)/findalldevstest-perf.c ../libpcap.a $(EXTRA_NETWORK_LIBS) $(LIBS)
+
 opentest: $(srcdir)/opentest.c ../libpcap.a
 	$(CC) $(FULL_CFLAGS) -I. -L. -o opentest $(srcdir)/opentest.c ../libpcap.a $(LIBS)
 
@@ -124,6 +130,9 @@
 valgrindtest: $(srcdir)/valgrindtest.c ../libpcap.a
 	$(CC) $(FULL_CFLAGS) -I. -L. -o valgrindtest $(srcdir)/valgrindtest.c ../libpcap.a $(LIBS)
 
+writecaptest: $(srcdir)/writecaptest.c ../libpcap.a
+	$(CC) $(FULL_CFLAGS) -I. -L. -o writecaptest $(srcdir)/writecaptest.c ../libpcap.a $(LIBS)
+
 clean:
 	rm -f $(CLEANFILES)
 	rm -rf *.dSYM
@@ -141,4 +150,4 @@
 	ctags -wtd $(TAGFILES)
 
 depend:
-	../$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
+	$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
diff --git a/testprogs/can_set_rfmon_test.c b/testprogs/can_set_rfmon_test.c
index f6188ba..96816f9 100644
--- a/testprogs/can_set_rfmon_test.c
+++ b/testprogs/can_set_rfmon_test.c
@@ -70,7 +70,6 @@
 		else
 			error("%s: pcap_can_set_rfmon failed: %s", argv[1],
 			    pcap_statustostr(status));
-		return 1;
 	}
 	printf("%s: Monitor mode %s be set\n", argv[1], status ? "can" : "cannot");
 	return 0;
diff --git a/testprogs/capturetest.c b/testprogs/capturetest.c
index d625cb4..4eadd33 100644
--- a/testprogs/capturetest.c
+++ b/testprogs/capturetest.c
@@ -38,6 +38,9 @@
   #include <unistd.h>
 #endif
 #include <errno.h>
+#ifndef _WIN32
+  #include <signal.h>
+#endif
 #include <sys/types.h>
 
 #include <pcap.h>
@@ -58,6 +61,37 @@
 static char *copy_argv(char **);
 
 static pcap_t *pd;
+#ifndef _WIN32
+static int breaksigint = 0;
+#endif
+
+#ifndef _WIN32
+static void
+sigint_handler(int signum _U_)
+{
+	if (breaksigint)
+		pcap_breakloop(pd);
+}
+#endif
+
+#ifdef _WIN32
+/*
+ * We don't have UN*X-style signals, so we don't have anything to test.
+ */
+#define B_OPTION	""
+#define R_OPTION	""
+#define S_OPTION	""
+#else
+/*
+ * We do have UN*X-style signals (we assume that "not Windows" means "UN*X").
+ */
+#define B_OPTION	"b"
+#define R_OPTION	"r"
+#define S_OPTION	"s"
+#endif
+
+#define COMMAND_OPTIONS	B_OPTION "i:mn" R_OPTION S_OPTION "t:"
+#define USAGE_OPTIONS	"-" B_OPTION "mn" R_OPTION S_OPTION
 
 int
 main(int argc, char **argv)
@@ -69,6 +103,10 @@
 	int timeout = 1000;
 	int immediate = 0;
 	int nonblock = 0;
+#ifndef _WIN32
+	int sigrestart = 0;
+	int catchsigint = 0;
+#endif
 	pcap_if_t *devlist;
 	bpf_u_int32 localnet, netmask;
 	struct bpf_program fcode;
@@ -83,9 +121,15 @@
 		program_name = argv[0];
 
 	opterr = 0;
-	while ((op = getopt(argc, argv, "i:mnt:")) != -1) {
+	while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) {
 		switch (op) {
 
+#ifndef _WIN32
+		case 'b':
+			breaksigint = 1;
+			break;
+#endif
+
 		case 'i':
 			device = optarg;
 			break;
@@ -98,6 +142,16 @@
 			nonblock = 1;
 			break;
 
+#ifndef _WIN32
+		case 'r':
+			sigrestart = 1;
+			break;
+
+		case 's':
+			catchsigint = 1;
+			break;
+#endif
+
 		case 't':
 			longarg = strtol(optarg, &p, 10);
 			if (p == optarg || *p != '\0') {
@@ -132,6 +186,28 @@
 		pcap_freealldevs(devlist);
 	}
 	*ebuf = '\0';
+
+#ifndef _WIN32
+	/*
+	 * If we were told to catch SIGINT, do so.
+	 */
+	if (catchsigint) {
+		struct sigaction action;
+
+		action.sa_handler = sigint_handler;
+		sigemptyset(&action.sa_mask);
+
+		/*
+		 * Should SIGINT interrupt, or restart, system calls?
+		 */
+		action.sa_flags = sigrestart ? SA_RESTART : 0;
+
+		if (sigaction(SIGINT, &action, NULL) == -1)
+			error("Can't catch SIGINT: %s\n",
+			    strerror(errno));
+	}
+#endif
+
 	pd = pcap_create(device, ebuf);
 	if (pd == NULL)
 		error("%s", ebuf);
@@ -188,6 +264,10 @@
 		if (status != 0) {
 			printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
 			    status, packet_count);
+			struct pcap_stat ps;
+			pcap_stats(pd, &ps);
+			printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n",
+			    ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
 		}
 	}
 	if (status == -2) {
@@ -197,13 +277,14 @@
 		 * Print an extra newline, just in case.
 		 */
 		putchar('\n');
+		printf("Broken out of loop from SIGINT handler\n");
 	}
 	(void)fflush(stdout);
 	if (status == -1) {
 		/*
 		 * Error.  Report it.
 		 */
-		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
+		(void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
 		    program_name, pcap_geterr(pd));
 	}
 	pcap_close(pd);
@@ -223,7 +304,7 @@
 static void
 usage(void)
 {
-	(void)fprintf(stderr, "Usage: %s [ -mn ] [ -i interface ] [ -t timeout] [expression]\n",
+	(void)fprintf(stderr, "Usage: %s [ " USAGE_OPTIONS " ] [ -i interface ] [ -t timeout] [expression]\n",
 	    program_name);
 	exit(1);
 }
@@ -271,7 +352,7 @@
 copy_argv(register char **argv)
 {
 	register char **p;
-	register u_int len = 0;
+	register size_t len = 0;
 	char *buf;
 	char *src, *dst;
 
diff --git a/testprogs/filtertest.c b/testprogs/filtertest.c
index 7e2d6d6..440b550 100644
--- a/testprogs/filtertest.c
+++ b/testprogs/filtertest.c
@@ -36,6 +36,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include <limits.h>
 #ifdef _WIN32
   #include "getopt.h"
   #include "unix.h"
@@ -56,6 +57,8 @@
 
 #include "pcap/funcattrs.h"
 
+#define MAXIMUM_SNAPLEN		262144
+
 #ifdef BDEBUG
 /*
  * We have pcap_set_optimizer_debug() and pcap_set_print_dot_graph() in
@@ -99,11 +102,21 @@
 	if (fstat(fd, &buf) < 0)
 		error("can't stat %s: %s", fname, pcap_strerror(errno));
 
+	/*
+	 * _read(), on Windows, has an unsigned int byte count and an
+	 * int return value, so we can't handle a file bigger than
+	 * INT_MAX - 1 bytes (and have no reason to do so; a filter *that*
+	 * big will take forever to compile).  (The -1 is for the '\0' at
+	 * the end of the string.)
+	 */
+	if (buf.st_size > INT_MAX - 1)
+		error("%s is larger than %d bytes; that's too large", fname,
+		    INT_MAX - 1);
 	cp = malloc((u_int)buf.st_size + 1);
 	if (cp == NULL)
 		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
 			fname, pcap_strerror(errno));
-	cc = read(fd, cp, (u_int)buf.st_size);
+	cc = (int)read(fd, cp, (u_int)buf.st_size);
 	if (cc < 0)
 		error("read %s: %s", fname, pcap_strerror(errno));
 	if (cc != buf.st_size)
@@ -163,7 +176,7 @@
 copy_argv(register char **argv)
 {
 	register char **p;
-	register u_int len = 0;
+	register size_t len = 0;
 	char *buf;
 	char *src, *dst;
 
@@ -196,10 +209,12 @@
 	char *cp;
 	int op;
 	int dflag;
+#ifdef BDEBUG
 	int gflag;
+#endif
 	char *infile;
 	int Oflag;
-	long snaplen;
+	int snaplen;
 	char *p;
 	int dlt;
 	int have_fcode = 0;
@@ -214,11 +229,13 @@
 #endif /* _WIN32 */
 
 	dflag = 1;
+#ifdef BDEBUG
 	gflag = 0;
+#endif
 
 	infile = NULL;
 	Oflag = 1;
-	snaplen = 68;
+	snaplen = MAXIMUM_SNAPLEN;
 
 	if ((cp = strrchr(argv[0], '/')) != NULL)
 		program_name = cp + 1;
@@ -272,13 +289,19 @@
 
 		case 's': {
 			char *end;
+			long long_snaplen;
 
-			snaplen = strtol(optarg, &end, 0);
+			long_snaplen = strtol(optarg, &end, 0);
 			if (optarg == end || *end != '\0'
-			    || snaplen < 0 || snaplen > 65535)
+			    || long_snaplen < 0
+			    || long_snaplen > MAXIMUM_SNAPLEN)
 				error("invalid snaplen %s", optarg);
-			else if (snaplen == 0)
-				snaplen = 65535;
+			else {
+				if (snaplen == 0)
+					snaplen = MAXIMUM_SNAPLEN;
+				else
+					snaplen = (int)long_snaplen;
+			}
 			break;
 		}
 
diff --git a/testprogs/findalldevstest-perf.c b/testprogs/findalldevstest-perf.c
new file mode 100644
index 0000000..4087566
--- /dev/null
+++ b/testprogs/findalldevstest-perf.c
@@ -0,0 +1,100 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#ifdef _WIN32
+  #include <winsock2.h>
+  #include <ws2tcpip.h>
+  #include <windows.h>
+#else
+  #include <unistd.h>
+  #include <sys/resource.h>
+#endif
+
+#include <pcap.h>
+
+#include "varattrs.h"
+#include "pcap/funcattrs.h"
+
+#ifdef _WIN32
+#include "portability.h"
+#endif
+
+int main(int argc _U_, char **argv _U_)
+{
+  pcap_if_t *alldevs;
+  int exit_status = 0;
+  char errbuf[PCAP_ERRBUF_SIZE+1];
+#ifdef _WIN32
+  FILETIME start_ktime, start_utime, end_ktime, end_utime;
+  FILETIME dummy1, dummy2;
+  ULARGE_INTEGER start_kticks, end_kticks, start_uticks, end_uticks;
+  ULONGLONG ktime, utime, tottime;
+#else
+  struct rusage start_rusage, end_rusage;
+  struct timeval ktime, utime, tottime;
+#endif
+
+#ifdef _WIN32
+  if (!GetProcessTimes(GetCurrentProcess(), &dummy1, &dummy2,
+                       &start_ktime, &start_utime))
+  {
+    fprintf(stderr, "GetProcessTimes() fails at start\n");
+    exit(1);
+  }
+  start_kticks.LowPart = start_ktime.dwLowDateTime;
+  start_kticks.HighPart = start_ktime.dwHighDateTime;
+  start_uticks.LowPart = start_utime.dwLowDateTime;
+  start_uticks.HighPart = start_utime.dwHighDateTime;
+#else
+  if (getrusage(RUSAGE_SELF, &start_rusage) == -1) {
+    fprintf(stderr, "getrusage() fails at start\n");
+    exit(1);
+  }
+#endif
+  for (int i = 0; i < 500; i++)
+  {
+    if (pcap_findalldevs(&alldevs, errbuf) == -1)
+    {
+      fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
+      exit(1);
+    }
+    pcap_freealldevs(alldevs);
+  }
+
+#ifdef _WIN32
+  if (!GetProcessTimes(GetCurrentProcess(), &dummy1, &dummy2,
+                       &end_ktime, &end_utime))
+  {
+    fprintf(stderr, "GetProcessTimes() fails at end\n");
+    exit(1);
+  }
+  end_kticks.LowPart = end_ktime.dwLowDateTime;
+  end_kticks.HighPart = end_ktime.dwHighDateTime;
+  end_uticks.LowPart = end_utime.dwLowDateTime;
+  end_uticks.HighPart = end_utime.dwHighDateTime;
+  ktime = end_kticks.QuadPart - start_kticks.QuadPart;
+  utime = end_uticks.QuadPart - start_uticks.QuadPart;
+  tottime = ktime + utime;
+  printf("Total CPU secs: kernel %g, user %g, total %g\n",
+      ((double)ktime) / 10000000.0,
+      ((double)utime) / 10000000.0,
+      ((double)tottime) / 10000000.0);
+#else
+  if (getrusage(RUSAGE_SELF, &end_rusage) == -1) {
+    fprintf(stderr, "getrusage() fails at end\n");
+    exit(1);
+  }
+  timersub(&end_rusage.ru_stime, &start_rusage.ru_stime, &ktime);
+  timersub(&end_rusage.ru_utime, &start_rusage.ru_utime, &utime);
+  timeradd(&ktime, &utime, &tottime);
+  printf("Total CPU secs: kernel %g, user %g, total %g\n",
+      (double)ktime.tv_sec + ((double)ktime.tv_usec / 1000000.0),
+      (double)utime.tv_sec + ((double)utime.tv_usec / 1000000.0),
+      (double)tottime.tv_sec + ((double)tottime.tv_usec / 1000000.0));
+#endif
+  exit(exit_status);
+}
diff --git a/testprogs/findalldevstest.c b/testprogs/findalldevstest.c
index e535e25..092fd04 100644
--- a/testprogs/findalldevstest.c
+++ b/testprogs/findalldevstest.c
@@ -19,6 +19,7 @@
 
 #include <pcap.h>
 
+#include "varattrs.h"
 #include "pcap/funcattrs.h"
 
 static int ifprint(pcap_if_t *d);
@@ -94,7 +95,11 @@
 }
 #endif
 
+#ifdef ENABLE_REMOTE
 int main(int argc, char **argv)
+#else
+int main(int argc _U_, char **argv _U_)
+#endif
 {
   pcap_if_t *alldevs;
   pcap_if_t *d;
@@ -152,8 +157,24 @@
   {
     if (pcap_lookupnet(alldevs->name, &net, &mask, errbuf) < 0)
     {
-      fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf);
-      exit_status = 2;
+      /*
+       * XXX - this doesn't distinguish between "a real error
+       * occurred" and "this interface doesn't *have* an IPv4
+       * address".  The latter shouldn't be treated as an error.
+       *
+       * We look for the interface name, followed by a colon and
+       * a space, and, if we find it,w e see if what follows it
+       * is "no IPv4 address assigned".
+       */
+      size_t devnamelen = strlen(alldevs->name);
+      if (strncmp(errbuf, alldevs->name, devnamelen) == 0 &&
+          strncmp(errbuf + devnamelen, ": ", 2) == 0 &&
+          strcmp(errbuf + devnamelen + 2, "no IPv4 address assigned") == 0)
+        printf("Preferred device is not on an IPv4 network\n");
+      else {
+        fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf);
+        exit_status = 2;
+      }
     }
     else
     {
diff --git a/testprogs/fuzz/CMakeLists.txt b/testprogs/fuzz/CMakeLists.txt
new file mode 100644
index 0000000..67250cc
--- /dev/null
+++ b/testprogs/fuzz/CMakeLists.txt
@@ -0,0 +1,43 @@
+add_executable(fuzz_pcap onefile.c fuzz_pcap.c)
+target_link_libraries(fuzz_pcap ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+  set_target_properties(fuzz_pcap PROPERTIES
+      LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+
+add_executable(fuzz_filter onefile.c fuzz_filter.c)
+target_link_libraries(fuzz_filter ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+  set_target_properties(fuzz_filter PROPERTIES
+      LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+
+add_executable(fuzz_both onefile.c fuzz_both.c)
+target_link_libraries(fuzz_both ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+  set_target_properties(fuzz_both PROPERTIES
+      LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+
+if(ENABLE_REMOTE AND "$ENV{CFLAGS}" MATCHES "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")
+add_executable(fuzz_rclient onefile.c fuzz_rclient.c)
+target_link_libraries(fuzz_rclient ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+  set_target_properties(fuzz_rclient PROPERTIES
+      LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+
+add_executable(fuzz_rserver onefile.c fuzz_rserver.c ../../rpcapd/daemon.c)
+check_function_exists(crypt HAVE_CRYPT_IN_SYSTEM_LIBRARIES)
+if(HAVE_CRYPT_IN_SYSTEM_LIBRARIES)
+    set(HAVE_CRYPT TRUE)
+else(HAVE_CRYPT_IN_SYSTEM_LIBRARIES)
+     set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} crypt)
+endif(HAVE_CRYPT_IN_SYSTEM_LIBRARIES)
+target_link_libraries(fuzz_rserver ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+  set_target_properties(fuzz_rserver PROPERTIES
+      LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+endif(ENABLE_REMOTE AND "$ENV{CFLAGS}" MATCHES "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")
diff --git a/testprogs/fuzz/fuzz_both.c b/testprogs/fuzz/fuzz_both.c
new file mode 100644
index 0000000..59e3d40
--- /dev/null
+++ b/testprogs/fuzz/fuzz_both.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <pcap/pcap.h>
+
+FILE * outfile = NULL;
+
+static int bufferToFile(const char * name, const uint8_t *Data, size_t Size) {
+    FILE * fd;
+    if (remove(name) != 0) {
+        if (errno != ENOENT) {
+            printf("failed remove, errno=%d\n", errno);
+            return -1;
+        }
+    }
+    fd = fopen(name, "wb");
+    if (fd == NULL) {
+        printf("failed open, errno=%d\n", errno);
+        return -2;
+    }
+    if (fwrite (Data, 1, Size, fd) != Size) {
+        fclose(fd);
+        return -3;
+    }
+    fclose(fd);
+    return 0;
+}
+
+void fuzz_openFile(const char * name) {
+    if (outfile != NULL) {
+        fclose(outfile);
+    }
+    outfile = fopen(name, "w");
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+    pcap_t * pkts;
+    char errbuf[PCAP_ERRBUF_SIZE];
+    const u_char *pkt;
+    struct pcap_pkthdr *header;
+    int r;
+    size_t filterSize;
+    char * filter;
+    struct bpf_program bpf;
+
+
+    //initialize output file
+    if (outfile == NULL) {
+        outfile = fopen("/dev/null", "w");
+        if (outfile == NULL) {
+            return 0;
+        }
+    }
+
+    if (Size < 1) {
+        return 0;
+    }
+    filterSize = Data[0];
+    if (Size < 1+filterSize || filterSize == 0) {
+        return 0;
+    }
+
+    //rewrite buffer to a file as libpcap does not have buffer inputs
+    if (bufferToFile("/tmp/fuzz.pcap", Data+1+filterSize, Size-(1+filterSize)) < 0) {
+        return 0;
+    }
+
+    //initialize structure
+    pkts = pcap_open_offline("/tmp/fuzz.pcap", errbuf);
+    if (pkts == NULL) {
+        fprintf(outfile, "Couldn't open pcap file %s\n", errbuf);
+        return 0;
+    }
+
+    filter = malloc(filterSize);
+    memcpy(filter, Data+1, filterSize);
+    //null terminate string
+    filter[filterSize-1] = 0;
+
+    if (pcap_compile(pkts, &bpf, filter, 1, PCAP_NETMASK_UNKNOWN) == 0) {
+        //loop over packets
+        r = pcap_next_ex(pkts, &header, &pkt);
+        while (r > 0) {
+            //checks filter
+            fprintf(outfile, "packet length=%d/%d filter=%d\n",header->caplen, header->len, pcap_offline_filter(&bpf, header, pkt));
+            r = pcap_next_ex(pkts, &header, &pkt);
+        }
+        //close structure
+        pcap_close(pkts);
+        pcap_freecode(&bpf);
+    }
+    else {
+        pcap_close(pkts);
+    }
+    free(filter);
+
+    return 0;
+}
diff --git a/testprogs/fuzz/fuzz_both.options b/testprogs/fuzz/fuzz_both.options
new file mode 100644
index 0000000..0824b19
--- /dev/null
+++ b/testprogs/fuzz/fuzz_both.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
diff --git a/testprogs/fuzz/fuzz_filter.c b/testprogs/fuzz/fuzz_filter.c
new file mode 100644
index 0000000..de35067
--- /dev/null
+++ b/testprogs/fuzz/fuzz_filter.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pcap/pcap.h>
+
+void fuzz_openFile(const char * name){
+    //do nothing
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+    pcap_t * pkts;
+    struct bpf_program bpf;
+    char * filter;
+
+    //we need at least 1 byte for linktype
+    if (Size < 1) {
+        return 0;
+    }
+
+    //initialize structure snaplen = 65535
+    pkts = pcap_open_dead(Data[Size-1], 0xFFFF);
+    if (pkts == NULL) {
+        printf("pcap_open_dead failed\n");
+        return 0;
+    }
+    filter = malloc(Size);
+    memcpy(filter, Data, Size);
+    //null terminate string
+    filter[Size-1] = 0;
+
+    if (pcap_compile(pkts, &bpf, filter, 1, PCAP_NETMASK_UNKNOWN) == 0) {
+        pcap_setfilter(pkts, &bpf);
+        pcap_close(pkts);
+        pcap_freecode(&bpf);
+    }
+    else {
+        pcap_close(pkts);
+    }
+    free(filter);
+
+    return 0;
+}
diff --git a/testprogs/fuzz/fuzz_filter.options b/testprogs/fuzz/fuzz_filter.options
new file mode 100644
index 0000000..9fda93f
--- /dev/null
+++ b/testprogs/fuzz/fuzz_filter.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 4096
diff --git a/testprogs/fuzz/fuzz_pcap.c b/testprogs/fuzz/fuzz_pcap.c
new file mode 100644
index 0000000..fba5312
--- /dev/null
+++ b/testprogs/fuzz/fuzz_pcap.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <pcap/pcap.h>
+
+FILE * outfile = NULL;
+
+static int bufferToFile(const char * name, const uint8_t *Data, size_t Size) {
+    FILE * fd;
+    if (remove(name) != 0) {
+        if (errno != ENOENT) {
+            printf("failed remove, errno=%d\n", errno);
+            return -1;
+        }
+    }
+    fd = fopen(name, "wb");
+    if (fd == NULL) {
+        printf("failed open, errno=%d\n", errno);
+        return -2;
+    }
+    if (fwrite (Data, 1, Size, fd) != Size) {
+        fclose(fd);
+        return -3;
+    }
+    fclose(fd);
+    return 0;
+}
+
+void fuzz_openFile(const char * name) {
+    if (outfile != NULL) {
+        fclose(outfile);
+    }
+    outfile = fopen(name, "w");
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+    pcap_t * pkts;
+    char errbuf[PCAP_ERRBUF_SIZE];
+    const u_char *pkt;
+    struct pcap_pkthdr *header;
+    struct pcap_stat stats;
+    int r;
+
+    //initialize output file
+    if (outfile == NULL) {
+        outfile = fopen("/dev/null", "w");
+        if (outfile == NULL) {
+            return 0;
+        }
+    }
+
+    //rewrite buffer to a file as libpcap does not have buffer inputs
+    if (bufferToFile("/tmp/fuzz.pcap", Data, Size) < 0) {
+        return 0;
+    }
+
+    //initialize structure
+    pkts = pcap_open_offline("/tmp/fuzz.pcap", errbuf);
+    if (pkts == NULL) {
+        fprintf(outfile, "Couldn't open pcap file %s\n", errbuf);
+        return 0;
+    }
+
+    //loop over packets
+    r = pcap_next_ex(pkts, &header, &pkt);
+    while (r > 0) {
+        //TODO pcap_offline_filter
+        fprintf(outfile, "packet length=%d/%d\n",header->caplen, header->len);
+        r = pcap_next_ex(pkts, &header, &pkt);
+    }
+    if (pcap_stats(pkts, &stats) == 0) {
+        fprintf(outfile, "number of packets=%d\n", stats.ps_recv);
+    }
+    //close structure
+    pcap_close(pkts);
+
+    return 0;
+}
diff --git a/testprogs/fuzz/fuzz_pcap.options b/testprogs/fuzz/fuzz_pcap.options
new file mode 100644
index 0000000..0824b19
--- /dev/null
+++ b/testprogs/fuzz/fuzz_pcap.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
diff --git a/testprogs/fuzz/fuzz_rclient.c b/testprogs/fuzz/fuzz_rclient.c
new file mode 100644
index 0000000..b5a6a91
--- /dev/null
+++ b/testprogs/fuzz/fuzz_rclient.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <pcap/pcap.h>
+
+FILE * outfile = NULL;
+struct pcap_rmtauth auth;
+
+void fuzz_openFile(const char * name) {
+    if (outfile != NULL) {
+        fclose(outfile);
+    }
+    outfile = fopen(name, "w");
+    auth.type = RPCAP_RMTAUTH_PWD;
+    auth.username = "user";
+    auth.password = "pass";
+}
+
+void sock_initfuzz(const uint8_t *Data, size_t Size);
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+    pcap_t * pkts;
+    char errbuf[PCAP_ERRBUF_SIZE];
+    const u_char *pkt;
+    struct pcap_pkthdr *header;
+    struct pcap_stat stats;
+    int r;
+
+    //initialization
+    if (outfile == NULL) {
+        fuzz_openFile("/dev/null");
+    }
+
+    sock_initfuzz(Data, Size);
+    //initialize structure
+    pkts = pcap_open("rpcap://127.0.0.1/fuzz.pcap", 0, 0, 1000, &auth, errbuf);
+    if (pkts == NULL) {
+        fprintf(outfile, "Couldn't open pcap file %s\n", errbuf);
+        return 0;
+    }
+
+    //loop over packets
+    r = pcap_next_ex(pkts, &header, &pkt);
+    while (r > 0) {
+        fprintf(outfile, "packet length=%d/%d\n",header->caplen, header->len);
+        r = pcap_next_ex(pkts, &header, &pkt);
+    }
+    if (pcap_stats(pkts, &stats) == 0) {
+        fprintf(outfile, "number of packets=%d\n", stats.ps_recv);
+    }
+    //close structure
+    pcap_close(pkts);
+
+    return 0;
+}
diff --git a/testprogs/fuzz/fuzz_rserver.c b/testprogs/fuzz/fuzz_rserver.c
new file mode 100644
index 0000000..c79a373
--- /dev/null
+++ b/testprogs/fuzz/fuzz_rserver.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include <pcap/pcap.h>
+
+FILE * outfile = NULL;
+
+void fuzz_openFile(const char * name) {
+    if (outfile != NULL) {
+        fclose(outfile);
+    }
+    outfile = fopen(name, "w");
+}
+
+typedef enum {
+    LOGPRIO_DEBUG,
+    LOGPRIO_INFO,
+    LOGPRIO_WARNING,
+    LOGPRIO_ERROR
+} log_priority;
+
+void rpcapd_log(log_priority priority, const char *message, ...)
+{
+    va_list ap;
+
+    va_start(ap, message);
+    fprintf(outfile, "rpcapd[%d]:", priority);
+    vfprintf(outfile, message, ap);
+    putc('\n', outfile);
+    va_end(ap);
+}
+
+void sock_initfuzz(const uint8_t *Data, size_t Size);
+int daemon_serviceloop(int sockctrl, int isactive, char *passiveClients, int nullAuthAllowed, int uses_ssl);
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+    int sock;
+
+    //initialization
+    if (outfile == NULL) {
+        fuzz_openFile("/dev/null");
+    }
+
+    sock_initfuzz(Data, Size);
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (sock == INVALID_SOCKET) {
+        abort();
+    }
+    //dummy socket, active, null auth allowed, no ssl
+    daemon_serviceloop(sock, 1, malloc(0), 1, 0);
+
+    return 0;
+}
diff --git a/testprogs/fuzz/onefile.c b/testprogs/fuzz/onefile.c
new file mode 100644
index 0000000..690a63b
--- /dev/null
+++ b/testprogs/fuzz/onefile.c
@@ -0,0 +1,54 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+void fuzz_openFile(const char * name);
+
+int main(int argc, char** argv)
+{
+    FILE * fp;
+    uint8_t *Data;
+    size_t Size;
+
+    if (argc == 3) {
+        fuzz_openFile(argv[2]);
+    } else if (argc != 2) {
+        return 1;
+    }
+    //opens the file, get its size, and reads it into a buffer
+    fp = fopen(argv[1], "rb");
+    if (fp == NULL) {
+        return 2;
+    }
+    if (fseek(fp, 0L, SEEK_END) != 0) {
+        fclose(fp);
+        return 2;
+    }
+    Size = ftell(fp);
+    if (Size == (size_t) -1) {
+        fclose(fp);
+        return 2;
+    }
+    if (fseek(fp, 0L, SEEK_SET) != 0) {
+        fclose(fp);
+        return 2;
+    }
+    Data = malloc(Size);
+    if (Data == NULL) {
+        fclose(fp);
+        return 2;
+    }
+    if (fread(Data, Size, 1, fp) != 1) {
+        fclose(fp);
+        free(Data);
+        return 2;
+    }
+
+    //launch fuzzer
+    LLVMFuzzerTestOneInput(Data, Size);
+    free(Data);
+    fclose(fp);
+    return 0;
+}
+
diff --git a/testprogs/opentest.c b/testprogs/opentest.c
index bad38eb..a441dda 100644
--- a/testprogs/opentest.c
+++ b/testprogs/opentest.c
@@ -45,7 +45,7 @@
   #include "portability.h"
 #endif
 
-#define MAXIMUM_SNAPLEN		65535
+#define MAXIMUM_SNAPLEN		262144
 
 static char *program_name;
 
@@ -81,7 +81,7 @@
 		switch (op) {
 
 		case 'i':
-			device = optarg;
+			device = strdup(optarg);
 			break;
 
 		case 'I':
@@ -95,13 +95,19 @@
 
 		case 's': {
 			char *end;
+			long long_snaplen;
 
-			snaplen = strtol(optarg, &end, 0);
+			long_snaplen = strtol(optarg, &end, 0);
 			if (optarg == end || *end != '\0'
-			    || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN)
+			    || long_snaplen < 0
+			    || long_snaplen > MAXIMUM_SNAPLEN)
 				error("invalid snaplen %s", optarg);
-			else if (snaplen == 0)
-				snaplen = MAXIMUM_SNAPLEN;
+			else {
+				if (snaplen == 0)
+					snaplen = MAXIMUM_SNAPLEN;
+				else
+					snaplen = (int)long_snaplen;
+			}
 			break;
 		}
 
@@ -186,6 +192,7 @@
 		else
 			printf("%s opened successfully\n", device);
 	}
+	free(device);
 	pcap_close(pd);
 	exit(status < 0 ? 1 : 0);
 }
diff --git a/testprogs/reactivatetest.c b/testprogs/reactivatetest.c
index d7f3e32..a9c987a 100644
--- a/testprogs/reactivatetest.c
+++ b/testprogs/reactivatetest.c
@@ -51,7 +51,6 @@
 		if (pd == NULL) {
 			error("Neither lo0 nor lo could be opened: %s",
 			    ebuf);
-			return 2;
 		}
 	}
 	status = pcap_activate(pd);
diff --git a/testprogs/selpolltest.c b/testprogs/selpolltest.c
index 329281d..569c829 100644
--- a/testprogs/selpolltest.c
+++ b/testprogs/selpolltest.c
@@ -69,13 +69,13 @@
 	register int op;
 	bpf_u_int32 localnet, netmask;
 	register char *cp, *cmdbuf, *device;
-	int doselect, dopoll, dotimeout, dononblock;
+	int doselect, dopoll, dotimeout, dononblock, quiet;
 	const char *mechanism;
 	struct bpf_program fcode;
 	char ebuf[PCAP_ERRBUF_SIZE];
 	pcap_if_t *devlist;
 	int selectable_fd;
-	struct timeval *required_timeout;
+	const struct timeval *required_timeout;
 	int status;
 	int packet_count;
 
@@ -85,13 +85,14 @@
 	mechanism = NULL;
 	dotimeout = 0;
 	dononblock = 0;
+	quiet = 0;
 	if ((cp = strrchr(argv[0], '/')) != NULL)
 		program_name = cp + 1;
 	else
 		program_name = argv[0];
 
 	opterr = 0;
-	while ((op = getopt(argc, argv, "i:sptn")) != -1) {
+	while ((op = getopt(argc, argv, "i:sptnq")) != -1) {
 		switch (op) {
 
 		case 'i':
@@ -116,6 +117,10 @@
 			dononblock = 1;
 			break;
 
+		case 'q':
+			quiet = 1;
+			break;
+
 		default:
 			usage();
 			/* NOTREACHED */
@@ -196,6 +201,7 @@
 		for (;;) {
 			fd_set setread, setexcept;
 			struct timeval seltimeout;
+			struct timeval *timeoutp;
 
 			FD_ZERO(&setread);
 			if (selectable_fd != -1) {
@@ -203,6 +209,7 @@
 				FD_ZERO(&setexcept);
 				FD_SET(selectable_fd, &setexcept);
 			}
+			required_timeout = pcap_get_required_select_timeout(pd);
 			if (dotimeout) {
 				seltimeout.tv_sec = 0;
 				if (required_timeout != NULL &&
@@ -210,37 +217,34 @@
 					seltimeout.tv_usec = required_timeout->tv_usec;
 				else
 					seltimeout.tv_usec = 1000;
-				status = select(selectable_fd + 1, &setread,
-				    NULL, &setexcept, &seltimeout);
+				timeoutp = &seltimeout;
 			} else if (required_timeout != NULL) {
 				seltimeout = *required_timeout;
-				status = select(selectable_fd + 1, &setread,
-				    NULL, &setexcept, &seltimeout);
+				timeoutp = &seltimeout;
 			} else {
-				status = select((selectable_fd == -1) ?
-				    0 : selectable_fd + 1, &setread,
-				    NULL, &setexcept, NULL);
+				timeoutp = NULL;
 			}
+			status = select((selectable_fd == -1) ?
+			    0 : selectable_fd + 1, &setread, NULL, &setexcept,
+			    timeoutp);
 			if (status == -1) {
 				printf("Select returns error (%s)\n",
 				    strerror(errno));
 			} else {
-				if (selectable_fd == -1) {
-					if (status != 0)
-						printf("Select returned a descriptor\n");
-				} else {
+				if (!quiet) {
 					if (status == 0)
 						printf("Select timed out: ");
-					else
+					else{
 						printf("Select returned a descriptor: ");
-					if (FD_ISSET(selectable_fd, &setread))
-						printf("readable, ");
-					else
-						printf("not readable, ");
-					if (FD_ISSET(selectable_fd, &setexcept))
-						printf("exceptional condition\n");
-					else
-						printf("no exceptional condition\n");
+						if (FD_ISSET(selectable_fd, &setread))
+							printf("readable, ");
+						else
+							printf("not readable, ");
+						if (FD_ISSET(selectable_fd, &setexcept))
+							printf("exceptional condition\n");
+						else
+							printf("no exceptional condition\n");
+					}
 				}
 				packet_count = 0;
 				status = pcap_dispatch(pd, -1, countme,
@@ -268,11 +272,12 @@
 
 			fd.fd = selectable_fd;
 			fd.events = POLLIN;
+			required_timeout = pcap_get_required_select_timeout(pd);
 			if (dotimeout)
 				polltimeout = 1;
 			else if (required_timeout != NULL &&
 			    required_timeout->tv_usec >= 1000)
-				polltimeout = required_timeout->tv_usec/1000;
+				polltimeout = (int)(required_timeout->tv_usec/1000);
 			else
 				polltimeout = -1;
 			status = poll(&fd, (selectable_fd == -1) ? 0 : 1, polltimeout);
@@ -280,10 +285,7 @@
 				printf("Poll returns error (%s)\n",
 				    strerror(errno));
 			} else {
-				if (selectable_fd == -1) {
-					if (status != 0)
-						printf("Poll returned a descriptor\n");
-				} else {
+				if (!quiet) {
 					if (status == 0)
 						printf("Poll timed out\n");
 					else {
@@ -349,7 +351,7 @@
 		/*
 		 * Error.  Report it.
 		 */
-		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
+		(void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
 		    program_name, pcap_geterr(pd));
 	}
 	pcap_close(pd);
@@ -367,7 +369,7 @@
 static void
 usage(void)
 {
-	(void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n",
+	(void)fprintf(stderr, "Usage: %s [ -sptnq ] [ -i interface ] [expression]\n",
 	    program_name);
 	exit(1);
 }
@@ -415,7 +417,7 @@
 copy_argv(register char **argv)
 {
 	register char **p;
-	register u_int len = 0;
+	register size_t len = 0;
 	char *buf;
 	char *src, *dst;
 
diff --git a/testprogs/threadsignaltest.c b/testprogs/threadsignaltest.c
index a60bb49..c9ade76 100644
--- a/testprogs/threadsignaltest.c
+++ b/testprogs/threadsignaltest.c
@@ -157,7 +157,7 @@
 		} else
 			printf("No packets seen by pcap_dispatch\n");
 	}
-	if (status == -2) {
+	if (status == PCAP_ERROR_BREAK) {
 		/*
 		 * We got interrupted, so perhaps we didn't
 		 * manage to finish a line we were printing.
@@ -167,11 +167,11 @@
 		printf("Loop got broken\n");
 	}
 	(void)fflush(stdout);
-	if (status == -1) {
+	if (status == PCAP_ERROR) {
 		/*
 		 * Error.  Report it.
 		 */
-		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
+		(void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
 		    program_name, pcap_geterr(pd));
 	}
 	return 0;
@@ -182,7 +182,7 @@
 {
 	register int op;
 	register char *cp, *cmdbuf, *device;
-	int immediate = 0;
+	int do_wakeup = 1;
 	pcap_if_t *devlist;
 	bpf_u_int32 localnet, netmask;
 	struct bpf_program fcode;
@@ -200,13 +200,17 @@
 		program_name = argv[0];
 
 	opterr = 0;
-	while ((op = getopt(argc, argv, "i:")) != -1) {
+	while ((op = getopt(argc, argv, "i:n")) != -1) {
 		switch (op) {
 
 		case 'i':
 			device = optarg;
 			break;
 
+		case 'n':
+			do_wakeup = 0;
+			break;
+
 		default:
 			usage();
 			/* NOTREACHED */
@@ -229,12 +233,6 @@
 	if (status != 0)
 		error("%s: pcap_set_snaplen failed: %s",
 			    device, pcap_statustostr(status));
-	if (immediate) {
-		status = pcap_set_immediate_mode(pd, 1);
-		if (status != 0)
-			error("%s: pcap_set_immediate_mode failed: %s",
-			    device, pcap_statustostr(status));
-	}
 	status = pcap_set_timeout(pd, 5*60*1000);
 	if (status != 0)
 		error("%s: pcap_set_timeout failed: %s",
@@ -280,21 +278,39 @@
 		error("Can't create capture thread: %s", strerror(status));
 #endif
 	sleep_secs(60);
+	printf("Doing pcap_breakloop()\n");
 	pcap_breakloop(pd);
+	if (do_wakeup) {
+		/*
+		 * Force a wakeup in the capture thread.
+		 *
+		 * On some platforms, with some devices,, pcap_breakloop()
+		 * can't do that itself.  On Windows, poke the device's
+		 * event handle; on UN*X, send a SIGUSR1 to the thread.
+		 */
 #ifdef _WIN32
-	printf("Setting event\n");
-	if (!SetEvent(pcap_getevent(pd)))
-		error("Can't set event for pcap_t: %s",
-		    win32_strerror(GetLastError()));
+		printf("Setting event\n");
+		if (!SetEvent(pcap_getevent(pd)))
+			error("Can't set event for pcap_t: %s",
+			    win32_strerror(GetLastError()));
+#else
+		printf("Sending SIGUSR1\n");
+		status = pthread_kill(capture_thread, SIGUSR1);
+		if (status != 0)
+			warning("Can't interrupt capture thread: %s",
+			strerror(status));
+#endif
+	}
+
+	/*
+	 * Now wait for the capture thread to terminate.
+	 */
+#ifdef _WIN32
 	if (WaitForSingleObject(capture_thread, INFINITE) == WAIT_FAILED)
 		error("Wait for thread termination failed: %s",
 		    win32_strerror(GetLastError()));
 	CloseHandle(capture_thread);
 #else
-	printf("Sending SIGUSR1\n");
-	status = pthread_kill(capture_thread, SIGUSR1);
-	if (status != 0)
-		warning("Can't interrupt capture thread: %s", strerror(status));
 	status = pthread_join(capture_thread, &retval);
 	if (status != 0)
 		error("Wait for thread termination failed: %s",
@@ -317,7 +333,7 @@
 static void
 usage(void)
 {
-	(void)fprintf(stderr, "Usage: %s [ -m ] [ -i interface ] [ -t timeout] [expression]\n",
+	(void)fprintf(stderr, "Usage: %s [ -n ] [ -i interface ] [ expression ]\n",
 	    program_name);
 	exit(1);
 }
@@ -365,7 +381,7 @@
 copy_argv(register char **argv)
 {
 	register char **p;
-	register u_int len = 0;
+	register size_t len = 0;
 	char *buf;
 	char *src, *dst;
 
diff --git a/testprogs/valgrindtest.c b/testprogs/valgrindtest.c
index 104ef6a..058b18b 100644
--- a/testprogs/valgrindtest.c
+++ b/testprogs/valgrindtest.c
@@ -59,6 +59,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include <limits.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -99,6 +100,23 @@
 
 #endif
 
+/*
+ * Squelch a warning.
+ *
+ * We include system headers to be able to directly set the filter to
+ * a program with uninitialized content, to make sure what we're testing
+ * is Valgrind's checking of the system call to set the filter, and we
+ * also include <pcap.h> to open the device in the first place, and that
+ * means that we may get collisions between their definitions of
+ * BPF_STMT and BPF_JUMP - and do, in fact, get them on Linux (the
+ * definitons may be semantically the same, but that's not sufficient to
+ * avoid the warnings, as the preprocessor doesn't know that u_short is
+ * just unsigned short).
+ *
+ * So we undefine BPF_STMT and BPF_JUMP to avoid the warning.
+ */
+#undef BPF_STMT
+#undef BPF_JUMP
 #include <pcap.h>
 
 static char *program_name;
@@ -132,11 +150,21 @@
 	if (fstat(fd, &buf) < 0)
 		error("can't stat %s: %s", fname, pcap_strerror(errno));
 
+	/*
+	 * _read(), on Windows, has an unsigned int byte count and an
+	 * int return value, so we can't handle a file bigger than
+	 * INT_MAX - 1 bytes (and have no reason to do so; a filter *that*
+	 * big will take forever to compile).  (The -1 is for the '\0' at
+	 * the end of the string.)
+	 */
+	if (buf.st_size > INT_MAX - 1)
+		error("%s is larger than %d bytes; that's too large", fname,
+		    INT_MAX - 1);
 	cp = malloc((u_int)buf.st_size + 1);
 	if (cp == NULL)
 		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
 			fname, pcap_strerror(errno));
-	cc = read(fd, cp, (u_int)buf.st_size);
+	cc = (int)read(fd, cp, (u_int)buf.st_size);
 	if (cc < 0)
 		error("read %s: %s", fname, pcap_strerror(errno));
 	if (cc != buf.st_size)
@@ -196,7 +224,7 @@
 copy_argv(register char **argv)
 {
 	register char **p;
-	register u_int len = 0;
+	register size_t len = 0;
 	char *buf;
 	char *src, *dst;
 
@@ -421,7 +449,7 @@
 	(void)fprintf(stderr, "%s, with %s\n", program_name,
 	    pcap_lib_version());
 	(void)fprintf(stderr,
-	    "Usage: %s [-aI] [ -F file ] [ -I interface ] [ expression ]\n",
+	    "Usage: %s [-aI] [ -F file ] [ -i interface ] [ expression ]\n",
 	    program_name);
 	exit(1);
 }
diff --git a/testprogs/visopts.py b/testprogs/visopts.py
index 03aa804..80c1463 100755
--- a/testprogs/visopts.py
+++ b/testprogs/visopts.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 """
-This program parse the output from pcap_compile() to visualize the CFG after
+This program parses the output from pcap_compile() to visualize the CFG after
 each optimize phase.
 
 Usage guide:
@@ -15,23 +15,24 @@
        testprogs/filtertest -g EN10MB host 192.168.1.1 > a.txt
 3. Send a.txt to this program's standard input
        cat a.txt | testprogs/visopts.py
+   (Graphviz must be installed)
 4. Step 2&3 can be merged:
        testprogs/filtertest -g EN10MB host 192.168.1.1 | testprogs/visopts.py
 5. The standard output is something like this:
        generated files under directory: /tmp/visopts-W9ekBw
          the directory will be removed when this programs finished.
        open this link: http://localhost:39062/expr1.html
-6. Using open link at the 3rd line `http://localhost:39062/expr1.html'
+6. Open the URL at the 3rd line in a browser.
 
 Note:
-1. The CFG is translated to SVG an document, expr1.html embeded them as external
-   document. If you open expr1.html as local file using file:// protocol, some
-   browsers will deny such requests so the web pages will not shown properly.
-   For chrome, you can run it using following command to avoid this:
+1. The CFG is translated to SVG images, expr1.html embeds them as external
+   documents. If you open expr1.html as local file using file:// protocol, some
+   browsers will deny such requests so the web page will not work properly.
+   For Chrome, you can run it using the following command to avoid this:
        chromium --disable-web-security
-   That's why this program start a localhost http server.
-2. expr1.html use jquery from http://ajax.googleapis.com, so you need internet
-   access to show the web page.
+   That's why this program starts a localhost HTTP server.
+2. expr1.html uses jQuery from https://ajax.googleapis.com, so it needs Internet
+   access to work.
 """
 
 import sys, os
@@ -52,7 +53,7 @@
       }
     </style>
 
-    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"/></script>
+    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"/></script>
     <!--script type="text/javascript" src="./jquery.min.js"/></script-->
     <script type="text/javascript">
       var expr = '$expr';
@@ -142,7 +143,7 @@
       }
       function load_left(index) {
         var url = gurl(index);
-        var frag = "<embed id='leftsvgc'  type='image/svg+xml' pluginspage='http://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
+        var frag = "<embed id='leftsvgc'  type='image/svg+xml' pluginspage='https://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
         $$("#lsvg").html(frag);
         $$("#lcomment").html(logs[index]);
         $$("#lsvglink").attr("href", url);
@@ -151,7 +152,7 @@
       }
       function load_right(index) {
         var url = gurl(index);
-        var frag = "<embed id='rightsvgc' type='image/svg+xml' pluginspage='http://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
+        var frag = "<embed id='rightsvgc' type='image/svg+xml' pluginspage='https://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
         $$("#rsvg").html(frag);
         $$("#rcomment").html(logs[index]);
         $$("#rsvglink").attr("href", url);
@@ -255,7 +256,13 @@
             log += line
 
         if indot == 2:
-            p = subprocess.Popen(['dot', '-Tsvg'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+            try:
+                p = subprocess.Popen(['dot', '-Tsvg'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+            except OSError as ose:
+                print "Failed to run 'dot':", ose
+                print "(Is Graphviz installed?)"
+                exit(1)
+
             svg = p.communicate(dot)[0]
             with file("expr1_g%03d.svg" % (gid), "wt") as f:
                 f.write(svg)
@@ -296,7 +303,7 @@
     os.chdir(tempfile.mkdtemp(prefix="visopts-"))
     atexit.register(shutil.rmtree, os.getcwd())
     print "generated files under directory: %s" % os.getcwd()
-    print "  the directory will be removed when this programs finished."
+    print "  the directory will be removed when this program has finished."
 
     if not render_on_html(sys.stdin):
         return 1
diff --git a/testprogs/writecaptest.c b/testprogs/writecaptest.c
new file mode 100644
index 0000000..4db532c
--- /dev/null
+++ b/testprogs/writecaptest.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
+ *	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 "varattrs.h"
+
+#ifndef lint
+static const char copyright[] _U_ =
+    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
+The Regents of the University of California.  All rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#ifdef _WIN32
+  #include "getopt.h"
+#else
+  #include <unistd.h>
+#endif
+#include <errno.h>
+#ifndef _WIN32
+  #include <signal.h>
+#endif
+#include <sys/types.h>
+
+#include <pcap.h>
+
+#include "pcap/funcattrs.h"
+
+#ifdef _WIN32
+  #include "portability.h"
+#endif
+
+static char *program_name;
+
+/* Forwards */
+static void PCAP_NORETURN usage(void);
+static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
+static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
+static char *copy_argv(char **);
+
+static pcap_t *pd;
+
+#ifdef _WIN32
+static BOOL WINAPI
+stop_capture(DWORD ctrltype _U_)
+{
+	pcap_breakloop(pd);
+	return TRUE;
+}
+#else
+static void
+stop_capture(int signum _U_)
+{
+	pcap_breakloop(pd);
+}
+#endif
+
+static long
+parse_interface_number(const char *device)
+{
+	const char *p;
+	long devnum;
+	char *end;
+
+	/*
+	 * Search for a colon, terminating any scheme at the beginning
+	 * of the device.
+	 */
+	p = strchr(device, ':');
+	if (p != NULL) {
+		/*
+		 * We found it.  Is it followed by "//"?
+		 */
+		p++;	/* skip the : */
+		if (strncmp(p, "//", 2) == 0) {
+			/*
+			 * Yes.  Search for the next /, at the end of the
+			 * authority part of the URL.
+			 */
+			p += 2;	/* skip the // */
+			p = strchr(p, '/');
+			if (p != NULL) {
+				/*
+				 * OK, past the / is the path.
+				 */
+				device = p + 1;
+			}
+		}
+	}
+	devnum = strtol(device, &end, 10);
+	if (device != end && *end == '\0') {
+		/*
+		 * It's all-numeric, but is it a valid number?
+		 */
+		if (devnum <= 0) {
+			/*
+			 * No, it's not an ordinal.
+			 */
+			error("Invalid adapter index");
+		}
+		return (devnum);
+	} else {
+		/*
+		 * It's not all-numeric; return -1, so our caller
+		 * knows that.
+		 */
+		return (-1);
+	}
+}
+
+static char *
+find_interface_by_number(long devnum)
+{
+	pcap_if_t *dev, *devlist;
+	long i;
+	char ebuf[PCAP_ERRBUF_SIZE];
+	char *device;
+	int status;
+
+	status = pcap_findalldevs(&devlist, ebuf);
+	if (status < 0)
+		error("%s", ebuf);
+	/*
+	 * Look for the devnum-th entry in the list of devices (1-based).
+	 */
+	for (i = 0, dev = devlist; i < devnum-1 && dev != NULL;
+	    i++, dev = dev->next)
+		;
+	if (dev == NULL)
+		error("Invalid adapter index");
+	device = strdup(dev->name);
+	pcap_freealldevs(devlist);
+	return (device);
+}
+
+static pcap_t *
+open_interface(const char *device, int snaplen_set, int snaplen, char *ebuf)
+{
+	pcap_t *pc;
+	int status;
+	char *cp;
+
+	pc = pcap_create(device, ebuf);
+	if (pc == NULL) {
+		/*
+		 * If this failed with "No such device", that means
+		 * the interface doesn't exist; return NULL, so that
+		 * the caller can see whether the device name is
+		 * actually an interface index.
+		 */
+		if (strstr(ebuf, "No such device") != NULL)
+			return (NULL);
+		error("%s", ebuf);
+	}
+	if (snaplen_set) {
+		status = pcap_set_snaplen(pc, snaplen);
+		if (status != 0)
+			error("%s: pcap_set_snaplen failed: %s",
+			    device, pcap_statustostr(status));
+	}
+	status = pcap_set_timeout(pc, 100);
+	if (status != 0)
+		error("%s: pcap_set_timeout failed: %s",
+		    device, pcap_statustostr(status));
+	status = pcap_activate(pc);
+	if (status < 0) {
+		/*
+		 * pcap_activate() failed.
+		 */
+		cp = pcap_geterr(pc);
+		if (status == PCAP_ERROR)
+			error("%s", cp);
+		else if (status == PCAP_ERROR_NO_SUCH_DEVICE) {
+			/*
+			 * Return an error for our caller to handle.
+			 */
+			snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
+			    device, pcap_statustostr(status), cp);
+		} else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
+			error("%s: %s\n(%s)", device,
+			    pcap_statustostr(status), cp);
+		else
+			error("%s: %s", device,
+			    pcap_statustostr(status));
+		pcap_close(pc);
+		return (NULL);
+	} else if (status > 0) {
+		/*
+		 * pcap_activate() succeeded, but it's warning us
+		 * of a problem it had.
+		 */
+		cp = pcap_geterr(pc);
+		if (status == PCAP_WARNING)
+			warning("%s", cp);
+		else if (status == PCAP_WARNING_PROMISC_NOTSUP &&
+		         *cp != '\0')
+			warning("%s: %s\n(%s)", device,
+			    pcap_statustostr(status), cp);
+		else
+			warning("%s: %s", device,
+			    pcap_statustostr(status));
+	}
+	return (pc);
+}
+
+#define COMMAND_OPTIONS	"DLi:s:w:y:"
+
+int
+main(int argc, char **argv)
+{
+	int op;
+	char *cp, *cmdbuf = NULL, *device, *end, *savefile = NULL;
+	int snaplen = 0;
+	int snaplen_set = 0;
+	pcap_if_t *devlist;
+	long devnum;
+	int show_interfaces = 0;
+	int show_dlt_types = 0;
+	int ndlts;
+	int *dlts;
+	bpf_u_int32 localnet, netmask;
+	struct bpf_program fcode;
+	char ebuf[PCAP_ERRBUF_SIZE];
+#ifndef _WIN32
+	struct sigaction action;
+#endif
+	int dlt;
+	const char *dlt_name = NULL;
+	int status;
+	pcap_dumper_t *pdd;
+
+	device = NULL;
+	if ((cp = strrchr(argv[0], '/')) != NULL)
+		program_name = cp + 1;
+	else
+		program_name = argv[0];
+
+	opterr = 0;
+	while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) {
+		switch (op) {
+
+		case 'D':
+			show_interfaces = 1;
+			break;
+
+		case 'L':
+			show_dlt_types = 1;
+			break;
+
+		case 'i':
+			device = optarg;
+			break;
+
+		case 's':
+			snaplen = (int)strtol(optarg, &end, 0);
+			if (optarg == end || *end != '\0' || snaplen < 0)
+				error("invalid snaplen %s (must be >= 0)",
+				    optarg);
+			snaplen_set = 1;
+			break;
+
+		case 'w':
+			savefile = optarg;
+			break;
+
+		case 'y':
+			dlt_name = optarg;
+			break;
+
+		default:
+			usage();
+			/* NOTREACHED */
+		}
+	}
+
+	if (show_interfaces) {
+		pcap_if_t *dev;
+		int i;
+
+		if (pcap_findalldevs(&devlist, ebuf) < 0)
+			error("%s", ebuf);
+		for (i = 0, dev = devlist; dev != NULL; i++, dev = dev->next) {
+			printf("%d.%s", i+1, dev->name);
+			if (dev->description != NULL)
+				printf(" (%s)", dev->description);
+			printf("\n");
+		}
+		pcap_freealldevs(devlist);
+		return (0);
+	}
+
+	if (device == NULL) {
+		if (pcap_findalldevs(&devlist, ebuf) == -1)
+			error("%s", ebuf);
+		if (devlist == NULL)
+			error("no interfaces available for capture");
+		device = strdup(devlist->name);
+		pcap_freealldevs(devlist);
+	}
+	if (show_dlt_types) {
+		pd = pcap_create(device, ebuf);
+		if (pd == NULL)
+			error("%s", ebuf);
+		status = pcap_activate(pd);
+		if (status < 0) {
+			/*
+			 * pcap_activate() failed.
+			 */
+			error("%s: %s\n(%s)", device,
+			    pcap_statustostr(status), pcap_geterr(pd));
+		}
+		ndlts = pcap_list_datalinks(pd, &dlts);
+		if (ndlts < 0) {
+			/*
+			 * pcap_list_datalinks() failed.
+			 */
+			error("%s: %s\n(%s)", device,
+			    pcap_statustostr(status), pcap_geterr(pd));
+		}
+		for (int i = 0; i < ndlts; i++) {
+			dlt_name = pcap_datalink_val_to_name(dlts[i]);
+			if (dlt_name == NULL)
+				printf("DLT %d", dlts[i]);
+			else
+				printf("%s", dlt_name);
+			printf("\n");
+		}
+		pcap_free_datalinks(dlts);
+		pcap_close(pd);
+		return 0;
+	}
+
+	if (savefile == NULL)
+		error("no savefile specified");
+
+	*ebuf = '\0';
+
+	pd = open_interface(device, snaplen_set, snaplen, ebuf);
+	if (pd == NULL) {
+		/*
+		 * That failed because the interface couldn't be found.
+		 *
+		 * If we can get a list of interfaces, and the interface name
+		 * is purely numeric, try to use it as a 1-based index
+		 * in the list of interfaces.
+		 */
+		devnum = parse_interface_number(device);
+		if (devnum == -1) {
+			/*
+			 * It's not a number; just report
+			 * the open error and fail.
+			 */
+			error("%s", ebuf);
+		}
+
+		/*
+		 * OK, it's a number; try to find the
+		 * interface with that index, and try
+		 * to open it.
+		 *
+		 * find_interface_by_number() exits if it
+		 * couldn't be found.
+		 */
+		device = find_interface_by_number(devnum);
+		pd = open_interface(device, snaplen_set, snaplen, ebuf);
+		if (pd == NULL)
+			error("%s", ebuf);
+	}
+
+	if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
+		localnet = 0;
+		netmask = 0;
+		warning("%s", ebuf);
+	}
+
+	if (dlt_name != NULL) {
+		dlt = pcap_datalink_name_to_val(dlt_name);
+		if (dlt == PCAP_ERROR)
+			error("%s isn't a valid DLT name", dlt_name);
+		if (pcap_set_datalink(pd, dlt) == PCAP_ERROR)
+			error("%s: %s", device, pcap_geterr(pd));
+	}
+
+	/*
+	 * Don't set a filter unless we were given one on the
+	 * command line; if capturing doesn't work, or doesn't
+	 * use the snapshot length, without a filter, that's
+	 * a bug.
+	 */
+	if (optind < argc) {
+		cmdbuf = copy_argv(&argv[optind]);
+
+		if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
+			error("%s", pcap_geterr(pd));
+
+		if (pcap_setfilter(pd, &fcode) < 0)
+			error("%s", pcap_geterr(pd));
+	}
+
+	pdd = pcap_dump_open(pd, savefile);
+	if (pdd == NULL)
+		error("%s", pcap_geterr(pd));
+
+#ifdef _WIN32
+	SetConsoleCtrlHandler(stop_capture, TRUE);
+#else
+	action.sa_handler = stop_capture;
+	sigemptyset(&action.sa_mask);
+	action.sa_flags = 0;
+	if (sigaction(SIGINT, &action, NULL) == -1)
+		error("Can't catch SIGINT: %s\n", strerror(errno));
+#endif
+
+	printf("Listening on %s, link-type ", device);
+	dlt = pcap_datalink(pd);
+	dlt_name = pcap_datalink_val_to_name(dlt);
+	if (dlt_name == NULL)
+		printf("DLT %d", dlt);
+	else
+		printf("%s", dlt_name);
+	printf("\n");
+	for (;;) {
+		status = pcap_dispatch(pd, -1, pcap_dump, (u_char *)pdd);
+		if (status < 0)
+			break;
+		if (status != 0) {
+			printf("%d packets seen\n", status);
+			struct pcap_stat ps;
+			pcap_stats(pd, &ps);
+			printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n",
+			    ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
+		}
+	}
+	if (status == -2) {
+		/*
+		 * We got interrupted, so perhaps we didn't
+		 * manage to finish a line we were printing.
+		 * Print an extra newline, just in case.
+		 */
+		putchar('\n');
+		printf("Broken out of loop from SIGINT handler\n");
+	}
+	(void)fflush(stdout);
+	if (status == -1) {
+		/*
+		 * Error.  Report it.
+		 */
+		(void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
+		    program_name, pcap_geterr(pd));
+	}
+	pcap_close(pd);
+	if (cmdbuf != NULL) {
+		pcap_freecode(&fcode);
+		free(cmdbuf);
+	}
+	exit(status == -1 ? 1 : 0);
+}
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr, "Usage: %s -D -L [ -i interface ] [ -s snaplen ] [ -w file ] [ -y dlt ] [expression]\n",
+	    program_name);
+	exit(1);
+}
+
+/* VARARGS */
+static void
+error(const char *fmt, ...)
+{
+	va_list ap;
+
+	(void)fprintf(stderr, "%s: ", program_name);
+	va_start(ap, fmt);
+	(void)vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	if (*fmt) {
+		fmt += strlen(fmt);
+		if (fmt[-1] != '\n')
+			(void)fputc('\n', stderr);
+	}
+	exit(1);
+	/* NOTREACHED */
+}
+
+/* VARARGS */
+static void
+warning(const char *fmt, ...)
+{
+	va_list ap;
+
+	(void)fprintf(stderr, "%s: WARNING: ", program_name);
+	va_start(ap, fmt);
+	(void)vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	if (*fmt) {
+		fmt += strlen(fmt);
+		if (fmt[-1] != '\n')
+			(void)fputc('\n', stderr);
+	}
+}
+
+/*
+ * Copy arg vector into a new buffer, concatenating arguments with spaces.
+ */
+static char *
+copy_argv(register char **argv)
+{
+	register char **p;
+	register size_t len = 0;
+	char *buf;
+	char *src, *dst;
+
+	p = argv;
+	if (*p == 0)
+		return 0;
+
+	while (*p)
+		len += strlen(*p++) + 1;
+
+	buf = (char *)malloc(len);
+	if (buf == NULL)
+		error("copy_argv: malloc");
+
+	p = argv;
+	dst = buf;
+	while ((src = *p++) != NULL) {
+		while ((*dst++ = *src++) != '\0')
+			;
+		dst[-1] = ' ';
+	}
+	dst[-1] = '\0';
+
+	return buf;
+}