diff options
-rw-r--r-- | Makefile.in | 2 | ||||
-rw-r--r-- | Win32/Prj/libpcap.dsp | 8 | ||||
-rw-r--r-- | config.h.in | 3 | ||||
-rwxr-xr-x | configure | 84 | ||||
-rw-r--r-- | configure.in | 60 | ||||
-rw-r--r-- | gencode.c | 9 | ||||
-rw-r--r-- | pcap-int.h | 4 | ||||
-rw-r--r-- | pcap-tc.c | 1286 | ||||
-rw-r--r-- | pcap-tc.h | 57 | ||||
-rw-r--r-- | pcap-win32.c | 39 | ||||
-rw-r--r-- | pcap.c | 7 | ||||
-rw-r--r-- | pcap/pcap.h | 6 |
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 @@ -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 . @@ -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) @@ -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); -} @@ -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 |