1335640Shselasky/* 2335640Shselasky * Copyright (c) 2008 CACE Technologies, Davis (California) 3335640Shselasky * All rights reserved. 4335640Shselasky * 5335640Shselasky * Redistribution and use in source and binary forms, with or without 6335640Shselasky * modification, are permitted provided that the following conditions 7335640Shselasky * are met: 8335640Shselasky * 9335640Shselasky * 1. Redistributions of source code must retain the above copyright 10335640Shselasky * notice, this list of conditions and the following disclaimer. 11335640Shselasky * 2. Redistributions in binary form must reproduce the above copyright 12335640Shselasky * notice, this list of conditions and the following disclaimer in the 13335640Shselasky * documentation and/or other materials provided with the distribution. 14335640Shselasky * 3. Neither the name of CACE Technologies nor the names of its 15335640Shselasky * contributors may be used to endorse or promote products derived from 16335640Shselasky * this software without specific prior written permission. 17335640Shselasky * 18335640Shselasky * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19335640Shselasky * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20335640Shselasky * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21335640Shselasky * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22335640Shselasky * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23335640Shselasky * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24335640Shselasky * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25335640Shselasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26335640Shselasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27335640Shselasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28335640Shselasky * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29335640Shselasky * 30335640Shselasky */ 31335640Shselasky 32335640Shselasky#ifdef HAVE_CONFIG_H 33335640Shselasky#include <config.h> 34335640Shselasky#endif 35335640Shselasky 36335640Shselasky#include <pcap.h> 37335640Shselasky#include <pcap-int.h> 38335640Shselasky 39335640Shselasky#include "pcap-tc.h" 40335640Shselasky 41335640Shselasky#include <malloc.h> 42335640Shselasky#include <memory.h> 43335640Shselasky#include <string.h> 44335640Shselasky#include <errno.h> 45335640Shselasky 46335640Shselasky#ifdef _WIN32 47335640Shselasky#include <tchar.h> 48335640Shselasky#endif 49335640Shselasky 50335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnQueryPortList) (PTC_PORT *ppPorts, PULONG pLength); 51335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnFreePortList) (TC_PORT *pPorts); 52335640Shselasky 53335640Shselaskytypedef PCHAR (TC_CALLCONV *TcFcnStatusGetString) (TC_STATUS status); 54335640Shselasky 55335640Shselaskytypedef PCHAR (TC_CALLCONV *TcFcnPortGetName) (TC_PORT port); 56335640Shselaskytypedef PCHAR (TC_CALLCONV *TcFcnPortGetDescription) (TC_PORT port); 57335640Shselasky 58335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnInstanceOpenByName) (PCHAR name, PTC_INSTANCE pInstance); 59335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnInstanceClose) (TC_INSTANCE instance); 60335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnInstanceSetFeature) (TC_INSTANCE instance, ULONG feature, ULONG value); 61335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnInstanceQueryFeature) (TC_INSTANCE instance, ULONG feature, PULONG pValue); 62335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnInstanceReceivePackets) (TC_INSTANCE instance, PTC_PACKETS_BUFFER pBuffer); 63335640Shselaskytypedef HANDLE (TC_CALLCONV *TcFcnInstanceGetReceiveWaitHandle) (TC_INSTANCE instance); 64335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnInstanceTransmitPackets) (TC_INSTANCE instance, TC_PACKETS_BUFFER pBuffer); 65335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnInstanceQueryStatistics) (TC_INSTANCE instance, PTC_STATISTICS pStatistics); 66335640Shselasky 67335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferCreate) (ULONG size, PTC_PACKETS_BUFFER pBuffer); 68335640Shselaskytypedef VOID (TC_CALLCONV *TcFcnPacketsBufferDestroy) (TC_PACKETS_BUFFER buffer); 69335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferQueryNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID *ppData); 70335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferCommitNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID pData); 71335640Shselasky 72335640Shselaskytypedef VOID (TC_CALLCONV *TcFcnStatisticsDestroy) (TC_STATISTICS statistics); 73335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnStatisticsUpdate) (TC_STATISTICS statistics); 74335640Shselaskytypedef TC_STATUS (TC_CALLCONV *TcFcnStatisticsQueryValue) (TC_STATISTICS statistics, ULONG counterId, PULONGLONG pValue); 75335640Shselasky 76335640Shselaskytypedef enum LONG 77335640Shselasky{ 78335640Shselasky TC_API_UNLOADED = 0, 79335640Shselasky TC_API_LOADED, 80335640Shselasky TC_API_CANNOT_LOAD, 81335640Shselasky TC_API_LOADING 82335640Shselasky} 83335640Shselasky TC_API_LOAD_STATUS; 84335640Shselasky 85335640Shselasky 86335640Shselaskytypedef struct _TC_FUNCTIONS 87335640Shselasky{ 88335640Shselasky TC_API_LOAD_STATUS LoadStatus; 89335640Shselasky#ifdef _WIN32 90335640Shselasky HMODULE hTcApiDllHandle; 91335640Shselasky#endif 92335640Shselasky TcFcnQueryPortList QueryPortList; 93335640Shselasky TcFcnFreePortList FreePortList; 94335640Shselasky TcFcnStatusGetString StatusGetString; 95335640Shselasky 96335640Shselasky TcFcnPortGetName PortGetName; 97335640Shselasky TcFcnPortGetDescription PortGetDescription; 98335640Shselasky 99335640Shselasky TcFcnInstanceOpenByName InstanceOpenByName; 100335640Shselasky TcFcnInstanceClose InstanceClose; 101335640Shselasky TcFcnInstanceSetFeature InstanceSetFeature; 102335640Shselasky TcFcnInstanceQueryFeature InstanceQueryFeature; 103335640Shselasky TcFcnInstanceReceivePackets InstanceReceivePackets; 104335640Shselasky#ifdef _WIN32 105335640Shselasky TcFcnInstanceGetReceiveWaitHandle InstanceGetReceiveWaitHandle; 106335640Shselasky#endif 107335640Shselasky TcFcnInstanceTransmitPackets InstanceTransmitPackets; 108335640Shselasky TcFcnInstanceQueryStatistics InstanceQueryStatistics; 109335640Shselasky 110335640Shselasky TcFcnPacketsBufferCreate PacketsBufferCreate; 111335640Shselasky TcFcnPacketsBufferDestroy PacketsBufferDestroy; 112335640Shselasky TcFcnPacketsBufferQueryNextPacket PacketsBufferQueryNextPacket; 113335640Shselasky TcFcnPacketsBufferCommitNextPacket PacketsBufferCommitNextPacket; 114335640Shselasky 115335640Shselasky TcFcnStatisticsDestroy StatisticsDestroy; 116335640Shselasky TcFcnStatisticsUpdate StatisticsUpdate; 117335640Shselasky TcFcnStatisticsQueryValue StatisticsQueryValue; 118335640Shselasky} 119335640Shselasky TC_FUNCTIONS; 120335640Shselasky 121335640Shselaskystatic pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port); 122335640Shselaskystatic int TcSetDatalink(pcap_t *p, int dlt); 123335640Shselaskystatic int TcGetNonBlock(pcap_t *p); 124335640Shselaskystatic int TcSetNonBlock(pcap_t *p, int nonblock); 125335640Shselaskystatic void TcCleanup(pcap_t *p); 126356341Scystatic int TcInject(pcap_t *p, const void *buf, int size); 127335640Shselaskystatic int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user); 128335640Shselaskystatic int TcStats(pcap_t *p, struct pcap_stat *ps); 129335640Shselaskystatic int TcSetFilter(pcap_t *p, struct bpf_program *fp); 130335640Shselasky#ifdef _WIN32 131335640Shselaskystatic struct pcap_stat *TcStatsEx(pcap_t *p, int *pcap_stat_size); 132335640Shselaskystatic int TcSetBuff(pcap_t *p, int dim); 133335640Shselaskystatic int TcSetMode(pcap_t *p, int mode); 134335640Shselaskystatic int TcSetMinToCopy(pcap_t *p, int size); 135335640Shselaskystatic HANDLE TcGetReceiveWaitHandle(pcap_t *p); 136335640Shselaskystatic int TcOidGetRequest(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp); 137335640Shselaskystatic int TcOidSetRequest(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp); 138335640Shselaskystatic u_int TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue, int sync); 139335640Shselaskystatic int TcSetUserBuffer(pcap_t *p, int size); 140335640Shselaskystatic int TcLiveDump(pcap_t *p, char *filename, int maxsize, int maxpacks); 141335640Shselaskystatic int TcLiveDumpEnded(pcap_t *p, int sync); 142335640Shselaskystatic PAirpcapHandle TcGetAirPcapHandle(pcap_t *p); 143335640Shselasky#endif 144335640Shselasky 145335640Shselasky#ifdef _WIN32 146335640ShselaskyTC_FUNCTIONS g_TcFunctions = 147335640Shselasky{ 148335640Shselasky TC_API_UNLOADED, /* LoadStatus */ 149335640Shselasky NULL, /* hTcApiDllHandle */ 150335640Shselasky NULL, /* QueryPortList */ 151335640Shselasky NULL, /* FreePortList */ 152335640Shselasky NULL, /* StatusGetString */ 153335640Shselasky NULL, /* PortGetName */ 154335640Shselasky NULL, /* PortGetDescription */ 155335640Shselasky NULL, /* InstanceOpenByName */ 156335640Shselasky NULL, /* InstanceClose */ 157335640Shselasky NULL, /* InstanceSetFeature */ 158335640Shselasky NULL, /* InstanceQueryFeature */ 159335640Shselasky NULL, /* InstanceReceivePackets */ 160335640Shselasky NULL, /* InstanceGetReceiveWaitHandle */ 161335640Shselasky NULL, /* InstanceTransmitPackets */ 162335640Shselasky NULL, /* InstanceQueryStatistics */ 163335640Shselasky NULL, /* PacketsBufferCreate */ 164335640Shselasky NULL, /* PacketsBufferDestroy */ 165335640Shselasky NULL, /* PacketsBufferQueryNextPacket */ 166335640Shselasky NULL, /* PacketsBufferCommitNextPacket */ 167335640Shselasky NULL, /* StatisticsDestroy */ 168335640Shselasky NULL, /* StatisticsUpdate */ 169335640Shselasky NULL /* StatisticsQueryValue */ 170335640Shselasky}; 171335640Shselasky#else 172335640ShselaskyTC_FUNCTIONS g_TcFunctions = 173335640Shselasky{ 174335640Shselasky TC_API_LOADED, /* LoadStatus */ 175335640Shselasky TcQueryPortList, 176335640Shselasky TcFreePortList, 177335640Shselasky TcStatusGetString, 178335640Shselasky TcPortGetName, 179335640Shselasky TcPortGetDescription, 180335640Shselasky TcInstanceOpenByName, 181335640Shselasky TcInstanceClose, 182335640Shselasky TcInstanceSetFeature, 183335640Shselasky TcInstanceQueryFeature, 184335640Shselasky TcInstanceReceivePackets, 185335640Shselasky#ifdef _WIN32 186335640Shselasky TcInstanceGetReceiveWaitHandle, 187335640Shselasky#endif 188335640Shselasky TcInstanceTransmitPackets, 189335640Shselasky TcInstanceQueryStatistics, 190335640Shselasky TcPacketsBufferCreate, 191335640Shselasky TcPacketsBufferDestroy, 192335640Shselasky TcPacketsBufferQueryNextPacket, 193335640Shselasky TcPacketsBufferCommitNextPacket, 194335640Shselasky TcStatisticsDestroy, 195335640Shselasky TcStatisticsUpdate, 196335640Shselasky TcStatisticsQueryValue, 197335640Shselasky}; 198335640Shselasky#endif 199335640Shselasky 200335640Shselasky#define MAX_TC_PACKET_SIZE 9500 201335640Shselasky 202335640Shselasky#pragma pack(push, 1) 203335640Shselasky 204335640Shselasky#define PPH_PH_FLAG_PADDING ((UCHAR)0x01) 205335640Shselasky#define PPH_PH_VERSION ((UCHAR)0x00) 206335640Shselasky 207335640Shselaskytypedef struct _PPI_PACKET_HEADER 208335640Shselasky{ 209335640Shselasky UCHAR PphVersion; 210335640Shselasky UCHAR PphFlags; 211335640Shselasky USHORT PphLength; 212335640Shselasky ULONG PphDlt; 213335640Shselasky} 214335640Shselasky PPI_PACKET_HEADER, *PPPI_PACKET_HEADER; 215335640Shselasky 216335640Shselaskytypedef struct _PPI_FIELD_HEADER 217335640Shselasky{ 218335640Shselasky USHORT PfhType; 219335640Shselasky USHORT PfhLength; 220335640Shselasky} 221335640Shselasky PPI_FIELD_HEADER, *PPPI_FIELD_HEADER; 222335640Shselasky 223335640Shselasky 224335640Shselasky#define PPI_FIELD_TYPE_AGGREGATION_EXTENSION ((UCHAR)0x08) 225335640Shselasky 226335640Shselaskytypedef struct _PPI_FIELD_AGGREGATION_EXTENSION 227335640Shselasky{ 228335640Shselasky ULONG InterfaceId; 229335640Shselasky} 230335640Shselasky PPI_FIELD_AGGREGATION_EXTENSION, *PPPI_FIELD_AGGREGATION_EXTENSION; 231335640Shselasky 232335640Shselasky 233335640Shselasky#define PPI_FIELD_TYPE_802_3_EXTENSION ((UCHAR)0x09) 234335640Shselasky 235335640Shselasky#define PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT ((ULONG)0x00000001) 236335640Shselasky 237335640Shselaskytypedef struct _PPI_FIELD_802_3_EXTENSION 238335640Shselasky{ 239335640Shselasky ULONG Flags; 240335640Shselasky ULONG Errors; 241335640Shselasky} 242335640Shselasky PPI_FIELD_802_3_EXTENSION, *PPPI_FIELD_802_3_EXTENSION; 243335640Shselasky 244335640Shselaskytypedef struct _PPI_HEADER 245335640Shselasky{ 246335640Shselasky PPI_PACKET_HEADER PacketHeader; 247335640Shselasky PPI_FIELD_HEADER AggregationFieldHeader; 248335640Shselasky PPI_FIELD_AGGREGATION_EXTENSION AggregationField; 249335640Shselasky PPI_FIELD_HEADER Dot3FieldHeader; 250335640Shselasky PPI_FIELD_802_3_EXTENSION Dot3Field; 251335640Shselasky} 252335640Shselasky PPI_HEADER, *PPPI_HEADER; 253335640Shselasky#pragma pack(pop) 254335640Shselasky 255335640Shselasky#ifdef _WIN32 256335640Shselasky// 257335640Shselasky// This wrapper around loadlibrary appends the system folder (usually c:\windows\system32) 258335640Shselasky// to the relative path of the DLL, so that the DLL is always loaded from an absolute path 259335640Shselasky// (It's no longer possible to load airpcap.dll from the application folder). 260335640Shselasky// This solves the DLL Hijacking issue discovered in August 2010 261335640Shselasky// http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html 262335640Shselasky// 263335640ShselaskyHMODULE LoadLibrarySafe(LPCTSTR lpFileName) 264335640Shselasky{ 265335640Shselasky TCHAR path[MAX_PATH]; 266335640Shselasky TCHAR fullFileName[MAX_PATH]; 267335640Shselasky UINT res; 268335640Shselasky HMODULE hModule = NULL; 269335640Shselasky do 270335640Shselasky { 271335640Shselasky res = GetSystemDirectory(path, MAX_PATH); 272335640Shselasky 273335640Shselasky if (res == 0) 274335640Shselasky { 275335640Shselasky // 276335640Shselasky // some bad failure occurred; 277335640Shselasky // 278335640Shselasky break; 279335640Shselasky } 280335640Shselasky 281335640Shselasky if (res > MAX_PATH) 282335640Shselasky { 283335640Shselasky // 284335640Shselasky // the buffer was not big enough 285335640Shselasky // 286335640Shselasky SetLastError(ERROR_INSUFFICIENT_BUFFER); 287335640Shselasky break; 288335640Shselasky } 289335640Shselasky 290335640Shselasky if (res + 1 + _tcslen(lpFileName) + 1 < MAX_PATH) 291335640Shselasky { 292335640Shselasky memcpy(fullFileName, path, res * sizeof(TCHAR)); 293335640Shselasky fullFileName[res] = _T('\\'); 294335640Shselasky memcpy(&fullFileName[res + 1], lpFileName, (_tcslen(lpFileName) + 1) * sizeof(TCHAR)); 295335640Shselasky 296335640Shselasky hModule = LoadLibrary(fullFileName); 297335640Shselasky } 298335640Shselasky else 299335640Shselasky { 300335640Shselasky SetLastError(ERROR_INSUFFICIENT_BUFFER); 301335640Shselasky } 302335640Shselasky 303335640Shselasky }while(FALSE); 304335640Shselasky 305335640Shselasky return hModule; 306335640Shselasky} 307335640Shselasky 308335640Shselasky/* 309335640Shselasky * NOTE: this function should be called by the pcap functions that can theoretically 310335640Shselasky * deal with the Tc library for the first time, namely listing the adapters and 311335640Shselasky * opening one. All the other ones (close, read, write, set parameters) work 312335640Shselasky * on an open instance of TC, so we do not care to call this function 313335640Shselasky */ 314335640ShselaskyTC_API_LOAD_STATUS LoadTcFunctions(void) 315335640Shselasky{ 316335640Shselasky TC_API_LOAD_STATUS currentStatus; 317335640Shselasky 318335640Shselasky do 319335640Shselasky { 320335640Shselasky currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_UNLOADED); 321335640Shselasky 322335640Shselasky while(currentStatus == TC_API_LOADING) 323335640Shselasky { 324335640Shselasky currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_LOADING); 325335640Shselasky Sleep(10); 326335640Shselasky } 327335640Shselasky 328335640Shselasky /* 329335640Shselasky * at this point we are either in the LOADED state, unloaded state (i.e. we are the ones loading everything) 330335640Shselasky * or in cannot load 331335640Shselasky */ 332335640Shselasky if(currentStatus == TC_API_LOADED) 333335640Shselasky { 334335640Shselasky return TC_API_LOADED; 335335640Shselasky } 336335640Shselasky 337335640Shselasky if (currentStatus == TC_API_CANNOT_LOAD) 338335640Shselasky { 339335640Shselasky return TC_API_CANNOT_LOAD; 340335640Shselasky } 341335640Shselasky 342335640Shselasky currentStatus = TC_API_CANNOT_LOAD; 343335640Shselasky 344335640Shselasky g_TcFunctions.hTcApiDllHandle = LoadLibrarySafe("TcApi.dll"); 345335640Shselasky if (g_TcFunctions.hTcApiDllHandle == NULL) break; 346335640Shselasky 347335640Shselasky g_TcFunctions.QueryPortList = (TcFcnQueryPortList) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList"); 348335640Shselasky g_TcFunctions.FreePortList = (TcFcnFreePortList) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcFreePortList"); 349335640Shselasky 350335640Shselasky g_TcFunctions.StatusGetString = (TcFcnStatusGetString) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString"); 351335640Shselasky 352335640Shselasky g_TcFunctions.PortGetName = (TcFcnPortGetName) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetName"); 353335640Shselasky g_TcFunctions.PortGetDescription = (TcFcnPortGetDescription) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription"); 354335640Shselasky 355335640Shselasky g_TcFunctions.InstanceOpenByName = (TcFcnInstanceOpenByName) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName"); 356335640Shselasky g_TcFunctions.InstanceClose = (TcFcnInstanceClose) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose"); 357335640Shselasky g_TcFunctions.InstanceSetFeature = (TcFcnInstanceSetFeature) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature"); 358335640Shselasky g_TcFunctions.InstanceQueryFeature = (TcFcnInstanceQueryFeature) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature"); 359335640Shselasky g_TcFunctions.InstanceReceivePackets = (TcFcnInstanceReceivePackets) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets"); 360335640Shselasky g_TcFunctions.InstanceGetReceiveWaitHandle = (TcFcnInstanceGetReceiveWaitHandle)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle"); 361335640Shselasky g_TcFunctions.InstanceTransmitPackets = (TcFcnInstanceTransmitPackets)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets"); 362335640Shselasky g_TcFunctions.InstanceQueryStatistics = (TcFcnInstanceQueryStatistics)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics"); 363335640Shselasky 364335640Shselasky g_TcFunctions.PacketsBufferCreate = (TcFcnPacketsBufferCreate) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate"); 365335640Shselasky g_TcFunctions.PacketsBufferDestroy = (TcFcnPacketsBufferDestroy) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy"); 366335640Shselasky g_TcFunctions.PacketsBufferQueryNextPacket = (TcFcnPacketsBufferQueryNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket"); 367335640Shselasky g_TcFunctions.PacketsBufferCommitNextPacket = (TcFcnPacketsBufferCommitNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket"); 368335640Shselasky 369335640Shselasky g_TcFunctions.StatisticsDestroy = (TcFcnStatisticsDestroy) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy"); 370335640Shselasky g_TcFunctions.StatisticsUpdate = (TcFcnStatisticsUpdate) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate"); 371335640Shselasky g_TcFunctions.StatisticsQueryValue = (TcFcnStatisticsQueryValue) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue"); 372335640Shselasky 373335640Shselasky if ( g_TcFunctions.QueryPortList == NULL 374335640Shselasky || g_TcFunctions.FreePortList == NULL 375335640Shselasky || g_TcFunctions.StatusGetString == NULL 376335640Shselasky || g_TcFunctions.PortGetName == NULL 377335640Shselasky || g_TcFunctions.PortGetDescription == NULL 378335640Shselasky || g_TcFunctions.InstanceOpenByName == NULL 379335640Shselasky || g_TcFunctions.InstanceClose == NULL 380335640Shselasky || g_TcFunctions.InstanceSetFeature == NULL 381335640Shselasky || g_TcFunctions.InstanceQueryFeature == NULL 382335640Shselasky || g_TcFunctions.InstanceReceivePackets == NULL 383335640Shselasky || g_TcFunctions.InstanceGetReceiveWaitHandle == NULL 384335640Shselasky || g_TcFunctions.InstanceTransmitPackets == NULL 385335640Shselasky || g_TcFunctions.InstanceQueryStatistics == NULL 386335640Shselasky || g_TcFunctions.PacketsBufferCreate == NULL 387335640Shselasky || g_TcFunctions.PacketsBufferDestroy == NULL 388335640Shselasky || g_TcFunctions.PacketsBufferQueryNextPacket == NULL 389335640Shselasky || g_TcFunctions.PacketsBufferCommitNextPacket == NULL 390335640Shselasky || g_TcFunctions.StatisticsDestroy == NULL 391335640Shselasky || g_TcFunctions.StatisticsUpdate == NULL 392335640Shselasky || g_TcFunctions.StatisticsQueryValue == NULL 393335640Shselasky ) 394335640Shselasky { 395335640Shselasky break; 396335640Shselasky } 397335640Shselasky 398335640Shselasky /* 399335640Shselasky * everything got loaded, yay!! 400335640Shselasky */ 401335640Shselasky currentStatus = TC_API_LOADED; 402335640Shselasky }while(FALSE); 403335640Shselasky 404335640Shselasky if (currentStatus != TC_API_LOADED) 405335640Shselasky { 406335640Shselasky if (g_TcFunctions.hTcApiDllHandle != NULL) 407335640Shselasky { 408335640Shselasky FreeLibrary(g_TcFunctions.hTcApiDllHandle); 409335640Shselasky g_TcFunctions.hTcApiDllHandle = NULL; 410335640Shselasky } 411335640Shselasky } 412335640Shselasky 413335640Shselasky InterlockedExchange((LONG*)&g_TcFunctions.LoadStatus, currentStatus); 414335640Shselasky 415335640Shselasky return currentStatus; 416335640Shselasky} 417335640Shselasky#else 418335640Shselasky// static linking 419335640ShselaskyTC_API_LOAD_STATUS LoadTcFunctions(void) 420335640Shselasky{ 421335640Shselasky return TC_API_LOADED; 422335640Shselasky} 423335640Shselasky#endif 424335640Shselasky 425335640Shselasky/* 426335640Shselasky * Private data for capturing on TurboCap devices. 427335640Shselasky */ 428335640Shselaskystruct pcap_tc { 429335640Shselasky TC_INSTANCE TcInstance; 430335640Shselasky TC_PACKETS_BUFFER TcPacketsBuffer; 431335640Shselasky ULONG TcAcceptedCount; 432335640Shselasky u_char *PpiPacket; 433335640Shselasky}; 434335640Shselasky 435335640Shselaskyint 436335640ShselaskyTcFindAllDevs(pcap_if_list_t *devlist, char *errbuf) 437335640Shselasky{ 438335640Shselasky TC_API_LOAD_STATUS loadStatus; 439335640Shselasky ULONG numPorts; 440335640Shselasky PTC_PORT pPorts = NULL; 441335640Shselasky TC_STATUS status; 442335640Shselasky int result = 0; 443356341Scy pcap_if_t *dev; 444335640Shselasky ULONG i; 445335640Shselasky 446335640Shselasky do 447335640Shselasky { 448335640Shselasky loadStatus = LoadTcFunctions(); 449335640Shselasky 450335640Shselasky if (loadStatus != TC_API_LOADED) 451335640Shselasky { 452335640Shselasky result = 0; 453335640Shselasky break; 454335640Shselasky } 455335640Shselasky 456335640Shselasky /* 457335640Shselasky * enumerate the ports, and add them to the list 458335640Shselasky */ 459335640Shselasky status = g_TcFunctions.QueryPortList(&pPorts, &numPorts); 460335640Shselasky 461335640Shselasky if (status != TC_SUCCESS) 462335640Shselasky { 463335640Shselasky result = 0; 464335640Shselasky break; 465335640Shselasky } 466335640Shselasky 467335640Shselasky for (i = 0; i < numPorts; i++) 468335640Shselasky { 469335640Shselasky /* 470335640Shselasky * transform the port into an entry in the list 471335640Shselasky */ 472335640Shselasky dev = TcCreatePcapIfFromPort(pPorts[i]); 473335640Shselasky 474335640Shselasky if (dev != NULL) 475356341Scy add_dev(devlist, dev->name, dev->flags, dev->description, errbuf); 476335640Shselasky } 477335640Shselasky 478335640Shselasky if (numPorts > 0) 479335640Shselasky { 480335640Shselasky /* 481335640Shselasky * ignore the result here 482335640Shselasky */ 483335640Shselasky status = g_TcFunctions.FreePortList(pPorts); 484335640Shselasky } 485335640Shselasky 486335640Shselasky }while(FALSE); 487335640Shselasky 488335640Shselasky return result; 489335640Shselasky} 490335640Shselasky 491335640Shselaskystatic pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port) 492335640Shselasky{ 493335640Shselasky CHAR *name; 494335640Shselasky CHAR *description; 495335640Shselasky pcap_if_t *newIf = NULL; 496335640Shselasky 497335640Shselasky newIf = (pcap_if_t*)malloc(sizeof(*newIf)); 498335640Shselasky if (newIf == NULL) 499335640Shselasky { 500335640Shselasky return NULL; 501335640Shselasky } 502335640Shselasky 503335640Shselasky memset(newIf, 0, sizeof(*newIf)); 504335640Shselasky 505335640Shselasky name = g_TcFunctions.PortGetName(port); 506335640Shselasky description = g_TcFunctions.PortGetDescription(port); 507335640Shselasky 508335640Shselasky newIf->name = (char*)malloc(strlen(name) + 1); 509335640Shselasky if (newIf->name == NULL) 510335640Shselasky { 511335640Shselasky free(newIf); 512335640Shselasky return NULL; 513335640Shselasky } 514335640Shselasky 515335640Shselasky newIf->description = (char*)malloc(strlen(description) + 1); 516335640Shselasky if (newIf->description == NULL) 517335640Shselasky { 518335640Shselasky free(newIf->name); 519335640Shselasky free(newIf); 520335640Shselasky return NULL; 521335640Shselasky } 522335640Shselasky 523335640Shselasky strcpy(newIf->name, name); 524335640Shselasky strcpy(newIf->description, description); 525335640Shselasky 526335640Shselasky newIf->addresses = NULL; 527335640Shselasky newIf->next = NULL; 528335640Shselasky newIf->flags = 0; 529335640Shselasky 530335640Shselasky return newIf; 531335640Shselasky 532335640Shselasky} 533335640Shselasky 534335640Shselaskystatic int 535335640ShselaskyTcActivate(pcap_t *p) 536335640Shselasky{ 537335640Shselasky struct pcap_tc *pt = p->priv; 538335640Shselasky TC_STATUS status; 539335640Shselasky ULONG timeout; 540335640Shselasky PPPI_HEADER pPpiHeader; 541335640Shselasky 542335640Shselasky if (p->opt.rfmon) 543335640Shselasky { 544335640Shselasky /* 545335640Shselasky * No monitor mode on Tc cards; they're Ethernet 546335640Shselasky * capture adapters. 547335640Shselasky */ 548335640Shselasky return PCAP_ERROR_RFMON_NOTSUP; 549335640Shselasky } 550335640Shselasky 551335640Shselasky pt->PpiPacket = malloc(sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE); 552335640Shselasky 553335640Shselasky if (pt->PpiPacket == NULL) 554335640Shselasky { 555335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory"); 556335640Shselasky return PCAP_ERROR; 557335640Shselasky } 558335640Shselasky 559335640Shselasky /* 560335640Shselasky * Turn a negative snapshot value (invalid), a snapshot value of 561335640Shselasky * 0 (unspecified), or a value bigger than the normal maximum 562335640Shselasky * value, into the maximum allowed value. 563335640Shselasky * 564335640Shselasky * If some application really *needs* a bigger snapshot 565335640Shselasky * length, we should just increase MAXIMUM_SNAPLEN. 566335640Shselasky */ 567335640Shselasky if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) 568335640Shselasky p->snapshot = MAXIMUM_SNAPLEN; 569335640Shselasky 570335640Shselasky /* 571335640Shselasky * Initialize the PPI fixed fields 572335640Shselasky */ 573335640Shselasky pPpiHeader = (PPPI_HEADER)pt->PpiPacket; 574335640Shselasky pPpiHeader->PacketHeader.PphDlt = DLT_EN10MB; 575335640Shselasky pPpiHeader->PacketHeader.PphLength = sizeof(PPI_HEADER); 576335640Shselasky pPpiHeader->PacketHeader.PphFlags = 0; 577335640Shselasky pPpiHeader->PacketHeader.PphVersion = 0; 578335640Shselasky 579335640Shselasky pPpiHeader->AggregationFieldHeader.PfhLength = sizeof(PPI_FIELD_AGGREGATION_EXTENSION); 580335640Shselasky pPpiHeader->AggregationFieldHeader.PfhType = PPI_FIELD_TYPE_AGGREGATION_EXTENSION; 581335640Shselasky 582335640Shselasky pPpiHeader->Dot3FieldHeader.PfhLength = sizeof(PPI_FIELD_802_3_EXTENSION); 583335640Shselasky pPpiHeader->Dot3FieldHeader.PfhType = PPI_FIELD_TYPE_802_3_EXTENSION; 584335640Shselasky 585335640Shselasky status = g_TcFunctions.InstanceOpenByName(p->opt.device, &pt->TcInstance); 586335640Shselasky 587335640Shselasky if (status != TC_SUCCESS) 588335640Shselasky { 589335640Shselasky /* Adapter detected but we are not able to open it. Return failure. */ 590335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status)); 591335640Shselasky return PCAP_ERROR; 592335640Shselasky } 593335640Shselasky 594335640Shselasky p->linktype = DLT_EN10MB; 595335640Shselasky p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 596335640Shselasky /* 597335640Shselasky * If that fails, just leave the list empty. 598335640Shselasky */ 599335640Shselasky if (p->dlt_list != NULL) { 600335640Shselasky p->dlt_list[0] = DLT_EN10MB; 601335640Shselasky p->dlt_list[1] = DLT_PPI; 602335640Shselasky p->dlt_count = 2; 603335640Shselasky } 604335640Shselasky 605335640Shselasky /* 606335640Shselasky * ignore promiscuous mode 607335640Shselasky * p->opt.promisc 608335640Shselasky */ 609335640Shselasky 610335640Shselasky 611335640Shselasky /* 612335640Shselasky * ignore all the buffer sizes 613335640Shselasky */ 614335640Shselasky 615335640Shselasky /* 616335640Shselasky * enable reception 617335640Shselasky */ 618335640Shselasky status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_RX_STATUS, 1); 619335640Shselasky 620335640Shselasky if (status != TC_SUCCESS) 621335640Shselasky { 622335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status)); 623335640Shselasky goto bad; 624335640Shselasky } 625335640Shselasky 626335640Shselasky /* 627335640Shselasky * enable transmission 628335640Shselasky */ 629335640Shselasky status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_TX_STATUS, 1); 630335640Shselasky /* 631335640Shselasky * Ignore the error here. 632335640Shselasky */ 633335640Shselasky 634335640Shselasky p->inject_op = TcInject; 635335640Shselasky /* 636335640Shselasky * if the timeout is -1, it means immediate return, no timeout 637335640Shselasky * if the timeout is 0, it means INFINITE 638335640Shselasky */ 639335640Shselasky 640335640Shselasky if (p->opt.timeout == 0) 641335640Shselasky { 642335640Shselasky timeout = 0xFFFFFFFF; 643335640Shselasky } 644335640Shselasky else 645335640Shselasky if (p->opt.timeout < 0) 646335640Shselasky { 647335640Shselasky /* 648335640Shselasky * we insert a minimal timeout here 649335640Shselasky */ 650335640Shselasky timeout = 10; 651335640Shselasky } 652335640Shselasky else 653335640Shselasky { 654335640Shselasky timeout = p->opt.timeout; 655335640Shselasky } 656335640Shselasky 657335640Shselasky status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_READ_TIMEOUT, timeout); 658335640Shselasky 659335640Shselasky if (status != TC_SUCCESS) 660335640Shselasky { 661335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status)); 662335640Shselasky goto bad; 663335640Shselasky } 664335640Shselasky 665335640Shselasky p->read_op = TcRead; 666335640Shselasky p->setfilter_op = TcSetFilter; 667335640Shselasky p->setdirection_op = NULL; /* Not implemented. */ 668335640Shselasky p->set_datalink_op = TcSetDatalink; 669335640Shselasky p->getnonblock_op = TcGetNonBlock; 670335640Shselasky p->setnonblock_op = TcSetNonBlock; 671335640Shselasky p->stats_op = TcStats; 672335640Shselasky#ifdef _WIN32 673335640Shselasky p->stats_ex_op = TcStatsEx; 674335640Shselasky p->setbuff_op = TcSetBuff; 675335640Shselasky p->setmode_op = TcSetMode; 676335640Shselasky p->setmintocopy_op = TcSetMinToCopy; 677335640Shselasky p->getevent_op = TcGetReceiveWaitHandle; 678335640Shselasky p->oid_get_request_op = TcOidGetRequest; 679335640Shselasky p->oid_set_request_op = TcOidSetRequest; 680335640Shselasky p->sendqueue_transmit_op = TcSendqueueTransmit; 681335640Shselasky p->setuserbuffer_op = TcSetUserBuffer; 682335640Shselasky p->live_dump_op = TcLiveDump; 683335640Shselasky p->live_dump_ended_op = TcLiveDumpEnded; 684335640Shselasky p->get_airpcap_handle_op = TcGetAirPcapHandle; 685335640Shselasky#else 686335640Shselasky p->selectable_fd = -1; 687335640Shselasky#endif 688335640Shselasky 689335640Shselasky p->cleanup_op = TcCleanup; 690335640Shselasky 691335640Shselasky return 0; 692335640Shselaskybad: 693335640Shselasky TcCleanup(p); 694335640Shselasky return PCAP_ERROR; 695335640Shselasky} 696335640Shselasky 697335640Shselaskypcap_t * 698335640ShselaskyTcCreate(const char *device, char *ebuf, int *is_ours) 699335640Shselasky{ 700335640Shselasky ULONG numPorts; 701335640Shselasky PTC_PORT pPorts = NULL; 702335640Shselasky TC_STATUS status; 703335640Shselasky int is_tc; 704335640Shselasky ULONG i; 705335640Shselasky pcap_t *p; 706335640Shselasky 707335640Shselasky if (LoadTcFunctions() != TC_API_LOADED) 708335640Shselasky { 709335640Shselasky /* 710335640Shselasky * XXX - report this as an error rather than as 711335640Shselasky * "not a TurboCap device"? 712335640Shselasky */ 713335640Shselasky *is_ours = 0; 714335640Shselasky return NULL; 715335640Shselasky } 716335640Shselasky 717335640Shselasky /* 718335640Shselasky * enumerate the ports, and add them to the list 719335640Shselasky */ 720335640Shselasky status = g_TcFunctions.QueryPortList(&pPorts, &numPorts); 721335640Shselasky 722335640Shselasky if (status != TC_SUCCESS) 723335640Shselasky { 724335640Shselasky /* 725335640Shselasky * XXX - report this as an error rather than as 726335640Shselasky * "not a TurboCap device"? 727335640Shselasky */ 728335640Shselasky *is_ours = 0; 729335640Shselasky return NULL; 730335640Shselasky } 731335640Shselasky 732335640Shselasky is_tc = FALSE; 733335640Shselasky for (i = 0; i < numPorts; i++) 734335640Shselasky { 735335640Shselasky if (strcmp(g_TcFunctions.PortGetName(pPorts[i]), device) == 0) 736335640Shselasky { 737335640Shselasky is_tc = TRUE; 738335640Shselasky break; 739335640Shselasky } 740335640Shselasky } 741335640Shselasky 742335640Shselasky if (numPorts > 0) 743335640Shselasky { 744335640Shselasky /* 745335640Shselasky * ignore the result here 746335640Shselasky */ 747335640Shselasky (void)g_TcFunctions.FreePortList(pPorts); 748335640Shselasky } 749335640Shselasky 750335640Shselasky if (!is_tc) 751335640Shselasky { 752335640Shselasky *is_ours = 0; 753335640Shselasky return NULL; 754335640Shselasky } 755335640Shselasky 756335640Shselasky /* OK, it's probably ours. */ 757335640Shselasky *is_ours = 1; 758335640Shselasky 759335640Shselasky p = pcap_create_common(ebuf, sizeof (struct pcap_tc)); 760335640Shselasky if (p == NULL) 761335640Shselasky return NULL; 762335640Shselasky 763335640Shselasky p->activate_op = TcActivate; 764335640Shselasky /* 765335640Shselasky * Set these up front, so that, even if our client tries 766335640Shselasky * to set non-blocking mode before we're activated, or 767335640Shselasky * query the state of non-blocking mode, they get an error, 768335640Shselasky * rather than having the non-blocking mode option set 769335640Shselasky * for use later. 770335640Shselasky */ 771335640Shselasky p->getnonblock_op = TcGetNonBlock; 772335640Shselasky p->setnonblock_op = TcSetNonBlock; 773335640Shselasky return p; 774335640Shselasky} 775335640Shselasky 776335640Shselaskystatic int TcSetDatalink(pcap_t *p, int dlt) 777335640Shselasky{ 778335640Shselasky /* 779335640Shselasky * We don't have to do any work here; pcap_set_datalink() checks 780335640Shselasky * whether the value is in the list of DLT_ values we 781335640Shselasky * supplied, so we don't have to, and, if it is valid, sets 782335640Shselasky * p->linktype to the new value; we don't have to do anything 783335640Shselasky * in hardware, we just use what's in p->linktype. 784335640Shselasky * 785335640Shselasky * We do have to have a routine, however, so that pcap_set_datalink() 786335640Shselasky * doesn't think we don't support setting the link-layer header 787335640Shselasky * type at all. 788335640Shselasky */ 789335640Shselasky return 0; 790335640Shselasky} 791335640Shselasky 792335640Shselaskystatic int TcGetNonBlock(pcap_t *p) 793335640Shselasky{ 794335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 795335640Shselasky "Non-blocking mode isn't supported for TurboCap ports"); 796335640Shselasky return -1; 797335640Shselasky} 798335640Shselasky 799335640Shselaskystatic int TcSetNonBlock(pcap_t *p, int nonblock) 800335640Shselasky{ 801335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 802335640Shselasky "Non-blocking mode isn't supported for TurboCap ports"); 803335640Shselasky return -1; 804335640Shselasky} 805335640Shselasky 806335640Shselaskystatic void TcCleanup(pcap_t *p) 807335640Shselasky{ 808335640Shselasky struct pcap_tc *pt = p->priv; 809335640Shselasky 810335640Shselasky if (pt->TcPacketsBuffer != NULL) 811335640Shselasky { 812335640Shselasky g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer); 813335640Shselasky pt->TcPacketsBuffer = NULL; 814335640Shselasky } 815335640Shselasky if (pt->TcInstance != NULL) 816335640Shselasky { 817335640Shselasky /* 818335640Shselasky * here we do not check for the error values 819335640Shselasky */ 820335640Shselasky g_TcFunctions.InstanceClose(pt->TcInstance); 821335640Shselasky pt->TcInstance = NULL; 822335640Shselasky } 823335640Shselasky 824335640Shselasky if (pt->PpiPacket != NULL) 825335640Shselasky { 826335640Shselasky free(pt->PpiPacket); 827335640Shselasky pt->PpiPacket = NULL; 828335640Shselasky } 829335640Shselasky 830335640Shselasky pcap_cleanup_live_common(p); 831335640Shselasky} 832335640Shselasky 833335640Shselasky/* Send a packet to the network */ 834356341Scystatic int TcInject(pcap_t *p, const void *buf, int size) 835335640Shselasky{ 836335640Shselasky struct pcap_tc *pt = p->priv; 837335640Shselasky TC_STATUS status; 838335640Shselasky TC_PACKETS_BUFFER buffer; 839335640Shselasky TC_PACKET_HEADER header; 840335640Shselasky 841335640Shselasky if (size >= 0xFFFF) 842335640Shselasky { 843335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k"); 844335640Shselasky return -1; 845335640Shselasky } 846335640Shselasky 847335640Shselasky status = g_TcFunctions.PacketsBufferCreate(sizeof(TC_PACKET_HEADER) + TC_ALIGN_USHORT_TO_64BIT((USHORT)size), &buffer); 848335640Shselasky 849335640Shselasky if (status != TC_SUCCESS) 850335640Shselasky { 851335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 852335640Shselasky return -1; 853335640Shselasky } 854335640Shselasky 855335640Shselasky /* 856335640Shselasky * we assume that the packet is without the checksum, as common with WinPcap 857335640Shselasky */ 858335640Shselasky memset(&header, 0, sizeof(header)); 859335640Shselasky 860335640Shselasky header.Length = (USHORT)size; 861335640Shselasky header.CapturedLength = header.Length; 862335640Shselasky 863335640Shselasky status = g_TcFunctions.PacketsBufferCommitNextPacket(buffer, &header, (PVOID)buf); 864335640Shselasky 865335640Shselasky if (status == TC_SUCCESS) 866335640Shselasky { 867335640Shselasky status = g_TcFunctions.InstanceTransmitPackets(pt->TcInstance, buffer); 868335640Shselasky 869335640Shselasky if (status != TC_SUCCESS) 870335640Shselasky { 871335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 872335640Shselasky } 873335640Shselasky } 874335640Shselasky else 875335640Shselasky { 876335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 877335640Shselasky } 878335640Shselasky 879335640Shselasky g_TcFunctions.PacketsBufferDestroy(buffer); 880335640Shselasky 881335640Shselasky if (status != TC_SUCCESS) 882335640Shselasky { 883335640Shselasky return -1; 884335640Shselasky } 885335640Shselasky else 886335640Shselasky { 887335640Shselasky return 0; 888335640Shselasky } 889335640Shselasky} 890335640Shselasky 891335640Shselaskystatic int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 892335640Shselasky{ 893335640Shselasky struct pcap_tc *pt = p->priv; 894335640Shselasky TC_STATUS status; 895335640Shselasky int n = 0; 896335640Shselasky 897335640Shselasky /* 898335640Shselasky * Has "pcap_breakloop()" been called? 899335640Shselasky */ 900335640Shselasky if (p->break_loop) 901335640Shselasky { 902335640Shselasky /* 903335640Shselasky * Yes - clear the flag that indicates that it 904335640Shselasky * has, and return -2 to indicate that we were 905335640Shselasky * told to break out of the loop. 906335640Shselasky */ 907335640Shselasky p->break_loop = 0; 908335640Shselasky return -2; 909335640Shselasky } 910335640Shselasky 911335640Shselasky if (pt->TcPacketsBuffer == NULL) 912335640Shselasky { 913335640Shselasky status = g_TcFunctions.InstanceReceivePackets(pt->TcInstance, &pt->TcPacketsBuffer); 914335640Shselasky if (status != TC_SUCCESS) 915335640Shselasky { 916335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 917335640Shselasky return -1; 918335640Shselasky } 919335640Shselasky } 920335640Shselasky 921335640Shselasky while (TRUE) 922335640Shselasky { 923335640Shselasky struct pcap_pkthdr hdr; 924335640Shselasky TC_PACKET_HEADER tcHeader; 925335640Shselasky PVOID data; 926335640Shselasky ULONG filterResult; 927335640Shselasky 928335640Shselasky /* 929335640Shselasky * Has "pcap_breakloop()" been called? 930335640Shselasky * If so, return immediately - if we haven't read any 931335640Shselasky * packets, clear the flag and return -2 to indicate 932335640Shselasky * that we were told to break out of the loop, otherwise 933335640Shselasky * leave the flag set, so that the *next* call will break 934335640Shselasky * out of the loop without having read any packets, and 935335640Shselasky * return the number of packets we've processed so far. 936335640Shselasky */ 937335640Shselasky if (p->break_loop) 938335640Shselasky { 939335640Shselasky if (n == 0) 940335640Shselasky { 941335640Shselasky p->break_loop = 0; 942335640Shselasky return -2; 943335640Shselasky } 944335640Shselasky else 945335640Shselasky { 946335640Shselasky return n; 947335640Shselasky } 948335640Shselasky } 949335640Shselasky 950335640Shselasky if (pt->TcPacketsBuffer == NULL) 951335640Shselasky { 952335640Shselasky break; 953335640Shselasky } 954335640Shselasky 955335640Shselasky status = g_TcFunctions.PacketsBufferQueryNextPacket(pt->TcPacketsBuffer, &tcHeader, &data); 956335640Shselasky 957335640Shselasky if (status == TC_ERROR_END_OF_BUFFER) 958335640Shselasky { 959335640Shselasky g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer); 960335640Shselasky pt->TcPacketsBuffer = NULL; 961335640Shselasky break; 962335640Shselasky } 963335640Shselasky 964335640Shselasky if (status != TC_SUCCESS) 965335640Shselasky { 966335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 967335640Shselasky return -1; 968335640Shselasky } 969335640Shselasky 970335640Shselasky /* No underlaying filtering system. We need to filter on our own */ 971335640Shselasky if (p->fcode.bf_insns) 972335640Shselasky { 973335640Shselasky filterResult = bpf_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength); 974335640Shselasky 975335640Shselasky if (filterResult == 0) 976335640Shselasky { 977335640Shselasky continue; 978335640Shselasky } 979335640Shselasky 980335640Shselasky if (filterResult > tcHeader.CapturedLength) 981335640Shselasky { 982335640Shselasky filterResult = tcHeader.CapturedLength; 983335640Shselasky } 984335640Shselasky } 985335640Shselasky else 986335640Shselasky { 987335640Shselasky filterResult = tcHeader.CapturedLength; 988335640Shselasky } 989335640Shselasky 990335640Shselasky pt->TcAcceptedCount ++; 991335640Shselasky 992335640Shselasky hdr.ts.tv_sec = (bpf_u_int32)(tcHeader.Timestamp / (ULONGLONG)(1000 * 1000 * 1000)); 993335640Shselasky hdr.ts.tv_usec = (bpf_u_int32)((tcHeader.Timestamp % (ULONGLONG)(1000 * 1000 * 1000)) / 1000); 994335640Shselasky 995335640Shselasky if (p->linktype == DLT_EN10MB) 996335640Shselasky { 997335640Shselasky hdr.caplen = filterResult; 998335640Shselasky hdr.len = tcHeader.Length; 999335640Shselasky (*callback)(user, &hdr, data); 1000335640Shselasky } 1001335640Shselasky else 1002335640Shselasky { 1003335640Shselasky PPPI_HEADER pPpiHeader = (PPPI_HEADER)pt->PpiPacket; 1004335640Shselasky PVOID data2 = pPpiHeader + 1; 1005335640Shselasky 1006335640Shselasky pPpiHeader->AggregationField.InterfaceId = TC_PH_FLAGS_RX_PORT_ID(tcHeader.Flags); 1007335640Shselasky pPpiHeader->Dot3Field.Errors = tcHeader.Errors; 1008335640Shselasky if (tcHeader.Flags & TC_PH_FLAGS_CHECKSUM) 1009335640Shselasky { 1010335640Shselasky pPpiHeader->Dot3Field.Flags = PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT; 1011335640Shselasky } 1012335640Shselasky else 1013335640Shselasky { 1014335640Shselasky pPpiHeader->Dot3Field.Flags = 0; 1015335640Shselasky } 1016335640Shselasky 1017335640Shselasky if (filterResult <= MAX_TC_PACKET_SIZE) 1018335640Shselasky { 1019335640Shselasky memcpy(data2, data, filterResult); 1020335640Shselasky hdr.caplen = sizeof(PPI_HEADER) + filterResult; 1021335640Shselasky hdr.len = sizeof(PPI_HEADER) + tcHeader.Length; 1022335640Shselasky } 1023335640Shselasky else 1024335640Shselasky { 1025335640Shselasky memcpy(data2, data, MAX_TC_PACKET_SIZE); 1026335640Shselasky hdr.caplen = sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE; 1027335640Shselasky hdr.len = sizeof(PPI_HEADER) + tcHeader.Length; 1028335640Shselasky } 1029335640Shselasky 1030335640Shselasky (*callback)(user, &hdr, pt->PpiPacket); 1031335640Shselasky 1032335640Shselasky } 1033335640Shselasky 1034335640Shselasky if (++n >= cnt && cnt > 0) 1035335640Shselasky { 1036335640Shselasky return n; 1037335640Shselasky } 1038335640Shselasky } 1039335640Shselasky 1040335640Shselasky return n; 1041335640Shselasky} 1042335640Shselasky 1043335640Shselaskystatic int 1044335640ShselaskyTcStats(pcap_t *p, struct pcap_stat *ps) 1045335640Shselasky{ 1046335640Shselasky struct pcap_tc *pt = p->priv; 1047335640Shselasky TC_STATISTICS statistics; 1048335640Shselasky TC_STATUS status; 1049335640Shselasky ULONGLONG counter; 1050335640Shselasky struct pcap_stat s; 1051335640Shselasky 1052335640Shselasky status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics); 1053335640Shselasky 1054335640Shselasky if (status != TC_SUCCESS) 1055335640Shselasky { 1056335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 1057335640Shselasky return -1; 1058335640Shselasky } 1059335640Shselasky 1060335640Shselasky memset(&s, 0, sizeof(s)); 1061335640Shselasky 1062335640Shselasky status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter); 1063335640Shselasky if (status != TC_SUCCESS) 1064335640Shselasky { 1065335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 1066335640Shselasky return -1; 1067335640Shselasky } 1068335640Shselasky if (counter <= (ULONGLONG)0xFFFFFFFF) 1069335640Shselasky { 1070335640Shselasky s.ps_recv = (ULONG)counter; 1071335640Shselasky } 1072335640Shselasky else 1073335640Shselasky { 1074335640Shselasky s.ps_recv = 0xFFFFFFFF; 1075335640Shselasky } 1076335640Shselasky 1077335640Shselasky status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter); 1078335640Shselasky if (status != TC_SUCCESS) 1079335640Shselasky { 1080335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 1081335640Shselasky return -1; 1082335640Shselasky } 1083335640Shselasky if (counter <= (ULONGLONG)0xFFFFFFFF) 1084335640Shselasky { 1085335640Shselasky s.ps_ifdrop = (ULONG)counter; 1086335640Shselasky s.ps_drop = (ULONG)counter; 1087335640Shselasky } 1088335640Shselasky else 1089335640Shselasky { 1090335640Shselasky s.ps_ifdrop = 0xFFFFFFFF; 1091335640Shselasky s.ps_drop = 0xFFFFFFFF; 1092335640Shselasky } 1093335640Shselasky 1094335640Shselasky#if defined(_WIN32) && defined(ENABLE_REMOTE) 1095335640Shselasky s.ps_capt = pt->TcAcceptedCount; 1096335640Shselasky#endif 1097335640Shselasky *ps = s; 1098335640Shselasky 1099335640Shselasky return 0; 1100335640Shselasky} 1101335640Shselasky 1102335640Shselasky 1103335640Shselasky/* 1104335640Shselasky * We filter at user level, since the kernel driver does't process the packets 1105335640Shselasky */ 1106335640Shselaskystatic int 1107335640ShselaskyTcSetFilter(pcap_t *p, struct bpf_program *fp) 1108335640Shselasky{ 1109335640Shselasky if(!fp) 1110335640Shselasky { 1111335640Shselasky strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); 1112335640Shselasky return -1; 1113335640Shselasky } 1114335640Shselasky 1115335640Shselasky /* Install a user level filter */ 1116335640Shselasky if (install_bpf_program(p, fp) < 0) 1117335640Shselasky { 1118335640Shselasky return -1; 1119335640Shselasky } 1120335640Shselasky 1121335640Shselasky return 0; 1122335640Shselasky} 1123335640Shselasky 1124335640Shselasky#ifdef _WIN32 1125335640Shselaskystatic struct pcap_stat * 1126335640ShselaskyTcStatsEx(pcap_t *p, int *pcap_stat_size) 1127335640Shselasky{ 1128335640Shselasky struct pcap_tc *pt = p->priv; 1129335640Shselasky TC_STATISTICS statistics; 1130335640Shselasky TC_STATUS status; 1131335640Shselasky ULONGLONG counter; 1132335640Shselasky 1133335640Shselasky *pcap_stat_size = sizeof (p->stat); 1134335640Shselasky 1135335640Shselasky status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics); 1136335640Shselasky 1137335640Shselasky if (status != TC_SUCCESS) 1138335640Shselasky { 1139335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 1140335640Shselasky return NULL; 1141335640Shselasky } 1142335640Shselasky 1143335640Shselasky memset(&p->stat, 0, sizeof(p->stat)); 1144335640Shselasky 1145335640Shselasky status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter); 1146335640Shselasky if (status != TC_SUCCESS) 1147335640Shselasky { 1148335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 1149335640Shselasky return NULL; 1150335640Shselasky } 1151335640Shselasky if (counter <= (ULONGLONG)0xFFFFFFFF) 1152335640Shselasky { 1153335640Shselasky p->stat.ps_recv = (ULONG)counter; 1154335640Shselasky } 1155335640Shselasky else 1156335640Shselasky { 1157335640Shselasky p->stat.ps_recv = 0xFFFFFFFF; 1158335640Shselasky } 1159335640Shselasky 1160335640Shselasky status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter); 1161335640Shselasky if (status != TC_SUCCESS) 1162335640Shselasky { 1163335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 1164335640Shselasky return NULL; 1165335640Shselasky } 1166335640Shselasky if (counter <= (ULONGLONG)0xFFFFFFFF) 1167335640Shselasky { 1168335640Shselasky p->stat.ps_ifdrop = (ULONG)counter; 1169335640Shselasky p->stat.ps_drop = (ULONG)counter; 1170335640Shselasky } 1171335640Shselasky else 1172335640Shselasky { 1173335640Shselasky p->stat.ps_ifdrop = 0xFFFFFFFF; 1174335640Shselasky p->stat.ps_drop = 0xFFFFFFFF; 1175335640Shselasky } 1176335640Shselasky 1177335640Shselasky#if defined(_WIN32) && defined(ENABLE_REMOTE) 1178335640Shselasky p->stat.ps_capt = pt->TcAcceptedCount; 1179335640Shselasky#endif 1180335640Shselasky 1181335640Shselasky return &p->stat; 1182335640Shselasky} 1183335640Shselasky 1184335640Shselasky/* Set the dimension of the kernel-level capture buffer */ 1185335640Shselaskystatic int 1186335640ShselaskyTcSetBuff(pcap_t *p, int dim) 1187335640Shselasky{ 1188335640Shselasky /* 1189335640Shselasky * XXX turbocap has an internal way of managing buffers. 1190335640Shselasky * And at the moment it's not configurable, so we just 1191335640Shselasky * silently ignore the request to set the buffer. 1192335640Shselasky */ 1193335640Shselasky return 0; 1194335640Shselasky} 1195335640Shselasky 1196335640Shselaskystatic int 1197335640ShselaskyTcSetMode(pcap_t *p, int mode) 1198335640Shselasky{ 1199335640Shselasky if (mode != MODE_CAPT) 1200335640Shselasky { 1201335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode); 1202335640Shselasky return -1; 1203335640Shselasky } 1204335640Shselasky 1205335640Shselasky return 0; 1206335640Shselasky} 1207335640Shselasky 1208335640Shselaskystatic int 1209335640ShselaskyTcSetMinToCopy(pcap_t *p, int size) 1210335640Shselasky{ 1211335640Shselasky struct pcap_tc *pt = p->priv; 1212335640Shselasky TC_STATUS status; 1213335640Shselasky 1214335640Shselasky if (size < 0) 1215335640Shselasky { 1216335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0."); 1217335640Shselasky return -1; 1218335640Shselasky } 1219335640Shselasky 1220335640Shselasky status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_MINTOCOPY, (ULONG)size); 1221335640Shselasky 1222335640Shselasky if (status != TC_SUCCESS) 1223335640Shselasky { 1224335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status); 1225335640Shselasky } 1226335640Shselasky 1227335640Shselasky return 0; 1228335640Shselasky} 1229335640Shselasky 1230335640Shselaskystatic HANDLE 1231335640ShselaskyTcGetReceiveWaitHandle(pcap_t *p) 1232335640Shselasky{ 1233335640Shselasky struct pcap_tc *pt = p->priv; 1234335640Shselasky 1235335640Shselasky return g_TcFunctions.InstanceGetReceiveWaitHandle(pt->TcInstance); 1236335640Shselasky} 1237335640Shselasky 1238335640Shselaskystatic int 1239335640ShselaskyTcOidGetRequest(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_) 1240335640Shselasky{ 1241335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 1242335640Shselasky "An OID get request cannot be performed on a TurboCap device"); 1243335640Shselasky return PCAP_ERROR; 1244335640Shselasky} 1245335640Shselasky 1246335640Shselaskystatic int 1247335640ShselaskyTcOidSetRequest(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, 1248335640Shselasky size_t *lenp _U_) 1249335640Shselasky{ 1250335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 1251335640Shselasky "An OID set request cannot be performed on a TurboCap device"); 1252335640Shselasky return PCAP_ERROR; 1253335640Shselasky} 1254335640Shselasky 1255335640Shselaskystatic u_int 1256335640ShselaskyTcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_) 1257335640Shselasky{ 1258335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 1259335640Shselasky "Packets cannot be bulk transmitted on a TurboCap device"); 1260335640Shselasky return 0; 1261335640Shselasky} 1262335640Shselasky 1263335640Shselaskystatic int 1264335640ShselaskyTcSetUserBuffer(pcap_t *p, int size _U_) 1265335640Shselasky{ 1266335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 1267335640Shselasky "The user buffer cannot be set on a TurboCap device"); 1268335640Shselasky return -1; 1269335640Shselasky} 1270335640Shselasky 1271335640Shselaskystatic int 1272335640ShselaskyTcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_) 1273335640Shselasky{ 1274335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 1275335640Shselasky "Live packet dumping cannot be performed on a TurboCap device"); 1276335640Shselasky return -1; 1277335640Shselasky} 1278335640Shselasky 1279335640Shselaskystatic int 1280335640ShselaskyTcLiveDumpEnded(pcap_t *p, int sync _U_) 1281335640Shselasky{ 1282335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 1283335640Shselasky "Live packet dumping cannot be performed on a TurboCap device"); 1284335640Shselasky return -1; 1285335640Shselasky} 1286335640Shselasky 1287335640Shselaskystatic PAirpcapHandle 1288335640ShselaskyTcGetAirPcapHandle(pcap_t *p _U_) 1289335640Shselasky{ 1290335640Shselasky return NULL; 1291335640Shselasky} 1292335640Shselasky#endif 1293