]> 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 0d985199e036691927939e152e4ab9bdb7e8cd13..ef1bbb71f87fed1a4d692db79b44768229f80f48 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -53,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,6 +63,8 @@ struct rtentry;               /* declarations in <net/if.h> */
 #include <errno.h>
 #include <limits.h>
 
+#include "diag-control.h"
+
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
 #endif
@@ -92,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,55 +125,187 @@ struct rtentry;          /* declarations in <net/if.h> */
 #include "pcap-dpdk.h"
 #endif
 
+#ifdef HAVE_AIRPCAP_API
+#include "pcap-airpcap.h"
+#endif
+
 #ifdef _WIN32
 /*
- * DllMain(), required when built as a Windows DLL.
+ * To quote the WSAStartup() documentation:
+ *
+ *   The WSAStartup function typically leads to protocol-specific helper
+ *   DLLs being loaded. As a result, the WSAStartup function should not
+ *   be called from the DllMain function in a application DLL. This can
+ *   potentially cause deadlocks.
+ *
+ * and the WSACleanup() documentation:
+ *
+ *   The WSACleanup function typically leads to protocol-specific helper
+ *   DLLs being unloaded. As a result, the WSACleanup function should not
+ *   be called from the DllMain function in a application DLL. This can
+ *   potentially cause deadlocks.
+ *
+ * So we don't initialize Winsock 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.)
  */
-BOOL WINAPI DllMain(
-  HANDLE hinstDLL,
-  DWORD dwReason,
-  LPVOID lpvReserved
-)
-{
-       return (TRUE);
-}
 
 /*
- * Start WinSock.
- * Exported in case some applications using WinPcap called it,
- * even though it wasn't exported.
+ * Start Winsock.
+ * Internal routine.
  */
-int
-wsockinit(void)
+static int
+internal_wsockinit(char *errbuf)
 {
        WORD wVersionRequested;
        WSADATA wsaData;
        static int err = -1;
        static int done = 0;
+       int status;
 
        if (done)
                return (err);
 
-       wVersionRequested = MAKEWORD( 1, 1);
-       err = WSAStartup( wVersionRequested, &wsaData );
-       atexit ((void(*)(void))WSACleanup);
+       /*
+        * 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 ( err != 0 )
-               err = -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 (wsockinit());
+       return (internal_wsockinit(NULL));
 }
 #endif /* _WIN32 */
 
+/*
+ * Do whatever initialization is needed for libpcap.
+ *
+ * The argument specifies whether we use the local code page or UTF-8
+ * for strings; on UN*X, we just assume UTF-8 in places where the encoding
+ * would matter, whereas, on Windows, we use the local code page for
+ * PCAP_CHAR_ENC_LOCAL and UTF-8 for PCAP_CHAR_ENC_UTF_8.
+ *
+ * On Windows, we also disable the hack in pcap_create() to deal with
+ * being handed UTF-16 strings, because if the user calls this they're
+ * explicitly declaring that they will either be passing local code
+ * page strings or UTF-8 strings, so we don't need to allow UTF-16LE
+ * strings to be passed.  For good measure, on Windows *and* UN*X,
+ * we disable pcap_lookupdev(), to prevent anybody from even
+ * *trying* to pass the result of pcap_lookupdev() - which might be
+ * UTF-16LE on Windows, for ugly compatibility reasons - to pcap_create()
+ * or pcap_open_live() or pcap_open().
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int pcap_new_api;              /* pcap_lookupdev() always fails */
+int pcap_utf_8_mode;           /* Strings should be in UTF-8. */
+
+int
+pcap_init(unsigned int opts, char *errbuf)
+{
+       static int initialized;
+
+       /*
+        * Don't allow multiple calls that set different modes; that
+        * may mean a library is initializing pcap in one mode and
+        * a program using that library, or another library used by
+        * that program, is initializing it in another mode.
+        */
+       switch (opts) {
+
+       case PCAP_CHAR_ENC_LOCAL:
+               /* Leave "UTF-8 mode" off. */
+               if (initialized) {
+                       if (pcap_utf_8_mode) {
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                                   "Multiple pcap_init calls with different character encodings");
+                               return (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
@@ -191,12 +324,12 @@ pcap_set_not_initialized_message(pcap_t *pcap)
 {
        if (pcap->activated) {
                /* A module probably forgot to set the function pointer */
-               (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+               (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
                    "This operation isn't properly handled by that device");
                return;
        }
        /* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */
-       (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+       (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
            "This handle hasn't been activated yet");
 }
 
@@ -258,7 +391,7 @@ pcap_stats_not_initialized(pcap_t *pcap, struct pcap_stat *ps _U_)
 }
 
 #ifdef _WIN32
-struct pcap_stat *
+static struct pcap_stat *
 pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_)
 {
        pcap_set_not_initialized_message(pcap);
@@ -313,7 +446,8 @@ pcap_oid_set_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
 }
 
 static u_int
-pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync)
+pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue _U_,
+    int sync _U_)
 {
        pcap_set_not_initialized_message(pcap);
        return (0);
@@ -385,8 +519,17 @@ 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);
@@ -397,8 +540,8 @@ pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp)
                }
                (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);
 }
 
 /*
@@ -470,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
@@ -489,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".
        */
@@ -525,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
@@ -542,6 +689,9 @@ static struct capture_source_type {
 #endif
 #ifdef PCAP_SUPPORT_DPDK
        { pcap_dpdk_findalldevs, pcap_dpdk_create },
+#endif
+#ifdef HAVE_AIRPCAP_API
+       { airpcap_findalldevs, airpcap_create },
 #endif
        { NULL, NULL }
 };
@@ -622,39 +772,26 @@ 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))
@@ -681,6 +818,13 @@ get_figure_of_merit(pcap_if_t *dev)
        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);
 }
 
@@ -881,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
@@ -1362,6 +1506,22 @@ pcap_lookupdev(char *errbuf)
        static char device[IF_NAMESIZE + 1];
        char *ret;
 
+       /*
+        * We disable this in "new API" mode, because 1) in WinPcap/Npcap,
+        * it may return UTF-16 strings, for backwards-compatibility
+        * reasons, and we're also disabling the hack to make that work,
+        * for not-going-past-the-end-of-a-string reasons, and 2) we
+        * want its behavior to be consistent.
+        *
+        * In addition, it's not thread-safe, so we've marked it as
+        * deprecated.
+        */
+       if (pcap_new_api) {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()");
+               return (NULL);
+       }
+
        if (pcap_findalldevs(&alldevs, errbuf) == -1)
                return (NULL);
 
@@ -1425,7 +1585,7 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
 #ifdef PCAP_SUPPORT_BT
            || strstr(device, "bluetooth") != NULL
 #endif
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
            || strstr(device, "usbmon") != NULL
 #endif
 #ifdef HAVE_SNF_API
@@ -1457,7 +1617,7 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
        (void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
        if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
                if (errno == EADDRNOTAVAIL) {
-                       (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                       (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "%s: no IPv4 address assigned", device);
                } else {
                        pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
@@ -1490,7 +1650,7 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
                else if (IN_CLASSC(*netp))
                        *maskp = IN_CLASSC_NET;
                else {
-                       (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                       (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "inet class for 0x%x unknown", *netp);
                        return (-1);
                }
@@ -1786,7 +1946,7 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
                                /*
                                 * 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);
@@ -1799,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);
@@ -1905,7 +2065,7 @@ pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port,
                        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);
                }
@@ -1934,7 +2094,7 @@ pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port,
 
                        pcap_strlcat(source, "/", PCAP_BUF_SIZE);
                } else {
-                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "The host name cannot be NULL.");
                        return (-1);
                }
@@ -1953,7 +2113,7 @@ pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port,
                return (0);
 
        default:
-               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "The interface type is not valid.");
                return (-1);
        }
@@ -2024,7 +2184,7 @@ pcap_parsesrcstr_ex(const char *source, int *type, char *host, char *port,
                 */
                if (host && tmphost) {
                        if (tmpuserinfo)
-                               pcap_snprintf(host, PCAP_BUF_SIZE, "%s@%s",
+                               snprintf(host, PCAP_BUF_SIZE, "%s@%s",
                                    tmpuserinfo, tmphost);
                        else
                                pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE);
@@ -2114,19 +2274,31 @@ pcap_create(const char *device, char *errbuf)
                 * string, not a string in the local code page.
                 *
                 * To work around that, we check whether the string
-                * looks as if it might be a UTF-16LE strinh and, if
+                * looks as if it might be a UTF-16LE string and, if
                 * so, convert it back to the local code page's
                 * extended ASCII.
                 *
-                * XXX - you *cannot* reliably detect whether a
-                * string is UTF-16LE or not; "a" could either
-                * be a one-character ASCII string or the first
-                * character of a UTF-16LE string.  This particular
-                * version of this heuristic dates back to WinPcap
-                * 4.1.1; PacketOpenAdapter() does uses the same
-                * heuristic, with the exact same vulnerability.
+                * We disable that check in "new API" mode, because:
+                *
+                *   1) You *cannot* reliably detect whether a
+                *   string is UTF-16LE or not; "a" could either
+                *   be a one-character ASCII string or the first
+                *   character of a UTF-16LE string.
+                *
+                *   2) Doing that test can run past the end of
+                *   the string, if it's a 1-character ASCII
+                *   string
+                *
+                * This particular version of this heuristic dates
+                * back to WinPcap 4.1.1; PacketOpenAdapter() does
+                * uses the same heuristic, with the exact same
+                * vulnerability.
+                *
+                * That's why we disable this in "new API" mode.
+                * We keep it around in legacy mode for backwards
+                * compatibility.
                 */
-               if (device[0] != '\0' && device[1] == '\0') {
+               if (!pcap_new_api && device[0] != '\0' && device[1] == '\0') {
                        size_t length;
 
                        length = wcslen((wchar_t *)device);
@@ -2138,7 +2310,7 @@ pcap_create(const char *device, char *errbuf)
                                return (NULL);
                        }
 
-                       pcap_snprintf(device_str, length + 1, "%ws",
+                       snprintf(device_str, length + 1, "%ws",
                            (const wchar_t *)device);
                } else
 #endif
@@ -2260,33 +2432,21 @@ initialize_ops(pcap_t *p)
 }
 
 static pcap_t *
-pcap_alloc_pcap_t(char *ebuf, size_t size)
+pcap_alloc_pcap_t(char *ebuf, size_t total_size, size_t private_offset)
 {
        char *chunk;
        pcap_t *p;
 
        /*
-        * Allocate a chunk of memory big enough for a pcap_t
-        * plus a structure following it of size "size".  The
-        * structure following it is a private data structure
-        * for the routines that handle this pcap_t.
-        *
-        * The structure following it must be aligned on
-        * the appropriate alignment boundary for this platform.
-        * We align on an 8-byte boundary as that's probably what
-        * at least some platforms do, even with 32-bit integers,
-        * and because we can't be sure that some values won't
-        * require 8-byte alignment even on platforms with 32-bit
-        * integers.
+        * total_size is the size of a structure containing a pcap_t
+        * followed by a private structure.
         */
-#define PCAP_T_ALIGNED_SIZE    ((sizeof(pcap_t) + 7) & ~0x7)
-       chunk = malloc(PCAP_T_ALIGNED_SIZE + size);
+       chunk = calloc(total_size, 1);
        if (chunk == NULL) {
                pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
                    errno, "malloc");
                return (NULL);
        }
-       memset(chunk, 0, PCAP_T_ALIGNED_SIZE + size);
 
        /*
         * Get a pointer to the pcap_t at the beginning.
@@ -2303,26 +2463,24 @@ pcap_alloc_pcap_t(char *ebuf, size_t size)
 #endif /* MSDOS */
 #endif /* _WIN32 */
 
-       if (size == 0) {
-               /* No private data was requested. */
-               p->priv = NULL;
-       } else {
-               /*
-                * Set the pointer to the private data; that's the structure
-                * of size "size" following the pcap_t.
-                */
-               p->priv = (void *)(chunk + PCAP_T_ALIGNED_SIZE);
-       }
+       /*
+        * private_offset is the offset, in bytes, of the private
+        * data from the beginning of the structure.
+        *
+        * Set the pointer to the private data; that's private_offset
+        * bytes past the pcap_t.
+        */
+       p->priv = (void *)(chunk + private_offset);
 
        return (p);
 }
 
 pcap_t *
-pcap_create_common(char *ebuf, size_t size)
+pcap_create_common(char *ebuf, size_t total_size, size_t private_offset)
 {
        pcap_t *p;
 
-       p = pcap_alloc_pcap_t(ebuf, size);
+       p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
        if (p == NULL)
                return (NULL);
 
@@ -2374,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);
        }
@@ -2582,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));
                }
 
@@ -2640,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) {
@@ -2686,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,
-                   PCAP_ERRBUF_SIZE - 3, 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), PCAP_ERRBUF_SIZE - 6, 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);
 
@@ -2880,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);
        }
@@ -2997,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"),
@@ -3128,11 +3310,16 @@ static struct dlt_choice dlt_choices[] = {
        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
 };
 
@@ -3182,7 +3369,7 @@ pcap_datalink_val_to_description_or_dlt(int dlt)
         if (description != NULL) {
                 return description;
         } else {
-                (void)pcap_snprintf(unkbuf, sizeof(unkbuf), "DLT %u", dlt);
+                (void)snprintf(unkbuf, sizeof(unkbuf), "DLT %d", dlt);
                 return unkbuf;
         }
 }
@@ -3199,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 }
 };
 
@@ -3284,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
@@ -3304,7 +3507,7 @@ pcap_get_selectable_fd(pcap_t *p)
        return (p->selectable_fd);
 }
 
-struct timeval *
+const struct timeval *
 pcap_get_required_select_timeout(pcap_t *p)
 {
        return (p->required_select_timeout);
@@ -3460,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");
@@ -3474,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);
 }
 
@@ -3502,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
 }
@@ -3523,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
@@ -3659,7 +3880,7 @@ 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);
@@ -3696,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
@@ -3764,6 +4005,10 @@ pcap_breakloop_common(pcap_t *p)
 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;
@@ -3842,12 +4087,85 @@ pcap_inject(pcap_t *p, const void *buf, size_t 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.
@@ -3869,7 +4187,7 @@ pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
 static int
 pcap_can_set_rfmon_dead(pcap_t *p)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "Rfmon mode doesn't apply on a pcap_open_dead pcap_t");
        return (PCAP_ERROR);
 }
@@ -3878,15 +4196,29 @@ static int
 pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
     u_char *user _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "Packets aren't available from a pcap_open_dead pcap_t");
        return (-1);
 }
 
+static 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_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "Packets can't be sent on a pcap_open_dead pcap_t");
        return (-1);
 }
@@ -3894,7 +4226,7 @@ pcap_inject_dead(pcap_t *p, const void *buf _U_, int size _U_)
 static int
 pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "A filter cannot be set on a pcap_open_dead pcap_t");
        return (-1);
 }
@@ -3902,7 +4234,7 @@ pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
 static int
 pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "The packet direction cannot be set on a pcap_open_dead pcap_t");
        return (-1);
 }
@@ -3910,7 +4242,7 @@ pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
 static int
 pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "The link-layer header type cannot be set on a pcap_open_dead pcap_t");
        return (-1);
 }
@@ -3918,7 +4250,7 @@ pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
 static int
 pcap_getnonblock_dead(pcap_t *p)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
        return (-1);
 }
@@ -3926,7 +4258,7 @@ pcap_getnonblock_dead(pcap_t *p)
 static int
 pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
        return (-1);
 }
@@ -3934,40 +4266,40 @@ pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
 static int
 pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "Statistics aren't available from a pcap_open_dead pcap_t");
        return (-1);
 }
 
 #ifdef _WIN32
-struct pcap_stat *
+static struct pcap_stat *
 pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "Statistics aren't available from a pcap_open_dead pcap_t");
        return (NULL);
 }
 
 static int
-pcap_setbuff_dead(pcap_t *p, int dim)
+pcap_setbuff_dead(pcap_t *p, int dim _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
        return (-1);
 }
 
 static int
-pcap_setmode_dead(pcap_t *p, int mode)
+pcap_setmode_dead(pcap_t *p, int mode _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "impossible to set mode on a pcap_open_dead pcap_t");
        return (-1);
 }
 
 static int
-pcap_setmintocopy_dead(pcap_t *p, int size)
+pcap_setmintocopy_dead(pcap_t *p, int size _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
        return (-1);
 }
@@ -3975,7 +4307,7 @@ pcap_setmintocopy_dead(pcap_t *p, int size)
 static HANDLE
 pcap_getevent_dead(pcap_t *p)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "A pcap_open_dead pcap_t has no event handle");
        return (INVALID_HANDLE_VALUE);
 }
@@ -3984,7 +4316,7 @@ 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,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "An OID get request cannot be performed on a pcap_open_dead pcap_t");
        return (PCAP_ERROR);
 }
@@ -3993,45 +4325,47 @@ 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,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "An OID set request cannot be performed on a pcap_open_dead pcap_t");
        return (PCAP_ERROR);
 }
 
 static u_int
-pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync)
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue _U_,
+    int sync _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "Packets cannot be transmitted on a pcap_open_dead pcap_t");
        return (0);
 }
 
 static int
-pcap_setuserbuffer_dead(pcap_t *p, int size)
+pcap_setuserbuffer_dead(pcap_t *p, int size _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "The user buffer cannot be set on a pcap_open_dead pcap_t");
        return (-1);
 }
 
 static int
-pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks)
+pcap_live_dump_dead(pcap_t *p, char *filename _U_, int maxsize _U_,
+    int maxpacks _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
        return (-1);
 }
 
 static int
-pcap_live_dump_ended_dead(pcap_t *p, int sync)
+pcap_live_dump_ended_dead(pcap_t *p, int sync _U_)
 {
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
            "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
        return (-1);
 }
 
 static PAirpcapHandle
-pcap_get_airpcap_handle_dead(pcap_t *p)
+pcap_get_airpcap_handle_dead(pcap_t *p _U_)
 {
        return (NULL);
 }
@@ -4094,6 +4428,7 @@ pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
        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;
 
        /*