From be84fb0f1cbc8c51220554f9890acd2520d69603 Mon Sep 17 00:00:00 2001 From: Robert Dickenson Date: Tue, 24 Sep 2002 15:08:14 +0000 Subject: [PATCH] Updated with latest version changes to original source by Politecnico di Torino. svn path=/trunk/; revision=3551 --- reactos/lib/packet/Packet32.c | 1121 +++++++++++++++++++------ reactos/lib/packet/include/packet32.h | 214 +++-- reactos/lib/packet/makefile | 7 +- reactos/lib/packet/packet.def | 53 +- reactos/lib/packet/trace.c | 53 ++ reactos/lib/packet/trace.h | 62 ++ 6 files changed, 1193 insertions(+), 317 deletions(-) create mode 100644 reactos/lib/packet/trace.c create mode 100644 reactos/lib/packet/trace.h diff --git a/reactos/lib/packet/Packet32.c b/reactos/lib/packet/Packet32.c index fd371f42d19..5f0a06d3cb8 100644 --- a/reactos/lib/packet/Packet32.c +++ b/reactos/lib/packet/Packet32.c @@ -23,27 +23,50 @@ #include #include -#include +//#include #include +#include "trace.h" + + +/****** KERNEL Macro APIs ******************************************************/ + +#define GetInstanceModule(hInst) (HMODULE)(hInst) +#define GlobalPtrHandle(lp) ((HGLOBAL)GlobalHandle(lp)) +#define GlobalLockPtr(lp) ((BOOL)GlobalLock(GlobalPtrHandle(lp))) +#define GlobalUnlockPtr(lp) GlobalUnlock(GlobalPtrHandle(lp)) +#define GlobalAllocPtr(flags, cb) (GlobalLock(GlobalAlloc((flags), (cb)))) +#define GlobalReAllocPtr(lp, cbNew, flags) (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), (flags)))) +#define GlobalFreePtr(lp) (GlobalUnlockPtr(lp), (BOOL)(ULONG_PTR)GlobalFree(GlobalPtrHandle(lp))) + +#undef GMEM_MOVEABLE +#define GMEM_MOVEABLE 0 + + /// Title of error windows TCHAR szWindowTitle[] = TEXT("PACKET.DLL"); -#if _DBG +#if DBG #define ODS(_x) OutputDebugString(TEXT(_x)) -#define ODSEx(_x, _y) +//#define ODSEx(_x, _y) +#define ODSEx TRACE #else #ifdef _DEBUG_TO_FILE #include -// Macro to print a debug string. The behavior differs depending on the debug level +/*! + \brief Macro to print a debug string. The behavior differs depending on the debug level +*/ #define ODS(_x) { \ FILE *f; \ f = fopen("winpcap_debug.txt", "a"); \ fprintf(f, "%s", _x); \ fclose(f); \ } -// Macro to print debug data with the printf convention. The behavior differs depending on */ +/*! + \brief Macro to print debug data with the printf convention. The behavior differs depending on + the debug level +*/ #define ODSEx(_x, _y) { \ FILE *f; \ f = fopen("winpcap_debug.txt", "a"); \ @@ -64,11 +87,15 @@ SC_HANDLE srvHandle = NULL; LPCTSTR NPFServiceName = TEXT("NPF"); LPCTSTR NPFServiceDesc = TEXT("Netgroup Packet Filter"); LPCTSTR NPFDriverName = TEXT("\\npf.sys"); -LPCTSTR NPFRegistryLocation = TEXT("SYSTEM\\CurrentControlSet\\Services\\NPF"); +LPCTSTR NPFRegistryLocation = TEXT("SYSTEM\\ControlSet001\\Services\\NPF"); //--------------------------------------------------------------------------- +/*! + \brief The main dll function. +*/ + BOOL APIENTRY DllMain (HANDLE DllHandle,DWORD Reason,LPVOID lpReserved) { BOOLEAN Status=TRUE; @@ -81,13 +108,13 @@ BOOL APIENTRY DllMain (HANDLE DllHandle,DWORD Reason,LPVOID lpReserved) #ifdef _DEBUG_TO_FILE // dump a bunch of registry keys useful for debug to file - PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", + PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", "adapters.reg"); - PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip", + PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip", "tcpip.reg"); - PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\NPF", + PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\NPF", "npf.reg"); - PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services", + PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services", "services.reg"); #endif break; @@ -102,7 +129,11 @@ BOOL APIENTRY DllMain (HANDLE DllHandle,DWORD Reason,LPVOID lpReserved) return Status; } -//--------------------------------------------------------------------------- +/*! + \brief Converts an ASCII string to UNICODE. Uses the MultiByteToWideChar() system function. + \param string The string to convert. + \return The converted string. +*/ WCHAR* SChar2WChar(char* string) { @@ -114,7 +145,14 @@ WCHAR* SChar2WChar(char* string) return TmpStr; } -//--------------------------------------------------------------------------- +/*! + \brief Sets the maximum possible lookahead buffer for the driver's Packet_tap() function. + \param AdapterObject Handle to the service control manager. + \return If the function succeeds, the return value is nonzero. + + The lookahead buffer is the portion of packet that Packet_tap() can access from the NIC driver's memory + without performing a copy. This function tries to increase the size of that buffer. +*/ BOOLEAN PacketSetMaxLookaheadsize (LPADAPTER AdapterObject) { @@ -138,12 +176,20 @@ BOOLEAN PacketSetMaxLookaheadsize (LPADAPTER AdapterObject) return Status; } -//--------------------------------------------------------------------------- +/*! + \brief Retrieves the event associated in the driver with a capture instance and stores it in an + _ADAPTER structure. + \param AdapterObject Handle to the service control manager. + \return If the function succeeds, the return value is nonzero. + + This function is used by PacketOpenAdapter() to retrieve the read event from the driver by means of an ioctl + call and set it in the _ADAPTER structure pointed by AdapterObject. +*/ BOOLEAN PacketSetReadEvt(LPADAPTER AdapterObject) { DWORD BytesReturned; - TCHAR EventName[39]; + WCHAR EventName[39]; // this tells the terminal service to retrieve the event from the global namespace wcsncpy(EventName,L"Global\\",sizeof(L"Global\\")); @@ -154,7 +200,7 @@ BOOLEAN PacketSetReadEvt(LPADAPTER AdapterObject) EventName[20]=0; // terminate the string // open the shared event - AdapterObject->ReadEvent=CreateEvent(NULL, + AdapterObject->ReadEvent=CreateEventW(NULL, TRUE, FALSE, EventName); @@ -165,7 +211,7 @@ BOOLEAN PacketSetReadEvt(LPADAPTER AdapterObject) CloseHandle(AdapterObject->ReadEvent); // open the shared event - AdapterObject->ReadEvent=CreateEvent(NULL, + AdapterObject->ReadEvent=CreateEventW(NULL, TRUE, FALSE, EventName+7); @@ -182,14 +228,22 @@ BOOLEAN PacketSetReadEvt(LPADAPTER AdapterObject) } -//--------------------------------------------------------------------------- +/*! + \brief Installs the NPF device driver. + \param ascmHandle Handle to the service control manager. + \param ascmHandle A pointer to a handle that will receive the pointer to the driver's service. + \param driverPath The full path of the .sys file to load. + \return If the function succeeds, the return value is nonzero. -BOOL PacketInstallDriver(SC_HANDLE ascmHandle,SC_HANDLE *srvHandle,TCHAR *driverPath) + This function installs the driver's service in the system using the CreateService function. +*/ + +BOOL PacketInstallDriver(SC_HANDLE ascmHandle, SC_HANDLE* srvHandle, TCHAR* driverPath) { BOOL result = FALSE; ULONG err; - ODS("installdriver\n") + ODS("installdriver\n"); if (GetFileAttributes(driverPath) != 0xffffffff) { *srvHandle = CreateService(ascmHandle, @@ -206,26 +260,35 @@ BOOL PacketInstallDriver(SC_HANDLE ascmHandle,SC_HANDLE *srvHandle,TCHAR *driver //npf.sys already existed result = TRUE; } - } - else { + } else { //Created service for npf.sys result = TRUE; } } - if (result == TRUE) - if (*srvHandle != NULL) + if (result == TRUE) { + if (*srvHandle != NULL) { CloseServiceHandle(*srvHandle); + } + } - if(result == FALSE){ + if (result == FALSE){ err = GetLastError(); - if(err != 2) + if (err != 2) { ODSEx("PacketInstallDriver failed, Error=%d\n",err); + } } return result; } -//--------------------------------------------------------------------------- +/*! + \brief Convert a Unicode dotted-quad to a 32-bit IP address. + \param cp A string containing the address. + \return the converted 32-bit numeric address. + + Doesn't check to make sure the address is valid. +*/ + ULONG inet_addrU(const WCHAR *cp) { @@ -255,7 +318,14 @@ ULONG inet_addrU(const WCHAR *cp) return val; } -//--------------------------------------------------------------------------- +/*! + \brief Dumps a registry key to disk in text format. Uses regedit. + \param KeyName Name of the ket to dump. All its subkeys will be saved recursively. + \param FileName Name of the file that will contain the dump. + \return If the function succeeds, the return value is nonzero. + + For debugging purposes, we use this function to obtain some registry keys from the user's machine. +*/ #ifdef _DEBUG_TO_FILE @@ -279,17 +349,41 @@ LONG PacketDumpRegistryKey(PCHAR KeyName, PCHAR FileName) // PUBLIC API //--------------------------------------------------------------------------- +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32 Packet.dll exported functions and variables + * @{ + */ + /// Current packet.dll Version. It can be retrieved directly or through the PacketGetVersion() function. char PacketLibraryVersion[] = "2.3"; -//--------------------------------------------------------------------------- - +/*! + \brief Returns a string with the dll version. + \return A char pointer to the version of the library. +*/ PCHAR PacketGetVersion(){ return PacketLibraryVersion; } -//--------------------------------------------------------------------------- +/*! + \brief Returns information about the MAC type of an adapter. + \param AdapterObject The adapter on which information is needed. + \param type Pointer to a NetType structure that will be filled by the function. + \return If the function succeeds, the return value is nonzero, otherwise the return value is zero. + This function return the link layer technology and the speed (in bps) of an opened adapter. + The LinkType field of the type parameter can have one of the following values: + + - NdisMedium802_3: Ethernet (802.3) + - NdisMediumWan: WAN + - NdisMedium802_5: Token Ring (802.5) + - NdisMediumFddi: FDDI + - NdisMediumAtm: ATM + - NdisMediumArcnet878_2: ARCNET (878.2) +*/ BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type) { BOOLEAN Status; @@ -320,8 +414,14 @@ BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type) return Status; } -//--------------------------------------------------------------------------- +/*! + \brief Stops and unloads the WinPcap device driver. + \return If the function succeeds, the return value is nonzero, otherwise it is zero. + This function can be used to unload the driver from memory when the application no more needs it. + Note that the driver is physically stopped and unloaded only when all the files on its devices + are closed, i.e. when all the applications that use WinPcap close all their adapters. +*/ BOOL PacketStopDriver() { SC_HANDLE scmHandle; @@ -361,8 +461,28 @@ BOOL PacketStopDriver() } -//--------------------------------------------------------------------------- +/*! + \brief Opens an adapter. + \param AdapterName A string containing the name of the device to open. + Use the PacketGetAdapterNames() function to retrieve the list of available devices. + \return If the function succeeds, the return value is the pointer to a properly initialized ADAPTER object, + otherwise the return value is NULL. + This function tries to load and start the packet driver at the first invocation. In this way, + the management of the driver is transparent to the application, that simply needs to open an adapter to start + WinPcap. + + \note the Windows 95 version of the NPF driver works with the ASCII string format, while the Windows NT + version works with UNICODE. Therefore, AdapterName \b should be an ASCII string in Windows 95, and a UNICODE + string in Windows NT. This difference is not a problem if the string pointed by AdapterName was obtained + through the PacketGetAdapterNames function, because it returns the names of the adapters in the proper format. + Problems can arise in Windows NT when the string is obtained from ANSI C functions like scanf, because they + use the ASCII format. Since this could be a relevant problem during the porting of command-line applications + from UNIX, we included in the Windows NT version of PacketOpenAdapter the ability to detect ASCII strings and + convert them to UNICODE before sending them to the device driver. Therefore PacketOpenAdapter in Windows NT + accepts both the ASCII and the UNICODE format. If a ASCII string is received, it is converted to UNICODE + by PACKET.DLL before being passed to the driver. +*/ LPADAPTER PacketOpenAdapter(LPTSTR AdapterName) { LPADAPTER lpAdapter; @@ -377,20 +497,18 @@ LPADAPTER PacketOpenAdapter(LPTSTR AdapterName) HKEY PathKey; SERVICE_STATUS SStat; BOOLEAN QuerySStat; + WCHAR SymbolicLink[128]; - ODSEx("PacketOpenAdapter: trying to open the adapter=%S\n",AdapterName) + ODSEx("PacketOpenAdapter: trying to open the adapter=%S\n",AdapterName); scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if(scmHandle == NULL){ error = GetLastError(); ODSEx("OpenSCManager failed! Error=%d\n", error); - } - else{ + } else { *driverPath = 0; GetCurrentDirectory(512, driverPath); - wsprintf(driverPath + wcslen(driverPath), - NPFDriverName); + wsprintf(driverPath + wcslen(driverPath), NPFDriverName); // check if the NPF registry key is already present // this means that the driver is already installed and that we don't need to call PacketInstallDriver @@ -402,8 +520,7 @@ LPADAPTER PacketOpenAdapter(LPTSTR AdapterName) if(KeyRes != ERROR_SUCCESS){ Result = PacketInstallDriver(scmHandle,&svcHandle,driverPath); - } - else{ + } else { Result = TRUE; RegCloseKey(PathKey); } @@ -416,11 +533,11 @@ LPADAPTER PacketOpenAdapter(LPTSTR AdapterName) QuerySStat = QueryServiceStatus(srvHandle, &SStat); ODSEx("The status of the driver is:%d\n",SStat.dwCurrentState); - if(!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING){ + if (!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING){ ODS("Calling startservice\n"); if (StartService(srvHandle, 0, NULL)==0){ error = GetLastError(); - if(error!=ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS){ + if (error!=ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS){ SetLastError(error); if (scmHandle != NULL) CloseServiceHandle(scmHandle); error = GetLastError(); @@ -429,38 +546,31 @@ LPADAPTER PacketOpenAdapter(LPTSTR AdapterName) } } } - } - else{ + } else { error = GetLastError(); ODSEx("OpenService failed! Error=%d", error); } - } - else{ - if( GetSystemDirectory(WinPath, sizeof(WinPath)/sizeof(TCHAR)) == 0) return FALSE; - wsprintf(driverPath, - TEXT("%s\\drivers%s"), - WinPath,NPFDriverName); + } else { + if (GetSystemDirectory(WinPath, sizeof(WinPath)/sizeof(TCHAR)) == 0) { + return FALSE; + } + wsprintf(driverPath, TEXT("%s\\drivers%s"), WinPath, NPFDriverName); - if(KeyRes != ERROR_SUCCESS) + if (KeyRes != ERROR_SUCCESS) { Result = PacketInstallDriver(scmHandle,&svcHandle,driverPath); - else + } else { Result = TRUE; - + } if (Result) { - srvHandle = OpenService(scmHandle,NPFServiceName,SERVICE_START); - if (srvHandle != NULL){ - + if (srvHandle != NULL) { QuerySStat = QueryServiceStatus(srvHandle, &SStat); ODSEx("The status of the driver is:%d\n",SStat.dwCurrentState); - - if(!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING){ - + if (!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING) { ODS("Calling startservice\n"); - - if (StartService(srvHandle, 0, NULL)==0){ + if (StartService(srvHandle, 0, NULL) == 0) { error = GetLastError(); - if(error!=ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS){ + if (error != ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS) { SetLastError(error); if (scmHandle != NULL) CloseServiceHandle(scmHandle); ODSEx("PacketOpenAdapter: StartService failed, Error=%d\n",error); @@ -468,48 +578,49 @@ LPADAPTER PacketOpenAdapter(LPTSTR AdapterName) } } } - } - else{ + } else { error = GetLastError(); ODSEx("OpenService failed! Error=%d", error); } } } } - if (scmHandle != NULL) CloseServiceHandle(scmHandle); - AdapterNameA=(char*)AdapterName; - if(AdapterNameA[1]!=0){ //ASCII - AdapterNameU=SChar2WChar(AdapterNameA); - AdapterName=AdapterNameU; - } else { //Unicode - AdapterNameU=NULL; + AdapterNameA = (char*)AdapterName; + if (AdapterNameA[1] != 0) { // ASCII + AdapterNameU = SChar2WChar(AdapterNameA); + AdapterName = AdapterNameU; + } else { // Unicode + AdapterNameU = NULL; } - lpAdapter=(LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(ADAPTER)); - if (lpAdapter==NULL) - { + lpAdapter = (LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(ADAPTER)); + if (lpAdapter == NULL) { ODS("PacketOpenAdapter: GlobalAlloc Failed\n"); - error=GetLastError(); + error = GetLastError(); if (AdapterNameU != NULL) free(AdapterNameU); //set the error to the one on which we failed SetLastError(error); ODS("PacketOpenAdapter: Failed to allocate the adapter structure\n"); return NULL; } - lpAdapter->NumWrites=1; + lpAdapter->NumWrites = 1; - wsprintf(lpAdapter->SymbolicLink,TEXT("\\\\.\\%s%s"),DOSNAMEPREFIX,&AdapterName[8]); + wsprintf(SymbolicLink,TEXT("\\\\.\\%s%s"), DOSNAMEPREFIX, &AdapterName[8]); + // Copy only the bytes that fit in the adapter structure. + // Note that lpAdapter->SymbolicLink is present for backward compatibility but will + // never be used by the apps + memcpy(lpAdapter->SymbolicLink, (PCHAR)SymbolicLink, MAX_LINK_NAME_LENGTH); + //try if it is possible to open the adapter immediately - lpAdapter->hFile=CreateFile(lpAdapter->SymbolicLink,GENERIC_WRITE | GENERIC_READ, - 0,NULL,OPEN_EXISTING,0,0); + lpAdapter->hFile = CreateFile(SymbolicLink,GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,0,0); if (lpAdapter->hFile != INVALID_HANDLE_VALUE) { - - if(PacketSetReadEvt(lpAdapter)==FALSE){ - error=GetLastError(); + ODSEx("PacketOpenAdapter: CreateFile(%S) successfull\n", SymbolicLink); + if (PacketSetReadEvt(lpAdapter) == FALSE) { + error = GetLastError(); ODS("PacketOpenAdapter: Unable to open the read event\n"); if (AdapterNameU != NULL) free(AdapterNameU); @@ -527,18 +638,20 @@ LPADAPTER PacketOpenAdapter(LPTSTR AdapterName) } //this is probably the first request on the packet driver. //We must create the dos device and set the access rights on it - else{ - Result=DefineDosDevice(DDD_RAW_TARGET_PATH,&lpAdapter->SymbolicLink[4],AdapterName); - if (Result) - { + else { + Result = DefineDosDevice(DDD_RAW_TARGET_PATH, + &SymbolicLink[4], + AdapterName); + if (Result) { - lpAdapter->hFile=CreateFile(lpAdapter->SymbolicLink,GENERIC_WRITE | GENERIC_READ, - 0,NULL,OPEN_EXISTING,0,0); - if (lpAdapter->hFile != INVALID_HANDLE_VALUE) - { - - if(PacketSetReadEvt(lpAdapter)==FALSE){ - error=GetLastError(); + ODSEx("PacketOpenAdapter: calling CreateFile(%S)\n", SymbolicLink); + + lpAdapter->hFile = CreateFile( + SymbolicLink, + GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,0,0); + if (lpAdapter->hFile != INVALID_HANDLE_VALUE) { + if (PacketSetReadEvt(lpAdapter) == FALSE) { + error = GetLastError(); ODS("PacketOpenAdapter: Unable to open the read event\n"); if (AdapterNameU != NULL) free(AdapterNameU); @@ -548,16 +661,18 @@ LPADAPTER PacketOpenAdapter(LPTSTR AdapterName) ODSEx("PacketOpenAdapter: PacketSetReadEvt failed, Error=1,%d\n",error); return NULL; } - PacketSetMaxLookaheadsize(lpAdapter); if (AdapterNameU != NULL) free(AdapterNameU); return lpAdapter; + } else { + ODS("PacketOpenAdapter: CreateFile failed\n"); } + } else { + ODSEx("PacketOpenAdapter: DefineDosDevice(%S) failed\n", &SymbolicLink[4]); } } - - error=GetLastError(); + error = GetLastError(); if (AdapterNameU != NULL) free(AdapterNameU); GlobalFreePtr(lpAdapter); @@ -568,8 +683,12 @@ LPADAPTER PacketOpenAdapter(LPTSTR AdapterName) } -//--------------------------------------------------------------------------- +/*! + \brief Closes an adapter. + \param lpAdapter the pointer to the adapter to close. + PacketCloseAdapter closes the given adapter and frees the associated ADAPTER structure +*/ VOID PacketCloseAdapter(LPADAPTER lpAdapter) { CloseHandle(lpAdapter->hFile); @@ -578,29 +697,58 @@ VOID PacketCloseAdapter(LPADAPTER lpAdapter) GlobalFreePtr(lpAdapter); } -//--------------------------------------------------------------------------- +/*! + \brief Allocates a _PACKET structure. + \return On succeess, the return value is the pointer to a _PACKET structure otherwise the + return value is NULL. + The structure returned will be passed to the PacketReceivePacket() function to receive the + packets from the driver. + + \warning The Buffer field of the _PACKET structure is not set by this function. + The buffer \b must be allocated by the application, and associated to the PACKET structure + with a call to PacketInitPacket. +*/ LPPACKET PacketAllocatePacket(void) { - LPPACKET lpPacket; - lpPacket=(LPPACKET)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(PACKET)); - if (lpPacket==NULL) - { + LPPACKET lpPacket; + lpPacket = (LPPACKET)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(PACKET)); + if (lpPacket == NULL) { ODS("PacketAllocatePacket: GlobalAlloc Failed\n"); return NULL; } return lpPacket; } -//--------------------------------------------------------------------------- +/*! + \brief Frees a _PACKET structure. + \param lpPacket The structure to free. + \warning the user-allocated buffer associated with the _PACKET structure is not deallocated + by this function and \b must be explicitly deallocated by the programmer. + +*/ VOID PacketFreePacket(LPPACKET lpPacket) { GlobalFreePtr(lpPacket); } -//--------------------------------------------------------------------------- +/*! + \brief Initializes a _PACKET structure. + \param lpPacket The structure to initialize. + \param Buffer A pointer to a user-allocated buffer that will contain the captured data. + \param Length the length of the buffer. This is the maximum buffer size that will be + transferred from the driver to the application using a single read. + + \note the size of the buffer associated with the PACKET structure is a parameter that can sensibly + influence the performance of the capture process, since this buffer will contain the packets received + from the the driver. The driver is able to return several packets using a single read call + (see the PacketReceivePacket() function for details), and the number of packets transferable to the + application in a call is limited only by the size of the buffer associated with the PACKET structure + passed to PacketReceivePacket(). Therefore setting a big buffer with PacketInitPacket can noticeably + decrease the number of system calls, reducing the impcat of the capture process on the processor. +*/ VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length) { @@ -610,8 +758,36 @@ VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length) lpPacket->bIoComplete = FALSE; } -//--------------------------------------------------------------------------- +/*! + \brief Read data (packets or statistics) from the NPF driver. + \param AdapterObject Pointer to an _ADAPTER structure identifying the network adapter from which + the data is received. + \param lpPacket Pointer to a PACKET structure that will contain the data. + \param Sync This parameter is deprecated and will be ignored. It is present for compatibility with + older applications. + \return If the function succeeds, the return value is nonzero. + The data received with this function can be a group of packets or a static on the network traffic, + depending on the working mode of the driver. The working mode can be set with the PacketSetMode() + function. Give a look at that function if you are interested in the format used to return statistics + values, here only the normal capture mode will be described. + + The number of packets received with this function is variable. It depends on the number of packets + currently stored in the driver’s buffer, on the size of these packets and on the size of the buffer + associated to the lpPacket parameter. The following figure shows the format used by the driver to pass + packets to the application. + + \image html encoding.gif "method used to encode the packets" + + Packets are stored in the buffer associated with the lpPacket _PACKET structure. The Length field of + that structure is updated with the amount of data copied in the buffer. Each packet has a header + consisting in a bpf_hdr structure that defines its length and contains its timestamp. A padding field + is used to word-align the data in the buffer (to speed up the access to the packets). The bh_datalen + and bh_hdrlen fields of the bpf_hdr structures should be used to extract the packets from the buffer. + + Examples can be seen either in the TestApp sample application (see the \ref packetsamps page) provided + in the developer's pack, or in the pcap_read() function of wpcap. +*/ BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync) { BOOLEAN res; @@ -620,24 +796,141 @@ BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sy res = ReadFile(AdapterObject->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->ulBytesReceived,NULL); return res; } -/* -ReadFile( - HANDLE hFile, - LPVOID lpBuffer, - DWORD nNumberOfBytesToRead, - LPDWORD lpNumberOfBytesRead, - LPOVERLAPPED lpOverlapped - ); - */ -//--------------------------------------------------------------------------- +/*! + \brief Sends one (or more) copies of a packet to the network. + \param AdapterObject Pointer to an _ADAPTER structure identifying the network adapter that will + send the packets. + \param lpPacket Pointer to a PACKET structure with the packet to send. + \param Sync This parameter is deprecated and will be ignored. It is present for compatibility with + older applications. + \return If the function succeeds, the return value is nonzero. + + This function is used to send a raw packet to the network. 'Raw packet' means that the programmer + will have to include the protocol headers, since the packet is sent to the network 'as is'. + The CRC needs not to be calculated and put at the end of the packet, because it will be transparently + added by the network interface. + + The behavior of this function is influenced by the PacketSetNumWrites() function. With PacketSetNumWrites(), + it is possible to change the number of times a single write must be repeated. The default is 1, + i.e. every call to PacketSendPacket() will correspond to one packet sent to the network. If this number is + greater than 1, for example 1000, every raw packet written by the application will be sent 1000 times on + the network. This feature mitigates the overhead of the context switches and therefore can be used to generate + high speed traffic. It is particularly useful for tools that test networks, routers, and servers and need + to obtain high network loads. + The optimized sending process is still limited to one packet at a time: for the moment it cannot be used + to send a buffer with multiple packets. + + \note The ability to write multiple packets is currently present only in the Windows NTx version of the + packet driver. In Windows 95/98/ME it is emulated at user level in packet.dll. This means that an application + that uses the multiple write method will run in Windows 9x as well, but its performance will be very low + compared to the one of WindowsNTx. +*/ BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync) { DWORD BytesTransfered; return WriteFile(AdapterObject->hFile,lpPacket->Buffer,lpPacket->Length,&BytesTransfered,NULL); } -//--------------------------------------------------------------------------- + +/*! + \brief Sends a buffer of packets to the network. + \param AdapterObject Pointer to an _ADAPTER structure identifying the network adapter that will + send the packets. + \param PacketBuff Pointer to buffer with the packets to send. + \param Size Size of the buffer pointed by the PacketBuff argument. + \param Sync if TRUE, the packets are sent respecting the timestamps. If FALSE, the packets are sent as + fast as possible + \return The amount of bytes actually sent. If the return value is smaller than the Size parameter, an + error occurred during the send. The error can be caused by a driver/adapter problem or by an + inconsistent/bogus packet buffer. + + This function is used to send a buffer of raw packets to the network. The buffer can contain an arbitrary + number of raw packets, each of which preceded by a dump_bpf_hdr structure. The dump_bpf_hdr is the same used + by WinPcap and libpcap to store the packets in a file, therefore sending a capture file is straightforward. + 'Raw packets' means that the sending application will have to include the protocol headers, since every packet + is sent to the network 'as is'. The CRC of the packets needs not to be calculated, because it will be + transparently added by the network interface. + + \note Using this function if more efficient than issuing a series of PacketSendPacket(), because the packets are + buffered in the kernel driver, so the number of context switches is reduced. + + \note When Sync is set to TRUE, the packets are synchronized in the kerenl with a high precision timestamp. + This requires a remarkable amount of CPU, but allows to send the packets with a precision of some microseconds + (depending on the precision of the performance counter of the machine). Such a precision cannot be reached + sending the packets separately with PacketSendPacket(). +*/ +INT PacketSendPackets(LPADAPTER AdapterObject, PVOID PacketBuff, ULONG Size, BOOLEAN Sync) +{ + BOOLEAN Res; + DWORD BytesTransfered, TotBytesTransfered=0; + struct timeval BufStartTime; + LARGE_INTEGER StartTicks, CurTicks, TargetTicks, TimeFreq; + + + ODS("PacketSendPackets"); + + // Obtain starting timestamp of the buffer + BufStartTime.tv_sec = ((struct timeval*)(PacketBuff))->tv_sec; + BufStartTime.tv_usec = ((struct timeval*)(PacketBuff))->tv_usec; + + // Retrieve the reference time counters + QueryPerformanceCounter(&StartTicks); + QueryPerformanceFrequency(&TimeFreq); + + CurTicks.QuadPart = StartTicks.QuadPart; + + do{ + // Send the data to the driver + Res = DeviceIoControl(AdapterObject->hFile, + (Sync)?pBIOCSENDPACKETSSYNC:pBIOCSENDPACKETSNOSYNC, + (PCHAR)PacketBuff + TotBytesTransfered, + Size - TotBytesTransfered, + NULL, + 0, + &BytesTransfered, + NULL); + + TotBytesTransfered += BytesTransfered; + + // calculate the time interval to wait before sending the next packet + TargetTicks.QuadPart = StartTicks.QuadPart + + (LONGLONG) + ((((struct timeval*)((PCHAR)PacketBuff + TotBytesTransfered))->tv_sec - BufStartTime.tv_sec) * 1000000 + + (((struct timeval*)((PCHAR)PacketBuff + TotBytesTransfered))->tv_usec - BufStartTime.tv_usec)) * + (TimeFreq.QuadPart) / 1000000; + + // Exit from the loop on termination or error + if(TotBytesTransfered >= Size || Res != TRUE) + break; + + // Wait until the time interval has elapsed + while( CurTicks.QuadPart <= TargetTicks.QuadPart ) + QueryPerformanceCounter(&CurTicks); + + } + while(TRUE); + + return TotBytesTransfered; +} + +/*! + \brief Defines the minimum amount of data that will be received in a read. + \param AdapterObject Pointer to an _ADAPTER structure + \param nbytes the minimum amount of data in the kernel buffer that will cause the driver to + release a read on this adapter. + \return If the function succeeds, the return value is nonzero. + + In presence of a large value for nbytes, the kernel waits for the arrival of several packets before + copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage, + i.e. better performance, which is a good setting for applications like sniffers. Vice versa, a small value + means that the kernel will copy the packets as soon as the application is ready to receive them. This is + suggested for real time applications (like, for example, a bridge) that need the better responsiveness from + the kernel. + + \b note: this function has effect only in Windows NTx. The driver for Windows 9x doesn't offer + this possibility, therefore PacketSetMinToCopy is implemented under these systems only for compatibility. +*/ BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes) { @@ -645,31 +938,213 @@ BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes) return DeviceIoControl(AdapterObject->hFile,pBIOCSMINTOCOPY,&nbytes,4,NULL,0,&BytesReturned,NULL); } -//--------------------------------------------------------------------------- +/*! + \brief Sets the working mode of an adapter. + \param AdapterObject Pointer to an _ADAPTER structure. + \param mode The new working mode of the adapter. + \return If the function succeeds, the return value is nonzero. + The device driver of WinPcap has 4 working modes: + - Capture mode (mode = PACKET_MODE_CAPT): normal capture mode. The packets transiting on the wire are copied + to the application when PacketReceivePacket() is called. This is the default working mode of an adapter. + - Statistical mode (mode = PACKET_MODE_STAT): programmable statistical mode. PacketReceivePacket() returns, at + precise intervals, statics values on the network traffic. The interval between the statistic samples is + by default 1 second but it can be set to any other value (with a 1 ms precision) with the + PacketSetReadTimeout() function. The data returned by PacketReceivePacket() when the adapter is in statistical + mode is shown in the following figure:

+ \image html stats.gif "data structure returned by statistical mode" + Two 64-bit counters are provided: the number of packets and the amount of bytes that satisfy a filter + previously set with PacketSetBPF(). If no filter has been set, all the packets are counted. The counters are + encapsulated in a bpf_hdr structure, so that they will be parsed correctly by wpcap. Statistical mode has a + very low impact on system performance compared to capture mode. + - Dump mode (mode = PACKET_MODE_DUMP): the packets are dumped to disk by the driver, in libpcap format. This + method is much faster than saving the packets after having captured them. No data is returned + by PacketReceivePacket(). If the application sets a filter with PacketSetBPF(), only the packets that satisfy + this filter are dumped to disk. + - Statitical Dump mode (mode = PACKET_MODE_STAT_DUMP): the packets are dumped to disk by the driver, in libpcap + format, like in dump mode. PacketReceivePacket() returns, at precise intervals, statics values on the + network traffic and on the amount of data saved to file, in a way similar to statistical mode. + The data returned by PacketReceivePacket() when the adapter is in statistical dump mode is shown in + the following figure:

+ \image html dump.gif "data structure returned by statistical dump mode" + Three 64-bit counters are provided: the number of packets accepted, the amount of bytes accepted and the + effective amount of data (including headers) dumped to file. If no filter has been set, all the packets are + dumped to disk. The counters are encapsulated in a bpf_hdr structure, so that they will be parsed correctly + by wpcap. + Look at the NetMeter example in the + WinPcap developer's pack to see how to use statistics mode. +*/ BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode) { DWORD BytesReturned; return DeviceIoControl(AdapterObject->hFile,pBIOCSMODE,&mode,4,NULL,0,&BytesReturned,NULL); } -//--------------------------------------------------------------------------- +/*! + \brief Sets the name of the file that will receive the packet when the adapter is in dump mode. + \param AdapterObject Pointer to an _ADAPTER structure. + \param name the file name, in ASCII or UNICODE. + \param len the length of the buffer containing the name, in bytes. + \return If the function succeeds, the return value is nonzero. + This function defines the file name that the driver will open to store the packets on disk when + it works in dump mode. The adapter must be in dump mode, i.e. PacketSetMode() should have been + called previously with mode = PACKET_MODE_DUMP. otherwise this function will fail. + If PacketSetDumpName was already invoked on the adapter pointed by AdapterObject, the driver + closes the old file and opens the new one. +*/ + +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len) +{ + DWORD BytesReturned; + WCHAR *FileName; + BOOLEAN res; + WCHAR NameWithPath[1024]; + int TStrLen; + WCHAR *NamePos; + + if(((PUCHAR)name)[1]!=0 && len>1){ //ASCII + FileName=SChar2WChar(name); + len*=2; + } + else { //Unicode + FileName=name; + } + + TStrLen=GetFullPathName(FileName,1024,NameWithPath,&NamePos); + + len=TStrLen*2+2; //add the terminating null character + + // Try to catch malformed strings + if(len>2048){ + if(((PUCHAR)name)[1]!=0 && len>1) free(FileName); + return FALSE; + } + + res = DeviceIoControl(AdapterObject->hFile,pBIOCSETDUMPFILENAME,NameWithPath,len,NULL,0,&BytesReturned,NULL); + free(FileName); + return res; +} + +/*! + \brief Set the dump mode limits. + \param AdapterObject Pointer to an _ADAPTER structure. + \param maxfilesize The maximum dimension of the dump file, in bytes. 0 means no limit. + \param maxnpacks The maximum number of packets contained in the dump file. 0 means no limit. + \return If the function succeeds, the return value is nonzero. + + This function sets the limits after which the NPF driver stops to save the packets to file when an adapter + is in dump mode. This allows to limit the dump file to a precise number of bytes or packets, avoiding that + very long dumps fill the disk space. If both maxfilesize and maxnpacks are set, the dump is stopped when + the first of the two is reached. + + \note When a limit is reached, the dump is stopped, but the file remains opened. In order to flush + correctly the data and access the file consistently, you need to close the adapter with PacketCloseAdapter(). +*/ +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks) +{ + DWORD BytesReturned; + UINT valbuff[2]; + + valbuff[0] = maxfilesize; + valbuff[1] = maxnpacks; + + return DeviceIoControl(AdapterObject->hFile, + pBIOCSETDUMPLIMITS, + valbuff, + sizeof valbuff, + NULL, + 0, + &BytesReturned, + NULL); +} + +/*! + \brief Returns the status of the kernel dump process, i.e. tells if one of the limits defined with PacketSetDumpLimits() was reached. + \param AdapterObject Pointer to an _ADAPTER structure. + \param sync if TRUE, the function blocks until the dump is finished, otherwise it returns immediately. + \return TRUE if the dump is ended, FALSE otherwise. + + PacketIsDumpEnded() informs the user about the limits that were set with a previous call to + PacketSetDumpLimits(). + + \warning If no calls to PacketSetDumpLimits() were performed or if the dump process has no limits + (i.e. if the arguments of the last call to PacketSetDumpLimits() were both 0), setting sync to TRUE will + block the application on this call forever. +*/ +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync) +{ + DWORD BytesReturned; + int IsDumpEnded; + BOOLEAN res; + + if(sync) + WaitForSingleObject(AdapterObject->ReadEvent, INFINITE); + + res = DeviceIoControl(AdapterObject->hFile, + pBIOCISDUMPENDED, + NULL, + 0, + &IsDumpEnded, + 4, + &BytesReturned, + NULL); + + if(res == FALSE) return TRUE; // If the IOCTL returns an error we consider the dump finished + + return (BOOLEAN)IsDumpEnded; +} + +/*! + \brief Returns the notification event associated with the read calls on an adapter. + \param AdapterObject Pointer to an _ADAPTER structure. + \return The handle of the event that the driver signals when some data is available in the kernel buffer. + + The event returned by this function is signaled by the driver if: + - The adapter pointed by AdapterObject is in capture mode and an amount of data greater or equal + than the one set with the PacketSetMinToCopy() function is received from the network. + - the adapter pointed by AdapterObject is in capture mode, no data has been received from the network + but the the timeout set with the PacketSetReadTimeout() function has elapsed. + - the adapter pointed by AdapterObject is in statics mode and the the timeout set with the + PacketSetReadTimeout() function has elapsed. This means that a new statistic sample is available. + + In every case, a call to PacketReceivePacket() will return immediately. + The event can be passed to standard Win32 functions (like WaitForSingleObject or WaitForMultipleObjects) + to wait until the driver's buffer contains some data. It is particularly useful in GUI applications that + need to wait concurrently on several events. + +*/ HANDLE PacketGetReadEvent(LPADAPTER AdapterObject) { return AdapterObject->ReadEvent; } -//--------------------------------------------------------------------------- +/*! + \brief Sets the number of times a single packet written with PacketSendPacket() will be repeated on the network. + \param AdapterObject Pointer to an _ADAPTER structure. + \param nwrites Number of copies of a packet that will be physically sent by the interface. + \return If the function succeeds, the return value is nonzero. + See PacketSendPacket() for details. +*/ BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites) { DWORD BytesReturned; return DeviceIoControl(AdapterObject->hFile,pBIOCSWRITEREP,&nwrites,4,NULL,0,&BytesReturned,NULL); } -//--------------------------------------------------------------------------- +/*! + \brief Sets the timeout after which a read on an adapter returns. + \param AdapterObject Pointer to an _ADAPTER structure. + \param timeout indicates the timeout, in milliseconds, after which a call to PacketReceivePacket() on + the adapter pointed by AdapterObject will be released, also if no packets have been captured by the driver. + Setting timeout to 0 means no timeout, i.e. PacketReceivePacket() never returns if no packet arrives. + A timeout of -1 causes PacketReceivePacket() to always return immediately. + \return If the function succeeds, the return value is nonzero. + \note This function works also if the adapter is working in statistics mode, and can be used to set the + time interval between two statistic reports. +*/ BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout) { DWORD BytesReturned; @@ -680,32 +1155,136 @@ BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout) return DeviceIoControl(AdapterObject->hFile,pBIOCSRTIMEOUT,&DriverTimeOut,4,NULL,0,&BytesReturned,NULL); } -//--------------------------------------------------------------------------- +/*! + \brief Sets the size of the kernel-level buffer associated with a capture. + \param AdapterObject Pointer to an _ADAPTER structure. + \param dim New size of the buffer, in \b kilobytes. + \return The function returns TRUE if successfully completed, FALSE if there is not enough memory to + allocate the new buffer. + When a new dimension is set, the data in the old buffer is discarded and the packets stored in it are + lost. + + Note: the dimension of the kernel buffer affects heavily the performances of the capture process. + An adequate buffer in the driver is able to keep the packets while the application is busy, compensating + the delays of the application and avoiding the loss of packets during bursts or high network activity. + The buffer size is set to 0 when an instance of the driver is opened: the programmer should remember to + set it to a proper value. As an example, wpcap sets the buffer size to 1MB at the beginning of a capture. +*/ BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim) { DWORD BytesReturned; return DeviceIoControl(AdapterObject->hFile,pBIOCSETBUFFERSIZE,&dim,4,NULL,0,&BytesReturned,NULL); } -//--------------------------------------------------------------------------- +/*! + \brief Sets a kernel-level packet filter. + \param AdapterObject Pointer to an _ADAPTER structure. + \param fp Pointer to a filtering program that will be associated with this capture or monitoring + instance and that will be executed on every incoming packet. + \return This function returns TRUE if the filter is set successfully, FALSE if an error occurs + or if the filter program is not accepted after a safeness check by the driver. The driver performs + the check in order to avoid system crashes due to buggy or malicious filters, and it rejects non + conformat filters. + This function associates a new BPF filter to the adapter AdapterObject. The filter, pointed by fp, is a + set of bpf_insn instructions. + + A filter can be automatically created by using the pcap_compile() function of wpcap. This function + converts a human readable text expression with the syntax of WinDump (see the manual of WinDump at + http://netgroup.polito.it/windump for details) into a BPF program. If your program doesn't link wpcap, but + you need to know the code of a particular filter, you can launch WinDump with the -d or -dd or -ddd + flags to obtain the pseudocode. + +*/ BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp) { DWORD BytesReturned; return DeviceIoControl(AdapterObject->hFile,pBIOCSETF,(char*)fp->bf_insns,fp->bf_len*sizeof(struct bpf_insn),NULL,0,&BytesReturned,NULL); } -//--------------------------------------------------------------------------- +/*! + \brief Returns a couple of statistic values about the current capture session. + \param AdapterObject Pointer to an _ADAPTER structure. + \param s Pointer to a user provided bpf_stat structure that will be filled by the function. + \return If the function succeeds, the return value is nonzero. + With this function, the programmer can know the value of two internal variables of the driver: + + - the number of packets that have been received by the adapter AdapterObject, starting at the + time in which it was opened with PacketOpenAdapter. + - the number of packets that have been dropped by the driver. A packet is dropped when the kernel + buffer associated with the adapter is full. +*/ BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s) { + BOOLEAN Res; DWORD BytesReturned; - return DeviceIoControl(AdapterObject->hFile,pBIOCGSTATS,NULL,0,s,sizeof(struct bpf_stat),&BytesReturned,NULL); + struct bpf_stat tmpstat; // We use a support structure to avoid kernel-level inconsistencies with old or malicious applications + + Res = DeviceIoControl(AdapterObject->hFile, + pBIOCGSTATS, + NULL, + 0, + &tmpstat, + sizeof(struct bpf_stat), + &BytesReturned, + NULL); + + // Copy only the first two values retrieved from the driver + s->bs_recv = tmpstat.bs_recv; + s->bs_drop = tmpstat.bs_drop; + + return Res; } -//--------------------------------------------------------------------------- +/*! + \brief Returns statistic values about the current capture session. Enhanced version of PacketGetStats(). + \param AdapterObject Pointer to an _ADAPTER structure. + \param s Pointer to a user provided bpf_stat structure that will be filled by the function. + \return If the function succeeds, the return value is nonzero. + With this function, the programmer can retireve the sname values provided by PacketGetStats(), plus: + + - the number of drops by interface (not yet supported, always 0). + - the number of packets that reached the application, i.e that were accepted by the kernel filter and + that fitted in the kernel buffer. +*/ +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s) +{ + BOOLEAN Res; + DWORD BytesReturned; + struct bpf_stat tmpstat; // We use a support structure to avoid kernel-level inconsistencies with old or malicious applications + + Res = DeviceIoControl(AdapterObject->hFile, + pBIOCGSTATS, + NULL, + 0, + &tmpstat, + sizeof(struct bpf_stat), + &BytesReturned, + NULL); + + s->bs_recv = tmpstat.bs_recv; + s->bs_drop = tmpstat.bs_drop; + s->ps_ifdrop = tmpstat.ps_ifdrop; + s->bs_capt = tmpstat.bs_capt; + + return Res; +} + +/*! + \brief Performs a query/set operation on an internal variable of the network card driver. + \param AdapterObject Pointer to an _ADAPTER structure. + \param Set Determines if the operation is a set (Set=TRUE) or a query (Set=FALSE). + \param OidData A pointer to a _PACKET_OID_DATA structure that contains or receives the data. + \return If the function succeeds, the return value is nonzero. + + \note not all the network adapters implement all the query/set functions. There is a set of mandatory + OID functions that is granted to be present on all the adapters, and a set of facultative functions, not + provided by all the cards (see the Microsoft DDKs to see which functions are mandatory). If you use a + facultative function, be careful to enclose it in an if statement to check the result. +*/ BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData) { DWORD BytesReturned; @@ -724,8 +1303,22 @@ BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA Oid return Result; } -//--------------------------------------------------------------------------- +/*! + \brief Sets a hardware filter on the incoming packets. + \param AdapterObject Pointer to an _ADAPTER structure. + \param Filter The identifier of the filter. + \return If the function succeeds, the return value is nonzero. + The filter defined with this filter is evaluated by the network card, at a level that is under the NPF + device driver. Here is a list of the most useful hardware filters (A complete list can be found in ntddndis.h): + + - NDIS_PACKET_TYPE_PROMISCUOUS: sets promiscuous mode. Every incoming packet is accepted by the adapter. + - NDIS_PACKET_TYPE_DIRECTED: only packets directed to the workstation's adapter are accepted. + - NDIS_PACKET_TYPE_BROADCAST: only broadcast packets are accepted. + - NDIS_PACKET_TYPE_MULTICAST: only multicast packets belonging to groups of which this adapter is a member are accepted. + - NDIS_PACKET_TYPE_ALL_MULTICAST: every multicast packet is accepted. + - NDIS_PACKET_TYPE_ALL_LOCAL: all local packets, i.e. NDIS_PACKET_TYPE_DIRECTED + NDIS_PACKET_TYPE_BROADCAST + NDIS_PACKET_TYPE_MULTICAST +*/ BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter) { BOOLEAN Status; @@ -745,74 +1338,98 @@ BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter) return Status; } -//--------------------------------------------------------------------------- +/*! + \brief Retrieve the list of available network adapters and their description. + \param pStr User allocated string that will be filled with the names of the adapters. + \param BufferSize Length of the buffer pointed by pStr. + \return If the function succeeds, the return value is nonzero. -BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize) + Usually, this is the first function that should be used to communicate with the driver. + It returns the names of the adapters installed on the system and supported by WinPcap. + After the names of the adapters, pStr contains a string that describes each of them. + + \b Warning: + the result of this function is obtained querying the registry, therefore the format + of the result in Windows NTx is different from the one in Windows 9x. Windows 9x uses the ASCII + encoding method to store a string, while Windows NTx uses UNICODE. After a call to PacketGetAdapterNames + in Windows 95x, pStr contains, in succession: + - a variable number of ASCII strings, each with the names of an adapter, separated by a "\0" + - a double "\0" + - a number of ASCII strings, each with the description of an adapter, separated by a "\0". The number + of descriptions is the same of the one of names. The fisrt description corresponds to the first name, and + so on. + - a double "\0". + + In Windows NTx, pStr contains: the names of the adapters, in UNICODE format, separated by a single UNICODE "\0" (i.e. 2 ASCII "\0"), a double UNICODE "\0", followed by the descriptions of the adapters, in ASCII format, separated by a single ASCII "\0" . The string is terminated by a double ASCII "\0". + - a variable number of UNICODE strings, each with the names of an adapter, separated by a UNICODE "\0" + - a double UNICODE "\0" + - a number of ASCII strings, each with the description of an adapter, separated by an ASCII "\0". + - a double ASCII "\0". +*/ + +BOOLEAN PacketGetAdapterNames(PTSTR pStr, PULONG BufferSize) { - HKEY LinkageKey,AdapKey; - DWORD RegKeySize=0; + HKEY LinkageKey, AdapKey; + DWORD RegKeySize = 0; LONG Status; ULONG Result; PTSTR BpStr; - char *TTpStr,*DpStr,*DescBuf; + char *TTpStr; + char *DpStr; + char *DescBuf; LPADAPTER adapter; - PPACKET_OID_DATA OidData; - int i=0,k,rewind; + PPACKET_OID_DATA OidData; + int i = 0, k, rewind; DWORD dim; TCHAR AdapName[256]; ODSEx("PacketGetAdapterNames: BufferSize=%d\n",*BufferSize); - OidData=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,512); + OidData = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, 512); if (OidData == NULL) { ODS("PacketGetAdapterNames: GlobalAlloc Failed\n"); return FALSE; } - Status=RegOpenKeyEx(HKEY_LOCAL_MACHINE, - TEXT("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"), - 0, - KEY_READ, - &AdapKey); + Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\ControlSet001\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"), + 0, KEY_READ, &AdapKey); // Get the size to allocate for the original device names - while((Result=RegEnumKey(AdapKey,i,AdapName,sizeof(AdapName)/2))==ERROR_SUCCESS) - { - Status=RegOpenKeyEx(AdapKey,AdapName,0,KEY_READ,&LinkageKey); - Status=RegOpenKeyEx(LinkageKey,L"Linkage",0,KEY_READ,&LinkageKey); - Status=RegQueryValueEx(LinkageKey,L"Export",NULL,NULL,NULL,&dim); + while ((Result = RegEnumKey(AdapKey, i, AdapName, sizeof(AdapName)/2)) == ERROR_SUCCESS) { + Status = RegOpenKeyEx(AdapKey, AdapName,0, KEY_READ, &LinkageKey); + Status = RegOpenKeyExW(LinkageKey, L"Linkage",0, KEY_READ, &LinkageKey); + Status = RegQueryValueExW(LinkageKey, L"Export", NULL, NULL, NULL, &dim); i++; - if(Status!=ERROR_SUCCESS) continue; - RegKeySize+=dim; + if (Status!=ERROR_SUCCESS) continue; + RegKeySize += dim; } // Allocate the memory for the original device names ODSEx("Need %d bytes for the names\n", RegKeySize+2); - BpStr=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,RegKeySize+2); + BpStr = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, RegKeySize+2); if (BpStr == NULL || RegKeySize > *BufferSize) { ODS("PacketGetAdapterNames: GlobalAlloc Failed\n"); GlobalFreePtr(OidData); return FALSE; } - - k=0; - i=0; + k = 0; + i = 0; ODS("PacketGetAdapterNames: Cycling through the adapters:\n"); // Copy the names to the buffer - while((Result=RegEnumKey(AdapKey,i,AdapName,sizeof(AdapName)/2))==ERROR_SUCCESS) - { + while ((Result = RegEnumKey(AdapKey, i, AdapName, sizeof(AdapName)/2)) == ERROR_SUCCESS) { WCHAR UpperBindStr[64]; i++; ODSEx(" %d) ", i); - Status=RegOpenKeyEx(AdapKey,AdapName,0,KEY_READ,&LinkageKey); - Status=RegOpenKeyEx(LinkageKey,L"Linkage",0,KEY_READ,&LinkageKey); + Status = RegOpenKeyEx(AdapKey,AdapName,0,KEY_READ,&LinkageKey); + Status = RegOpenKeyExW(LinkageKey,L"Linkage",0,KEY_READ,&LinkageKey); dim=sizeof(UpperBindStr); - Status=RegQueryValueEx(LinkageKey,L"UpperBind",NULL,NULL,(PUCHAR)UpperBindStr,&dim); + Status=RegQueryValueExW(LinkageKey,L"UpperBind",NULL,NULL,(PUCHAR)UpperBindStr,&dim); ODSEx("UpperBind=%S ", UpperBindStr); @@ -822,7 +1439,7 @@ BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize) } dim=RegKeySize-k; - Status=RegQueryValueEx(LinkageKey,L"Export",NULL,NULL,(LPBYTE)BpStr+k,&dim); + Status=RegQueryValueExW(LinkageKey,L"Export",NULL,NULL,(LPBYTE)BpStr+k,&dim); if(Status!=ERROR_SUCCESS){ ODS("Name = SKIPPED (error reading the key)\n"); continue; @@ -875,9 +1492,9 @@ BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize) // Create the device name rewind=k; memcpy(pStr+k,BpStr+i,16); - memcpy(pStr+k+8,TEXT("Packet_"),14); + memcpy(pStr+k+8,TEXT("NPF_"),8); i+=8; - k+=15; + k+=12; while(BpStr[i-1]!=0){ pStr[k++]=BpStr[i++]; } @@ -912,134 +1529,146 @@ BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize) PacketCloseAdapter(adapter); } - *DpStr=0; + *DpStr = 0; - pStr[k++]=0; - pStr[k]=0; + pStr[k++] = 0; + pStr[k] = 0; - if((ULONG)(DpStr-DescBuf+k) < *BufferSize) - memcpy(pStr+k,DescBuf,DpStr-DescBuf); - else{ + if ((ULONG)(DpStr - DescBuf + k) < *BufferSize) { + memcpy(pStr + k, DescBuf, DpStr - DescBuf); + } else { GlobalFreePtr(OidData); - GlobalFreePtr (BpStr); - GlobalFreePtr (DescBuf); + GlobalFreePtr(BpStr); + GlobalFreePtr(DescBuf); ODS("\nPacketGetAdapterNames: ended with failure\n"); return FALSE; } GlobalFreePtr(OidData); - GlobalFreePtr (BpStr); - GlobalFreePtr (DescBuf); + GlobalFreePtr(BpStr); + GlobalFreePtr(DescBuf); ODS("\nPacketGetAdapterNames: ended correctly\n"); return TRUE; } else{ - DWORD RegType; + DWORD RegType; - ODS("Adapters not found under SYSTEM\\CurrentControlSet\\Control\\Class. Using the TCP/IP bindings.\n"); + ODS("Adapters not found under SYSTEM\\ControlSet001\\Control\\Class. Using the TCP/IP bindings.\n"); - GlobalFreePtr (BpStr); - - Status=RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage"),0,KEY_READ,&LinkageKey); - if (Status == ERROR_SUCCESS) - { + GlobalFreePtr(BpStr); + Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\ControlSet001\\Services\\Tcpip\\Linkage"), + 0, KEY_READ, &LinkageKey); + if (Status == ERROR_SUCCESS) { // Retrieve the length of the key - Status=RegQueryValueEx(LinkageKey,TEXT("bind"),NULL,&RegType,NULL,&RegKeySize); + Status = RegQueryValueEx(LinkageKey, TEXT("bind"), NULL, &RegType, NULL, &RegKeySize); // Allocate the buffer - BpStr=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,RegKeySize+2); + BpStr = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, RegKeySize + 2); if (BpStr == NULL || RegKeySize > *BufferSize) { GlobalFreePtr(OidData); return FALSE; } - Status=RegQueryValueEx(LinkageKey,TEXT("bind"),NULL,&RegType,(LPBYTE)BpStr,&RegKeySize); + Status = RegQueryValueEx(LinkageKey, TEXT("bind"), NULL, &RegType, (LPBYTE)BpStr, &RegKeySize); RegCloseKey(LinkageKey); + } else { + //ODS("SYSTEM\\ControlSet001\\Control\\Class - RegKey not found.\n"); + ODS("SYSTEM\\ControlSet001\\Services\\Tcpip\\Linkage - RegKey not found.\n"); } - - if (Status==ERROR_SUCCESS){ - - DescBuf=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, 4096); + if (Status == ERROR_SUCCESS) { + DescBuf = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, 4096); if (DescBuf == NULL) { - GlobalFreePtr (BpStr); + GlobalFreePtr(BpStr); GlobalFreePtr(OidData); return FALSE; } - DpStr=DescBuf; - - for(i=0,k=0;BpStr[i]!=0 || BpStr[i+1]!=0;){ - - if(k+wcslen(BpStr+i)+30 > *BufferSize){ + DpStr = DescBuf; + for (i = 0, k = 0; BpStr[i] != 0 || BpStr[i+1] != 0; ) { + if (k + wcslen(BpStr + i) + 30 > *BufferSize) { // Input buffer too small GlobalFreePtr(OidData); - GlobalFreePtr (BpStr); - GlobalFreePtr (DescBuf); + GlobalFreePtr(BpStr); + GlobalFreePtr(DescBuf); return FALSE; } - + + ODS("\tCreating a device name - started.\n"); + // Create the device name - rewind=k; - memcpy(pStr+k,BpStr+i,16); - memcpy(pStr+k+8,TEXT("Packet_"),14); - i+=8; - k+=15; - while(BpStr[i-1]!=0){ - pStr[k++]=BpStr[i++]; + rewind = k; + memcpy(pStr + k,BpStr + i,16); + memcpy(pStr + k + 8, TEXT("NPF_"), 8); + i += 8; + k += 12; + while (BpStr[i - 1] != 0) { + pStr[k++] = BpStr[i++]; } - // Open the adapter - adapter=PacketOpenAdapter(pStr+rewind); - if(adapter==NULL){ - k=rewind; + adapter = PacketOpenAdapter(pStr+rewind); + if (adapter == NULL) { + k = rewind; continue; } - // Retrieve the description OidData->Oid = OID_GEN_VENDOR_DESCRIPTION; OidData->Length = 256; - Status = PacketRequest(adapter,FALSE,OidData); - if(Status==0 || ((char*)OidData->Data)[0]==0){ - k=rewind; + Status = PacketRequest(adapter, FALSE, OidData); + if (Status == 0 || ((char*)OidData->Data)[0] == 0) { + k = rewind; + ODS("\tCreating a device name - Retrieve the description.\n"); continue; } // Copy the description - TTpStr=(char*)(OidData->Data); - while(*TTpStr!=0){ - *DpStr++=*TTpStr++; + TTpStr = (char*)(OidData->Data); + while (*TTpStr != 0){ + *DpStr++ = *TTpStr++; } - *DpStr++=*TTpStr++; - + *DpStr++ = *TTpStr++; // Close the adapter PacketCloseAdapter(adapter); - + + ODS("\tCreating a device name - completed.\n"); } - *DpStr=0; + *DpStr = 0; - pStr[k++]=0; - pStr[k]=0; + pStr[k++] = 0; + pStr[k] = 0; - if((ULONG)(DpStr-DescBuf+k) < *BufferSize) - memcpy(pStr+k,DescBuf,DpStr-DescBuf); - else{ + if ((ULONG)(DpStr - DescBuf + k) < *BufferSize) { + memcpy(pStr + k, DescBuf, DpStr-DescBuf); + } else { GlobalFreePtr(OidData); - GlobalFreePtr (BpStr); - GlobalFreePtr (DescBuf); + GlobalFreePtr(BpStr); + GlobalFreePtr(DescBuf); return FALSE; } GlobalFreePtr(OidData); - GlobalFreePtr (BpStr); - GlobalFreePtr (DescBuf); + GlobalFreePtr(BpStr); + GlobalFreePtr(DescBuf); + ODS("PacketGetAdapterNames() returning TRUE\n"); return TRUE; - } - else{ + } else { MessageBox(NULL,TEXT("Can not find TCP/IP bindings.\nIn order to run the packet capture driver you must install TCP/IP."),szWindowTitle,MB_OK); - ODS("Cannot find the TCP/IP bindings"); + ODS("Cannot find the TCP/IP bindings\n"); return FALSE; } } } -//--------------------------------------------------------------------------- +/*! + \brief Returns comprehensive information the addresses of an adapter. + \param AdapterName String that contain _ADAPTER structure. + \param buffer A user allocated array of npf_if_addr that will be filled by the function. + \param NEntries Size of the array (in npf_if_addr). + \return If the function succeeds, the return value is nonzero. + + This function grabs from the registry information like the IP addresses, the netmasks + and the broadcast addresses of an interface. The buffer passed by the user is filled with + npf_if_addr structures, each of which contains the data for a single address. If the buffer + is full, the reaming addresses are dropeed, therefore set its dimension to sizeof(npf_if_addr) + if you want only the first address. +*/ BOOLEAN PacketGetNetInfoEx(LPTSTR AdapterName, npf_if_addr* buffer, PLONG NEntries) { @@ -1067,17 +1696,19 @@ BOOLEAN PacketGetNetInfoEx(LPTSTR AdapterName, npf_if_addr* buffer, PLONG NEntri } else { //Unicode AdapterNameU = NULL; } - ifname = wcsrchr(AdapterName, '\\'); + ifname = wcsrchr(AdapterName, '\\'); if (ifname == NULL) ifname = AdapterName; else ifname++; - if (wcsncmp(ifname, L"Packet_", 7) == 0) - ifname += 7; + if (wcsncmp(ifname, L"NPF_", 4) == 0) + ifname += 4; - if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"), 0, KEY_READ, &UnderTcpKey) == ERROR_SUCCESS) + if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"), + 0, KEY_READ, &UnderTcpKey) == ERROR_SUCCESS) { - status = RegOpenKeyEx(UnderTcpKey,ifname,0,KEY_READ,&TcpIpKey); + status = RegOpenKeyExW(UnderTcpKey,ifname,0,KEY_READ,&TcpIpKey); if (status != ERROR_SUCCESS) { RegCloseKey(UnderTcpKey); goto fail; @@ -1087,10 +1718,12 @@ BOOLEAN PacketGetNetInfoEx(LPTSTR AdapterName, npf_if_addr* buffer, PLONG NEntri { // Query the registry key with the interface's adresses - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SYSTEM\\CurrentControlSet"),0,KEY_READ,&SystemKey); + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\ControlSet001\\Services"), + 0,KEY_READ,&SystemKey); if (status != ERROR_SUCCESS) goto fail; - status = RegOpenKeyEx(SystemKey,ifname,0,KEY_READ,&InterfaceKey); + status = RegOpenKeyExW(SystemKey,ifname,0,KEY_READ,&InterfaceKey); if (status != ERROR_SUCCESS) { RegCloseKey(SystemKey); goto fail; @@ -1277,7 +1910,15 @@ fail: return FALSE; } -//--------------------------------------------------------------------------- +/*! + \brief Returns the IP address and the netmask of an adapter. + \param AdapterName String that contain _ADAPTER structure. + \param netp Pointer to a variable that will receive the IP address of the adapter. + \param maskp Pointer to a variable that will receive the netmask of the adapter. + \return If the function succeeds, the return value is nonzero. + + \note this function is obsolete and is maintained for backward compatibility. Use PacketGetNetInfoEx() instead. +*/ BOOLEAN PacketGetNetInfo(LPTSTR AdapterName, PULONG netp, PULONG maskp) { @@ -1307,12 +1948,14 @@ BOOLEAN PacketGetNetInfo(LPTSTR AdapterName, PULONG netp, PULONG maskp) ifname = AdapterName; else ifname++; - if (wcsncmp(ifname, L"Packet_", 7) == 0) - ifname += 7; - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SYSTEM\\CurrentControlSet\\Services"),0,KEY_READ,&SystemKey); + if (wcsncmp(ifname, L"NPF_", 4) == 0) + ifname += 4; + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\ControlSet001\\Services"), + 0,KEY_READ,&SystemKey); if (status != ERROR_SUCCESS) goto fail; - status = RegOpenKeyEx(SystemKey,ifname,0,KEY_READ,&InterfaceKey); + status = RegOpenKeyExW(SystemKey,ifname,0,KEY_READ,&InterfaceKey); if (status != ERROR_SUCCESS) { RegCloseKey(SystemKey); goto fail; @@ -1409,3 +2052,5 @@ fail: free(AdapterNameU); return FALSE; } + +/* @} */ diff --git a/reactos/lib/packet/include/packet32.h b/reactos/lib/packet/include/packet32.h index 5431091254a..bcb167ad668 100644 --- a/reactos/lib/packet/include/packet32.h +++ b/reactos/lib/packet/include/packet32.h @@ -19,6 +19,17 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32h Packet.dll definitions and data structures + * Packet32.h contains the data structures and the definitions used by packet.dll. + * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included + * by the applications that use the functions of this library + * @{ + */ + #ifndef __PACKET32 #define __PACKET32 @@ -42,31 +53,41 @@ #define IOCTL_OPEN CTL_CODE(FILE_DEVICE_PROTOCOL, 7 , METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_CLOSE CTL_CODE(FILE_DEVICE_PROTOCOL, 8 , METHOD_BUFFERED, FILE_ANY_ACCESS) -#define pBIOCSETBUFFERSIZE 9592 -#define pBIOCSETF 9030 -#define pBIOCGSTATS 9031 -#define pBIOCSRTIMEOUT 7416 -#define pBIOCSMODE 7412 -#define pBIOCSWRITEREP 7413 -#define pBIOCSMINTOCOPY 7414 -#define pBIOCSETOID 2147483648 -#define pBIOCQUERYOID 2147483652 -#define pATTACHPROCESS 7117 -#define pDETACHPROCESS 7118 -#define pBIOCSETDUMPFILENAME 9029 -#define pBIOCEVNAME 7415 +#define pBIOCSETBUFFERSIZE 9592 ///< IOCTL code: set kernel buffer size. +#define pBIOCSETF 9030 ///< IOCTL code: set packet filtering program. +#define pBIOCGSTATS 9031 ///< IOCTL code: get the capture stats. +#define pBIOCSRTIMEOUT 7416 ///< IOCTL code: set the read timeout. +#define pBIOCSMODE 7412 ///< IOCTL code: set working mode. +#define pBIOCSWRITEREP 7413 ///< IOCTL code: set number of physical repetions of every packet written by the app. +#define pBIOCSMINTOCOPY 7414 ///< IOCTL code: set minimum amount of data in the kernel buffer that unlocks a read call. +#define pBIOCSETOID 2147483648 ///< IOCTL code: set an OID value. +#define pBIOCQUERYOID 2147483652 ///< IOCTL code: get an OID value. +#define pATTACHPROCESS 7117 ///< IOCTL code: attach a process to the driver. Used in Win9x only. +#define pDETACHPROCESS 7118 ///< IOCTL code: detach a process from the driver. Used in Win9x only. +#define pBIOCSETDUMPFILENAME 9029 ///< IOCTL code: set the name of a the file used by kernel dump mode. +#define pBIOCEVNAME 7415 ///< IOCTL code: get the name of the event that the driver signals when some data is present in the buffer. +#define pBIOCSENDPACKETSNOSYNC 9032 ///< IOCTL code: Send a buffer containing multiple packets to the network, ignoring the timestamps associated with the packets. +#define pBIOCSENDPACKETSSYNC 9033 ///< IOCTL code: Send a buffer containing multiple packets to the network, respecting the timestamps associated with the packets. +#define pBIOCSETDUMPLIMITS 9034 ///< IOCTL code: Set the dump file limits. See the PacketSetDumpLimits() function. +#define pBIOCISDUMPENDED 7411 ///< IOCTL code: Get the status of the kernel dump process. See the PacketIsDumpEnded() function. -#define pBIOCSTIMEZONE 7471 +#define pBIOCSTIMEZONE 7471 ///< IOCTL code: set time zone. Used in Win9x only. -// Alignment macros. Packet_WORDALIGN rounds up to the next -// even multiple of Packet_ALIGNMENT. + +/// Alignment macro. Defines the alignment size. #define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. #define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ typedef struct NetType { - UINT LinkType; - UINT LinkSpeed; + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + UINT LinkSpeed; ///< The speed of the network in bits per second }NetType; @@ -74,75 +95,160 @@ typedef struct NetType #ifndef BPF_MAJOR_VERSION +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ struct bpf_program { - UINT bf_len; - struct bpf_insn *bf_insns; + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. }; +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ struct bpf_insn { - USHORT code; - UCHAR jt; - UCHAR jf; - int k; + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. }; +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ struct bpf_stat { - UINT bs_recv; + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; +/*! + \brief Packet header. - UINT bs_drop; + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr { + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; +/*! + \brief Dump packet header. + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). }; -struct bpf_hdr { - struct timeval bh_tstamp; - UINT bh_caplen; - UINT bh_datalen; - USHORT bh_hdrlen; -}; #endif -#define DOSNAMEPREFIX TEXT("Packet_") -#define MAX_LINK_NAME_LENGTH 64 +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links #define NMAX_PACKET 65535 +/*! + \brief Describes a network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ typedef struct _ADAPTER { - HANDLE hFile; - TCHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; - int NumWrites; - HANDLE ReadEvent; - UINT ReadTimeOut; + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured } ADAPTER, *LPADAPTER; +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ typedef struct _PACKET { - HANDLE hEvent; - OVERLAPPED OverLapped; - PVOID Buffer; - UINT Length; - UINT ulBytesReceived; - BOOLEAN bIoComplete; + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. } PACKET, *LPPACKET; -struct _PACKET_OID_DATA { - ULONG Oid; - ULONG Length; - UCHAR Data[1]; +/*! + \brief Structure containing an OID request. + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. }; typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ typedef struct npf_if_addr { - struct sockaddr IPAddress; - struct sockaddr SubnetMask; - struct sockaddr Broadcast; + struct sockaddr IPAddress; ///< IP address. + struct sockaddr SubnetMask; ///< Netmask for that address. + struct sockaddr Broadcast; ///< Broadcast address. }npf_if_addr; #ifdef __cplusplus extern "C" { #endif +/** + * @} + */ + //--------------------------------------------------------------------------- // FUNCTIONS //--------------------------------------------------------------------------- @@ -154,10 +260,12 @@ BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); LPADAPTER PacketOpenAdapter(LPTSTR AdapterName); BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); LPPACKET PacketAllocatePacket(void); VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); VOID PacketFreePacket(LPPACKET lpPacket); @@ -169,6 +277,8 @@ BOOLEAN PacketGetNetInfoEx(LPTSTR AdapterName, npf_if_addr* buffer, PLONG NEntri BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); BOOL PacketStopDriver(); VOID PacketCloseAdapter(LPADAPTER lpAdapter); diff --git a/reactos/lib/packet/makefile b/reactos/lib/packet/makefile index ac38a9a21d6..2717e16254a 100644 --- a/reactos/lib/packet/makefile +++ b/reactos/lib/packet/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.2 2002/08/17 15:58:38 robd Exp $ +# $Id: makefile,v 1.3 2002/09/24 15:08:14 robd Exp $ PATH_TO_TOP = ../.. @@ -8,12 +8,13 @@ TARGET_NAME = packet TARGET_BASE = 0x77780000 -TARGET_CFLAGS = -I./include -DUNICODE -DLE -DDBG +TARGET_CFLAGS = -I./include -DUNICODE -D_UNICODE -DLE -DDBG -D_DEBUG TARGET_SDKLIBS = ntdll.a kernel32.a advapi32.a TARGET_OBJECTS = \ - Packet32.o + Packet32.o \ + trace.o TARGET_CLEAN = $(TARGET_OBJECTS) diff --git a/reactos/lib/packet/packet.def b/reactos/lib/packet/packet.def index f7619089a56..bba1a4c4e35 100644 --- a/reactos/lib/packet/packet.def +++ b/reactos/lib/packet/packet.def @@ -3,27 +3,32 @@ LIBRARY packet DESCRIPTION 'Packet driver dll' EXPORTS -PacketLibraryVersion -PacketGetVersion -PacketOpenAdapter -PacketSendPacket -PacketAllocatePacket -PacketInitPacket -PacketFreePacket -PacketReceivePacket -PacketCloseAdapter -PacketSetHwFilter -PacketGetAdapterNames -PacketRequest -PacketSetBuff -PacketSetBpf -PacketGetStats -PacketGetNetType -PacketSetReadTimeout -PacketSetMode -PacketSetNumWrites -PacketGetNetInfo -PacketGetNetInfoEx -PacketSetMinToCopy -PacketGetReadEvent -PacketStopDriver + PacketLibraryVersion + PacketGetVersion + PacketOpenAdapter + PacketSendPacket + PacketSendPackets + PacketAllocatePacket + PacketInitPacket + PacketFreePacket + PacketReceivePacket + PacketCloseAdapter + PacketSetHwFilter + PacketGetAdapterNames + PacketRequest + PacketSetBuff + PacketSetBpf + PacketGetStats + PacketGetStatsEx + PacketGetNetType + PacketSetReadTimeout + PacketSetMode + PacketSetNumWrites + PacketGetNetInfo + PacketGetNetInfoEx + PacketSetMinToCopy + PacketGetReadEvent + PacketStopDriver + PacketSetDumpName + PacketSetDumpLimits + PacketIsDumpEnded diff --git a/reactos/lib/packet/trace.c b/reactos/lib/packet/trace.c new file mode 100644 index 00000000000..8104ebc6451 --- /dev/null +++ b/reactos/lib/packet/trace.c @@ -0,0 +1,53 @@ +///////////////////////////////////////////////////////////////////////////// +// Diagnostic Trace +// +#include +#include +#include +//#include +#include "trace.h" + +#ifdef _DEBUG + +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; + +void _DebugBreak(void) +{ + DebugBreak(); +} + +//void Trace(TCHAR* lpszFormat, ...) +void Trace(char* lpszFormat, ...) +{ + va_list args; + int nBuf; + char szBuffer[512]; + + va_start(args, lpszFormat); + nBuf = _vsnprintf(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), lpszFormat, args); + OutputDebugStringA(szBuffer); + // was there an error? was the expanded string too long? + //ASSERT(nBuf >= 0); + va_end(args); +} + +void Assert(void* assert, const char* file, int line, void* msg) +{ + if (msg == NULL) { + printf("ASSERT -- %s occured on line %u of file %s.\n", + assert, line, file); + } else { + printf("ASSERT -- %s occured on line %u of file %s: Message = %s.\n", + assert, line, file, msg); + } +} + +#else + +//void Trace(TCHAR* lpszFormat, ...) { }; +void Trace(char* lpszFormat, ...) { }; +void Assert(void* assert, const char* file, int line, void* msg) { }; + +#endif //_DEBUG +///////////////////////////////////////////////////////////////////////////// diff --git a/reactos/lib/packet/trace.h b/reactos/lib/packet/trace.h new file mode 100644 index 00000000000..a227b166022 --- /dev/null +++ b/reactos/lib/packet/trace.h @@ -0,0 +1,62 @@ +///////////////////////////////////////////////////////////////////////////// +// Diagnostic Trace +// +#ifndef __TRACE_H__ +#define __TRACE_H__ + +#ifdef _DEBUG + +#ifdef _X86_ +#define BreakPoint() _asm { int 3h } +#else +#define BreakPoint() _DebugBreak() +#endif + +#ifndef ASSERT +#define ASSERT(exp) \ +{ \ + if (!(exp)) { \ + Assert(#exp, __FILE__, __LINE__, NULL); \ + BreakPoint(); \ + } \ +} \ + +#define ASSERTMSG(exp, msg) \ +{ \ + if (!(exp)) { \ + Assert(#exp, __FILE__, __LINE__, msg); \ + BreakPoint(); \ + } \ +} +#endif + +//============================================================================= +// MACRO: TRACE() +//============================================================================= + +#define TRACE Trace + + +#else // _DEBUG + +//============================================================================= +// Define away MACRO's ASSERT() and TRACE() in non debug builds +//============================================================================= + +#ifndef ASSERT +#define ASSERT(exp) +#define ASSERTMSG(exp, msg) +#endif + +#define TRACE 0 ? (void)0 : Trace + +#endif // !_DEBUG + + +void Assert(void* assert, const char* file, int line, void* msg); +//void Trace(TCHAR* lpszFormat, ...); +void Trace(char* lpszFormat, ...); + + +#endif // __TRACE_H__ +/////////////////////////////////////////////////////////////////////////////