]> The Tcpdump Group git mirrors - libpcap/blobdiff - pcap.c
Update config.{guess,sub}, timestamps 2023-01-01,2023-01-21
[libpcap] / pcap.c
diff --git a/pcap.c b/pcap.c
index 01869797d9566bc835f410b7b02d356d1aeec437..ef1bbb71f87fed1a4d692db79b44768229f80f48 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -36,9 +36,7 @@
 #endif
 
 #include <pcap-types.h>
-#ifdef _WIN32
-#include <Packet32.h>  /* for PacketGetVersion() */
-#else
+#ifndef _WIN32
 #include <sys/param.h>
 #ifndef MSDOS
 #include <sys/file.h>
@@ -55,7 +53,6 @@ struct rtentry;               /* declarations in <net/if.h> */
 #include <netinet/in.h>
 #endif /* _WIN32 */
 
-#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -64,11 +61,9 @@ struct rtentry;              /* declarations in <net/if.h> */
 #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"
@@ -80,6 +75,8 @@ struct rtentry;               /* declarations in <net/if.h> */
 
 #include "pcap-int.h"
 
+#include "optimize.h"
+
 #ifdef HAVE_DAG_API
 #include "pcap-dag.h"
 #endif /* HAVE_DAG_API */
@@ -96,7 +93,7 @@ struct rtentry;               /* declarations in <net/if.h> */
 #include "pcap-tc.h"
 #endif /* HAVE_TC_API */
 
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
 #include "pcap-usb-linux.h"
 #endif
 
@@ -124,46 +121,364 @@ struct rtentry;          /* declarations in <net/if.h> */
 #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
+/*
+ * 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 in a DllMain() routine.
+ *
+ * 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.)
+ */
+
+/*
+ * Start Winsock.
+ * Internal routine.
+ */
 static int
-pcap_not_initialized(pcap_t *pcap)
+internal_wsockinit(char *errbuf)
+{
+       WORD wVersionRequested;
+       WSADATA wsaData;
+       static int err = -1;
+       static int done = 0;
+       int status;
+
+       if (done)
+               return (err);
+
+       /*
+        * Versions of Windows that don't support Winsock 2.2 are
+        * too old for us.
+        */
+       wVersionRequested = MAKEWORD(2, 2);
+       status = WSAStartup(wVersionRequested, &wsaData);
+       done = 1;
+       if (status != 0) {
+               if (errbuf != NULL) {
+                       pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE,
+                           status, "WSAStartup() failed");
+               }
+               return (err);
+       }
+       atexit ((void(*)(void))WSACleanup);
+       err = 0;
+       return (err);
+}
+
+/*
+ * Exported in case some applications using WinPcap/Npcap called it,
+ * even though it wasn't exported.
+ */
+int
+wsockinit(void)
+{
+       return (internal_wsockinit(NULL));
+}
+
+/*
+ * This is the exported function; new programs should call this.
+ * *Newer* programs should call pcap_init().
+ */
+int
+pcap_wsockinit(void)
+{
+       return (internal_wsockinit(NULL));
+}
+#endif /* _WIN32 */
+
+/*
+ * Do whatever initialization is needed for libpcap.
+ *
+ * The argument specifies whether we use the local code page or UTF-8
+ * for strings; on UN*X, we just assume UTF-8 in places where the encoding
+ * would matter, whereas, on Windows, we use the local code page for
+ * PCAP_CHAR_ENC_LOCAL and UTF-8 for PCAP_CHAR_ENC_UTF_8.
+ *
+ * On Windows, we also disable the hack in pcap_create() to deal with
+ * being handed UTF-16 strings, because if the user calls this they're
+ * explicitly declaring that they will either be passing local code
+ * page strings or UTF-8 strings, so we don't need to allow UTF-16LE
+ * strings to be passed.  For good measure, on Windows *and* UN*X,
+ * we disable pcap_lookupdev(), to prevent anybody from even
+ * *trying* to pass the result of pcap_lookupdev() - which might be
+ * UTF-16LE on Windows, for ugly compatibility reasons - to pcap_create()
+ * or pcap_open_live() or pcap_open().
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int pcap_new_api;              /* pcap_lookupdev() always fails */
+int pcap_utf_8_mode;           /* Strings should be in UTF-8. */
+
+int
+pcap_init(unsigned int opts, char *errbuf)
+{
+       static int initialized;
+
+       /*
+        * Don't allow multiple calls that set different modes; that
+        * may mean a library is initializing pcap in one mode and
+        * a program using that library, or another library used by
+        * that program, is initializing it in another mode.
+        */
+       switch (opts) {
+
+       case PCAP_CHAR_ENC_LOCAL:
+               /* Leave "UTF-8 mode" off. */
+               if (initialized) {
+                       if (pcap_utf_8_mode) {
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                                   "Multiple pcap_init calls with different character encodings");
+                               return (PCAP_ERROR);
+                       }
+               }
+               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 (PCAP_ERROR);
+                       }
+               }
+               pcap_utf_8_mode = 1;
+               break;
+
+       default:
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unknown options specified");
+               return (PCAP_ERROR);
+       }
+
+       /*
+        * 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 (PCAP_ERROR);
+       }
+#endif
+
+       /*
+        * We're done.
+        */
+       initialized = 1;
+       pcap_new_api = 1;
+       return (0);
+}
+
+/*
+ * String containing the library version.
+ * Not explicitly exported via a header file - the right API to use
+ * is pcap_lib_version() - but some programs included it, so we
+ * provide it.
+ *
+ * We declare it here, right before defining it, to squelch any
+ * warnings we might get from compilers about the lack of a
+ * declaration.
+ */
+PCAP_API char pcap_version[];
+PCAP_API_DEF char pcap_version[] = PACKAGE_VERSION;
+
+static void
+pcap_set_not_initialized_message(pcap_t *pcap)
 {
+       if (pcap->activated) {
+               /* A module probably forgot to set the function pointer */
+               (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+                   "This operation isn't properly handled by that device");
+               return;
+       }
        /* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */
-       (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+       (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
            "This handle hasn't been activated yet");
+}
+
+static int
+pcap_read_not_initialized(pcap_t *pcap, int cnt _U_, pcap_handler callback _U_,
+    u_char *user _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       /* this means 'not initialized' */
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, int size _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       /* this means 'not initialized' */
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setfilter_not_initialized(pcap_t *pcap, struct bpf_program *fp _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       /* this means 'not initialized' */
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setdirection_not_initialized(pcap_t *pcap, pcap_direction_t d _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       /* this means 'not initialized' */
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_set_datalink_not_initialized(pcap_t *pcap, int dlt _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       /* this means 'not initialized' */
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_getnonblock_not_initialized(pcap_t *pcap)
+{
+       pcap_set_not_initialized_message(pcap);
+       /* this means 'not initialized' */
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_stats_not_initialized(pcap_t *pcap, struct pcap_stat *ps _U_)
+{
+       pcap_set_not_initialized_message(pcap);
        /* this means 'not initialized' */
        return (PCAP_ERROR_NOT_ACTIVATED);
 }
 
 #ifdef _WIN32
-static void *
-pcap_not_initialized_ptr(pcap_t *pcap)
+static struct pcap_stat *
+pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_)
 {
-       (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
-           "This handle hasn't been activated yet");
+       pcap_set_not_initialized_message(pcap);
        return (NULL);
 }
 
+static int
+pcap_setbuff_not_initialized(pcap_t *pcap, int dim _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       /* this means 'not initialized' */
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setmode_not_initialized(pcap_t *pcap, int mode _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       /* this means 'not initialized' */
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setmintocopy_not_initialized(pcap_t *pcap, int size _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       /* this means 'not initialized' */
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
 static HANDLE
 pcap_getevent_not_initialized(pcap_t *pcap)
 {
-       (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
-           "This handle hasn't been activated yet");
+       pcap_set_not_initialized_message(pcap);
        return (INVALID_HANDLE_VALUE);
 }
 
+static int
+pcap_oid_get_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
+    void *data _U_, size_t *lenp _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_oid_set_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
+    const void *data _U_, size_t *lenp _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
 static u_int
-pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync)
+pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue _U_,
+    int sync _U_)
 {
-       (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
-           "This handle hasn't been activated yet");
+       pcap_set_not_initialized_message(pcap);
        return (0);
 }
 
+static int
+pcap_setuserbuffer_not_initialized(pcap_t *pcap, int size _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_live_dump_not_initialized(pcap_t *pcap, char *filename _U_, int maxsize _U_,
+    int maxpacks _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_live_dump_ended_not_initialized(pcap_t *pcap, int sync _U_)
+{
+       pcap_set_not_initialized_message(pcap);
+       return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
 static PAirpcapHandle
 pcap_get_airpcap_handle_not_initialized(pcap_t *pcap)
 {
-       (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
-           "This handle hasn't been activated yet");
+       pcap_set_not_initialized_message(pcap);
        return (NULL);
 }
 #endif
@@ -204,20 +519,29 @@ pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp)
        if (p->tstamp_type_count == 0) {
                /*
                 * We don't support multiple time stamp types.
+                * That means the only type we support is PCAP_TSTAMP_HOST;
+                * set up a list containing only that type.
                 */
-               *tstamp_typesp = NULL;
+               *tstamp_typesp = (int*)malloc(sizeof(**tstamp_typesp));
+               if (*tstamp_typesp == NULL) {
+                       pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+                           errno, "malloc");
+                       return (PCAP_ERROR);
+               }
+               **tstamp_typesp = PCAP_TSTAMP_HOST;
+               return (1);
        } else {
                *tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp),
                    p->tstamp_type_count);
                if (*tstamp_typesp == NULL) {
-                       (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
-                           "malloc: %s", pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+                           errno, "malloc");
                        return (PCAP_ERROR);
                }
                (void)memcpy(*tstamp_typesp, p->tstamp_type_list,
                    sizeof(**tstamp_typesp) * p->tstamp_type_count);
+               return (p->tstamp_type_count);
        }
-       return (p->tstamp_type_count);
 }
 
 /*
@@ -289,7 +613,9 @@ pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header,
                 * Return codes for pcap_offline_read() are:
                 *   -  0: EOF
                 *   - -1: error
-                *   - >1: OK
+                *   - >0: OK - result is number of packets read, so
+                *         it will be 1 in this case, as we've passed
+                *         a maximum packet count of 1
                 * The first one ('0') conflicts with the return code of
                 * 0 from pcap_read() meaning "no packets arrived before
                 * the timeout expired", so we map it to -2 so you can
@@ -308,7 +634,9 @@ pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header,
         *   -  0: timeout
         *   - -1: error
         *   - -2: loop was broken out of with pcap_breakloop()
-        *   - >1: OK
+        *   - >0: OK, result is number of packets captured, so
+        *         it will be 1 in this case, as we've passed
+        *         a maximum packet count of 1
         * The first one ('0') conflicts with the return code of 0 from
         * pcap_offline_read() meaning "end of file".
        */
@@ -344,7 +672,7 @@ static struct capture_source_type {
 #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
@@ -358,6 +686,12 @@ static struct capture_source_type {
 #endif
 #ifdef PCAP_SUPPORT_RDMASNIFF
        { rdmasniff_findalldevs, rdmasniff_create },
+#endif
+#ifdef PCAP_SUPPORT_DPDK
+       { pcap_dpdk_findalldevs, pcap_dpdk_create },
+#endif
+#ifdef HAVE_AIRPCAP_API
+       { airpcap_findalldevs, airpcap_create },
 #endif
        { NULL, NULL }
 };
@@ -438,45 +772,59 @@ dup_sockaddr(struct sockaddr *sa, size_t sa_length)
  *
  * 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))
                n |= 0x40000000;
-       if (dev->flags & PCAP_IF_LOOPBACK)
+
+       /*
+        * Give non-wireless interfaces that aren't disconnected a better
+        * figure of merit than interfaces that are disconnected, as
+        * "disconnected" should indicate that the interface isn't
+        * plugged into a network and thus won't give you any traffic.
+        *
+        * For wireless interfaces, it means "associated with a network",
+        * which we presume not to necessarily prevent capture, as you
+        * might run the adapter in some flavor of monitor mode.
+        */
+       if (!(dev->flags & PCAP_IF_WIRELESS) &&
+           (dev->flags & PCAP_IF_CONNECTION_STATUS) == PCAP_IF_CONNECTION_STATUS_DISCONNECTED)
                n |= 0x20000000;
+
+       /*
+        * Sort loopback devices after non-loopback devices, *except* for
+        * disconnected devices.
+        */
+       if (dev->flags & PCAP_IF_LOOPBACK)
+               n |= 0x10000000;
+
+       /*
+        * Sort the "any" device before loopback and disconnected devices,
+        * but after all other devices.
+        */
+       if (strcmp(dev->name, "any") == 0)
+               n |= 0x08000000;
+
        return (n);
 }
 
@@ -501,7 +849,7 @@ get_figure_of_merit(pcap_if_t *dev)
  * description available, it still might be nice to get some description
  * string based on the device type or something such as that.
  *
- * In OS X, the System Configuration framework can apparently return
+ * In macOS, the System Configuration framework can apparently return
  * names in 10.4 and later.
  *
  * It also appears that freedesktop.org's HAL offers an "info.product"
@@ -531,9 +879,9 @@ get_figure_of_merit(pcap_if_t *dev)
  * description?
  */
 static char *
+#ifdef SIOCGIFDESCR
 get_if_description(const char *name)
 {
-#ifdef SIOCGIFDESCR
        char *description = NULL;
        int s;
        struct ifreq ifrdesc;
@@ -547,7 +895,7 @@ get_if_description(const char *name)
         * Get the description for the interface.
         */
        memset(&ifrdesc, 0, sizeof ifrdesc);
-       strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
+       pcap_strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
        s = socket(AF_INET, SOCK_DGRAM, 0);
        if (s >= 0) {
 #ifdef __FreeBSD__
@@ -598,7 +946,7 @@ get_if_description(const char *name)
                }
 #endif /* __FreeBSD__ */
                close(s);
-               if (description != NULL && strlen(description) == 0) {
+               if (description != NULL && description[0] == '\0') {
                        /*
                         * Description is empty, so discard it.
                         */
@@ -629,20 +977,13 @@ get_if_description(const char *name)
                                 * OK, it's a valid number that's not
                                 * bigger than INT_MAX.  Construct
                                 * a description from it.
+                                * (If that fails, we don't worry about
+                                * it, we just return NULL.)
                                 */
-                               static const char descr_prefix[] = "USB bus number ";
-                               size_t descr_size;
-
-                               /*
-                                * Allow enough room for a 32-bit bus number.
-                                * sizeof (descr_prefix) includes the
-                                * terminating NUL.
-                                */
-                               descr_size = sizeof (descr_prefix) + 10;
-                               description = malloc(descr_size);
-                               if (description != NULL) {
-                                       pcap_snprintf(description, descr_size,
-                                           "%s%ld", descr_prefix, busnum);
+                               if (pcap_asprintf(&description,
+                                   "USB bus number %ld", busnum) == -1) {
+                                       /* Failed. */
+                                       description = NULL;
                                }
                        }
                }
@@ -650,6 +991,8 @@ get_if_description(const char *name)
 #endif
        return (description);
 #else /* SIOCGIFDESCR */
+get_if_description(const char *name _U_)
+{
        return (NULL);
 #endif /* SIOCGIFDESCR */
 }
@@ -665,7 +1008,7 @@ get_if_description(const char *name)
  */
 pcap_if_t *
 find_or_add_if(pcap_if_list_t *devlistp, const char *name,
-    bpf_u_int32 if_flags, char *errbuf)
+    bpf_u_int32 if_flags, get_if_flags_func get_flags_func, char *errbuf)
 {
        bpf_u_int32 pcap_flags;
 
@@ -682,7 +1025,7 @@ find_or_add_if(pcap_if_list_t *devlistp, const char *name,
         * 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
@@ -699,7 +1042,7 @@ find_or_add_if(pcap_if_list_t *devlistp, const char *name,
         * attempt to add one.
         */
        return (find_or_add_dev(devlistp, name, pcap_flags,
-           get_if_description(name), errbuf));
+           get_flags_func, get_if_description(name), errbuf));
 }
 
 /*
@@ -722,7 +1065,7 @@ find_or_add_if(pcap_if_list_t *devlistp, const char *name,
  */
 int
 add_addr_to_if(pcap_if_list_t *devlistp, const char *name,
-    bpf_u_int32 if_flags,
+    bpf_u_int32 if_flags, get_if_flags_func get_flags_func,
     struct sockaddr *addr, size_t addr_size,
     struct sockaddr *netmask, size_t netmask_size,
     struct sockaddr *broadaddr, size_t broadaddr_size,
@@ -734,7 +1077,8 @@ add_addr_to_if(pcap_if_list_t *devlistp, const char *name,
        /*
         * Check whether the device exists and, if not, add it.
         */
-       curdev = find_or_add_if(devlistp, name, if_flags, errbuf);
+       curdev = find_or_add_if(devlistp, name, if_flags, get_flags_func,
+           errbuf);
        if (curdev == NULL) {
                /*
                 * Error - give up.
@@ -780,8 +1124,8 @@ add_addr_to_dev(pcap_if_t *curdev,
         */
        curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t));
        if (curaddr == NULL) {
-               (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "malloc: %s", pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "malloc");
                return (-1);
        }
 
@@ -789,8 +1133,8 @@ add_addr_to_dev(pcap_if_t *curdev,
        if (addr != NULL && addr_size != 0) {
                curaddr->addr = (struct sockaddr *)dup_sockaddr(addr, addr_size);
                if (curaddr->addr == NULL) {
-                       (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                           "malloc: %s", pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                           errno, "malloc");
                        free(curaddr);
                        return (-1);
                }
@@ -800,8 +1144,8 @@ add_addr_to_dev(pcap_if_t *curdev,
        if (netmask != NULL && netmask_size != 0) {
                curaddr->netmask = (struct sockaddr *)dup_sockaddr(netmask, netmask_size);
                if (curaddr->netmask == NULL) {
-                       (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                           "malloc: %s", pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                           errno, "malloc");
                        if (curaddr->addr != NULL)
                                free(curaddr->addr);
                        free(curaddr);
@@ -813,8 +1157,8 @@ add_addr_to_dev(pcap_if_t *curdev,
        if (broadaddr != NULL && broadaddr_size != 0) {
                curaddr->broadaddr = (struct sockaddr *)dup_sockaddr(broadaddr, broadaddr_size);
                if (curaddr->broadaddr == NULL) {
-                       (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                           "malloc: %s", pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                           errno, "malloc");
                        if (curaddr->netmask != NULL)
                                free(curaddr->netmask);
                        if (curaddr->addr != NULL)
@@ -828,8 +1172,8 @@ add_addr_to_dev(pcap_if_t *curdev,
        if (dstaddr != NULL && dstaddr_size != 0) {
                curaddr->dstaddr = (struct sockaddr *)dup_sockaddr(dstaddr, dstaddr_size);
                if (curaddr->dstaddr == NULL) {
-                       (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                           "malloc: %s", pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                           errno, "malloc");
                        if (curaddr->broadaddr != NULL)
                                free(curaddr->broadaddr);
                        if (curaddr->netmask != NULL)
@@ -882,7 +1226,7 @@ add_addr_to_dev(pcap_if_t *curdev,
  */
 pcap_if_t *
 find_or_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
-    const char *description, char *errbuf)
+    get_if_flags_func get_flags_func, const char *description, char *errbuf)
 {
        pcap_if_t *curdev;
 
@@ -898,7 +1242,21 @@ find_or_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
        }
 
        /*
-        * No, we didn't find it.  Try to add it to the list of devices.
+        * No, we didn't find it.
+        */
+
+       /*
+        * Try to get additional flags for the device.
+        */
+       if ((*get_flags_func)(name, &flags, errbuf) == -1) {
+               /*
+                * Failed.
+                */
+               return (NULL);
+       }
+
+       /*
+        * Now, try to add it to the list of devices.
         */
        return (add_dev(devlistp, name, flags, description, errbuf));
 }
@@ -950,8 +1308,8 @@ add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
 
        curdev = malloc(sizeof(pcap_if_t));
        if (curdev == NULL) {
-               (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "malloc: %s", pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "malloc");
                return (NULL);
        }
 
@@ -961,8 +1319,8 @@ add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
        curdev->next = NULL;
        curdev->name = strdup(name);
        if (curdev->name == NULL) {
-               (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "malloc: %s", pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "malloc");
                free(curdev);
                return (NULL);
        }
@@ -977,8 +1335,8 @@ add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
                 */
                curdev->description = strdup(description);
                if (curdev->description == NULL) {
-                       (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                           "malloc: %s", pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                           errno, "malloc");
                        free(curdev->name);
                        free(curdev);
                        return (NULL);
@@ -1107,35 +1465,230 @@ pcap_freealldevs(pcap_if_t *alldevs)
        }
 }
 
-#ifdef HAVE_REMOTE
-#include "pcap-rpcap.h"
-
 /*
- * Extract a substring from a string.
+ * pcap-npf.c has its own pcap_lookupdev(), for compatibility reasons, as
+ * it actually returns the names of all interfaces, with a NUL separator
+ * between them; some callers may depend on that.
+ *
+ * MS-DOS has its own pcap_lookupdev(), but that might be useful only
+ * as an optimization.
+ *
+ * In all other cases, we just use pcap_findalldevs() to get a list of
+ * devices, and pick from that list.
  */
-static char *
-get_substring(const char *p, size_t len, char *ebuf)
+#if !defined(HAVE_PACKET32) && !defined(MSDOS)
+/*
+ * Return the name of a network interface attached to the system, or NULL
+ * if none can be found.  The interface must be configured up; the
+ * lowest unit number is preferred; loopback is ignored.
+ */
+char *
+pcap_lookupdev(char *errbuf)
 {
-       char *token;
+       pcap_if_t *alldevs;
+#ifdef _WIN32
+  /*
+   * Windows - use the same size as the old WinPcap 3.1 code.
+   * XXX - this is probably bigger than it needs to be.
+   */
+  #define IF_NAMESIZE 8192
+#else
+  /*
+   * UN*X - use the system's interface name size.
+   * XXX - that might not be large enough for capture devices
+   * that aren't regular network interfaces.
+   */
+  /* for old BSD systems, including bsdi3 */
+  #ifndef IF_NAMESIZE
+  #define IF_NAMESIZE IFNAMSIZ
+  #endif
+#endif
+       static char device[IF_NAMESIZE + 1];
+       char *ret;
 
-       token = malloc(len + 1);
-       if (token == NULL) {
-               pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                   pcap_strerror(errno));
+       /*
+        * 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);
        }
-       memcpy(token, p, len);
-       token[len] = '\0';
-       return (token);
-}
 
-/*
- * Parse a capture source that might be a URL.
- *
- * If the source is not a URL, *schemep, *userinfop, *hostp, and *portp
- * are set to NULL, *pathp is set to point to the source, and 0 is
- * returned.
- *
+       if (pcap_findalldevs(&alldevs, errbuf) == -1)
+               return (NULL);
+
+       if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
+               /*
+                * There are no devices on the list, or the first device
+                * on the list is a loopback device, which means there
+                * are no non-loopback devices on the list.  This means
+                * we can't return any device.
+                *
+                * XXX - why not return a loopback device?  If we can't
+                * capture on it, it won't be on the list, and if it's
+                * on the list, there aren't any non-loopback devices,
+                * so why not just supply it as the default device?
+                */
+               (void)pcap_strlcpy(errbuf, "no suitable device found",
+                   PCAP_ERRBUF_SIZE);
+               ret = NULL;
+       } else {
+               /*
+                * Return the name of the first device on the list.
+                */
+               (void)pcap_strlcpy(device, alldevs->name, sizeof(device));
+               ret = device;
+       }
+
+       pcap_freealldevs(alldevs);
+       return (ret);
+}
+#endif /* !defined(HAVE_PACKET32) && !defined(MSDOS) */
+
+#if !defined(_WIN32) && !defined(MSDOS)
+/*
+ * We don't just fetch the entire list of devices, search for the
+ * particular device, and use its first IPv4 address, as that's too
+ * much work to get just one device's netmask.
+ *
+ * If we had an API to get attributes for a given device, we could
+ * use that.
+ */
+int
+pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
+    char *errbuf)
+{
+       register int fd;
+       register struct sockaddr_in *sin4;
+       struct ifreq ifr;
+
+       /*
+        * The pseudo-device "any" listens on all interfaces and therefore
+        * has the network address and -mask "0.0.0.0" therefore catching
+        * all traffic. Using NULL for the interface is the same as "any".
+        */
+       if (!device || strcmp(device, "any") == 0
+#ifdef HAVE_DAG_API
+           || strstr(device, "dag") != NULL
+#endif
+#ifdef HAVE_SEPTEL_API
+           || strstr(device, "septel") != NULL
+#endif
+#ifdef PCAP_SUPPORT_BT
+           || strstr(device, "bluetooth") != NULL
+#endif
+#ifdef PCAP_SUPPORT_LINUX_USBMON
+           || strstr(device, "usbmon") != NULL
+#endif
+#ifdef HAVE_SNF_API
+           || strstr(device, "snf") != NULL
+#endif
+#ifdef PCAP_SUPPORT_NETMAP
+           || strncmp(device, "netmap:", 7) == 0
+           || strncmp(device, "vale", 4) == 0
+#endif
+#ifdef PCAP_SUPPORT_DPDK
+           || strncmp(device, "dpdk:", 5) == 0
+#endif
+           ) {
+               *netp = *maskp = 0;
+               return 0;
+       }
+
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd < 0) {
+               pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "socket");
+               return (-1);
+       }
+       memset(&ifr, 0, sizeof(ifr));
+#ifdef linux
+       /* XXX Work around Linux kernel bug */
+       ifr.ifr_addr.sa_family = AF_INET;
+#endif
+       (void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+       if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+               if (errno == EADDRNOTAVAIL) {
+                       (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "%s: no IPv4 address assigned", device);
+               } else {
+                       pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                           errno, "SIOCGIFADDR: %s", device);
+               }
+               (void)close(fd);
+               return (-1);
+       }
+       sin4 = (struct sockaddr_in *)&ifr.ifr_addr;
+       *netp = sin4->sin_addr.s_addr;
+       memset(&ifr, 0, sizeof(ifr));
+#ifdef linux
+       /* XXX Work around Linux kernel bug */
+       ifr.ifr_addr.sa_family = AF_INET;
+#endif
+       (void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+       if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
+               pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "SIOCGIFNETMASK: %s", device);
+               (void)close(fd);
+               return (-1);
+       }
+       (void)close(fd);
+       *maskp = sin4->sin_addr.s_addr;
+       if (*maskp == 0) {
+               if (IN_CLASSA(*netp))
+                       *maskp = IN_CLASSA_NET;
+               else if (IN_CLASSB(*netp))
+                       *maskp = IN_CLASSB_NET;
+               else if (IN_CLASSC(*netp))
+                       *maskp = IN_CLASSC_NET;
+               else {
+                       (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "inet class for 0x%x unknown", *netp);
+                       return (-1);
+               }
+       }
+       *netp &= *maskp;
+       return (0);
+}
+#endif /* !defined(_WIN32) && !defined(MSDOS) */
+
+#ifdef ENABLE_REMOTE
+#include "pcap-rpcap.h"
+
+/*
+ * Extract a substring from a string.
+ */
+static char *
+get_substring(const char *p, size_t len, char *ebuf)
+{
+       char *token;
+
+       token = malloc(len + 1);
+       if (token == NULL) {
+               pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+                   errno, "malloc");
+               return (NULL);
+       }
+       memcpy(token, p, len);
+       token[len] = '\0';
+       return (token);
+}
+
+/*
+ * Parse a capture source that might be a URL.
+ *
+ * If the source is not a URL, *schemep, *userinfop, *hostp, and *portp
+ * are set to NULL, *pathp is set to point to the source, and 0 is
+ * returned.
+ *
  * If source is a URL, and the URL refers to a local device (a special
  * case of rpcap:), *schemep, *userinfop, *hostp, and *portp are set
  * to NULL, *pathp is set to point to the device name, and 0 is returned.
@@ -1215,8 +1768,8 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
                 */
                *pathp = strdup(source);
                if (*pathp == NULL) {
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                           pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+                           errno, "malloc");
                        return (-1);
                }
                return (0);
@@ -1240,8 +1793,8 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
                 */
                *pathp = strdup(source);
                if (*pathp == NULL) {
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                           pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+                           errno, "malloc");
                        return (-1);
                }
                return (0);
@@ -1258,13 +1811,13 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
        scheme_len = colonp - source;
        scheme = malloc(scheme_len + 1);
        if (scheme == NULL) {
-               pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                   pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+                   errno, "malloc");
                return (-1);
        }
        memcpy(scheme, source, scheme_len);
        scheme[scheme_len] = '\0';
-        
+
        /*
         * Treat file: specially - take everything after file:// as
         * the pathname.
@@ -1272,10 +1825,12 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
        if (pcap_strcasecmp(scheme, "file") == 0) {
                *pathp = strdup(colonp + 3);
                if (*pathp == NULL) {
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                           pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+                           errno, "malloc");
+                       free(scheme);
                        return (-1);
                }
+               *schemep = scheme;
                return (0);
        }
 
@@ -1287,7 +1842,8 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
         *
         * 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.
@@ -1298,8 +1854,8 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
                free(scheme);
                *pathp = strdup(colonp + 3);
                if (*pathp == NULL) {
-                       pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                           pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+                           errno, "malloc");
                        return (-1);
                }
                return (0);
@@ -1378,14 +1934,19 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
                         * Treat verything up to the closing square
                         * bracket as the IP-Literal; we don't worry
                         * about whether it's a valid IPv6address or
-                        * IPvFuture.
+                        * IPvFuture (or an IPv4address, for that
+                        * matter, just in case we get handed a
+                        * URL with an IPv4 IP-Literal, of the sort
+                        * that pcap_createsrcstr() used to generate,
+                        * and that pcap_parsesrcstr(), in the original
+                        * WinPcap code, accepted).
                         */
                        bracketp = strchr(parsep, ']');
                        if (bracketp == NULL) {
                                /*
                                 * There's no closing square bracket.
                                 */
-                               pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                               snprintf(ebuf, PCAP_ERRBUF_SIZE,
                                    "IP-literal in URL doesn't end with ]");
                                free(userinfo);
                                free(authority);
@@ -1398,7 +1959,7 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
                                 * 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);
@@ -1476,8 +2037,8 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
        else
                path = strdup(endp + 1);
        if (path == NULL) {
-               pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                   pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+                   errno, "malloc");
                free(port);
                free(host);
                free(userinfo);
@@ -1493,24 +2054,26 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
 }
 
 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) {
 
        case PCAP_SRC_FILE:
-               strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
+               pcap_strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
                if (name != NULL && *name != '\0') {
-                       strlcat(source, name, PCAP_BUF_SIZE);
+                       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:
-               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) {
                                /*
@@ -1518,47 +2081,55 @@ pcap_createsrcstr(char *source, int type, const char *host, const char *port,
                                 * probably an IPv6 address, and needs to
                                 * be included in square brackets.
                                 */
-                               strlcat(source, "[", PCAP_BUF_SIZE);
-                               strlcat(source, host, PCAP_BUF_SIZE);
-                               strlcat(source, "]", PCAP_BUF_SIZE);
+                               pcap_strlcat(source, "[", PCAP_BUF_SIZE);
+                               pcap_strlcat(source, host, PCAP_BUF_SIZE);
+                               pcap_strlcat(source, "]", PCAP_BUF_SIZE);
                        } else
-                               strlcat(source, host, PCAP_BUF_SIZE);
+                               pcap_strlcat(source, host, PCAP_BUF_SIZE);
 
                        if (port != NULL && *port != '\0') {
-                               strlcat(source, ":", PCAP_BUF_SIZE);
-                               strlcat(source, port, PCAP_BUF_SIZE);
+                               pcap_strlcat(source, ":", PCAP_BUF_SIZE);
+                               pcap_strlcat(source, port, PCAP_BUF_SIZE);
                        }
 
-                       strlcat(source, "/", PCAP_BUF_SIZE);
+                       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);
                }
 
                if (name != NULL && *name != '\0')
-                       strlcat(source, name, PCAP_BUF_SIZE);
+                       pcap_strlcat(source, name, PCAP_BUF_SIZE);
 
                return (0);
 
        case PCAP_SRC_IFLOCAL:
-               strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
+               pcap_strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
 
                if (name != NULL && *name != '\0')
-                       strlcat(source, name, PCAP_BUF_SIZE);
+                       pcap_strlcat(source, name, PCAP_BUF_SIZE);
 
                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;
 
@@ -1569,6 +2140,8 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
                *port = '\0';
        if (name)
                *name = '\0';
+       if (uses_ssl)
+               *uses_ssl = 0;
 
        /* Parse the source string */
        if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost,
@@ -1584,38 +2157,49 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
                 * Local device.
                 */
                if (name && tmppath)
-                       strlcpy(name, tmppath, PCAP_BUF_SIZE);
+                       pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
                if (type)
                        *type = PCAP_SRC_IFLOCAL;
                free(tmppath);
+               free(tmpport);
                free(tmphost);
                free(tmpuserinfo);
                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
-                               strlcpy(host, tmphost, PCAP_BUF_SIZE);
+                               pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE);
                }
                if (port && tmpport)
-                       strlcpy(port, tmpport, PCAP_BUF_SIZE);
+                       pcap_strlcpy(port, tmpport, PCAP_BUF_SIZE);
                if (name && tmppath)
-                       strlcpy(name, tmppath, PCAP_BUF_SIZE);
+                       pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
                if (type)
                        *type = PCAP_SRC_IFREMOTE;
                free(tmppath);
+               free(tmpport);
                free(tmphost);
                free(tmpuserinfo);
+               free(scheme);
                return (0);
        }
 
@@ -1624,12 +2208,14 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
                 * file://
                 */
                if (name && tmppath)
-                       strlcpy(name, tmppath, PCAP_BUF_SIZE);
+                       pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
                if (type)
                        *type = PCAP_SRC_FILE;
                free(tmppath);
+               free(tmpport);
                free(tmphost);
                free(tmpuserinfo);
+               free(scheme);
                return (0);
        }
 
@@ -1638,14 +2224,23 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
         * as a local device.
         */
        if (name)
-               strlcpy(name, source, PCAP_BUF_SIZE);
+               pcap_strlcpy(name, source, PCAP_BUF_SIZE);
        if (type)
                *type = PCAP_SRC_IFLOCAL;
        free(tmppath);
+       free(tmpport);
        free(tmphost);
        free(tmpuserinfo);
+       free(scheme);
        return (0);
 }
+
+int
+pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
+    char *name, char *errbuf)
+{
+       return (pcap_parsesrcstr_ex(source, type, host, port, name, NULL, errbuf));
+}
 #endif
 
 pcap_t *
@@ -1668,32 +2263,62 @@ pcap_create(const char *device, char *errbuf)
        else {
 #ifdef _WIN32
                /*
-                * If the string appears to be little-endian UCS-2/UTF-16,
-                * convert it to ASCII.
+                * On Windows, for backwards compatibility reasons,
+                * pcap_lookupdev() returns a pointer to a sequence of
+                * pairs of UTF-16LE device names and local code page
+                * description strings.
+                *
+                * This means that if a program uses pcap_lookupdev()
+                * to get a default device, and hands that to an API
+                * that opens devices, we'll get handed a UTF-16LE
+                * string, not a string in the local code page.
+                *
+                * To work around that, we check whether the string
+                * looks as if it might be a UTF-16LE string and, if
+                * so, convert it back to the local code page's
+                * extended ASCII.
                 *
-                * XXX - to UTF-8 instead?  Or report an error if any
-                * character isn't ASCII?
+                * We disable that check in "new API" mode, because:
+                *
+                *   1) You *cannot* reliably detect whether a
+                *   string is UTF-16LE or not; "a" could either
+                *   be a one-character ASCII string or the first
+                *   character of a UTF-16LE string.
+                *
+                *   2) Doing that test can run past the end of
+                *   the string, if it's a 1-character ASCII
+                *   string
+                *
+                * This particular version of this heuristic dates
+                * back to WinPcap 4.1.1; PacketOpenAdapter() does
+                * uses the same heuristic, with the exact same
+                * vulnerability.
+                *
+                * That's why we disable this in "new API" mode.
+                * We keep it around in legacy mode for backwards
+                * compatibility.
                 */
-               if (device[0] != '\0' && device[1] == '\0') {
+               if (!pcap_new_api && device[0] != '\0' && device[1] == '\0') {
                        size_t length;
 
                        length = wcslen((wchar_t *)device);
                        device_str = (char *)malloc(length + 1);
                        if (device_str == NULL) {
-                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                                   "malloc: %s", pcap_strerror(errno));
+                               pcap_fmt_errmsg_for_errno(errbuf,
+                                   PCAP_ERRBUF_SIZE, errno,
+                                   "malloc");
                                return (NULL);
                        }
 
-                       pcap_snprintf(device_str, length + 1, "%ws",
+                       snprintf(device_str, length + 1, "%ws",
                            (const wchar_t *)device);
                } else
 #endif
                        device_str = strdup(device);
        }
        if (device_str == NULL) {
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                   "malloc: %s", pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "malloc");
                return (NULL);
        }
 
@@ -1763,25 +2388,25 @@ initialize_ops(pcap_t *p)
         * an activated pcap_t to point to a routine that returns
         * a "this isn't activated" error.
         */
-       p->read_op = (read_op_t)pcap_not_initialized;
-       p->inject_op = (inject_op_t)pcap_not_initialized;
-       p->setfilter_op = (setfilter_op_t)pcap_not_initialized;
-       p->setdirection_op = (setdirection_op_t)pcap_not_initialized;
-       p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized;
-       p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized;
-       p->stats_op = (stats_op_t)pcap_not_initialized;
+       p->read_op = pcap_read_not_initialized;
+       p->inject_op = pcap_inject_not_initialized;
+       p->setfilter_op = pcap_setfilter_not_initialized;
+       p->setdirection_op = pcap_setdirection_not_initialized;
+       p->set_datalink_op = pcap_set_datalink_not_initialized;
+       p->getnonblock_op = pcap_getnonblock_not_initialized;
+       p->stats_op = pcap_stats_not_initialized;
 #ifdef _WIN32
-       p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr;
-       p->setbuff_op = (setbuff_op_t)pcap_not_initialized;
-       p->setmode_op = (setmode_op_t)pcap_not_initialized;
-       p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized;
+       p->stats_ex_op = pcap_stats_ex_not_initialized;
+       p->setbuff_op = pcap_setbuff_not_initialized;
+       p->setmode_op = pcap_setmode_not_initialized;
+       p->setmintocopy_op = pcap_setmintocopy_not_initialized;
        p->getevent_op = pcap_getevent_not_initialized;
-       p->oid_get_request_op = (oid_get_request_op_t)pcap_not_initialized;
-       p->oid_set_request_op = (oid_set_request_op_t)pcap_not_initialized;
+       p->oid_get_request_op = pcap_oid_get_request_not_initialized;
+       p->oid_set_request_op = pcap_oid_set_request_not_initialized;
        p->sendqueue_transmit_op = pcap_sendqueue_transmit_not_initialized;
-       p->setuserbuffer_op = (setuserbuffer_op_t)pcap_not_initialized;
-       p->live_dump_op = (live_dump_op_t)pcap_not_initialized;
-       p->live_dump_ended_op = (live_dump_ended_op_t)pcap_not_initialized;
+       p->setuserbuffer_op = pcap_setuserbuffer_not_initialized;
+       p->live_dump_op = pcap_live_dump_not_initialized;
+       p->live_dump_ended_op = pcap_live_dump_ended_not_initialized;
        p->get_airpcap_handle_op = pcap_get_airpcap_handle_not_initialized;
 #endif
 
@@ -1797,27 +2422,31 @@ initialize_ops(pcap_t *p)
         * 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.
+        * total_size is the size of a structure containing a pcap_t
+        * followed by a private structure.
         */
-       chunk = malloc(sizeof (pcap_t) + size);
+       chunk = calloc(total_size, 1);
        if (chunk == NULL) {
-               pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                   pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+                   errno, "malloc");
                return (NULL);
        }
-       memset(chunk, 0, sizeof (pcap_t) + size);
 
        /*
         * Get a pointer to the pcap_t at the beginning.
@@ -1826,31 +2455,32 @@ pcap_alloc_pcap_t(char *ebuf, size_t size)
 
 #ifdef _WIN32
        p->handle = INVALID_HANDLE_VALUE;       /* not opened yet */
-#else
+#else /* _WIN32 */
        p->fd = -1;     /* not opened yet */
+#ifndef MSDOS
        p->selectable_fd = -1;
-#endif
+       p->required_select_timeout = NULL;
+#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 + sizeof (pcap_t));
-       }
+       /*
+        * 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);
 
@@ -1902,7 +2532,7 @@ int
 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);
        }
@@ -2110,7 +2740,7 @@ pcap_activate(pcap_t *p)
                         * 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));
                }
 
@@ -2128,12 +2758,22 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *er
 {
        pcap_t *p;
        int status;
-#ifdef HAVE_REMOTE
+#ifdef ENABLE_REMOTE
        char host[PCAP_BUF_SIZE + 1];
        char port[PCAP_BUF_SIZE + 1];
        char name[PCAP_BUF_SIZE + 1];
        int srctype;
 
+       /*
+        * A null device name is equivalent to the "any" device -
+        * which might not be supported on this platform, but
+        * this means that you'll get a "not supported" error
+        * rather than, say, a crash when we try to dereference
+        * the null pointer.
+        */
+       if (device == NULL)
+               device = "any";
+
        /*
         * Retrofit - we have to make older applications compatible with
         * remote capture.
@@ -2158,7 +2798,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *er
                    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) {
@@ -2174,7 +2814,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *er
                                device += strlen(PCAP_SRC_IF_STRING);
                }
        }
-#endif /* HAVE_REMOTE */
+#endif /* ENABLE_REMOTE */
 
        p = pcap_create(device, errbuf);
        if (p == NULL)
@@ -2204,27 +2844,51 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *er
                goto fail;
        return (p);
 fail:
-       if (status == PCAP_ERROR)
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
-                   p->errbuf);
-       else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
+       if (status == PCAP_ERROR) {
+               /*
+                * Another buffer is a bit cumbersome, but it avoids
+                * -Wformat-truncation.
+                */
+               char trimbuf[PCAP_ERRBUF_SIZE - 5]; /* 2 bytes shorter */
+
+               pcap_strlcpy(trimbuf, p->errbuf, sizeof(trimbuf));
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device,
+                   PCAP_ERRBUF_SIZE - 3, trimbuf);
+       } 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,
-                   pcap_statustostr(status), p->errbuf);
-       else
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
+           status == PCAP_ERROR_PROMISC_PERM_DENIED) {
+               /*
+                * Only show the additional message if it's not
+                * empty.
+                */
+               if (p->errbuf[0] != '\0') {
+                       /*
+                        * Idem.
+                        */
+                       char trimbuf[PCAP_ERRBUF_SIZE - 8]; /* 2 bytes shorter */
+
+                       pcap_strlcpy(trimbuf, p->errbuf, sizeof(trimbuf));
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%.*s)",
+                           device, pcap_statustostr(status),
+                           PCAP_ERRBUF_SIZE - 6, trimbuf);
+               } else {
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
+                           device, pcap_statustostr(status));
+               }
+       } else {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
                    pcap_statustostr(status));
+       }
        pcap_close(p);
        return (NULL);
 }
 
 pcap_t *
-pcap_open_offline_common(char *ebuf, size_t 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);
 
@@ -2275,7 +2939,7 @@ pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
 void
 pcap_breakloop(pcap_t *p)
 {
-       p->break_loop = 1;
+       p->breakloop_op(p);
 }
 
 int
@@ -2308,8 +2972,8 @@ pcap_list_datalinks(pcap_t *p, int **dlt_buffer)
                 */
                *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer));
                if (*dlt_buffer == NULL) {
-                       (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
-                           "malloc: %s", pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+                           errno, "malloc");
                        return (PCAP_ERROR);
                }
                **dlt_buffer = p->linktype;
@@ -2317,8 +2981,8 @@ pcap_list_datalinks(pcap_t *p, int **dlt_buffer)
        } else {
                *dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count);
                if (*dlt_buffer == NULL) {
-                       (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
-                           "malloc: %s", pcap_strerror(errno));
+                       pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+                           errno, "malloc");
                        return (PCAP_ERROR);
                }
                (void)memcpy(*dlt_buffer, p->dlt_list,
@@ -2398,11 +3062,11 @@ pcap_set_datalink(pcap_t *p, int dlt)
 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);
        }
@@ -2515,7 +3179,7 @@ static struct dlt_choice dlt_choices[] = {
        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"),
@@ -2524,7 +3188,7 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE(FRELAY, "Frame Relay"),
        DLT_CHOICE(LOOP, "OpenBSD loopback"),
        DLT_CHOICE(ENC, "OpenBSD encapsulated IP"),
-       DLT_CHOICE(LINUX_SLL, "Linux cooked"),
+       DLT_CHOICE(LINUX_SLL, "Linux cooked v1"),
        DLT_CHOICE(LTALK, "Localtalk"),
        DLT_CHOICE(PFLOG, "OpenBSD pflog file"),
        DLT_CHOICE(PFSYNC, "Packet filter state syncing"),
@@ -2558,7 +3222,7 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE(GPF_T, "GPF-T"),
        DLT_CHOICE(GPF_F, "GPF-F"),
        DLT_CHOICE(JUNIPER_PIC_PEER, "Juniper PIC Peer"),
-       DLT_CHOICE(ERF_ETH,     "Ethernet with Endace ERF header"),
+       DLT_CHOICE(ERF_ETH, "Ethernet with Endace ERF header"),
        DLT_CHOICE(ERF_POS, "Packet-over-SONET with Endace ERF header"),
        DLT_CHOICE(LINUX_LAPD, "Linux vISDN LAPD"),
        DLT_CHOICE(JUNIPER_ETHER, "Juniper Ethernet"),
@@ -2582,10 +3246,11 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE(SITA, "SITA pseudo-header"),
        DLT_CHOICE(ERF, "Endace ERF header"),
        DLT_CHOICE(RAIF1, "Ethernet with u10 Networks pseudo-header"),
-       DLT_CHOICE(IPMB, "IPMB"),
+       DLT_CHOICE(IPMB_KONTRON, "IPMB with Kontron pseudo-header"),
        DLT_CHOICE(JUNIPER_ST, "Juniper Secure Tunnel"),
        DLT_CHOICE(BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"),
        DLT_CHOICE(AX25_KISS, "AX.25 with KISS header"),
+       DLT_CHOICE(IPMB_LINUX, "IPMB with Linux/Pigeon Point pseudo-header"),
        DLT_CHOICE(IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"),
        DLT_CHOICE(MPLS, "MPLS with label as link-layer header"),
        DLT_CHOICE(LINUX_EVDEV, "Linux evdev events"),
@@ -2639,6 +3304,22 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE(TI_LLN_SNIFFER, "TI LLN sniffer frames"),
        DLT_CHOICE(VSOCK, "Linux vsock"),
        DLT_CHOICE(NORDIC_BLE, "Nordic Semiconductor Bluetooth LE sniffer frames"),
+       DLT_CHOICE(DOCSIS31_XRA31, "Excentis XRA-31 DOCSIS 3.1 RF sniffer frames"),
+       DLT_CHOICE(ETHERNET_MPACKET, "802.3br mPackets"),
+       DLT_CHOICE(DISPLAYPORT_AUX, "DisplayPort AUX channel monitoring data"),
+       DLT_CHOICE(LINUX_SLL2, "Linux cooked v2"),
+       DLT_CHOICE(OPENVIZSLA, "OpenVizsla USB"),
+       DLT_CHOICE(EBHSCR, "Elektrobit High Speed Capture and Replay (EBHSCR)"),
+       DLT_CHOICE(VPP_DISPATCH, "VPP graph dispatch tracer"),
+       DLT_CHOICE(DSA_TAG_BRCM, "Broadcom tag"),
+       DLT_CHOICE(DSA_TAG_BRCM_PREPEND, "Broadcom tag (prepended)"),
+       DLT_CHOICE(IEEE802_15_4_TAP, "IEEE 802.15.4 with pseudo-header"),
+       DLT_CHOICE(DSA_TAG_DSA, "Marvell DSA"),
+       DLT_CHOICE(DSA_TAG_EDSA, "Marvell EDSA"),
+       DLT_CHOICE(ELEE, "ELEE lawful intercept packets"),
+       DLT_CHOICE(Z_WAVE_SERIAL, "Z-Wave serial frames between host and chip"),
+       DLT_CHOICE(USB_2_0, "USB 2.0/1.1/1.0 as transmitted over the cable"),
+       DLT_CHOICE(ATSC_ALP, "ATSC Link-Layer Protocol packets"),
        DLT_CHOICE_SENTINEL
 };
 
@@ -2678,6 +3359,21 @@ pcap_datalink_val_to_description(int dlt)
        return (NULL);
 }
 
+const char *
+pcap_datalink_val_to_description_or_dlt(int dlt)
+{
+        static char unkbuf[40];
+        const char *description;
+
+        description = pcap_datalink_val_to_description(dlt);
+        if (description != NULL) {
+                return description;
+        } else {
+                (void)snprintf(unkbuf, sizeof(unkbuf), "DLT %d", dlt);
+                return unkbuf;
+        }
+}
+
 struct tstamp_type_choice {
        const char *name;
        const char *description;
@@ -2690,6 +3386,7 @@ static struct tstamp_type_choice tstamp_type_choices[] = {
        { "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 }
 };
 
@@ -2775,18 +3472,33 @@ pcap_file(pcap_t *p)
        return (p->rfile);
 }
 
+#ifdef _WIN32
 int
 pcap_fileno(pcap_t *p)
 {
-#ifndef _WIN32
-       return (p->fd);
-#else
-       if (p->handle != INVALID_HANDLE_VALUE)
-               return ((int)(DWORD)p->handle);
-       else
+       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 intptr_t.  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)(intptr_t)p->handle);
+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
@@ -2794,6 +3506,12 @@ pcap_get_selectable_fd(pcap_t *p)
 {
        return (p->selectable_fd);
 }
+
+const struct timeval *
+pcap_get_required_select_timeout(pcap_t *p)
+{
+       return (p->required_select_timeout);
+}
 #endif
 
 void
@@ -2824,7 +3542,7 @@ pcap_getnonblock(pcap_t *p, char *errbuf)
                 * We copy the error message to errbuf, so callers
                 * can find it in either place.
                 */
-               strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
+               pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
        }
        return (ret);
 }
@@ -2841,8 +3559,8 @@ pcap_getnonblock_fd(pcap_t *p)
 
        fdflags = fcntl(p->fd, F_GETFL, 0);
        if (fdflags == -1) {
-               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
-                   pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "F_GETFL");
                return (-1);
        }
        if (fdflags & O_NONBLOCK)
@@ -2868,7 +3586,7 @@ pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
                 * We copy the error message to errbuf, so callers
                 * can find it in either place.
                 */
-               strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
+               pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
        }
        return (ret);
 }
@@ -2887,8 +3605,8 @@ pcap_setnonblock_fd(pcap_t *p, int nonblock)
 
        fdflags = fcntl(p->fd, F_GETFL, 0);
        if (fdflags == -1) {
-               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
-                   pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "F_GETFL");
                return (-1);
        }
        if (nonblock)
@@ -2896,43 +3614,14 @@ pcap_setnonblock_fd(pcap_t *p, int nonblock)
        else
                fdflags &= ~O_NONBLOCK;
        if (fcntl(p->fd, F_SETFL, fdflags) == -1) {
-               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s",
-                   pcap_strerror(errno));
+               pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "F_SETFL");
                return (-1);
        }
        return (0);
 }
 #endif
 
-#ifdef _WIN32
-/*
- * Generate a string for a Win32-specific error (i.e. an error generated when
- * calling a Win32 API).
- * For errors occurred during standard C calls, we still use pcap_strerror()
- */
-void
-pcap_win32_err_to_str(DWORD error, char *errbuf)
-{
-       size_t errlen;
-       char *p;
-
-       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
-           PCAP_ERRBUF_SIZE, NULL);
-
-       /*
-        * "FormatMessage()" "helpfully" sticks CR/LF at the end of the
-        * message.  Get rid of it.
-        */
-       errlen = strlen(errbuf);
-       if (errlen >= 2) {
-               errbuf[errlen - 1] = '\0';
-               errbuf[errlen - 2] = '\0';
-       }
-       p = strchr(errbuf, '\0');
-       pcap_snprintf (p, PCAP_ERRBUF_SIZE+1-(p-errbuf), " (%lu)", error);
-}
-#endif
-
 /*
  * Generate error strings for PCAP_ERROR_ and PCAP_WARNING_ values.
  */
@@ -2974,7 +3663,7 @@ pcap_statustostr(int errnum)
                return ("That operation is supported only in monitor mode");
 
        case PCAP_ERROR_PERM_DENIED:
-               return ("You don't have permission to capture on that device");
+               return ("You don't have permission to perform this capture on that device");
 
        case PCAP_ERROR_IFACE_NOT_UP:
                return ("That device is not up");
@@ -2988,7 +3677,7 @@ pcap_statustostr(int errnum)
        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);
 }
 
@@ -3004,7 +3693,7 @@ pcap_strerror(int errnum)
        errno_t err = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum);
 
        if (err != 0) /* err = 0 if successful */
-               strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE);
+               pcap_strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE);
        return (errbuf);
 #else
        return (strerror(errnum));
@@ -3016,7 +3705,7 @@ pcap_strerror(int errnum)
 
        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
 }
@@ -3037,11 +3726,29 @@ int
 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
@@ -3050,14 +3757,6 @@ pcap_stats(pcap_t *p, struct pcap_stat *ps)
        return (p->stats_op(p, ps));
 }
 
-static int
-pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "Statistics aren't available from a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 #ifdef _WIN32
 struct pcap_stat *
 pcap_stats_ex(pcap_t *p, int *pcap_stat_size)
@@ -3071,86 +3770,36 @@ pcap_setbuff(pcap_t *p, int dim)
        return (p->setbuff_op(p, dim));
 }
 
-static int
-pcap_setbuff_dead(pcap_t *p, int dim)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 int
 pcap_setmode(pcap_t *p, int mode)
 {
        return (p->setmode_op(p, mode));
 }
 
-static int
-pcap_setmode_dead(pcap_t *p, int mode)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "impossible to set mode on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 int
 pcap_setmintocopy(pcap_t *p, int size)
 {
        return (p->setmintocopy_op(p, size));
 }
 
-static int
-pcap_setmintocopy_dead(pcap_t *p, int size)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 HANDLE
 pcap_getevent(pcap_t *p)
 {
        return (p->getevent_op(p));
 }
 
-static HANDLE
-pcap_getevent_dead(pcap_t *p)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "A pcap_open_dead pcap_t has no event handle");
-       return (INVALID_HANDLE_VALUE);
-}
-
 int
 pcap_oid_get_request(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp)
 {
        return (p->oid_get_request_op(p, oid, data, lenp));
 }
 
-static int
-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,
-           "An OID get request cannot be performed on a pcap_open_dead pcap_t");
-       return (PCAP_ERROR);
-}
-
 int
 pcap_oid_set_request(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp)
 {
        return (p->oid_set_request_op(p, oid, data, lenp));
 }
 
-static int
-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,
-           "An OID set request cannot be performed on a pcap_open_dead pcap_t");
-       return (PCAP_ERROR);
-}
-
 pcap_send_queue *
 pcap_sendqueue_alloc(u_int memsize)
 {
@@ -3206,56 +3855,24 @@ pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync)
        return (p->sendqueue_transmit_op(p, queue, sync));
 }
 
-static u_int
-pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "Packets cannot be transmitted on a pcap_open_dead pcap_t");
-       return (0);
-}
-
 int
 pcap_setuserbuffer(pcap_t *p, int size)
 {
        return (p->setuserbuffer_op(p, size));
 }
 
-static int
-pcap_setuserbuffer_dead(pcap_t *p, int size)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "The user buffer cannot be set on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 int
 pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks)
 {
        return (p->live_dump_op(p, filename, maxsize, maxpacks));
 }
 
-static int
-pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
-int
-pcap_live_dump_ended(pcap_t *p, int sync)
+int
+pcap_live_dump_ended(pcap_t *p, int sync)
 {
        return (p->live_dump_ended_op(p, sync));
 }
 
-static int
-pcap_live_dump_ended_dead(pcap_t *p, int sync)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 PAirpcapHandle
 pcap_get_airpcap_handle(pcap_t *p)
 {
@@ -3263,17 +3880,11 @@ pcap_get_airpcap_handle(pcap_t *p)
 
        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);
 }
-
-static PAirpcapHandle
-pcap_get_airpcap_handle_dead(pcap_t *p)
-{
-       return (NULL);
-}
 #endif
 
 /*
@@ -3306,8 +3917,28 @@ pcap_close_all(void)
 {
        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
@@ -3322,7 +3953,7 @@ pcap_do_addexit(pcap_t *p)
                        /*
                         * "atexit()" failed; let our caller know.
                         */
-                       strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE);
+                       pcap_strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE);
                        return (0);
                }
                did_atexit = 1;
@@ -3364,9 +3995,20 @@ pcap_remove_from_pcaps_to_close(pcap_t *p)
        }
 }
 
+void
+pcap_breakloop_common(pcap_t *p)
+{
+       p->break_loop = 1;
+}
+
+
 void
 pcap_cleanup_live_common(pcap_t *p)
 {
+       if (p->opt.device != NULL) {
+               free(p->opt.device);
+               p->opt.device = NULL;
+       }
        if (p->buffer != NULL) {
                free(p->buffer);
                p->buffer = NULL;
@@ -3396,66 +4038,6 @@ pcap_cleanup_live_common(pcap_t *p)
 #endif
 }
 
-static void
-pcap_cleanup_dead(pcap_t *p _U_)
-{
-       /* Nothing to do. */
-}
-
-pcap_t *
-pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
-{
-       pcap_t *p;
-
-       switch (precision) {
-
-       case PCAP_TSTAMP_PRECISION_MICRO:
-       case PCAP_TSTAMP_PRECISION_NANO:
-               break;
-
-       default:
-               return NULL;
-       }
-       p = malloc(sizeof(*p));
-       if (p == NULL)
-               return NULL;
-       memset (p, 0, sizeof(*p));
-       p->snapshot = snaplen;
-       p->linktype = linktype;
-       p->opt.tstamp_precision = precision;
-       p->stats_op = pcap_stats_dead;
-#ifdef _WIN32
-       p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr;
-       p->setbuff_op = pcap_setbuff_dead;
-       p->setmode_op = pcap_setmode_dead;
-       p->setmintocopy_op = pcap_setmintocopy_dead;
-       p->getevent_op = pcap_getevent_dead;
-       p->oid_get_request_op = pcap_oid_get_request_dead;
-       p->oid_set_request_op = pcap_oid_set_request_dead;
-       p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead;
-       p->setuserbuffer_op = pcap_setuserbuffer_dead;
-       p->live_dump_op = pcap_live_dump_dead;
-       p->live_dump_ended_op = pcap_live_dump_ended_dead;
-       p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead;
-#endif
-       p->cleanup_op = pcap_cleanup_dead;
-
-       /*
-        * A "dead" pcap_t never requires special BPF code generation.
-        */
-       p->bpf_codegen_flags = 0;
-
-       p->activated = 1;
-       return (p);
-}
-
-pcap_t *
-pcap_open_dead(int linktype, int snaplen)
-{
-       return (pcap_open_dead_with_tstamp_precision(linktype, snaplen,
-           PCAP_TSTAMP_PRECISION_MICRO));
-}
-
 /*
  * API compatible with WinPcap's "send a packet" routine - returns -1
  * on error, 0 otherwise.
@@ -3465,6 +4047,12 @@ pcap_open_dead(int linktype, int snaplen)
 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);
@@ -3477,18 +4065,107 @@ pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
 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
 pcap_close(pcap_t *p)
 {
-       if (p->opt.device != NULL)
-               free(p->opt.device);
        p->cleanup_op(p);
        free(p);
 }
 
+/*
+ * Helpers for safely loading 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.
@@ -3502,205 +4179,273 @@ pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
        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);
 }
 
-#include "pcap_version.h"
+static int
+pcap_can_set_rfmon_dead(pcap_t *p)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Rfmon mode doesn't apply on a pcap_open_dead pcap_t");
+       return (PCAP_ERROR);
+}
+
+static int
+pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
+    u_char *user _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Packets aren't available from a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static void
+pcap_breakloop_dead(pcap_t *p _U_)
+{
+       /*
+        * A "dead" pcap_t is just a placeholder to use in order to
+        * compile a filter to BPF code or to open a savefile for
+        * writing.  It doesn't support any operations, including
+        * capturing or reading packets, so there will never be a
+        * get-packets loop in progress to break out *of*.
+        *
+        * As such, this routine doesn't need to do anything.
+        */
+}
+
+static int
+pcap_inject_dead(pcap_t *p, const void *buf _U_, int size _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Packets can't be sent on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "A filter cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The packet direction cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The link-layer header type cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_getnonblock_dead(pcap_t *p)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+       return (-1);
+}
+
+static int
+pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+       return (-1);
+}
 
-static const char *pcap_lib_version_string;
+static int
+pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Statistics aren't available from a pcap_open_dead pcap_t");
+       return (-1);
+}
 
 #ifdef _WIN32
+static struct pcap_stat *
+pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Statistics aren't available from a pcap_open_dead pcap_t");
+       return (NULL);
+}
 
-#ifdef HAVE_VERSION_H
-/*
- * libpcap being built for Windows, as part of a WinPcap/Npcap source
- * tree.  Include version.h from that source tree to get the WinPcap/Npcap
- * version.
- *
- * XXX - it'd be nice if we could somehow generate the WinPcap version number
- * when building WinPcap.  (It'd be nice to do so for the packet.dll version
- * number as well.)
- */
-#include "../../version.h"
+static int
+pcap_setbuff_dead(pcap_t *p, int dim _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
 
-static const char wpcap_version_string[] = WINPCAP_VER_STRING;
-static const char pcap_version_string_fmt[] =
-       WINPCAP_PRODUCT_NAME " version %s, based on %s";
-static const char pcap_version_string_packet_dll_fmt[] =
-       WINPCAP_PRODUCT_NAME " version %s (packet.dll version %s), based on %s";
+static int
+pcap_setmode_dead(pcap_t *p, int mode _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "impossible to set mode on a pcap_open_dead pcap_t");
+       return (-1);
+}
 
-const char *
-pcap_lib_version(void)
+static int
+pcap_setmintocopy_dead(pcap_t *p, int size _U_)
 {
-       char *packet_version_string;
-       size_t full_pcap_version_string_len;
-       char *full_pcap_version_string;
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
 
-       if (pcap_lib_version_string == NULL) {
-               /*
-                * Generate the version string.
-                */
-               packet_version_string = PacketGetVersion();
-               if (strcmp(wpcap_version_string, packet_version_string) == 0) {
-                       /*
-                        * WinPcap version string and packet.dll version
-                        * string are the same; just report the WinPcap
-                        * version.
-                        */
-                       full_pcap_version_string_len =
-                           (sizeof pcap_version_string_fmt - 4) +
-                           strlen(wpcap_version_string) +
-                           strlen(pcap_version_string);
-                       full_pcap_version_string =
-                           malloc(full_pcap_version_string_len);
-                       if (full_pcap_version_string == NULL)
-                               return (NULL);
-                       pcap_snprintf(full_pcap_version_string,
-                           full_pcap_version_string_len,
-                           pcap_version_string_fmt,
-                           wpcap_version_string,
-                           pcap_version_string);
-               } else {
-                       /*
-                        * WinPcap version string and packet.dll version
-                        * string are different; that shouldn't be the
-                        * case (the two libraries should come from the
-                        * same version of WinPcap), so we report both
-                        * versions.
-                        */
-                       full_pcap_version_string_len =
-                           (sizeof pcap_version_string_packet_dll_fmt - 6) +
-                           strlen(wpcap_version_string) +
-                           strlen(packet_version_string) +
-                           strlen(pcap_version_string);
-                       full_pcap_version_string = malloc(full_pcap_version_string_len);
-                       if (full_pcap_version_string == NULL)
-                               return (NULL);
-                       pcap_snprintf(full_pcap_version_string,
-                           full_pcap_version_string_len,
-                           pcap_version_string_packet_dll_fmt,
-                           wpcap_version_string,
-                           packet_version_string,
-                           pcap_version_string);
-               }
-               pcap_lib_version_string = full_pcap_version_string;
-       }
-       return (pcap_lib_version_string);
+static HANDLE
+pcap_getevent_dead(pcap_t *p)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "A pcap_open_dead pcap_t has no event handle");
+       return (INVALID_HANDLE_VALUE);
 }
 
-#else /* HAVE_VERSION_H */
+static int
+pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+    size_t *lenp _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "An OID get request cannot be performed on a pcap_open_dead pcap_t");
+       return (PCAP_ERROR);
+}
 
-/*
- * libpcap being built for Windows, not as part of a WinPcap/Npcap source
- * tree.
- */
-static const char pcap_version_string_packet_dll_fmt[] =
-       "%s (packet.dll version %s)";
-const char *
-pcap_lib_version(void)
+static int
+pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
+    size_t *lenp _U_)
 {
-       char *packet_version_string;
-       size_t full_pcap_version_string_len;
-       char *full_pcap_version_string;
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "An OID set request cannot be performed on a pcap_open_dead pcap_t");
+       return (PCAP_ERROR);
+}
 
-       if (pcap_lib_version_string == NULL) {
-               /*
-                * Generate the version string.  Report the packet.dll
-                * version.
-                */
-               packet_version_string = PacketGetVersion();
-               full_pcap_version_string_len =
-                   (sizeof pcap_version_string_packet_dll_fmt - 4) +
-                   strlen(pcap_version_string) +
-                   strlen(packet_version_string);
-               full_pcap_version_string = malloc(full_pcap_version_string_len);
-               if (full_pcap_version_string == NULL)
-                       return (NULL);
-               pcap_snprintf(full_pcap_version_string,
-                   full_pcap_version_string_len,
-                   pcap_version_string_packet_dll_fmt,
-                   pcap_version_string,
-                   packet_version_string);
-               pcap_lib_version_string = full_pcap_version_string;
-       }
-       return (pcap_lib_version_string);
+static u_int
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue _U_,
+    int sync _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Packets cannot be transmitted on a pcap_open_dead pcap_t");
+       return (0);
 }
 
-#endif /* HAVE_VERSION_H */
+static int
+pcap_setuserbuffer_dead(pcap_t *p, int size _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The user buffer cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
 
-#elif defined(MSDOS)
+static int
+pcap_live_dump_dead(pcap_t *p, char *filename _U_, int maxsize _U_,
+    int maxpacks _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+       return (-1);
+}
 
-const char *
-pcap_lib_version(void)
+static int
+pcap_live_dump_ended_dead(pcap_t *p, int sync _U_)
 {
-       char *packet_version_string;
-       size_t full_pcap_version_string_len;
-       char *full_pcap_version_string;
-       static char dospfx[] = "DOS-";
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+       return (-1);
+}
 
-       if (pcap_lib_version_string == NULL) {
-               /*
-                * Generate the version string.
-                */
-               full_pcap_version_string_len =
-                   sizeof dospfx + strlen(pcap_version_string);
-               full_pcap_version_string =
-                   malloc(full_pcap_version_string_len);
-               if (full_pcap_version_string == NULL)
-                       return (NULL);
-               strcpy(full_pcap_version_string, dospfx);
-               strcat(full_pcap_version_string, pcap_version_string);
-               pcap_lib_version_string = full_pcap_version_string;
-       }
-       return (pcap_lib_version_string);
+static PAirpcapHandle
+pcap_get_airpcap_handle_dead(pcap_t *p _U_)
+{
+       return (NULL);
 }
+#endif /* _WIN32 */
 
-#else /* UN*X */
+static void
+pcap_cleanup_dead(pcap_t *p _U_)
+{
+       /* Nothing to do. */
+}
 
-const char *
-pcap_lib_version(void)
+pcap_t *
+pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
 {
-       const char *platform_version_string;
-       size_t full_pcap_version_string_len;
-       char *full_pcap_version_string;
+       pcap_t *p;
 
-       if (pcap_lib_version_string == NULL) {
+       switch (precision) {
+
+       case PCAP_TSTAMP_PRECISION_MICRO:
+       case PCAP_TSTAMP_PRECISION_NANO:
+               break;
+
+       default:
                /*
-                * Generate the version string.
-                * Get any platform-specific information.
-                *
-                * XXX - what about all the local capture modules other
-                * that the "native interface" one?  That could make
-                * the version string really long.
+                * This doesn't really matter, but we don't have any way
+                * to report particular errors, so the only failure we
+                * should have is a memory allocation failure.  Just
+                * pick microsecond precision.
                 */
-               platform_version_string = pcap_platform_lib_version();
-               if (platform_version_string == NULL) {
-                       /*
-                        * No platform-specific information.
-                        */
-                       pcap_lib_version_string = pcap_version_string;
-               } else {
-                       /*
-                        * Add on the platform-specific information.
-                        */
-                       full_pcap_version_string_len =
-                           strlen(pcap_version_string) + 2 + strlen(platform_version_string) + 1 + 1;
-                       full_pcap_version_string =
-                           malloc(full_pcap_version_string_len);
-                       if (full_pcap_version_string == NULL)
-                               return (NULL);
-                       pcap_snprintf(full_pcap_version_string,
-                           full_pcap_version_string_len,
-                           "%s (%s)", pcap_version_string,
-                           platform_version_string);
-                       pcap_lib_version_string = full_pcap_version_string;
-               }
+               precision = PCAP_TSTAMP_PRECISION_MICRO;
+               break;
        }
-       return (pcap_lib_version_string);
-}
+       p = malloc(sizeof(*p));
+       if (p == NULL)
+               return NULL;
+       memset (p, 0, sizeof(*p));
+       p->snapshot = snaplen;
+       p->linktype = linktype;
+       p->opt.tstamp_precision = precision;
+       p->can_set_rfmon_op = pcap_can_set_rfmon_dead;
+       p->read_op = pcap_read_dead;
+       p->inject_op = pcap_inject_dead;
+       p->setfilter_op = pcap_setfilter_dead;
+       p->setdirection_op = pcap_setdirection_dead;
+       p->set_datalink_op = pcap_set_datalink_dead;
+       p->getnonblock_op = pcap_getnonblock_dead;
+       p->setnonblock_op = pcap_setnonblock_dead;
+       p->stats_op = pcap_stats_dead;
+#ifdef _WIN32
+       p->stats_ex_op = pcap_stats_ex_dead;
+       p->setbuff_op = pcap_setbuff_dead;
+       p->setmode_op = pcap_setmode_dead;
+       p->setmintocopy_op = pcap_setmintocopy_dead;
+       p->getevent_op = pcap_getevent_dead;
+       p->oid_get_request_op = pcap_oid_get_request_dead;
+       p->oid_set_request_op = pcap_oid_set_request_dead;
+       p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead;
+       p->setuserbuffer_op = pcap_setuserbuffer_dead;
+       p->live_dump_op = pcap_live_dump_dead;
+       p->live_dump_ended_op = pcap_live_dump_ended_dead;
+       p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead;
 #endif
+       p->breakloop_op = pcap_breakloop_dead;
+       p->cleanup_op = pcap_cleanup_dead;
+
+       /*
+        * A "dead" pcap_t never requires special BPF code generation.
+        */
+       p->bpf_codegen_flags = 0;
+
+       p->activated = 1;
+       return (p);
+}
+
+pcap_t *
+pcap_open_dead(int linktype, int snaplen)
+{
+       return (pcap_open_dead_with_tstamp_precision(linktype, snaplen,
+           PCAP_TSTAMP_PRECISION_MICRO));
+}
 
 #ifdef YYDEBUG
 /*
@@ -3720,32 +4465,6 @@ PCAP_API void pcap_set_parser_debug(int value);
 PCAP_API_DEF void
 pcap_set_parser_debug(int value)
 {
-       extern int pcap_debug;
-
        pcap_debug = value;
 }
 #endif
-
-#ifdef BDEBUG
-/*
- * Set the internal "debug printout" flag for the filter expression optimizer.
- * The code to print that stuff is present only if BDEBUG is defined, so
- * the flag, and the routine to set it, are defined only if BDEBUG is
- * defined.
- *
- * This is intended for libpcap developers, not for general use.
- * If you want to set these in a program, you'll have to declare this
- * routine yourself, with the appropriate DLL import attribute on Windows;
- * it's not declared in any header file, and won't be declared in any
- * header file provided by libpcap.
- */
-PCAP_API void pcap_set_optimizer_debug(int value);
-
-PCAP_API_DEF void
-pcap_set_optimizer_debug(int value)
-{
-       extern int pcap_optimizer_debug;
-
-       pcap_optimizer_debug = value;
-}
-#endif