]> The Tcpdump Group git mirrors - libpcap/commitdiff
Support AirPcap devices with a pcap module.
authorGuy Harris <[email protected]>
Fri, 8 May 2020 03:11:06 +0000 (20:11 -0700)
committerGuy Harris <[email protected]>
Fri, 8 May 2020 03:11:06 +0000 (20:11 -0700)
This allows us to update the support for newer APIs in the future - and
in the present, with pcap_set_datalink() - and would allow Npcap to
remove its AirPcap support.

Add another test program, while we're at it.

14 files changed:
CMakeLists.txt
Makefile.in
cmake/Modules/FindAirPcap.cmake [new file with mode: 0644]
cmakeconfig.h.in
pcap-airpcap.c [new file with mode: 0644]
pcap-airpcap.h [new file with mode: 0644]
pcap-int.h
pcap-npf.c
pcap-tc.c
pcap.c
testprogs/.gitignore
testprogs/CMakeLists.txt
testprogs/Makefile.in
testprogs/writecaptest.c [new file with mode: 0644]

index c2d84782314f722414533baf75b7a927b8722891..df3071e0c6e71a6db54ce602a4791acddbfb08a4 100644 (file)
@@ -185,6 +185,7 @@ endif(WIN32)
 option(BUILD_SHARED_LIBS "Build shared libraries" ON)
 if(WIN32)
     set(Packet_ROOT "" CACHE PATH "Path to directory with include and lib subdirectories for packet.dll")
+    set(AirPcap_ROOT "" CACHE PATH "Path to directory with include and lib subdirectories for airpcap.dll")
 endif(WIN32)
 
 option(ENABLE_PROFILING "Enable code profiling" OFF)
@@ -1794,6 +1795,27 @@ if(NOT DISABLE_SNF)
     endif()
 endif()
 
+# Check for Riverbed AirPcap support.
+if(NOT DISABLE_AIRPCAP)
+    #
+    # Try to find the AirPcap header file and library.
+    #
+    find_package(AirPcap)
+
+    #
+    # Did we succeed?
+    #
+    if(AIRPCAP_FOUND)
+        #
+        # Yes.
+        #
+        include_directories(AFTER ${AIRPCAP_INCLUDE_DIRS})
+        set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-airpcap.c)
+        set(HAVE_AIRPCAP_API TRUE)
+        set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${AIRPCAP_LIBRARIES})
+    endif()
+endif()
+
 # Check for Riverbed TurboCap support.
 if(NOT DISABLE_TC)
     #
@@ -1811,7 +1833,7 @@ if(NOT DISABLE_TC)
         include_directories(AFTER ${TC_INCLUDE_DIRS})
         set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-tc.c)
         set(HAVE_TC_API TRUE)
-        set(PCAP_LINK_LIBRARIES "${PCAP_LINK_LIBRARIES} ${TC_LIBRARIES} ${CMAKE_USE_PTHREADS_INIT} stdc++")
+        set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${TC_LIBRARIES} ${CMAKE_USE_PTHREADS_INIT} stdc++)
     endif()
 endif()
 
index 0cdca03d1206c0f38018553c62e654729df45116..49d8b4c1814c7211a3017841b93c57596fbae3c7 100644 (file)
@@ -310,6 +310,8 @@ EXTRA_DIST = \
        msdos/readme.dos \
        nomkdep \
        org.tcpdump.chmod_bpf.plist \
+       pcap-airpcap.c \
+       pcap-airpcap.h \
        pcap-bpf.c \
        pcap-bt-linux.c \
        pcap-bt-linux.h \
diff --git a/cmake/Modules/FindAirPcap.cmake b/cmake/Modules/FindAirPcap.cmake
new file mode 100644 (file)
index 0000000..8198f70
--- /dev/null
@@ -0,0 +1,69 @@
+#
+# FindAirPcap
+# ==========
+#
+# Find the AirPcap library and include files.
+#
+# This module defines the following variables:
+#
+# AIRPCAP_INCLUDE_DIR     - absolute path to the directory containing airpcap.h.
+#
+# AIRPCAP_LIBRARY         - relative or absolute path to the AirPcap library to
+#                          link with. An absolute path is will be used if the
+#                          AirPcap library is not located in the compiler's
+#                          default search path.
+
+# AIRPCAP_FOUND           - TRUE if the AirPcap library *and* header are found.
+#
+# Hints and Backward Compatibility
+# ================================
+#
+# To tell this module where to look, a user may set the environment variable
+# AirPcap_ROOT to point cmake to the *root* of a directory with include and
+# lib subdirectories for airpcap.dll (e.g Airpcap_Devpack).
+# Alternatively, AirPcap_ROOT may also be set from the CMake command
+# line or GUI (e.g cmake -DAirPcap_ROOT=C:\path\to\airpcap_sdk [...])
+#
+
+# The 64-bit airpcap.lib is located under /x64
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+  #
+  # For the WinPcap and Npcap SDKs, the Lib subdirectory of the top-level
+  # directory contains 32-bit libraries; the 64-bit libraries are in the
+  # Lib/x64 directory.
+  #
+  # The only way to *FORCE* CMake to look in the Lib/x64 directory
+  # without searching in the Lib directory first appears to be to set
+  # CMAKE_LIBRARY_ARCHITECTURE to "x64".
+  #
+  # In newer versions of CMake, CMAKE_LIBRARY_ARCHITECTURE is set according to
+  # the language, e.g., CMAKE_<LANG>_LIBRARY_ARCHITECTURE. So, set the new
+  # variable, CMAKE_C_LIBRARY_ARCHITECTURE, so that CMAKE_LIBRARY_ARCHITECTURE
+  # inherits the correct value.
+  #
+  set(CMAKE_C_LIBRARY_ARCHITECTURE "x64")
+  set(CMAKE_LIBRARY_ARCHITECTURE "x64")
+endif()
+
+# Find the header
+find_path(AIRPCAP_INCLUDE_DIR airpcap.h
+  PATH_SUFFIXES include
+)
+
+# Find the library
+find_library(AIRPCAP_LIBRARY
+  NAMES airpcap
+)
+
+# Set AIRPCAP_FOUND to TRUE if AIRPCAP_INCLUDE_DIR and AIRPCAP_LIBRARY are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(AIRPCAP
+  DEFAULT_MSG
+  AIRPCAP_INCLUDE_DIR
+  AIRPCAP_LIBRARY
+)
+
+mark_as_advanced(AIRPCAP_INCLUDE_DIR AIRPCAP_LIBRARY)
+
+set(AIRPCAP_INCLUDE_DIRS ${AIRPCAP_INCLUDE_DIR})
+set(AIRPCAP_LIBRARIES ${AIRPCAP_LIBRARY})
index 84fb42aee94d8dd3eb7488c463ccf35e31b26dda..074a7be5c0524694a093ac8e2b9f2f7166293c44 100644 (file)
@@ -15,6 +15,9 @@
 /* define if we have the AIX getprotobyname_r() */
 #cmakedefine HAVE_AIX_GETPROTOBYNAME_R 1
 
+/* define if you have the AirPcap API */
+#cmakedefine HAVE_AIRPCAP_API 1
+
 /* Define to 1 if you have the `asprintf' function. */
 #cmakedefine HAVE_ASPRINTF 1
 
diff --git a/pcap-airpcap.c b/pcap-airpcap.c
new file mode 100644 (file)
index 0000000..a9ef47d
--- /dev/null
@@ -0,0 +1,984 @@
+/*
+ * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino, CACE Technologies
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pcap-int.h"
+
+#include <airpcap.h>
+
+#include "pcap-airpcap.h"
+
+/* Default size of the buffer we allocate in userland. */
+#define        AIRPCAP_DEFAULT_USER_BUFFER_SIZE 256000
+
+/* Default size of the buffer for the AirPcap adapter. */
+#define        AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE 1000000
+
+//
+// We load the AirPcap DLL dynamically, so that the code will
+// work whether you have it installed or not, and there don't
+// have to be two different versions of the library, one linked
+// to the AirPcap library and one not linked to it.
+//
+static pcap_code_handle_t airpcap_lib;
+
+typedef PCHAR (*AirpcapGetLastErrorHandler)(PAirpcapHandle);
+typedef BOOL (*AirpcapGetDeviceListHandler)(PAirpcapDeviceDescription *, PCHAR);
+typedef VOID (*AirpcapFreeDeviceListHandler)(PAirpcapDeviceDescription);
+typedef PAirpcapHandle (*AirpcapOpenHandler)(PCHAR, PCHAR);
+typedef VOID (*AirpcapCloseHandler)(PAirpcapHandle);
+typedef BOOL (*AirpcapSetLinkTypeHandler)(PAirpcapHandle, AirpcapLinkType);
+typedef BOOL (*AirpcapGetLinkTypeHandler)(PAirpcapHandle, PAirpcapLinkType);
+typedef BOOL (*AirpcapSetKernelBufferHandler)(PAirpcapHandle, UINT);
+typedef BOOL (*AirpcapSetFilterHandler)(PAirpcapHandle, PVOID, UINT);
+typedef BOOL (*AirpcapSetMinToCopyHandler)(PAirpcapHandle, UINT);
+typedef BOOL (*AirpcapGetReadEventHandler)(PAirpcapHandle, HANDLE *);
+typedef BOOL (*AirpcapReadHandler)(PAirpcapHandle, PBYTE, UINT, PUINT);
+typedef BOOL (*AirpcapWriteHandler)(PAirpcapHandle, PCHAR, ULONG);
+typedef BOOL (*AirpcapGetStatsHandler)(PAirpcapHandle, PAirpcapStats);
+
+static AirpcapGetLastErrorHandler p_AirpcapGetLastError;
+static AirpcapGetDeviceListHandler p_AirpcapGetDeviceList;
+static AirpcapFreeDeviceListHandler p_AirpcapFreeDeviceList;
+static AirpcapOpenHandler p_AirpcapOpen;
+static AirpcapCloseHandler p_AirpcapClose;
+static AirpcapSetLinkTypeHandler p_AirpcapSetLinkType;
+static AirpcapGetLinkTypeHandler p_AirpcapGetLinkType;
+static AirpcapSetKernelBufferHandler p_AirpcapSetKernelBuffer;
+static AirpcapSetFilterHandler p_AirpcapSetFilter;
+static AirpcapSetMinToCopyHandler p_AirpcapSetMinToCopy;
+static AirpcapGetReadEventHandler p_AirpcapGetReadEvent;
+static AirpcapReadHandler p_AirpcapRead;
+static AirpcapWriteHandler p_AirpcapWrite;
+static AirpcapGetStatsHandler p_AirpcapGetStats;
+
+typedef enum LONG
+{
+       AIRPCAP_API_UNLOADED = 0,
+       AIRPCAP_API_LOADED,
+       AIRPCAP_API_CANNOT_LOAD,
+       AIRPCAP_API_LOADING
+} AIRPCAP_API_LOAD_STATUS;
+
+static AIRPCAP_API_LOAD_STATUS airpcap_load_status;
+
+/*
+ * NOTE: this function should be called by the pcap functions that can
+ *       theoretically deal with the AirPcap library for the first time,
+ *       namely listing the adapters and creating a pcap_t for an adapter.
+ *       All the other ones (activate, close, read, write, set parameters)
+ *       work on a pcap_t for an AirPcap device, meaning we've already
+ *       created the pcap_t and thus have loaded the functions, so we do
+ *       not need to call this function.
+ */
+static AIRPCAP_API_LOAD_STATUS
+load_airpcap_functions(void)
+{
+       AIRPCAP_API_LOAD_STATUS current_status;
+
+       /*
+        * We don't use a mutex because there's no place that
+        * we can guarantee we'll be called before any threads
+        * other than the main thread exists.  (For example,
+        * this might be a static library, so we can't arrange
+        * to be called by DllMain(), and there's no guarantee
+        * that the application called pcap_init() - which is
+        * supposed to be called only from one thread - so
+        * we can't arrange to be called from it.)
+        *
+        * If nobody's tried to load it yet, mark it as
+        * loading; in any case, return the status before
+        * we modified it.
+        */
+       current_status = InterlockedCompareExchange((LONG *)&airpcap_load_status,
+           AIRPCAP_API_LOADING, AIRPCAP_API_UNLOADED);
+
+       /*
+        * If the status was AIRPCAP_API_UNLOADED, we've set it
+        * to AIRPCAP_API_LOADING, because we're going to be
+        * the ones to load the library but current_status is
+        * AIRPCAP_API_UNLOADED.
+        *
+        * if it was AIRPCAP_API_LOADING, meaning somebody else
+        * was trying to load it, spin until they finish and
+        * set the status to a value reflecting whether they
+        * succeeded.
+        */
+       while (current_status == AIRPCAP_API_LOADING) {
+               current_status = InterlockedCompareExchange((LONG*)&airpcap_load_status,
+                   AIRPCAP_API_LOADING, AIRPCAP_API_LOADING);
+               Sleep(10);
+       }
+
+       /*
+        * At this point, current_status is either:
+        *
+        *      AIRPCAP_API_LOADED, in which case another thread
+        *      loaded the library, so we're done;
+        *
+        *      AIRPCAP_API_CANNOT_LOAD, in which another thread
+        *      tried and failed to load the library, so we're
+        *      done - we won't try it ourselves;
+        *
+        *      AIRPCAP_API_LOADING, in which case *we're* the
+        *      ones loading it, and should now try to do so.
+        */
+       if (current_status  == AIRPCAP_API_LOADED)
+               return AIRPCAP_API_LOADED;
+
+       if (current_status == AIRPCAP_API_CANNOT_LOAD)
+               return AIRPCAP_API_CANNOT_LOAD;
+
+       /*
+        * Start out assuming we can't load it.
+        */
+       current_status = AIRPCAP_API_CANNOT_LOAD;
+
+       airpcap_lib = pcap_load_code("airpcap.dll");
+       if (airpcap_lib != NULL) {
+               /*
+                * OK, we've loaded the library; now try to find the
+                * functions we need in it.
+                */
+               p_AirpcapGetLastError = (AirpcapGetLastErrorHandler) pcap_find_function(airpcap_lib, "AirpcapGetLastError");
+               p_AirpcapGetDeviceList = (AirpcapGetDeviceListHandler) pcap_find_function(airpcap_lib, "AirpcapGetDeviceList");
+               p_AirpcapFreeDeviceList = (AirpcapFreeDeviceListHandler) pcap_find_function(airpcap_lib, "AirpcapFreeDeviceList");
+               p_AirpcapOpen = (AirpcapOpenHandler) pcap_find_function(airpcap_lib, "AirpcapOpen");
+               p_AirpcapClose = (AirpcapCloseHandler) pcap_find_function(airpcap_lib, "AirpcapClose");
+               p_AirpcapSetLinkType = (AirpcapSetLinkTypeHandler) pcap_find_function(airpcap_lib, "AirpcapSetLinkType");
+               p_AirpcapGetLinkType = (AirpcapGetLinkTypeHandler) pcap_find_function(airpcap_lib, "AirpcapGetLinkType");
+               p_AirpcapSetKernelBuffer = (AirpcapSetKernelBufferHandler) pcap_find_function(airpcap_lib, "AirpcapSetKernelBuffer");
+               p_AirpcapSetFilter = (AirpcapSetFilterHandler) pcap_find_function(airpcap_lib, "AirpcapSetFilter");
+               p_AirpcapSetMinToCopy = (AirpcapSetMinToCopyHandler) pcap_find_function(airpcap_lib, "AirpcapSetMinToCopy");
+               p_AirpcapGetReadEvent = (AirpcapGetReadEventHandler) pcap_find_function(airpcap_lib, "AirpcapGetReadEvent");
+               p_AirpcapRead = (AirpcapReadHandler) pcap_find_function(airpcap_lib, "AirpcapRead");
+               p_AirpcapWrite = (AirpcapWriteHandler) pcap_find_function(airpcap_lib, "AirpcapWrite");
+               p_AirpcapGetStats = (AirpcapGetStatsHandler) pcap_find_function(airpcap_lib, "AirpcapGetStats");
+
+               //
+               // Make sure that we found everything
+               //
+               if (p_AirpcapGetLastError != NULL &&
+                   p_AirpcapGetDeviceList != NULL &&
+                   p_AirpcapFreeDeviceList != NULL &&
+                   p_AirpcapOpen != NULL &&
+                   p_AirpcapClose != NULL &&
+                   p_AirpcapSetLinkType != NULL &&
+                   p_AirpcapGetLinkType != NULL &&
+                   p_AirpcapSetKernelBuffer != NULL &&
+                   p_AirpcapSetFilter != NULL &&
+                   p_AirpcapSetMinToCopy != NULL &&
+                   p_AirpcapGetReadEvent != NULL &&
+                   p_AirpcapRead != NULL &&
+                   p_AirpcapWrite != NULL &&
+                   p_AirpcapGetStats != NULL) {
+                       /*
+                        * We have all we need.
+                        */
+                       current_status = AIRPCAP_API_LOADED;
+               }
+       }
+
+       if (current_status != AIRPCAP_API_LOADED) {
+               /*
+                * We failed; if we found the DLL, close the
+                * handle for it.
+                */
+               if (airpcap_lib != NULL) {
+                       FreeLibrary(airpcap_lib);
+                       airpcap_lib = NULL;
+               }
+       }
+
+       /*
+        * Now set the status appropriately - and atomically.
+        */
+       InterlockedExchange((LONG *)&airpcap_load_status, current_status);
+
+       return current_status;
+}
+
+/*
+ * Private data for capturing on AirPcap devices.
+ */
+struct pcap_airpcap {
+       PAirpcapHandle adapter;
+       int filtering_in_kernel;
+       int nonblock;
+       int read_timeout;
+       HANDLE read_event;
+       struct pcap_stat stat;
+};
+
+static int
+airpcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+       struct pcap_airpcap *pa = p->priv;
+
+       if (!p_AirpcapSetFilter(pa->adapter, fp->bf_insns,
+           fp->bf_len * sizeof(struct bpf_insn))) {
+               /*
+                * Kernel filter not installed.
+                *
+                * XXX - we don't know whether this failed because:
+                *
+                *  the kernel rejected the filter program as invalid,
+                *  in which case we should fall back on userland
+                *  filtering;
+                *
+                *  the kernel rejected the filter program as too big,
+                *  in which case we should again fall back on
+                *  userland filtering;
+                *
+                *  there was some other problem, in which case we
+                *  should probably report an error;
+                *
+                * So we just fall back on userland filtering in
+                * all cases.
+                */
+
+               /*
+                * install_bpf_program() validates the program.
+                *
+                * XXX - what if we already have a filter in the kernel?
+                */
+               if (install_bpf_program(p, fp) < 0)
+                       return (-1);
+               pa->filtering_in_kernel = 0;    /* filtering in userland */
+               return (0);
+       }
+
+       /*
+        * It worked.
+        */
+       pa->filtering_in_kernel = 1;    /* filtering in the kernel */
+
+       /*
+        * Discard any previously-received packets, as they might have
+        * passed whatever filter was formerly in effect, but might
+        * not pass this filter (BIOCSETF discards packets buffered
+        * in the kernel, so you can lose packets in any case).
+        */
+       p->cc = 0;
+       return (0);
+}
+
+static int
+airpcap_set_datalink(pcap_t *p, int dlt)
+{
+       struct pcap_airpcap *pa = p->priv;
+       AirpcapLinkType type;
+
+       switch (dlt) {
+
+       case DLT_IEEE802_11_RADIO:
+               type = AIRPCAP_LT_802_11_PLUS_RADIO;
+               break;
+
+       case DLT_PPI:
+               type = AIRPCAP_LT_802_11_PLUS_PPI;
+               break;
+
+       case DLT_IEEE802_11:
+               type = AIRPCAP_LT_802_11;
+               break;
+
+       default:
+               /* This can't happen; just return. */
+               return (0);
+       }
+       if (!p_AirpcapSetLinkType(pa->adapter, type)) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapSetLinkType() failed: %s",
+                   p_AirpcapGetLastError(pa->adapter));
+               return (-1);
+       }
+       p->linktype = dlt;
+       return (0);
+}
+
+static int
+airpcap_getnonblock(pcap_t *p)
+{
+       struct pcap_airpcap *pa = p->priv;
+
+       return (pa->nonblock);
+}
+
+static int
+airpcap_setnonblock(pcap_t *p, int nonblock)
+{
+       struct pcap_airpcap *pa = p->priv;
+       int newtimeout;
+
+       if (nonblock) {
+               /*
+                * Set the packet buffer timeout to -1 for non-blocking
+                * mode.
+                */
+               newtimeout = -1;
+       } else {
+               /*
+                * Restore the timeout set when the device was opened.
+                * (Note that this may be -1, in which case we're not
+                * really leaving non-blocking mode.  However, although
+                * the timeout argument to pcap_set_timeout() and
+                * pcap_open_live() is an int, you're not supposed to
+                * supply a negative value, so that "shouldn't happen".)
+                */
+               newtimeout = p->opt.timeout;
+       }
+       pa->read_timeout = newtimeout;
+       pa->nonblock = (newtimeout == -1);
+       return (0);
+}
+
+static int
+airpcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+       struct pcap_airpcap *pa = p->priv;
+       AirpcapStats tas;
+
+       /*
+        * Try to get statistics.
+        */
+       if (!p_AirpcapGetStats(pa->adapter, &tas)) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapGetStats() failed: %s",
+                   p_AirpcapGetLastError(pa->adapter));
+               return (-1);
+       }
+               
+       ps->ps_drop = tas.Drops;
+       ps->ps_recv = tas.Recvs;
+       ps->ps_ifdrop = tas.IfDrops;
+
+       return (0);
+}
+
+/*
+ * Win32-only routine for getting statistics.
+ *
+ * This way is definitely safer than passing the pcap_stat * from the userland.
+ * In fact, there could happen than the user allocates a variable which is not
+ * big enough for the new structure, and the library will write in a zone
+ * which is not allocated to this variable.
+ *
+ * In this way, we're pretty sure we are writing on memory allocated to this
+ * variable.
+ *
+ * XXX - but this is the wrong way to handle statistics.  Instead, we should
+ * have an API that returns data in a form like the Options section of a
+ * pcapng Interface Statistics Block:
+ *
+ *    https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6
+ *
+ * which would let us add new statistics straightforwardly and indicate which
+ * statistics we are and are *not* providing, rather than having to provide
+ * possibly-bogus values for statistics we can't provide.
+ */
+static struct pcap_stat *
+airpcap_stats_ex(pcap_t *p, int *pcap_stat_size)
+{
+       struct pcap_airpcap *pa = p->priv;
+       AirpcapStats tas;
+
+       *pcap_stat_size = sizeof (p->stat);
+
+       /*
+        * Try to get statistics.
+        */
+       if (!p_AirpcapGetStats(pa->adapter, &tas)) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapGetStats() failed: %s",
+                   p_AirpcapGetLastError(pa->adapter));
+               return (NULL);
+       }
+               
+       p->stat.ps_recv = tas.Recvs;
+       p->stat.ps_drop = tas.Drops;
+       p->stat.ps_ifdrop = tas.IfDrops;
+#ifdef ENABLE_REMOTE
+       p->stat.ps_capt = tas.Capt;
+#endif
+       return (&p->stat);
+}
+
+/* Set the dimension of the kernel-level capture buffer */
+static int
+airpcap_setbuff(pcap_t *p, int dim)
+{
+       struct pcap_airpcap *pa = p->priv;
+
+       if (!p_AirpcapSetKernelBuffer(pa->adapter, dim)) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapSetKernelBuffer() failed: %s",
+                   p_AirpcapGetLastError(pa->adapter));
+               return (-1);
+       }
+       return (0);
+}
+
+/* Set the driver working mode */
+static int
+airpcap_setmode(pcap_t *p, int mode)
+{
+        if (mode != MODE_CAPT) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "Only MODE_CAPT is supported on an AirPcap adapter");
+               return (-1);
+        }
+        return (0);
+}
+
+/*set the minimum amount of data that will release a read call*/
+static int
+airpcap_setmintocopy(pcap_t *p, int size)
+{
+       struct pcap_airpcap *pa = p->priv;
+
+       if (!p_AirpcapSetMinToCopy(pa->adapter, size)) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapSetMinToCopy() failed: %s",
+                   p_AirpcapGetLastError(pa->adapter));
+               return (-1);
+       }
+       return (0);
+}
+
+static HANDLE
+airpcap_getevent(pcap_t *p)
+{
+       struct pcap_airpcap *pa = p->priv;
+
+       return (pa->read_event);
+}
+
+static int
+airpcap_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+    size_t *lenp _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Getting OID values is not supported on an AirPcap adapter");
+       return (PCAP_ERROR);
+}
+
+static int
+airpcap_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
+    size_t *lenp _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Setting OID values is not supported on an AirPcap adapter");
+       return (PCAP_ERROR);
+}
+
+static u_int
+airpcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Cannot queue packets for transmission on an AirPcap adapter");
+       return (0);
+}
+
+static int
+airpcap_setuserbuffer(pcap_t *p, int size)
+{
+       unsigned char *new_buff;
+
+       if (size <= 0) {
+               /* Bogus parameter */
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "Error: invalid size %d",size);
+               return (-1);
+       }
+
+       /* Allocate the buffer */
+       new_buff = (unsigned char *)malloc(sizeof(char)*size);
+
+       if (!new_buff) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "Error: not enough memory");
+               return (-1);
+       }
+
+       free(p->buffer);
+
+       p->buffer = new_buff;
+       p->bufsize = size;
+
+       return (0);
+}
+
+static int
+airpcap_live_dump(pcap_t *p, char *filename _U_, int maxsize _U_,
+    int maxpacks _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "AirPcap adapters don't support live dump");
+       return (-1);
+}
+
+static int
+airpcap_live_dump_ended(pcap_t *p, int sync _U_)
+{
+       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "AirPcap adapters don't support live dump");
+       return (-1);
+}
+
+static PAirpcapHandle
+airpcap_get_airpcap_handle(pcap_t *p)
+{
+       struct pcap_airpcap *pa = p->priv;
+
+       return (pa->adapter);
+}
+
+static int
+airpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+       struct pcap_airpcap *pa = p->priv;
+       int cc;
+       int n;
+       register u_char *bp, *ep;
+       UINT bytes_read;
+       u_char *datap;
+
+       cc = p->cc;
+       if (cc == 0) {
+               /*
+                * Has "pcap_breakloop()" been called?
+                */
+               if (p->break_loop) {
+                       /*
+                        * Yes - clear the flag that indicates that it
+                        * has, and return PCAP_ERROR_BREAK to indicate
+                        * that we were told to break out of the loop.
+                        */
+                       p->break_loop = 0;
+                       return (PCAP_ERROR_BREAK);
+               }
+
+               //
+               // If we're not in non-blocking mode, wait for data to
+               // arrive.
+               //
+               if (pa->read_timeout != -1) {
+                       WaitForSingleObject(pa->read_event,
+                           (pa->read_timeout ==0 )? INFINITE: pa->read_timeout);
+               }
+
+               //
+               // Read the data.
+               // p_AirpcapRead doesn't block.
+               //
+               if (!p_AirpcapRead(pa->adapter, (char *)p->buffer,
+                   p->bufsize, &bytes_read)) {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "AirpcapRead() failed: %s",
+                           p_AirpcapGetLastError(pa->adapter));
+                       return (-1);
+               }
+               cc = bytes_read;
+               bp = (u_char *)p->buffer;
+       } else
+               bp = p->bp;
+
+       /*
+        * Loop through each packet.
+        */
+#define bhp ((AirpcapBpfHeader *)bp)
+       n = 0;
+       ep = bp + cc;
+       for (;;) {
+               register u_int caplen, hdrlen;
+
+               /*
+                * Has "pcap_breakloop()" been called?
+                * If so, return immediately - if we haven't read any
+                * packets, clear the flag and return PCAP_ERROR_BREAK
+                * to indicate that we were told to break out of the loop,
+                * otherwise leave the flag set, so that the *next* call
+                * will break out of the loop without having read any
+                * packets, and return the number of packets we've
+                * processed so far.
+                */
+               if (p->break_loop) {
+                       if (n == 0) {
+                               p->break_loop = 0;
+                               return (PCAP_ERROR_BREAK);
+                       } else {
+                               p->bp = bp;
+                               p->cc = (int) (ep - bp);
+                               return (n);
+                       }
+               }
+               if (bp >= ep)
+                       break;
+
+               caplen = bhp->Caplen;
+               hdrlen = bhp->Hdrlen;
+               datap = bp + hdrlen;
+               /*
+                * Short-circuit evaluation: if using BPF filter
+                * in the AirPcap adapter, no need to do it now -
+                * we already know the packet passed the filter.
+                */
+               if (pa->filtering_in_kernel ||
+                   p->fcode.bf_insns == NULL ||
+                   pcap_filter(p->fcode.bf_insns, datap, bhp->Originallen, caplen)) {
+                       struct pcap_pkthdr pkthdr;
+
+                       pkthdr.ts.tv_sec = bhp->TsSec;
+                       pkthdr.ts.tv_usec = bhp->TsUsec;
+                       pkthdr.caplen = caplen;
+                       pkthdr.len = bhp->Originallen;
+                       (*callback)(user, &pkthdr, datap);
+                       bp += AIRPCAP_WORDALIGN(caplen + hdrlen);
+                       if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
+                               p->bp = bp;
+                               p->cc = (int)(ep - bp);
+                               return (n);
+                       }
+               } else {
+                       /*
+                        * Skip this packet.
+                        */
+                       bp += AIRPCAP_WORDALIGN(caplen + hdrlen);
+               }
+       }
+#undef bhp
+       p->cc = 0;
+       return (n);
+}
+
+static int
+airpcap_inject(pcap_t *p, const void *buf, int size)
+{
+       struct pcap_airpcap *pa = p->priv;
+
+       /*
+        * XXX - the second argument to AirpcapWrite() *should* have
+        * been declared as a const pointer - a write function that
+        * stomps on what it writes is *extremely* rude - but such
+        * is life.  We assume it is, in fact, not going to write on
+        * our buffer.
+        */
+       if (!p_AirpcapWrite(pa->adapter, (void *)buf, size)) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapWrite() failed: %s",
+                   p_AirpcapGetLastError(pa->adapter));
+               return (-1);
+       }
+
+       /*
+        * We assume it all got sent if "AirpcapWrite()" succeeded.
+        * "pcap_inject()" is expected to return the number of bytes
+        * sent.
+        */
+       return (size);
+}
+
+static void
+airpcap_cleanup(pcap_t *p)
+{
+       struct pcap_airpcap *pa = p->priv;
+
+       if (pa->adapter != NULL) {
+               AirpcapClose(pa->adapter);
+               pa->adapter = NULL;
+       }
+       pcap_cleanup_live_common(p);
+}
+
+static int
+airpcap_activate(pcap_t *p)
+{
+       struct pcap_airpcap *pa = p->priv;
+       char *device = p->opt.device;
+       char airpcap_errbuf[AIRPCAP_ERRBUF_SIZE];
+       BOOL status;
+
+       pa->adapter = p_AirpcapOpen(device, airpcap_errbuf);
+       if (pa->adapter == NULL) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", airpcap_errbuf);
+               return (PCAP_ERROR);
+       }
+
+       /*
+        * Set monitor mode appropriately.
+        * Always turn off the "ACK frames sent to the card" mode.
+        */
+       if (p->opt.rfmon) {
+               status = AirpcapSetDeviceMacFlags(pa->adapter,
+                   AIRPCAP_MF_MONITOR_MODE_ON);
+       } else
+               status = AirpcapSetDeviceMacFlags(pa->adapter,
+                   AIRPCAP_MF_ACK_FRAMES_ON);
+       if (!status) {
+               AirpcapClose(pa->adapter);
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapSetDeviceMacFlags() failed: %s",
+                   p_AirpcapGetLastError(pa->adapter));
+               return (PCAP_ERROR);
+       }
+               
+
+       /*
+        * Turn a negative snapshot value (invalid), a snapshot value of
+        * 0 (unspecified), or a value bigger than the normal maximum
+        * value, into the maximum allowed value.
+        *
+        * If some application really *needs* a bigger snapshot
+        * length, we should just increase MAXIMUM_SNAPLEN.
+        */
+       if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
+               p->snapshot = MAXIMUM_SNAPLEN;
+
+       if (p->snapshot < 96)
+               /*
+                * NIT requires a snapshot length of at least 96.
+                */
+               p->snapshot = 96;
+
+       /*
+        * If the buffer size wasn't explicitly set, default to
+        * AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE.
+        */
+       if (p->opt.buffer_size == 0)
+               p->opt.buffer_size = AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE;
+
+       if (!p_AirpcapSetKernelBuffer(pa->adapter, p->opt.buffer_size)) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapSetKernelBuffer() failed: %s",
+                   p_AirpcapGetLastError(pa->adapter));
+               goto bad;
+       }
+
+       if(!p_AirpcapGetReadEvent(pa->adapter, &pa->read_event)) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapGetReadEvent() failed: %s",
+                   p_AirpcapGetLastError(pa->adapter));
+               goto bad;
+       }
+
+       /* Set the buffer size */
+       p->bufsize = AIRPCAP_DEFAULT_USER_BUFFER_SIZE;
+       p->buffer = malloc(p->bufsize);
+       if (p->buffer == NULL) {
+               pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+                   errno, "malloc");
+               goto bad;
+       }
+
+       if (p->opt.immediate) {
+               /* Tell the driver to copy the buffer as soon as data arrives. */
+               if (!p_AirpcapSetMinToCopy(pa->adapter, 0)) {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "AirpcapSetMinToCopy() failed: %s",
+                           p_AirpcapGetLastError(pa->adapter));
+                       goto bad;
+               }
+       } else {
+               /*
+                * Tell the driver to copy the buffer only if it contains
+                * at least 16K.
+                */
+               if (!p_AirpcapSetMinToCopy(pa->adapter, 16000)) {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "AirpcapSetMinToCopy() failed: %s",
+                           p_AirpcapGetLastError(pa->adapter));
+                       goto bad;
+               }
+       }
+
+       /*
+        * AirPcap devices support Radiotap, PPI, and raw 802.11.
+        */
+       p->linktype = DLT_IEEE802_11_RADIO;
+       p->dlt_list = (u_int *) malloc(sizeof(u_int) * 3);
+       if (p->dlt_list == NULL)
+               goto bad;
+       p->dlt_count = 3;
+       p->dlt_list[0] = DLT_IEEE802_11_RADIO;
+       p->dlt_list[1] = DLT_PPI;
+       p->dlt_list[2] = DLT_IEEE802_11;
+
+       p->read_op = airpcap_read;
+       p->inject_op = airpcap_inject;
+       p->setfilter_op = airpcap_setfilter;
+       p->setdirection_op = NULL;      /* Not implemented. */
+       p->set_datalink_op = airpcap_set_datalink;
+       p->getnonblock_op = airpcap_getnonblock;
+       p->setnonblock_op = airpcap_setnonblock;
+       p->stats_op = airpcap_stats;
+       p->stats_ex_op = airpcap_stats_ex;
+       p->setbuff_op = airpcap_setbuff;
+       p->setmode_op = airpcap_setmode;
+       p->setmintocopy_op = airpcap_setmintocopy;
+       p->getevent_op = airpcap_getevent;
+       p->oid_get_request_op = airpcap_oid_get_request;
+       p->oid_set_request_op = airpcap_oid_set_request;
+       p->sendqueue_transmit_op = airpcap_sendqueue_transmit;
+       p->setuserbuffer_op = airpcap_setuserbuffer;
+       p->live_dump_op = airpcap_live_dump;
+       p->live_dump_ended_op = airpcap_live_dump_ended;
+       p->get_airpcap_handle_op = airpcap_get_airpcap_handle;
+       p->cleanup_op = airpcap_cleanup;
+
+       return (0);
+ bad:
+       airpcap_cleanup(p);
+       return (PCAP_ERROR);
+}
+
+/*
+ * Monitor mode is supported.
+ */
+static int
+airpcap_can_set_rfmon(pcap_t *p)
+{
+       return (1);
+}
+
+int
+device_is_airpcap(const char *device, char *ebuf)
+{
+       static const char airpcap_prefix[] = "\\\\.\\airpcap";
+
+       /*
+        * We don't determine this by calling AirpcapGetDeviceList()
+        * and looking at the list, as that appears to be a costly
+        * operation.
+        *
+        * Instead, we just check whether it begins with "\\.\airpcap".
+        */
+       if (strncmp(device, airpcap_prefix, sizeof airpcap_prefix - 1) == 0) {
+               /*
+                * Yes, it's an AirPcap device.
+                */
+               return (1);
+       }
+
+       /*
+        * No, it's not an AirPcap device.
+        */
+       return (0);
+}
+
+pcap_t *
+airpcap_create(const char *device, char *ebuf, int *is_ours)
+{
+       int ret;
+       pcap_t *p;
+
+       /*
+        * This can be called before we've tried loading the library,
+        * so do so if we haven't already tried to do so.
+        */
+       if (load_airpcap_functions() != AIRPCAP_API_LOADED) {
+               snprintf(ebuf, PCAP_ERRBUF_SIZE, "Couldn't load AirPcap DLL\n");
+               return (NULL);
+       }
+
+       /*
+        * Is this an AirPcap device?
+        */
+       ret = device_is_airpcap(device, ebuf);
+       if (ret == -1) {
+               /* Error. */
+               return (NULL);
+       }
+       if (ret == 0) {
+               /* No. */
+               *is_ours = 0;
+               return (NULL);
+       }
+
+       /*
+        * Yes.
+        */
+       *is_ours = 1;
+       p = pcap_create_common(ebuf, sizeof (struct pcap_airpcap));
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = airpcap_activate;
+       p->can_set_rfmon_op = airpcap_can_set_rfmon;
+       return (p);
+}
+
+/*
+ * Add all AirPcap devices.
+ */
+int
+airpcap_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
+{
+       AirpcapDeviceDescription *airpcap_devices, *airpcap_device;
+       char airpcap_errbuf[AIRPCAP_ERRBUF_SIZE];
+
+       /*
+        * This can be called before we've tried loading the library,
+        * so do so if we haven't already tried to do so.
+        */
+       if (load_airpcap_functions() != AIRPCAP_API_LOADED) {
+               /*
+                * XXX - unless the error is "no such DLL", report this
+                * as an error rather than as "no AirPcap devices"?
+                */
+               return (0);
+       }
+
+       if (!p_AirpcapGetDeviceList(&airpcap_devices, airpcap_errbuf)) {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "AirpcapGetDeviceList() failed: %s", errbuf);
+               return (-1);
+       }
+
+       for (airpcap_device = airpcap_devices; airpcap_device != NULL;
+           airpcap_device = airpcap_device->next) {
+               if (add_dev(devlistp, airpcap_device->Name, 0,
+                   airpcap_device->Description, errbuf) == NULL) {
+                       /*
+                        * Failure.
+                        */
+                       AirpcapFreeDeviceList(airpcap_devices);
+                       return (-1);
+               }
+       }
+       AirpcapFreeDeviceList(airpcap_devices);
+       return (0);
+}
diff --git a/pcap-airpcap.h b/pcap-airpcap.h
new file mode 100644 (file)
index 0000000..aa1164e
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino, CACE Technologies
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+pcap_t *airpcap_create(const char *, char *, int *);
+int airpcap_findalldevs(pcap_if_list_t *devlistp, char *errbuf);
+int device_is_airpcap(const char *device, char *ebuf);
index f07dc22fe9f5ef52a32fc36c19878f25265c3157..d67decefc398e2e730f4a579c9839aac468c57c1 100644 (file)
@@ -545,6 +545,17 @@ FILE       *charset_fopen(const char *path, const char *mode);
 #define charset_fopen(path, mode)      fopen((path), (mode))
 #endif
 
+/*
+ * Internal interfaces for loading code at run time.
+ */
+#ifdef _WIN32
+#define pcap_code_handle_t     HMODULE
+#define pcap_funcptr_t         FARPROC
+
+pcap_code_handle_t     pcap_load_code(const char *);
+pcap_funcptr_t         pcap_find_function(pcap_code_handle_t, const char *);
+#endif
+
 /*
  * Internal interfaces for doing user-mode filtering of packets and
  * validating filter programs.
index 407d64a0e5f1dc4b434b3287c826a90e9e305705..e9c7226fbf03043acfbf7e15d1f991329f908d71 100644 (file)
@@ -57,6 +57,8 @@
 
 #include "diag-control.h"
 
+#include "pcap-airpcap.h"
+
 static int pcap_setfilter_npf(pcap_t *, struct bpf_program *);
 static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *);
 static int pcap_getnonblock_npf(pcap_t *);
@@ -1838,6 +1840,18 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
        name = &AdaptersName[0];
        while (*name != '\0') {
                bpf_u_int32 flags = 0;
+
+               /*
+                * Is this an AirPcap device?
+                * If so, ignore it; it'll get added later, by the
+                * AirPcap code.
+                */
+               if (device_is_airpcap(name, errbuf) == 1) {
+                       name += strlen(name) + 1;
+                       desc += strlen(desc) + 1;
+                       continue;
+               }
+
 #ifdef HAVE_PACKET_IS_LOOPBACK_ADAPTER
                /*
                 * Is this a loopback interface?
index 167443354d4732845d7ed0840950936f2286d85d..ef409d323edc4162f40052727e6834e18a2a3e74 100644 (file)
--- a/pcap-tc.c
+++ b/pcap-tc.c
@@ -252,58 +252,6 @@ typedef struct _PPI_HEADER
 #pragma pack(pop)
 
 #ifdef _WIN32
-//
-// This wrapper around loadlibrary appends the system folder (usually c:\windows\system32)
-// to the relative path of the DLL, so that the DLL is always loaded from an absolute path
-// (It's no longer possible to load airpcap.dll from the application folder).
-// This solves the DLL Hijacking issue discovered in August 2010
-// http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html
-//
-HMODULE LoadLibrarySafe(LPCTSTR lpFileName)
-{
-  TCHAR path[MAX_PATH];
-  TCHAR fullFileName[MAX_PATH];
-  UINT res;
-  HMODULE hModule = NULL;
-  do
-  {
-       res = GetSystemDirectory(path, MAX_PATH);
-
-       if (res == 0)
-       {
-               //
-               // some bad failure occurred;
-               //
-               break;
-       }
-
-       if (res > MAX_PATH)
-       {
-               //
-               // the buffer was not big enough
-               //
-               SetLastError(ERROR_INSUFFICIENT_BUFFER);
-               break;
-       }
-
-       if (res + 1 + _tcslen(lpFileName) + 1 < MAX_PATH)
-       {
-               memcpy(fullFileName, path, res * sizeof(TCHAR));
-               fullFileName[res] = _T('\\');
-               memcpy(&fullFileName[res + 1], lpFileName, (_tcslen(lpFileName) + 1) * sizeof(TCHAR));
-
-               hModule = LoadLibrary(fullFileName);
-       }
-       else
-       {
-               SetLastError(ERROR_INSUFFICIENT_BUFFER);
-       }
-
-  }while(FALSE);
-
-  return hModule;
-}
-
 /*
  * NOTE: this function should be called by the pcap functions that can theoretically
  *       deal with the Tc library for the first time, namely listing the adapters and
@@ -340,34 +288,34 @@ TC_API_LOAD_STATUS LoadTcFunctions(void)
 
                currentStatus = TC_API_CANNOT_LOAD;
 
-               g_TcFunctions.hTcApiDllHandle = LoadLibrarySafe("TcApi.dll");
+               g_TcFunctions.hTcApiDllHandle = pcap_load_code("TcApi.dll");
                if (g_TcFunctions.hTcApiDllHandle == NULL)      break;
 
-               g_TcFunctions.QueryPortList                                     = (TcFcnQueryPortList)                  GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList");
-               g_TcFunctions.FreePortList                                      = (TcFcnFreePortList)                   GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcFreePortList");
+               g_TcFunctions.QueryPortList                     = (TcFcnQueryPortList)                  pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList");
+               g_TcFunctions.FreePortList                      = (TcFcnFreePortList)                   pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcFreePortList");
 
-               g_TcFunctions.StatusGetString                           = (TcFcnStatusGetString)                GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString");
+               g_TcFunctions.StatusGetString                   = (TcFcnStatusGetString)                pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString");
 
-               g_TcFunctions.PortGetName                                       = (TcFcnPortGetName)                    GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetName");
-               g_TcFunctions.PortGetDescription                        = (TcFcnPortGetDescription)             GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription");
+               g_TcFunctions.PortGetName                       = (TcFcnPortGetName)                    pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetName");
+               g_TcFunctions.PortGetDescription                = (TcFcnPortGetDescription)             pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription");
 
-               g_TcFunctions.InstanceOpenByName                        = (TcFcnInstanceOpenByName)             GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName");
-               g_TcFunctions.InstanceClose                                     = (TcFcnInstanceClose)                  GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose");
-               g_TcFunctions.InstanceSetFeature                        = (TcFcnInstanceSetFeature)             GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature");
-               g_TcFunctions.InstanceQueryFeature                      = (TcFcnInstanceQueryFeature)   GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature");
-               g_TcFunctions.InstanceReceivePackets            = (TcFcnInstanceReceivePackets) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets");
-               g_TcFunctions.InstanceGetReceiveWaitHandle      = (TcFcnInstanceGetReceiveWaitHandle)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle");
-               g_TcFunctions.InstanceTransmitPackets           = (TcFcnInstanceTransmitPackets)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets");
-               g_TcFunctions.InstanceQueryStatistics           = (TcFcnInstanceQueryStatistics)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics");
+               g_TcFunctions.InstanceOpenByName                = (TcFcnInstanceOpenByName)             pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName");
+               g_TcFunctions.InstanceClose                     = (TcFcnInstanceClose)                  pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose");
+               g_TcFunctions.InstanceSetFeature                = (TcFcnInstanceSetFeature)             pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature");
+               g_TcFunctions.InstanceQueryFeature              = (TcFcnInstanceQueryFeature)   pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature");
+               g_TcFunctions.InstanceReceivePackets            = (TcFcnInstanceReceivePackets) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets");
+               g_TcFunctions.InstanceGetReceiveWaitHandle      = (TcFcnInstanceGetReceiveWaitHandle)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle");
+               g_TcFunctions.InstanceTransmitPackets           = (TcFcnInstanceTransmitPackets)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets");
+               g_TcFunctions.InstanceQueryStatistics           = (TcFcnInstanceQueryStatistics)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics");
 
-               g_TcFunctions.PacketsBufferCreate                       = (TcFcnPacketsBufferCreate)    GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate");
-               g_TcFunctions.PacketsBufferDestroy                      = (TcFcnPacketsBufferDestroy)   GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy");
-               g_TcFunctions.PacketsBufferQueryNextPacket      = (TcFcnPacketsBufferQueryNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket");
-               g_TcFunctions.PacketsBufferCommitNextPacket     = (TcFcnPacketsBufferCommitNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket");
+               g_TcFunctions.PacketsBufferCreate               = (TcFcnPacketsBufferCreate)    pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate");
+               g_TcFunctions.PacketsBufferDestroy              = (TcFcnPacketsBufferDestroy)   pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy");
+               g_TcFunctions.PacketsBufferQueryNextPacket      = (TcFcnPacketsBufferQueryNextPacket)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket");
+               g_TcFunctions.PacketsBufferCommitNextPacket     = (TcFcnPacketsBufferCommitNextPacket)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket");
 
-               g_TcFunctions.StatisticsDestroy                         = (TcFcnStatisticsDestroy)              GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy");
-               g_TcFunctions.StatisticsUpdate                          = (TcFcnStatisticsUpdate)               GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate");
-               g_TcFunctions.StatisticsQueryValue                      = (TcFcnStatisticsQueryValue)   GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue");
+               g_TcFunctions.StatisticsDestroy                 = (TcFcnStatisticsDestroy)              pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy");
+               g_TcFunctions.StatisticsUpdate                  = (TcFcnStatisticsUpdate)               pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate");
+               g_TcFunctions.StatisticsQueryValue              = (TcFcnStatisticsQueryValue)   pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue");
 
                if (   g_TcFunctions.QueryPortList == NULL
                        || g_TcFunctions.FreePortList == NULL
diff --git a/pcap.c b/pcap.c
index 19670ab01bbd5c0ef620842c60fe433cccae54e5..38aaf379bfaf35c130c70f55b54a5da481c0d5e0 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -123,6 +123,10 @@ 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.
@@ -141,8 +145,10 @@ struct rtentry;            /* declarations in <net/if.h> */
  *   be called from the DllMain function in a application DLL. This can
  *   potentially cause deadlocks.
  *
- * So we don't actually do anything here.  pcap_init() should be called
- * to initialize pcap on both UN*X and Windows.
+ * So we don't initialize Winsock here.  pcap_init() should be called
+ * to initialize pcap on both UN*X and Windows; it will initialize
+ * Winsock on Windows.  (It will also be initialized as needed if
+ * pcap_init() hasn't been called.)
  */
 BOOL WINAPI DllMain(
   HANDLE hinstDLL _U_,
@@ -686,6 +692,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 }
 };
@@ -4057,6 +4066,71 @@ pcap_close(pcap_t *p)
        free(p);
 }
 
+/*
+ * Helpers for safely loding code at run time.
+ * Currently Windows-only.
+ */
+#ifdef _WIN32
+//
+// This wrapper around loadlibrary appends the system folder (usually
+// C:\Windows\System32) to the relative path of the DLL, so that the DLL
+// is always loaded from an absolute path (it's no longer possible to
+// load modules from the application folder).
+// This solves the DLL Hijacking issue discovered in August 2010
+// http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html
+//
+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.
index b37eda1dfb279e9c6abc5a265150907192171d9e..b57c7bb4e49ed605ad739f8982ee468ce636f7a8 100644 (file)
@@ -12,3 +12,4 @@ opentest
 reactivatetest
 selpolltest
 threadsignaltest
+writecaptest
index 9491a9dc1c069c6238fe7ac1487e0c63723c9f67..bf5736131dd95c0d361fe9b50e6a333ea78d698c 100644 (file)
@@ -33,6 +33,7 @@ add_test_executable(findalldevstest)
 add_test_executable(findalldevstest-perf)
 add_test_executable(opentest)
 add_test_executable(reactivatetest)
+add_test_executable(writecaptest)
 
 if(NOT WIN32)
   add_test_executable(selpolltest)
index 8acfe213c519415c6856fe847f4cf5915944a757..7b91b32cadccbf1685786371b70fde8d1bc09d0e 100644 (file)
@@ -88,7 +88,8 @@ SRC = @VALGRINDTEST_SRC@ \
        opentest.c \
        reactivatetest.c \
        selpolltest.c \
-       threadsignaltest.c
+       threadsignaltest.c \
+       writecaptest.c
 
 TESTS = $(SRC:.c=)
 
@@ -129,6 +130,9 @@ threadsignaltest: $(srcdir)/threadsignaltest.c ../libpcap.a
 valgrindtest: $(srcdir)/valgrindtest.c ../libpcap.a
        $(CC) $(FULL_CFLAGS) -I. -L. -o valgrindtest $(srcdir)/valgrindtest.c ../libpcap.a $(LIBS)
 
+writecaptest: $(srcdir)/writecaptest.c ../libpcap.a
+       $(CC) $(FULL_CFLAGS) -I. -L. -o writecaptest $(srcdir)/writecaptest.c ../libpcap.a $(LIBS)
+
 clean:
        rm -f $(CLEANFILES)
        rm -rf *.dSYM
diff --git a/testprogs/writecaptest.c b/testprogs/writecaptest.c
new file mode 100644 (file)
index 0000000..947904a
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "varattrs.h"
+
+#ifndef lint
+static const char copyright[] _U_ =
+    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
+The Regents of the University of California.  All rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#ifdef _WIN32
+  #include "getopt.h"
+#else
+  #include <unistd.h>
+#endif
+#include <errno.h>
+#ifndef _WIN32
+  #include <signal.h>
+#endif
+#include <sys/types.h>
+
+#include <pcap.h>
+
+#include "pcap/funcattrs.h"
+
+#ifdef _WIN32
+  #include "portability.h"
+#endif
+
+static char *program_name;
+
+/* Forwards */
+static void PCAP_NORETURN usage(void);
+static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
+static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
+static char *copy_argv(char **);
+
+static pcap_t *pd;
+
+#ifdef _WIN32
+static BOOL WINAPI
+stop_capture(DWORD ctrltype _U_)
+{
+       pcap_breakloop(pd);
+       return TRUE;
+}
+#else
+static void
+stop_capture(int signum _U_)
+{
+       pcap_breakloop(pd);
+}
+#endif
+
+#define COMMAND_OPTIONS        "Li:w:y:"
+
+int
+main(int argc, char **argv)
+{
+       register int op;
+       register char *cp, *cmdbuf, *device, *savefile;
+       pcap_if_t *devlist;
+       int show_dlt_types = 0;
+       int ndlts;
+       int *dlts;
+       bpf_u_int32 localnet, netmask;
+       struct bpf_program fcode;
+       char ebuf[PCAP_ERRBUF_SIZE];
+#ifndef _WIN32
+       struct sigaction action;
+#endif
+       int dlt;
+       const char *dlt_name = NULL;
+       int status;
+       pcap_dumper_t *pdd;
+
+       device = NULL;
+       if ((cp = strrchr(argv[0], '/')) != NULL)
+               program_name = cp + 1;
+       else
+               program_name = argv[0];
+
+       opterr = 0;
+       while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) {
+               switch (op) {
+
+               case 'L':
+                       show_dlt_types = 1;
+                       break;
+
+               case 'i':
+                       device = optarg;
+                       break;
+
+               case 'w':
+                       savefile = optarg;
+                       break;
+
+               case 'y':
+                       dlt_name = optarg;
+                       break;
+
+               default:
+                       usage();
+                       /* NOTREACHED */
+               }
+       }
+
+       if (device == NULL) {
+               if (pcap_findalldevs(&devlist, ebuf) == -1)
+                       error("%s", ebuf);
+               if (devlist == NULL)
+                       error("no interfaces available for capture");
+               device = strdup(devlist->name);
+               pcap_freealldevs(devlist);
+       }
+       if (show_dlt_types) {
+               pd = pcap_create(device, ebuf);
+               if (pd == NULL)
+                       error("%s", ebuf);
+               status = pcap_activate(pd);
+               if (status < 0) {
+                       /*
+                        * pcap_activate() failed.
+                        */
+                       error("%s: %s\n(%s)", device,
+                           pcap_statustostr(status), pcap_geterr(pd));
+               }
+               ndlts = pcap_list_datalinks(pd, &dlts);
+               if (ndlts < 0) {
+                       /*
+                        * pcap_list_datalinks() failed.
+                        */
+                       error("%s: %s\n(%s)", device,
+                           pcap_statustostr(status), pcap_geterr(pd));
+               }
+               for (int i = 0; i < ndlts; i++) {
+                       dlt_name = pcap_datalink_val_to_name(dlts[i]);
+                       if (dlt_name == NULL)
+                               printf("DLT %d", dlts[i]);
+                       else
+                               printf("%s", dlt_name);
+                       printf("\n");
+               }
+               pcap_free_datalinks(dlts);
+               pcap_close(pd);
+               return 0;
+       }
+               
+       if (savefile == NULL)
+               error("no savefile specified");
+
+       *ebuf = '\0';
+
+       pd = pcap_create(device, ebuf);
+       if (pd == NULL)
+               error("%s", ebuf);
+       status = pcap_set_snaplen(pd, 262144);
+       if (status != 0)
+               error("%s: pcap_set_snaplen failed: %s",
+                           device, pcap_statustostr(status));
+       status = pcap_set_timeout(pd, 100);
+       if (status != 0)
+               error("%s: pcap_set_timeout failed: %s",
+                   device, pcap_statustostr(status));
+       status = pcap_activate(pd);
+       if (status < 0) {
+               /*
+                * pcap_activate() failed.
+                */
+               error("%s: %s\n(%s)", device,
+                   pcap_statustostr(status), pcap_geterr(pd));
+       } else if (status > 0) {
+               /*
+                * pcap_activate() succeeded, but it's warning us
+                * of a problem it had.
+                */
+               warning("%s: %s\n(%s)", device,
+                   pcap_statustostr(status), pcap_geterr(pd));
+       }
+       if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
+               localnet = 0;
+               netmask = 0;
+               warning("%s", ebuf);
+       }
+
+       if (dlt_name != NULL) {
+               dlt = pcap_datalink_name_to_val(dlt_name);
+               if (dlt == PCAP_ERROR)
+                       error("%s isn't a valid DLT name", dlt_name);
+               if (pcap_set_datalink(pd, dlt) == PCAP_ERROR)
+                       error("%s: %s", device, pcap_geterr(pd));
+       }
+
+       cmdbuf = copy_argv(&argv[optind]);
+
+       if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
+               error("%s", pcap_geterr(pd));
+
+       if (pcap_setfilter(pd, &fcode) < 0)
+               error("%s", pcap_geterr(pd));
+
+       pdd = pcap_dump_open(pd, savefile);
+       if (pdd == NULL)
+               error("%s", pcap_geterr(pd));
+
+#ifdef _WIN32
+       SetConsoleCtrlHandler(stop_capture, TRUE);
+#else
+       action.sa_handler = stop_capture;
+       sigemptyset(&action.sa_mask);
+       action.sa_flags = 0;
+       if (sigaction(SIGINT, &action, NULL) == -1)
+               error("Can't catch SIGINT: %s\n", strerror(errno));
+#endif
+
+       printf("Listening on %s, link-type ", device);
+       dlt = pcap_datalink(pd);
+       dlt_name = pcap_datalink_val_to_name(dlt);
+       if (dlt_name == NULL)
+               printf("DLT %d", dlt);
+       else
+               printf("%s", dlt_name);
+       printf("\n");
+       for (;;) {
+               status = pcap_dispatch(pd, -1, pcap_dump, (u_char *)pdd);
+               if (status < 0)
+                       break;
+               if (status != 0) {
+                       printf("%d packets seen\n", status);
+                       struct pcap_stat ps;
+                       pcap_stats(pd, &ps);
+                       printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n",
+                           ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
+               }
+       }
+       if (status == -2) {
+               /*
+                * We got interrupted, so perhaps we didn't
+                * manage to finish a line we were printing.
+                * Print an extra newline, just in case.
+                */
+               putchar('\n');
+               printf("Broken out of loop from SIGINT handler\n");
+       }
+       (void)fflush(stdout);
+       if (status == -1) {
+               /*
+                * Error.  Report it.
+                */
+               (void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
+                   program_name, pcap_geterr(pd));
+       }
+       pcap_close(pd);
+       pcap_freecode(&fcode);
+       free(cmdbuf);
+       exit(status == -1 ? 1 : 0);
+}
+
+static void
+usage(void)
+{
+       (void)fprintf(stderr, "Usage: %s -L [ -i interface ] [ -w file ] [ -y dlt ] [expression]\n",
+           program_name);
+       exit(1);
+}
+
+/* VARARGS */
+static void
+error(const char *fmt, ...)
+{
+       va_list ap;
+
+       (void)fprintf(stderr, "%s: ", program_name);
+       va_start(ap, fmt);
+       (void)vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       if (*fmt) {
+               fmt += strlen(fmt);
+               if (fmt[-1] != '\n')
+                       (void)fputc('\n', stderr);
+       }
+       exit(1);
+       /* NOTREACHED */
+}
+
+/* VARARGS */
+static void
+warning(const char *fmt, ...)
+{
+       va_list ap;
+
+       (void)fprintf(stderr, "%s: WARNING: ", program_name);
+       va_start(ap, fmt);
+       (void)vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       if (*fmt) {
+               fmt += strlen(fmt);
+               if (fmt[-1] != '\n')
+                       (void)fputc('\n', stderr);
+       }
+}
+
+/*
+ * Copy arg vector into a new buffer, concatenating arguments with spaces.
+ */
+static char *
+copy_argv(register char **argv)
+{
+       register char **p;
+       register size_t len = 0;
+       char *buf;
+       char *src, *dst;
+
+       p = argv;
+       if (*p == 0)
+               return 0;
+
+       while (*p)
+               len += strlen(*p++) + 1;
+
+       buf = (char *)malloc(len);
+       if (buf == NULL)
+               error("copy_argv: malloc");
+
+       p = argv;
+       dst = buf;
+       while ((src = *p++) != NULL) {
+               while ((*dst++ = *src++) != '\0')
+                       ;
+               dst[-1] = ' ';
+       }
+       dst[-1] = '\0';
+
+       return buf;
+}