ada6f083b9
MFC after: 1 month
1285 lines
34 KiB
C
1285 lines
34 KiB
C
/*
|
|
* 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
|