summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2015-09-03 13:19:44 -0700
committerGuy Harris <guy@alum.mit.edu>2015-09-05 14:23:58 -0700
commit863ffee683bffca3db3a9a94505267ea4c5afbfa (patch)
treefc8f94c8a27fb29dcde0f16184e45cde9964592c
parent734d0e2e532ea105033c32382c6c5199e484900e (diff)
downloadlibpcap-863ffee683bffca3db3a9a94505267ea4c5afbfa.tar.gz
Add TurboCap support from WinPcap.
1) It's also apparently supported on Linux. 2) This cleans it up to match the way we're currently dealing with pcap modules. 3) This cleans it up to the way we're handling the Win32 extensions. Fix the configure script so that, if a pcap module that is supported only if the relevant support software is available is being configured in, we *add* its source to the list of source files to compile, rather than making it *the* source file to compile, in case there's more than one of them. Fix a typo in a comment. Add a comment about TurboCap using DLT_PPI for Ethernet. Move the struct pcap_stat used for pcap_stats_ex() into the pcap structure on Windows, as it's used by multiple modules. Remove the stuff that handles TurboCap from pcap-win32.c, as the routines that did that are now just module ops, so we call the TurboCap versions for TurboCap devices. Remove the stuff that handles remote captures from there as well; that will eventually be handles by modules (plural) for the remote capture protocols (plural). Make all of the fields added to struct pcap_stat dependent on _WIN32 and HAVE_REMOTE being defined. We don't want any of them for UN*X, as that would potentially break binary compatibility; we make them all dependent on HAVE_REMOTE being defined because that's what WinPcap currently does (yes, that's a bad idea, but we'll be fixing this by deprecating that structure as well as pcap_stats() and pcap_stats_ex() in favor of something a bit more pcapng-like, which would be more extensible).
-rw-r--r--Makefile.in2
-rw-r--r--Win32/Prj/libpcap.dsp8
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure84
-rw-r--r--configure.in60
-rw-r--r--gencode.c9
-rw-r--r--pcap-int.h4
-rw-r--r--pcap-tc.c1286
-rw-r--r--pcap-tc.h57
-rw-r--r--pcap-win32.c39
-rw-r--r--pcap.c7
-rw-r--r--pcap/pcap.h6
12 files changed, 1524 insertions, 41 deletions
diff --git a/Makefile.in b/Makefile.in
index 4c35bde7..8c9bb2df 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -328,6 +328,8 @@ EXTRA_DIST = \
pcap-snf.h \
pcap-snit.c \
pcap-snoop.c \
+ pcap-tc.c \
+ pcap-tc.h \
pcap-usb-linux.c \
pcap-usb-linux.h \
pcap-win32.c \
diff --git a/Win32/Prj/libpcap.dsp b/Win32/Prj/libpcap.dsp
index 7082122c..358007c8 100644
--- a/Win32/Prj/libpcap.dsp
+++ b/Win32/Prj/libpcap.dsp
@@ -150,6 +150,14 @@ SOURCE=..\..\optimize.c
# End Source File
# Begin Source File
+SOURCE="..\..\pcap-tc.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\pcap-tc.h"
+# End Source File
+# Begin Source File
+
SOURCE="..\..\Pcap-win32.c"
# End Source File
# Begin Source File
diff --git a/config.h.in b/config.h.in
index 3b9f90a4..c78371fa 100644
--- a/config.h.in
+++ b/config.h.in
@@ -196,6 +196,9 @@
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
+/* define if you have the TurboCap API */
+#undef HAVE_TC_API
+
/* if if_packet.h has tpacket_stats defined */
#undef HAVE_TPACKET_STATS
diff --git a/configure b/configure
index 1bf8bef3..20cba7eb 100755
--- a/configure
+++ b/configure
@@ -742,6 +742,7 @@ with_septel
with_snf
with_snf_includes
with_snf_libraries
+with_turbocap
with_flex
with_bison
enable_universal
@@ -1415,6 +1416,8 @@ Optional Packages:
--with-snf-includes=DIR Myricom SNF include directory
--with-snf-libraries=DIR
Myricom SNF library directory
+ --with-turbocap[=DIR] include Riverbed TurboCap support ["yes", "no" or
+ DIR; default="yes" on BSD and Linux if present]
--without-flex don't use flex
--without-bison don't use bison
@@ -6222,7 +6225,7 @@ if test $ac_cv_lbl_dag_api = yes; then
V_INCLS="$V_INCLS -I$dag_include_dir"
if test $V_PCAP != dag ; then
- SSRC="pcap-dag.c"
+ SSRC="$SSRC pcap-dag.c"
fi
# See if we can find a general version string.
@@ -6511,7 +6514,7 @@ $as_echo_n "checking whether we have Septel API... " >&6; }
ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o"
if test "$V_PCAP" != septel ; then
- SSRC="pcap-septel.c"
+ SSRC="$SSRC pcap-septel.c"
fi
ac_cv_lbl_septel_api=yes
fi
@@ -6544,7 +6547,7 @@ if test "${with_snf+set}" = set; then :
want_snf=no
elif test "$withval" = yes
then
- # User wants SNF support but hasn't specific a directory.
+ # User wants SNF support but hasn't specified a directory.
want_snf=yes
else
# User wants SNF support with a specified directory.
@@ -6690,7 +6693,7 @@ fi
LIBS="$LIBS -lsnf"
LDFLAGS="$LDFLAGS -L$snf_lib_dir"
if test "$V_PCAP" != snf ; then
- SSRC="pcap-snf.c"
+ SSRC="$SSRC pcap-snf.c"
fi
$as_echo "#define HAVE_SNF_API 1" >>confdefs.h
@@ -6703,6 +6706,79 @@ if test "$V_PCAP" = snf -a "$ac_cv_lbl_snf_api" = no; then
as_fn_error $? "Specifying the capture type as 'snf' requires the Myricom Sniffer API to be present; use --with-snf=DIR" "$LINENO" 5
fi
+# Check for Riverbed TurboCap support.
+
+# Check whether --with-turbocap was given.
+if test "${with_turbocap+set}" = set; then :
+ withval=$with_turbocap;
+ if test "$withval" = no
+ then
+ # User explicitly doesn't want TurboCap
+ want_turbocap=no
+ elif test "$withval" = yes
+ then
+ # User wants TurboCap support but hasn't specified a directory.
+ want_turbocap=yes
+ else
+ # User wants TurboCap support with a specified directory.
+ want_turbocap=yes
+ turbocap_root=$withval
+ fi
+
+else
+
+ #
+ # Use TurboCap API if present, otherwise don't
+ #
+ want_turbocap=ifpresent
+
+fi
+
+
+ac_cv_lbl_turbocap_api=no
+if test "$with_turbocap" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether TurboCap is supported" >&5
+$as_echo_n "checking whether TurboCap is supported... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <TcApi.h>
+
+int
+main ()
+{
+
+ TC_INSTANCE a; TC_PORT b; TC_BOARD c;
+ TC_INSTANCE i;
+ (void)TcInstanceCreateByName("foo", &i);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_lbl_turbocap_api=yes
+else
+ ac_cv_lbl_turbocap_api=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_turbocap_api" >&5
+$as_echo "$ac_cv_lbl_turbocap_api" >&6; }
+ if test $ac_cv_lbl_turbocap_api = no; then
+ if test "$want_turbocap" = yes; then
+ as_fn_error $? "TurboCap API not found" "$LINENO" 5
+ fi
+ else
+
+$as_echo "#define HAVE_TC_API 1" >>confdefs.h
+
+ SSRC="$SSRC pcap-tc.c"
+ LIBS="$LIBS -lTcApi -lpthread -lstdc++"
+ fi
+fi
+
# Check whether --with-flex was given.
if test "${with_flex+set}" = set; then :
diff --git a/configure.in b/configure.in
index 31287d0d..dad57b07 100644
--- a/configure.in
+++ b/configure.in
@@ -808,7 +808,7 @@ if test $ac_cv_lbl_dag_api = yes; then
V_INCLS="$V_INCLS -I$dag_include_dir"
if test $V_PCAP != dag ; then
- SSRC="pcap-dag.c"
+ SSRC="$SSRC pcap-dag.c"
fi
# See if we can find a general version string.
@@ -918,7 +918,7 @@ if test "$with_septel" != no; then
ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o"
if test "$V_PCAP" != septel ; then
- SSRC="pcap-septel.c"
+ SSRC="$SSRC pcap-septel.c"
fi
ac_cv_lbl_septel_api=yes
fi
@@ -947,7 +947,7 @@ AC_HELP_STRING([--with-snf@<:@=DIR@:>@],[include Myricom SNF support @<:@"yes",
want_snf=no
elif test "$withval" = yes
then
- # User wants SNF support but hasn't specific a directory.
+ # User wants SNF support but hasn't specified a directory.
want_snf=yes
else
# User wants SNF support with a specified directory.
@@ -1040,7 +1040,7 @@ if test "$with_snf" != no; then
LIBS="$LIBS -lsnf"
LDFLAGS="$LDFLAGS -L$snf_lib_dir"
if test "$V_PCAP" != snf ; then
- SSRC="pcap-snf.c"
+ SSRC="$SSRC pcap-snf.c"
fi
AC_DEFINE(HAVE_SNF_API, 1, [define if you have Myricom SNF API])
fi
@@ -1051,6 +1051,58 @@ if test "$V_PCAP" = snf -a "$ac_cv_lbl_snf_api" = no; then
AC_MSG_ERROR(Specifying the capture type as 'snf' requires the Myricom Sniffer API to be present; use --with-snf=DIR)
fi
+# Check for Riverbed TurboCap support.
+AC_ARG_WITH([turbocap],
+AC_HELP_STRING([--with-turbocap@<:@=DIR@:>@],[include Riverbed TurboCap support @<:@"yes", "no" or DIR; default="yes" on BSD and Linux if present@:>@]),
+[
+ if test "$withval" = no
+ then
+ # User explicitly doesn't want TurboCap
+ want_turbocap=no
+ elif test "$withval" = yes
+ then
+ # User wants TurboCap support but hasn't specified a directory.
+ want_turbocap=yes
+ else
+ # User wants TurboCap support with a specified directory.
+ want_turbocap=yes
+ turbocap_root=$withval
+ fi
+],[
+ #
+ # Use TurboCap API if present, otherwise don't
+ #
+ want_turbocap=ifpresent
+])
+
+ac_cv_lbl_turbocap_api=no
+if test "$with_turbocap" != no; then
+ AC_MSG_CHECKING(whether TurboCap is supported)
+
+ AC_TRY_COMPILE(
+ [
+ #include <TcApi.h>
+ ],
+ [
+ TC_INSTANCE a; TC_PORT b; TC_BOARD c;
+ TC_INSTANCE i;
+ (void)TcInstanceCreateByName("foo", &i);
+ ],
+ ac_cv_lbl_turbocap_api=yes,
+ ac_cv_lbl_turbocap_api=no)
+
+ AC_MSG_RESULT($ac_cv_lbl_turbocap_api)
+ if test $ac_cv_lbl_turbocap_api = no; then
+ if test "$want_turbocap" = yes; then
+ AC_MSG_ERROR(TurboCap API not found)
+ fi
+ else
+ AC_DEFINE(HAVE_TC_API, 1, [define if you have the TurboCap API])
+ SSRC="$SSRC pcap-tc.c"
+ LIBS="$LIBS -lTcApi -lpthread -lstdc++"
+ fi
+fi
+
AC_LBL_LEX_AND_YACC(V_LEX, V_YACC, pcap_)
if test "$V_LEX" = lex ; then
# Some versions of lex can't handle the definitions section of scanner.l .
diff --git a/gencode.c b/gencode.c
index 85c1a5c6..d99bd69f 100644
--- a/gencode.c
+++ b/gencode.c
@@ -628,6 +628,15 @@ finish_parse(p)
/*
* For DLT_PPI captures, generate a check of the per-packet
* DLT value to make sure it's DLT_IEEE802_11.
+ *
+ * XXX - TurboCap cards use DLT_PPI for Ethernet.
+ * Can we just define some DLT_ETHERNET_WITH_PHDR pseudo-header
+ * with appropriate Ethernet information and use that rather
+ * than using something such as DLT_PPI where you don't know
+ * the link-layer header type until runtime, which, in the
+ * general case, would force us to generate both Ethernet *and*
+ * 802.11 code (*and* anything else for which PPI is used)
+ * and choose between them early in the BPF program?
*/
ppi_dlt_check = gen_ppi_dlt_check();
if (ppi_dlt_check != NULL)
diff --git a/pcap-int.h b/pcap-int.h
index 8a228f31..79e80337 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -207,6 +207,10 @@ struct pcap {
*/
u_char *pkt;
+#ifdef _WIN32
+ struct pcap_stat stat; /* used for pcap_stats_ex() */
+#endif
+
/* We're accepting only packets in this direction/these directions. */
pcap_direction_t direction;
diff --git a/pcap-tc.c b/pcap-tc.c
new file mode 100644
index 00000000..50924cca
--- /dev/null
+++ b/pcap-tc.c
@@ -0,0 +1,1286 @@
+/*
+ * Copyright (c) 2008 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 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.h>
+#include <pcap-int.h>
+
+#include "pcap-tc.h"
+
+#include <malloc.h>
+#include <memory.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <tchar.h>
+#endif
+
+typedef TC_STATUS (TC_CALLCONV *TcFcnQueryPortList) (PTC_PORT *ppPorts, PULONG pLength);
+typedef TC_STATUS (TC_CALLCONV *TcFcnFreePortList) (TC_PORT *pPorts);
+
+typedef PCHAR (TC_CALLCONV *TcFcnStatusGetString) (TC_STATUS status);
+
+typedef PCHAR (TC_CALLCONV *TcFcnPortGetName) (TC_PORT port);
+typedef PCHAR (TC_CALLCONV *TcFcnPortGetDescription) (TC_PORT port);
+
+typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceOpenByName) (PCHAR name, PTC_INSTANCE pInstance);
+typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceClose) (TC_INSTANCE instance);
+typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceSetFeature) (TC_INSTANCE instance, ULONG feature, ULONG value);
+typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceQueryFeature) (TC_INSTANCE instance, ULONG feature, PULONG pValue);
+typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceReceivePackets) (TC_INSTANCE instance, PTC_PACKETS_BUFFER pBuffer);
+typedef HANDLE (TC_CALLCONV *TcFcnInstanceGetReceiveWaitHandle) (TC_INSTANCE instance);
+typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceTransmitPackets) (TC_INSTANCE instance, TC_PACKETS_BUFFER pBuffer);
+typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceQueryStatistics) (TC_INSTANCE instance, PTC_STATISTICS pStatistics);
+
+typedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferCreate) (ULONG size, PTC_PACKETS_BUFFER pBuffer);
+typedef VOID (TC_CALLCONV *TcFcnPacketsBufferDestroy) (TC_PACKETS_BUFFER buffer);
+typedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferQueryNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID *ppData);
+typedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferCommitNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID pData);
+
+typedef VOID (TC_CALLCONV *TcFcnStatisticsDestroy) (TC_STATISTICS statistics);
+typedef TC_STATUS (TC_CALLCONV *TcFcnStatisticsUpdate) (TC_STATISTICS statistics);
+typedef TC_STATUS (TC_CALLCONV *TcFcnStatisticsQueryValue) (TC_STATISTICS statistics, ULONG counterId, PULONGLONG pValue);
+
+typedef enum LONG
+{
+ TC_API_UNLOADED = 0,
+ TC_API_LOADED,
+ TC_API_CANNOT_LOAD,
+ TC_API_LOADING
+}
+ TC_API_LOAD_STATUS;
+
+
+typedef struct _TC_FUNCTIONS
+{
+ TC_API_LOAD_STATUS LoadStatus;
+#ifdef _WIN32
+ HMODULE hTcApiDllHandle;
+#endif
+ TcFcnQueryPortList QueryPortList;
+ TcFcnFreePortList FreePortList;
+ TcFcnStatusGetString StatusGetString;
+
+ TcFcnPortGetName PortGetName;
+ TcFcnPortGetDescription PortGetDescription;
+
+ TcFcnInstanceOpenByName InstanceOpenByName;
+ TcFcnInstanceClose InstanceClose;
+ TcFcnInstanceSetFeature InstanceSetFeature;
+ TcFcnInstanceQueryFeature InstanceQueryFeature;
+ TcFcnInstanceReceivePackets InstanceReceivePackets;
+#ifdef _WIN32
+ TcFcnInstanceGetReceiveWaitHandle InstanceGetReceiveWaitHandle;
+#endif
+ TcFcnInstanceTransmitPackets InstanceTransmitPackets;
+ TcFcnInstanceQueryStatistics InstanceQueryStatistics;
+
+ TcFcnPacketsBufferCreate PacketsBufferCreate;
+ TcFcnPacketsBufferDestroy PacketsBufferDestroy;
+ TcFcnPacketsBufferQueryNextPacket PacketsBufferQueryNextPacket;
+ TcFcnPacketsBufferCommitNextPacket PacketsBufferCommitNextPacket;
+
+ TcFcnStatisticsDestroy StatisticsDestroy;
+ TcFcnStatisticsUpdate StatisticsUpdate;
+ TcFcnStatisticsQueryValue StatisticsQueryValue;
+}
+ TC_FUNCTIONS;
+
+static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port);
+static int TcSetDatalink(pcap_t *p, int dlt);
+static int TcGetNonBlock(pcap_t *p, char *errbuf);
+static int TcSetNonBlock(pcap_t *p, int nonblock, char *errbuf);
+static void TcCleanup(pcap_t *p);
+static int TcInject(pcap_t *p, const void *buf, size_t size);
+static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
+static int TcStats(pcap_t *p, struct pcap_stat *ps);
+static int TcSetFilter(pcap_t *p, struct bpf_program *fp);
+#ifdef _WIN32
+static struct pcap_stat *TcStatsEx(pcap_t *p, int *pcap_stat_size);
+static int TcSetBuff(pcap_t *p, int dim);
+static int TcSetMode(pcap_t *p, int mode);
+static int TcSetMinToCopy(pcap_t *p, int size);
+static HANDLE TcGetReceiveWaitHandle(pcap_t *p);
+static int TcOidGetRequest(pcap_t *p, pcap_oid_data_t *data);
+static int TcOidSetRequest(pcap_t *p, pcap_oid_data_t *data);
+static u_int TcOidSendqueueTransmit(pcap_t *p, pcap_send_queue *queue, int sync);
+static int TcSetUserBuffer(pcap_t *p, int size);
+static int TcLiveDump(pcap_t *p, char *filename, int maxsize, int maxpacks);
+static int TcLiveDumpEnded(pcap_t *p, int sync);
+static int TcGetAirPcapHandle(pcap_t *p);
+#endif
+
+#ifdef _WIN32
+TC_FUNCTIONS g_TcFunctions =
+{
+ TC_API_UNLOADED, /* LoadStatus */
+ NULL, /* hTcApiDllHandle */
+ NULL, /* QueryPortList */
+ NULL, /* FreePortList */
+ NULL, /* StatusGetString */
+ NULL, /* PortGetName */
+ NULL, /* PortGetDescription */
+ NULL, /* InstanceOpenByName */
+ NULL, /* InstanceClose */
+ NULL, /* InstanceSetFeature */
+ NULL, /* InstanceQueryFeature */
+ NULL, /* InstanceReceivePackets */
+ NULL, /* InstanceGetReceiveWaitHandle */
+ NULL, /* InstanceTransmitPackets */
+ NULL, /* InstanceQueryStatistics */
+ NULL, /* PacketsBufferCreate */
+ NULL, /* PacketsBufferDestroy */
+ NULL, /* PacketsBufferQueryNextPacket */
+ NULL, /* PacketsBufferCommitNextPacket */
+ NULL, /* StatisticsDestroy */
+ NULL, /* StatisticsUpdate */
+ NULL /* StatisticsQueryValue */
+};
+#else
+TC_FUNCTIONS g_TcFunctions =
+{
+ TC_API_LOADED, /* LoadStatus */
+ TcQueryPortList,
+ TcFreePortList,
+ TcStatusGetString,
+ TcPortGetName,
+ TcPortGetDescription,
+ TcInstanceOpenByName,
+ TcInstanceClose,
+ TcInstanceSetFeature,
+ TcInstanceQueryFeature,
+ TcInstanceReceivePackets,
+#ifdef _WIN32
+ TcInstanceGetReceiveWaitHandle,
+#endif
+ TcInstanceTransmitPackets,
+ TcInstanceQueryStatistics,
+ TcPacketsBufferCreate,
+ TcPacketsBufferDestroy,
+ TcPacketsBufferQueryNextPacket,
+ TcPacketsBufferCommitNextPacket,
+ TcStatisticsDestroy,
+ TcStatisticsUpdate,
+ TcStatisticsQueryValue,
+};
+#endif
+
+#define MAX_TC_PACKET_SIZE 9500
+
+#pragma pack(push, 1)
+
+#define PPH_PH_FLAG_PADDING ((UCHAR)0x01)
+#define PPH_PH_VERSION ((UCHAR)0x00)
+
+typedef struct _PPI_PACKET_HEADER
+{
+ UCHAR PphVersion;
+ UCHAR PphFlags;
+ USHORT PphLength;
+ ULONG PphDlt;
+}
+ PPI_PACKET_HEADER, *PPPI_PACKET_HEADER;
+
+typedef struct _PPI_FIELD_HEADER
+{
+ USHORT PfhType;
+ USHORT PfhLength;
+}
+ PPI_FIELD_HEADER, *PPPI_FIELD_HEADER;
+
+
+#define PPI_FIELD_TYPE_AGGREGATION_EXTENSION ((UCHAR)0x08)
+
+typedef struct _PPI_FIELD_AGGREGATION_EXTENSION
+{
+ ULONG InterfaceId;
+}
+ PPI_FIELD_AGGREGATION_EXTENSION, *PPPI_FIELD_AGGREGATION_EXTENSION;
+
+
+#define PPI_FIELD_TYPE_802_3_EXTENSION ((UCHAR)0x09)
+
+#define PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT ((ULONG)0x00000001)
+
+typedef struct _PPI_FIELD_802_3_EXTENSION
+{
+ ULONG Flags;
+ ULONG Errors;
+}
+ PPI_FIELD_802_3_EXTENSION, *PPPI_FIELD_802_3_EXTENSION;
+
+typedef struct _PPI_HEADER
+{
+ PPI_PACKET_HEADER PacketHeader;
+ PPI_FIELD_HEADER AggregationFieldHeader;
+ PPI_FIELD_AGGREGATION_EXTENSION AggregationField;
+ PPI_FIELD_HEADER Dot3FieldHeader;
+ PPI_FIELD_802_3_EXTENSION Dot3Field;
+}
+ PPI_HEADER, *PPPI_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
+ * opening one. All the other ones (close, read, write, set parameters) work
+ * on an open instance of TC, so we do not care to call this function
+ */
+TC_API_LOAD_STATUS LoadTcFunctions(void)
+{
+ TC_API_LOAD_STATUS currentStatus;
+
+ do
+ {
+ currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_UNLOADED);
+
+ while(currentStatus == TC_API_LOADING)
+ {
+ currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_LOADING);
+ Sleep(10);
+ }
+
+ /*
+ * at this point we are either in the LOADED state, unloaded state (i.e. we are the ones loading everything)
+ * or in cannot load
+ */
+ if(currentStatus == TC_API_LOADED)
+ {
+ return TC_API_LOADED;
+ }
+
+ if (currentStatus == TC_API_CANNOT_LOAD)
+ {
+ return TC_API_CANNOT_LOAD;
+ }
+
+ currentStatus = TC_API_CANNOT_LOAD;
+
+ g_TcFunctions.hTcApiDllHandle = LoadLibrarySafe("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.StatusGetString = (TcFcnStatusGetString) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString");
+
+ g_TcFunctions.PortGetName = (TcFcnPortGetName) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetName");
+ g_TcFunctions.PortGetDescription = (TcFcnPortGetDescription) GetProcAddress(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.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.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");
+
+ if ( g_TcFunctions.QueryPortList == NULL
+ || g_TcFunctions.FreePortList == NULL
+ || g_TcFunctions.StatusGetString == NULL
+ || g_TcFunctions.PortGetName == NULL
+ || g_TcFunctions.PortGetDescription == NULL
+ || g_TcFunctions.InstanceOpenByName == NULL
+ || g_TcFunctions.InstanceClose == NULL
+ || g_TcFunctions.InstanceSetFeature == NULL
+ || g_TcFunctions.InstanceQueryFeature == NULL
+ || g_TcFunctions.InstanceReceivePackets == NULL
+ || g_TcFunctions.InstanceGetReceiveWaitHandle == NULL
+ || g_TcFunctions.InstanceTransmitPackets == NULL
+ || g_TcFunctions.InstanceQueryStatistics == NULL
+ || g_TcFunctions.PacketsBufferCreate == NULL
+ || g_TcFunctions.PacketsBufferDestroy == NULL
+ || g_TcFunctions.PacketsBufferQueryNextPacket == NULL
+ || g_TcFunctions.PacketsBufferCommitNextPacket == NULL
+ || g_TcFunctions.StatisticsDestroy == NULL
+ || g_TcFunctions.StatisticsUpdate == NULL
+ || g_TcFunctions.StatisticsQueryValue == NULL
+ )
+ {
+ break;
+ }
+
+ /*
+ * everything got loaded, yay!!
+ */
+ currentStatus = TC_API_LOADED;
+ }while(FALSE);
+
+ if (currentStatus != TC_API_LOADED)
+ {
+ if (g_TcFunctions.hTcApiDllHandle != NULL)
+ {
+ FreeLibrary(g_TcFunctions.hTcApiDllHandle);
+ g_TcFunctions.hTcApiDllHandle = NULL;
+ }
+ }
+
+ InterlockedExchange((LONG*)&g_TcFunctions.LoadStatus, currentStatus);
+
+ return currentStatus;
+}
+#else
+// static linking
+TC_API_LOAD_STATUS LoadTcFunctions(void)
+{
+ return TC_API_LOADED;
+}
+#endif
+
+/*
+ * Private data for capturing on TurboCap devices.
+ */
+struct pcap_tc {
+ TC_INSTANCE TcInstance;
+ TC_PACKETS_BUFFER TcPacketsBuffer;
+ ULONG TcAcceptedCount;
+ PCHAR PpiPacket;
+};
+
+int
+TcFindAllDevs(pcap_if_t **alldevsp, char *errbuf)
+{
+ TC_API_LOAD_STATUS loadStatus;
+ ULONG numPorts;
+ PTC_PORT pPorts = NULL;
+ TC_STATUS status;
+ int result = 0;
+ pcap_if_t *dev, *cursor;
+ ULONG i;
+
+ do
+ {
+ loadStatus = LoadTcFunctions();
+
+ if (loadStatus != TC_API_LOADED)
+ {
+ result = 0;
+ break;
+ }
+
+ /*
+ * enumerate the ports, and add them to the list
+ */
+ status = g_TcFunctions.QueryPortList(&pPorts, &numPorts);
+
+ if (status != TC_SUCCESS)
+ {
+ result = 0;
+ break;
+ }
+
+ for (i = 0; i < numPorts; i++)
+ {
+ /*
+ * transform the port into an entry in the list
+ */
+ dev = TcCreatePcapIfFromPort(pPorts[i]);
+
+ if (dev != NULL)
+ {
+ /*
+ * append it at the end
+ */
+ if (*alldevsp == NULL)
+ {
+ *alldevsp = dev;
+ }
+ else
+ {
+ for(cursor = *alldevsp; cursor->next != NULL; cursor = cursor->next);
+ cursor->next = dev;
+ }
+ }
+ }
+
+ if (numPorts > 0)
+ {
+ /*
+ * ignore the result here
+ */
+ status = g_TcFunctions.FreePortList(pPorts);
+ }
+
+ }while(FALSE);
+
+ return result;
+}
+
+static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port)
+{
+ CHAR *name;
+ CHAR *description;
+ pcap_if_t *newIf = NULL;
+
+ newIf = (pcap_if_t*)malloc(sizeof(*newIf));
+ if (newIf == NULL)
+ {
+ return NULL;
+ }
+
+ memset(newIf, 0, sizeof(*newIf));
+
+ name = g_TcFunctions.PortGetName(port);
+ description = g_TcFunctions.PortGetDescription(port);
+
+ newIf->name = (char*)malloc(strlen(name) + 1);
+ if (newIf->name == NULL)
+ {
+ free(newIf);
+ return NULL;
+ }
+
+ newIf->description = (char*)malloc(strlen(description) + 1);
+ if (newIf->description == NULL)
+ {
+ free(newIf->name);
+ free(newIf);
+ return NULL;
+ }
+
+ strcpy(newIf->name, name);
+ strcpy(newIf->description, description);
+
+ newIf->addresses = NULL;
+ newIf->next = NULL;
+ newIf->flags = 0;
+
+ return newIf;
+
+}
+
+static int
+TcActivate(pcap_t *p)
+{
+ struct pcap_tc *pt = p->priv;
+ TC_STATUS status;
+ ULONG timeout;
+ PPPI_HEADER pPpiHeader;
+
+ if (p->opt.rfmon)
+ {
+ /*
+ * No monitor mode on Tc cards; they're Ethernet
+ * capture adapters.
+ */
+ return (PCAP_ERROR_RFMON_NOTSUP);
+ }
+
+ pt->PpiPacket = (PCHAR)malloc(sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE);
+
+ if (pt->PpiPacket == NULL)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory");
+ return PCAP_ERROR;
+ }
+
+ /*
+ * Initialize the PPI fixed fields
+ */
+ pPpiHeader = (PPPI_HEADER)pt->PpiPacket;
+ pPpiHeader->PacketHeader.PphDlt = DLT_EN10MB;
+ pPpiHeader->PacketHeader.PphLength = sizeof(PPI_HEADER);
+ pPpiHeader->PacketHeader.PphFlags = 0;
+ pPpiHeader->PacketHeader.PphVersion = 0;
+
+ pPpiHeader->AggregationFieldHeader.PfhLength = sizeof(PPI_FIELD_AGGREGATION_EXTENSION);
+ pPpiHeader->AggregationFieldHeader.PfhType = PPI_FIELD_TYPE_AGGREGATION_EXTENSION;
+
+ pPpiHeader->Dot3FieldHeader.PfhLength = sizeof(PPI_FIELD_802_3_EXTENSION);
+ pPpiHeader->Dot3FieldHeader.PfhType = PPI_FIELD_TYPE_802_3_EXTENSION;
+
+ status = g_TcFunctions.InstanceOpenByName(p->opt.source, &pt->TcInstance);
+
+ if (status != TC_SUCCESS)
+ {
+ /* Adapter detected but we are not able to open it. Return failure. */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status));
+ return PCAP_ERROR;
+ }
+
+ p->linktype = DLT_EN10MB;
+ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
+ /*
+ * If that fails, just leave the list empty.
+ */
+ if (p->dlt_list != NULL) {
+ p->dlt_list[0] = DLT_EN10MB;
+ p->dlt_list[1] = DLT_PPI;
+ p->dlt_count = 2;
+ }
+
+ /*
+ * ignore promiscuous mode
+ * p->opt.promisc
+ */
+
+
+ /*
+ * ignore all the buffer sizes
+ */
+
+ /*
+ * enable reception
+ */
+ status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_RX_STATUS, 1);
+
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
+ goto bad;
+ }
+
+ /*
+ * enable transmission
+ */
+ status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_TX_STATUS, 1);
+ /*
+ * Ignore the error here.
+ */
+
+ p->inject_op = TcInject;
+ /*
+ * if the timeout is -1, it means immediate return, no timeout
+ * if the timeout is 0, it means INFINITE
+ */
+
+ if (p->md.timeout == 0)
+ {
+ timeout = 0xFFFFFFFF;
+ }
+ else
+ if (p->md.timeout < 0)
+ {
+ /*
+ * we insert a minimal timeout here
+ */
+ timeout = 10;
+ }
+ else
+ {
+ timeout = p->md.timeout;
+ }
+
+ status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_READ_TIMEOUT, timeout);
+
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
+ goto bad;
+ }
+
+ p->read_op = TcRead;
+ p->setfilter_op = TcSetFilter;
+ p->setdirection_op = NULL; /* Not implemented. */
+ p->set_datalink_op = TcSetDatalink;
+ p->getnonblock_op = TcGetNonBlock;
+ p->setnonblock_op = TcSetNonBlock;
+ p->stats_op = TcStats;
+#ifdef _WIN32
+ p->stats_ex_op = TcStatsEx;
+ p->setbuff_op = TcSetBuff;
+ p->setmode_op = TcSetMode;
+ p->setmintocopy_op = TcSetMinToCopy;
+ p->getevent_op = TcGetReceiveWaitHandle;
+ p->oid_get_request_op = TcOidGetRequest;
+ p->oid_set_request_op = TcOidSetRequest;
+ p->sendqueue_transmit_op = TcOidSendqueueTransmit;
+ p->set_userbuffer_op = TcSetUserBuffer;
+ p->live_dump_op = TcLiveDump;
+ p->live_dump_ended_op = TcLiveDumpEnded;
+ p->get_airpcap_handle_op = TcGetAirPcapHandle;
+#else
+ p->selectable_fd = -1;
+#endif
+
+ p->cleanup_op = TcCleanup;
+
+ return (0);
+bad:
+ TcCleanup(p);
+ return (PCAP_ERROR);
+}
+
+pcap_t *
+TcCreate(const char *device, char *ebuf, int *is_ours)
+{
+ ULONG numPorts;
+ PTC_PORT pPorts = NULL;
+ TC_STATUS status;
+ int is_tc;
+ ULONG i;
+ pcap_t *p;
+
+ if (LoadTcFunctions() != TC_API_LOADED)
+ {
+ /*
+ * XXX - report this as an error rather than as
+ * "not a TurboCap device"?
+ */
+ *is_ours = 0;
+ return NULL;
+ }
+
+ /*
+ * enumerate the ports, and add them to the list
+ */
+ status = g_TcFunctions.QueryPortList(&pPorts, &numPorts);
+
+ if (status != TC_SUCCESS)
+ {
+ /*
+ * XXX - report this as an error rather than as
+ * "not a TurboCap device"?
+ */
+ *is_ours = 0;
+ return NULL;
+ }
+
+ is_tc = FALSE;
+ for (i = 0; i < numPorts; i++)
+ {
+ if (strcmp(g_TcFunctions.PortGetName(pPorts[i]), source) == 0)
+ {
+ is_tc = TRUE;
+ break;
+ }
+ }
+
+ if (numPorts > 0)
+ {
+ /*
+ * ignore the result here
+ */
+ (void)g_TcFunctions.FreePortList(pPorts);
+ }
+
+ if (!is_tc)
+ {
+ *is_ours = 0;
+ return NULL;
+ }
+
+ /* OK, it's probably ours. */
+ *is_ours = 1;
+
+ p = pcap_create_common(device, ebuf, sizeof (struct pcap_tc));
+ if (p == NULL)
+ return NULL;
+
+ p->activate_op = TcActivate;
+ return p;
+}
+
+static int TcSetDatalink(pcap_t *p, int dlt)
+{
+ /*
+ * always return 0, as the check is done by pcap_set_datalink
+ */
+ return 0;
+}
+
+static int TcGetNonBlock(pcap_t *p, char *errbuf)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Getting the non blocking status is not available for TurboCap ports");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Getting the non blocking status is not available for TurboCap ports");
+ return -1;
+
+}
+static int TcSetNonBlock(pcap_t *p, int nonblock, char *errbuf)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Setting the non blocking status is not available for TurboCap ports");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Setting the non blocking status is not available for TurboCap ports");
+ return -1;
+}
+
+
+static void TcCleanup(pcap_t *p)
+{
+ struct pcap_tc *pt = p->priv;
+
+ if (pt->TcPacketsBuffer != NULL)
+ {
+ g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer);
+ pt->TcPacketsBuffer = NULL;
+ }
+ if (pt->TcInstance != NULL)
+ {
+ /*
+ * here we do not check for the error values
+ */
+ g_TcFunctions.InstanceClose(pt->TcInstance);
+ pt->TcInstance = NULL;
+ }
+
+ if (pt->PpiPacket != NULL)
+ {
+ free(pt->PpiPacket);
+ pt->PpiPacket = NULL;
+ }
+
+ pcap_cleanup_live_common(p);
+}
+
+/* Send a packet to the network */
+static int TcInject(pcap_t *p, const void *buf, size_t size)
+{
+ struct pcap_tc *pt = p->priv;
+ TC_STATUS status;
+ TC_PACKETS_BUFFER buffer;
+ TC_PACKET_HEADER header;
+
+ if (size >= 0xFFFF)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k");
+ return -1;
+ }
+
+ status = g_TcFunctions.PacketsBufferCreate(sizeof(TC_PACKET_HEADER) + TC_ALIGN_USHORT_TO_64BIT((USHORT)size), &buffer);
+
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ return -1;
+ }
+
+ /*
+ * we assume that the packet is without the checksum, as common with WinPcap
+ */
+ memset(&header, 0, sizeof(header));
+
+ header.Length = (USHORT)size;
+ header.CapturedLength = header.Length;
+
+ status = g_TcFunctions.PacketsBufferCommitNextPacket(buffer, &header, (PVOID)buf);
+
+ if (status == TC_SUCCESS)
+ {
+ status = g_TcFunctions.InstanceTransmitPackets(pt->TcInstance, buffer);
+
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ }
+ }
+ else
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ }
+
+ g_TcFunctions.PacketsBufferDestroy(buffer);
+
+ if (status != TC_SUCCESS)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ struct pcap_tc *pt = p->priv;
+ TC_STATUS status;
+ int n = 0;
+
+ /*
+ * Has "pcap_breakloop()" been called?
+ */
+ if (p->break_loop)
+ {
+ /*
+ * Yes - clear the flag that indicates that it
+ * has, and return -2 to indicate that we were
+ * told to break out of the loop.
+ */
+ p->break_loop = 0;
+ return (-2);
+ }
+
+ if (pt->TcPacketsBuffer == NULL)
+ {
+ status = g_TcFunctions.InstanceReceivePackets(pt->TcInstance, &pt->TcPacketsBuffer);
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ return (-1);
+ }
+ }
+
+ while (TRUE)
+ {
+ struct pcap_pkthdr hdr;
+ TC_PACKET_HEADER tcHeader;
+ PVOID data;
+ ULONG filterResult;
+
+ /*
+ * Has "pcap_breakloop()" been called?
+ * If so, return immediately - if we haven't read any
+ * packets, clear the flag and return -2 to indicate
+ * that we were told to break out of the loop, otherwise
+ * leave the flag set, so that the *next* call will break
+ * out of the loop without having read any packets, and
+ * return the number of packets we've processed so far.
+ */
+ if (p->break_loop)
+ {
+ if (n == 0)
+ {
+ p->break_loop = 0;
+ return (-2);
+ }
+ else
+ {
+ return (n);
+ }
+ }
+
+ if (pt->TcPacketsBuffer == NULL)
+ {
+ break;
+ }
+
+ status = g_TcFunctions.PacketsBufferQueryNextPacket(pt->TcPacketsBuffer, &tcHeader, &data);
+
+ if (status == TC_ERROR_END_OF_BUFFER)
+ {
+ g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer);
+ pt->TcPacketsBuffer = NULL;
+ break;
+ }
+
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ return (-1);
+ }
+
+ /* No underlaying filtering system. We need to filter on our own */
+ if (p->fcode.bf_insns)
+ {
+ filterResult = bpf_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength);
+
+ if (filterResult == 0)
+ {
+ continue;
+ }
+
+ if (filterResult > tcHeader.CapturedLength)
+ {
+ filterResult = tcHeader.CapturedLength;
+ }
+ }
+ else
+ {
+ filterResult = tcHeader.CapturedLength;
+ }
+
+ pt->TcAcceptedCount ++;
+
+ hdr.ts.tv_sec = (bpf_u_int32)(tcHeader.Timestamp / (ULONGLONG)(1000 * 1000 * 1000));
+ hdr.ts.tv_usec = (bpf_u_int32)((tcHeader.Timestamp % (ULONGLONG)(1000 * 1000 * 1000)) / 1000);
+
+ if (p->linktype == DLT_EN10MB)
+ {
+ hdr.caplen = filterResult;
+ hdr.len = tcHeader.Length;
+ (*callback)(user, &hdr, data);
+ }
+ else
+ {
+ PPPI_HEADER pPpiHeader = (PPPI_HEADER)pt->PpiPacket;
+ PVOID data2 = pPpiHeader + 1;
+
+ pPpiHeader->AggregationField.InterfaceId = TC_PH_FLAGS_RX_PORT_ID(tcHeader.Flags);
+ pPpiHeader->Dot3Field.Errors = tcHeader.Errors;
+ if (tcHeader.Flags & TC_PH_FLAGS_CHECKSUM)
+ {
+ pPpiHeader->Dot3Field.Flags = PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT;
+ }
+ else
+ {
+ pPpiHeader->Dot3Field.Flags = 0;
+ }
+
+ if (filterResult <= MAX_TC_PACKET_SIZE)
+ {
+ memcpy(data2, data, filterResult);
+ hdr.caplen = sizeof(PPI_HEADER) + filterResult;
+ hdr.len = sizeof(PPI_HEADER) + tcHeader.Length;
+ }
+ else
+ {
+ memcpy(data2, data, MAX_TC_PACKET_SIZE);
+ hdr.caplen = sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE;
+ hdr.len = sizeof(PPI_HEADER) + tcHeader.Length;
+ }
+
+ (*callback)(user, &hdr, pt->PpiPacket);
+
+ }
+
+ if (++n >= cnt && cnt > 0)
+ {
+ return (n);
+ }
+ }
+
+ return (n);
+}
+
+static int
+TcStats(pcap_t *p, struct pcap_stat *ps)
+{
+ struct pcap_tc *pt = p->priv;
+ TC_STATISTICS statistics;
+ TC_STATUS status;
+ ULONGLONG counter;
+ struct pcap_stat s;
+
+ status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics);
+
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ return -1;
+ }
+
+ memset(&s, 0, sizeof(s));
+
+ status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ return -1;
+ }
+ if (counter <= (ULONGLONG)0xFFFFFFFF)
+ {
+ s.ps_recv = (ULONG)counter;
+ }
+ else
+ {
+ s.ps_recv = 0xFFFFFFFF;
+ }
+
+ status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ return -1;
+ }
+ if (counter <= (ULONGLONG)0xFFFFFFFF)
+ {
+ s.ps_ifdrop = (ULONG)counter;
+ s.ps_drop = (ULONG)counter;
+ }
+ else
+ {
+ s.ps_ifdrop = 0xFFFFFFFF;
+ s.ps_drop = 0xFFFFFFFF;
+ }
+
+#if defined(_WIN32) && define(HAVE_REMOTE)
+ s.ps_capt = pt->TcAcceptedCount;
+#endif
+ *ps = s;
+
+ return 0;
+}
+
+
+/*
+ * We filter at user level, since the kernel driver does't process the packets
+ */
+static int
+TcSetFilter(pcap_t *p, struct bpf_program *fp)
+{
+ if(!fp)
+ {
+ strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf));
+ return -1;
+ }
+
+ /* Install a user level filter */
+ if (install_bpf_program(p, fp) < 0)
+ {
+ snprintf(p->errbuf, sizeof(p->errbuf),
+ "setfilter, unable to install the filter: %s", pcap_strerror(errno));
+ return -1;
+ }
+
+ p->md.use_bpf = 0;
+
+ return (0);
+}
+
+#ifdef _WIN32
+static struct pcap_stat *
+TcStatsEx(pcap_t *p, int *pcap_stat_size)
+{
+ struct pcap_tc *pt = p->priv;
+ TC_STATISTICS statistics;
+ TC_STATUS status;
+ ULONGLONG counter;
+ struct pcap_stat s;
+
+ *pcap_stat_size = sizeof (p->stat);
+
+ status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics);
+
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ return -1;
+ }
+
+ memset(&p->stat, 0, sizeof(p->stat));
+
+ status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ return -1;
+ }
+ if (counter <= (ULONGLONG)0xFFFFFFFF)
+ {
+ p->stat.ps_recv = (ULONG)counter;
+ }
+ else
+ {
+ p->stat.ps_recv = 0xFFFFFFFF;
+ }
+
+ status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ return -1;
+ }
+ if (counter <= (ULONGLONG)0xFFFFFFFF)
+ {
+ p->stat.ps_ifdrop = (ULONG)counter;
+ p->stat.ps_drop = (ULONG)counter;
+ }
+ else
+ {
+ p->stat.ps_ifdrop = 0xFFFFFFFF;
+ p->stat.ps_drop = 0xFFFFFFFF;
+ }
+
+#ifdef HAVE_REMOTE
+ p->stat.ps_capt = pt->TcAcceptedCount;
+#endif
+
+ return &p->stat;
+}
+
+/* Set the dimension of the kernel-level capture buffer */
+static int
+TcSetBuff(pcap_t *p, int dim)
+{
+ /*
+ * XXX turbocap has an internal way of managing buffers.
+ * And at the moment it's not configurable, so we just
+ * silently ignore the request to set the buffer.
+ */
+ return 0;
+}
+
+static int
+TcSetMode(pcap_t *p, int mode)
+{
+ if (mode != MODE_CAPT)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+TcSetMinToCopy(pcap_t *p, int size)
+{
+ struct pcap_tc *pt = p->priv;
+ TC_STATUS status;
+
+ if (size < 0)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0.");
+ return -1;
+ }
+
+ status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_MINTOCOPY, (ULONG)size);
+
+ if (status != TC_SUCCESS)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ }
+
+ return 0;
+}
+
+static HANDLE
+TcGetReceiveWaitHandle(pcap_t *p)
+{
+ struct pcap_tc *pt = p->priv;
+
+ return g_TcFunctions.InstanceGetReceiveWaitHandle(pt->TcInstance);
+}
+
+static int
+TcOidGetRequest(pcap_t *p, pcap_oid_data_t *data _U))
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "An OID get request cannot be performed on a TurboCap device");
+ return (PCAP_ERROR);
+}
+
+static int
+TcOidSetRequest(pcap_t *p, pcap_oid_data_t *data _U_))
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "An OID set request cannot be performed on a TurboCap device");
+ return (PCAP_ERROR);
+}
+
+static u_int
+TcOidSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_);
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets cannot be bulk transmitted on a TurboCap device");
+ return (0);
+}
+
+static int
+TcSetUserBuffer(pcap_t *p, int size _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The user buffer cannot be set on a TurboCap device");
+ return (-1);
+}
+
+static int
+TcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Live packet dumping cannot be performed on a TurboCap device");
+ return (-1);
+}
+
+static int
+TcLiveDumpEnded(pcap_t *p, int sync _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Live packet dumping cannot be performed on a TurboCap device");
+ return (-1);
+}
+
+static int
+TcGetAirPcapHandle(pcap_t *p _U_)
+{
+ return (NULL);
+}
+#endif
diff --git a/pcap-tc.h b/pcap-tc.h
new file mode 100644
index 00000000..ecb89325
--- /dev/null
+++ b/pcap-tc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008 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 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.
+ *
+ */
+
+#ifndef __PCAP_TC_H__
+#define __PCAP_TC_H__
+
+/*
+ * needed because gcc headers do not have C_ASSERT
+ */
+#ifndef C_ASSERT
+#define C_ASSERT(a)
+#endif
+
+#include <TcApi.h>
+
+/*
+ * functions used effectively by the pcap library
+ */
+
+pcap_t *
+TcCreate(const char *device, char *ebuf, int *is_ours);
+
+int
+TcFindAllDevs(pcap_if_t **alldevsp, char *errbuf);
+
+HANDLE
+TcGetReceiveWaitHandle(pcap_t *p);
+
+#endif
diff --git a/pcap-win32.c b/pcap-win32.c
index a12b163a..03dcd77e 100644
--- a/pcap-win32.c
+++ b/pcap-win32.c
@@ -52,6 +52,8 @@ int* _errno();
#define errno (*_errno())
#endif /* __MINGW32__ */
+#include "pcap-tc.h"
+
static int pcap_setfilter_win32_npf(pcap_t *, struct bpf_program *);
static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *);
static int pcap_getnonblock_win32(pcap_t *, char *);
@@ -74,8 +76,6 @@ struct pcap_win {
int filtering_in_kernel; /* using kernel filter */
- struct pcap_stat stat; /* need this to count captured packets */
-
#ifdef HAVE_DAG_API
int dag_fcs_bits; /* Number of checksum bits from link layer */
#endif
@@ -182,19 +182,10 @@ pcap_stats_win32(pcap_t *p, struct pcap_stat *ps)
struct pcap_stat *
pcap_stats_ex_win32(pcap_t *p, int *pcap_stat_size)
{
- struct pcap_win *pw = p->priv;
struct bpf_stat bstats;
char errbuf[PCAP_ERRBUF_SIZE+1];
- *pcap_stat_size = sizeof (pw->stat);
-
-#ifdef HAVE_REMOTE
- if (p->rmt_clientside)
- {
- /* We are on an remote capture */
- return pcap_stats_ex_remote(p);
- }
-#endif
+ *pcap_stat_size = sizeof (p->stat);
/*
* Try to get statistics.
@@ -209,11 +200,11 @@ pcap_stats_ex_win32(pcap_t *p, int *pcap_stat_size)
"PacketGetStatsEx error: %s", errbuf);
return NULL;
}
- pw->stat.ps_recv = bstats.bs_recv;
- pw->stat.ps_drop = bstats.bs_drop;
- pw->stat.ps_ifdrop = bstats.ps_ifdrop;
- pw->stat.ps_capt = bstats.bs_capt;
- return (&pw->stat);
+ p->stat.ps_recv = bstats.bs_recv;
+ p->stat.ps_drop = bstats.bs_drop;
+ p->stat.ps_ifdrop = bstats.ps_ifdrop;
+ p->stat.ps_capt = bstats.bs_capt;
+ return (&p->stat);
}
/* Set the dimension of the kernel-level capture buffer */
@@ -256,10 +247,7 @@ pcap_setmintocopy_win32(pcap_t *p, int size)
static HANDLE
pcap_getevent_win32(pcap_t *p)
{
- if (p->TcInstance != NULL)
- return TcGetReceiveWaitHandle(p);
- else
- return PacketGetReadEvent(p->adapter);
+ return PacketGetReadEvent(p->adapter);
}
static int
@@ -539,7 +527,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
break;
/* Increase the number of captured packets */
- pw->stat.ps_recv++;
+ p->stat.ps_recv++;
/* Find the beginning of the packet */
dp = ((u_char *)header) + dag_record_size;
@@ -1157,10 +1145,3 @@ pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf)
pw->nonblock = (newtimeout == -1);
return (0);
}
-
-/*platform-dependent routine to add devices other than NDIS interfaces*/
-int
-pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
-{
- return (0);
-}
diff --git a/pcap.c b/pcap.c
index 164cbbc5..94e1ca68 100644
--- a/pcap.c
+++ b/pcap.c
@@ -80,6 +80,10 @@
#include "pcap-snf.h"
#endif /* HAVE_SNF_API */
+#ifdef HAVE_TC_API
+#include "pcap-tc.h"
+#endif /* HAVE_TC_API */
+
#ifdef PCAP_SUPPORT_USB
#include "pcap-usb-linux.h"
#endif
@@ -352,6 +356,9 @@ struct capture_source_type {
#ifdef HAVE_SNF_API
{ snf_findalldevs, snf_create },
#endif
+#ifdef HAVE_TC_API
+ { TcFindAllDevs, TcCreate },
+#endif
#ifdef PCAP_SUPPORT_BT
{ bt_findalldevs, bt_create },
#endif
diff --git a/pcap/pcap.h b/pcap/pcap.h
index 3c6afe37..0008cb0b 100644
--- a/pcap/pcap.h
+++ b/pcap/pcap.h
@@ -170,13 +170,11 @@ struct pcap_stat {
u_int ps_recv; /* number of packets received */
u_int ps_drop; /* number of packets dropped */
u_int ps_ifdrop; /* drops by interface -- only supported on some platforms */
-#ifdef _WIN32
+#if defined(_WIN32) && defined(HAVE_REMOTE)
u_int ps_capt; /* number of packets that reach the application */
-#ifdef HAVE_REMOTE
u_int ps_sent; /* number of packets sent by the server on the network */
u_int ps_netdrop; /* number of packets lost on the network */
-#endif /* HAVE_REMOTE */
-#endif /* _WIN32 */
+#endif /* _WIN32 && HAVE_REMOTE */
};
#ifdef MSDOS