You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1284 lines
34 KiB
1284 lines
34 KiB
/* |
|
* 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, bpf_u_int32 oid, void *data, size_t *lenp); |
|
static int TcOidSetRequest(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp); |
|
static u_int TcSendqueueTransmit(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 PAirpcapHandle 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; |
|
u_char *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 = malloc(sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE); |
|
|
|
if (pt->PpiPacket == NULL) |
|
{ |
|
pcap_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.device, &pt->TcInstance); |
|
|
|
if (status != TC_SUCCESS) |
|
{ |
|
/* Adapter detected but we are not able to open it. Return failure. */ |
|
pcap_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) |
|
{ |
|
pcap_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->opt.timeout == 0) |
|
{ |
|
timeout = 0xFFFFFFFF; |
|
} |
|
else |
|
if (p->opt.timeout < 0) |
|
{ |
|
/* |
|
* we insert a minimal timeout here |
|
*/ |
|
timeout = 10; |
|
} |
|
else |
|
{ |
|
timeout = p->opt.timeout; |
|
} |
|
|
|
status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_READ_TIMEOUT, timeout); |
|
|
|
if (status != TC_SUCCESS) |
|
{ |
|
pcap_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 = TcSendqueueTransmit; |
|
p->setuserbuffer_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]), device) == 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(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) |
|
{ |
|
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
|
"Getting the non blocking status is not available for TurboCap ports"); |
|
pcap_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) |
|
{ |
|
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
|
"Setting the non blocking status is not available for TurboCap ports"); |
|
pcap_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) |
|
{ |
|
pcap_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) |
|
{ |
|
pcap_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) |
|
{ |
|
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); |
|
} |
|
} |
|
else |
|
{ |
|
pcap_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) |
|
{ |
|
pcap_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) |
|
{ |
|
pcap_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) |
|
{ |
|
pcap_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) |
|
{ |
|
pcap_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) |
|
{ |
|
pcap_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) && defined(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) |
|
{ |
|
pcap_snprintf(p->errbuf, sizeof(p->errbuf), |
|
"setfilter, unable to install the filter: %s", pcap_strerror(errno)); |
|
return -1; |
|
} |
|
|
|
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; |
|
|
|
*pcap_stat_size = sizeof (p->stat); |
|
|
|
status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics); |
|
|
|
if (status != TC_SUCCESS) |
|
{ |
|
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status); |
|
return NULL; |
|
} |
|
|
|
memset(&p->stat, 0, sizeof(p->stat)); |
|
|
|
status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter); |
|
if (status != TC_SUCCESS) |
|
{ |
|
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); |
|
return NULL; |
|
} |
|
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) |
|
{ |
|
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); |
|
return NULL; |
|
} |
|
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) |
|
{ |
|
pcap_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) |
|
{ |
|
pcap_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) |
|
{ |
|
pcap_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, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_) |
|
{ |
|
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
|
"An OID get request cannot be performed on a TurboCap device"); |
|
return PCAP_ERROR; |
|
} |
|
|
|
static int |
|
TcOidSetRequest(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, |
|
size_t *lenp _U_) |
|
{ |
|
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
|
"An OID set request cannot be performed on a TurboCap device"); |
|
return PCAP_ERROR; |
|
} |
|
|
|
static u_int |
|
TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_) |
|
{ |
|
pcap_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_) |
|
{ |
|
pcap_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_) |
|
{ |
|
pcap_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_) |
|
{ |
|
pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
|
"Live packet dumping cannot be performed on a TurboCap device"); |
|
return -1; |
|
} |
|
|
|
static PAirpcapHandle |
|
TcGetAirPcapHandle(pcap_t *p _U_) |
|
{ |
|
return NULL; |
|
} |
|
#endif
|
|
|