diff --git a/drivers/3rdparty/CMakeLists.txt b/drivers/3rdparty/CMakeLists.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/drivers/3rdparty/npf/DEBUG.H b/drivers/3rdparty/npf/DEBUG.H new file mode 100644 index 0000000000000..8f1cf1bd83a21 --- /dev/null +++ b/drivers/3rdparty/npf/DEBUG.H @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __DEBUG_INCLUDE +#define __DEBUG_INCLUDE + + +#if DBG + +#define IF_PACKETDEBUG(f) if (PacketDebugFlag & (f)) +extern ULONG PacketDebugFlag; + +#define PACKET_DEBUG_LOUD 0x00000001 // debugging info +#define PACKET_DEBUG_VERY_LOUD 0x00000002 // excessive debugging info + +#define PACKET_DEBUG_INIT 0x00000100 // init debugging info + +// +// unfortunately, NT4 does not have the __FUNCTION__ macro, so we define it as null +// +#ifndef __FUNCTION__ +#define __FUNCTION__ +#endif + +// +// Macro for deciding whether to dump lots of debugging information. +// + +#define IF_LOUD(A) IF_PACKETDEBUG( PACKET_DEBUG_LOUD ) { A } +#define IF_VERY_LOUD(A) IF_PACKETDEBUG( PACKET_DEBUG_VERY_LOUD ) { A } +#define IF_INIT_LOUD(A) IF_PACKETDEBUG( PACKET_DEBUG_INIT ) { A } + +#define TRACE_ENTER() DbgPrint("--> " __FUNCTION__) +#define TRACE_EXIT() DbgPrint("<-- " __FUNCTION__) +#define TRACE_MESSAGE(__level__, __message__) do{ if (PacketDebugFlag & (__level__)) DbgPrint(" " __FUNCTION__ ": " __message__);} while(FALSE) + +#define TRACE_MESSAGE1(__level__, __message__, __p1__) do \ + { \ + if (PacketDebugFlag & (__level__)) \ + DbgPrint(" " __FUNCTION__ ": " __message__, __p1__); \ + } while(FALSE) + +#define TRACE_MESSAGE2(__level__, __message__, __p1__, __p2__) do \ + { \ + if (PacketDebugFlag & (__level__)) \ + DbgPrint(" " __FUNCTION__ ": " __message__, __p1__, __p2__); \ + } while(FALSE) + +#define TRACE_MESSAGE3(__level__, __message__, __p1__, __p2__, __p3__) do \ + { \ + if (PacketDebugFlag & (__level__)) \ + DbgPrint(" " __FUNCTION__ ": " __message__, __p1__, __p2__, __p3__); \ + } while(FALSE) + +#define TRACE_MESSAGE4(__level__, __message__, __p1__, __p2__, __p3__, __p4__) do \ + { \ + if (PacketDebugFlag & (__level__)) \ + DbgPrint(" " __FUNCTION__ ": " __message__, __p1__, __p2__, __p3__, __p4__ ); \ + } while(FALSE) + + +#else //DBG + +#define IF_LOUD(A) +#define IF_VERY_LOUD(A) +#define IF_INIT_LOUD(A) + +#define TRACE_ENTER() +#define TRACE_EXIT() +#define TRACE_MESSAGE(__level__, __message__) +#define TRACE_MESSAGE1(__level__, __message__, __p1__) +#define TRACE_MESSAGE2(__level__, __message__, __p1__, __p2__) +#define TRACE_MESSAGE3(__level__, __message__, __p1__, __p2__, __p3__) +#define TRACE_MESSAGE4(__level__, __message__, __p1__, __p2__, __p3__, __p4__) + +#endif + +#endif /*#define __DEBUG_INCLUDE*/ diff --git a/drivers/3rdparty/npf/Driver.vcproj b/drivers/3rdparty/npf/Driver.vcproj new file mode 100644 index 0000000000000..a9aa1dafa71a7 --- /dev/null +++ b/drivers/3rdparty/npf/Driver.vcproj @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/3rdparty/npf/MAKEFILE b/drivers/3rdparty/npf/MAKEFILE new file mode 100644 index 0000000000000..58189757d61c2 --- /dev/null +++ b/drivers/3rdparty/npf/MAKEFILE @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/drivers/3rdparty/npf/NPF.RC b/drivers/3rdparty/npf/NPF.RC new file mode 100644 index 0000000000000..aea560336dcb7 --- /dev/null +++ b/drivers/3rdparty/npf/NPF.RC @@ -0,0 +1,48 @@ +#include "windows.h" +#include "..\..\version.h" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +VS_VERSION_INFO VERSIONINFO + FILEVERSION WINPCAP_MAJOR,WINPCAP_MINOR,WINPCAP_REV,WINPCAP_BUILD + PRODUCTVERSION WINPCAP_MAJOR,WINPCAP_MINOR,WINPCAP_REV,WINPCAP_BUILD + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x3L + FILESUBTYPE 0x7L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", WINPCAP_COMPANY_NAME +#ifdef __NPF_NT4__ + VALUE "FileDescription", "npf.sys (NT4) Kernel Driver" +#elif defined(_AMD64_) + VALUE "FileDescription", "npf.sys (NT5/6 AMD64) Kernel Driver" +#else + VALUE "FileDescription", "npf.sys (NT5/6 x86) Kernel Driver" +#endif + VALUE "FileVersion", WINPCAP_VER_STRING + VALUE "InternalName", "NPF + TME" + VALUE "LegalCopyright", WINPCAP_COPYRIGHT_STRING + VALUE "LegalTrademarks", "" + VALUE "OriginalFilename", "npf.sys" + VALUE "ProductName", WINPCAP_PRODUCT_NAME + VALUE "ProductVersion", WINPCAP_VER_STRING + VALUE "Build Description", WINPCAP_BUILD_DESCRIPTION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + diff --git a/drivers/3rdparty/npf/Openclos.c b/drivers/3rdparty/npf/Openclos.c new file mode 100644 index 0000000000000..77d0528695b1d --- /dev/null +++ b/drivers/3rdparty/npf/Openclos.c @@ -0,0 +1,988 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "debug.h" +#include "packet.h" +#include "..\..\Common\WpcapNames.h" + + +static +VOID +NPF_ReleaseOpenInstanceResources(POPEN_INSTANCE pOpen); + +static NDIS_MEDIUM MediumArray[] = { + NdisMedium802_3, +// NdisMediumWan, + NdisMediumFddi, + NdisMediumArcnet878_2, + NdisMediumAtm, + NdisMedium802_5 +}; + +#define NUM_NDIS_MEDIA (sizeof MediumArray / sizeof MediumArray[0]) + +//Itoa. Replaces the buggy RtlIntegerToUnicodeString +void PacketItoa(UINT n,PUCHAR buf){ +int i; + + for(i=0;i<20;i+=2){ + buf[18-i]=(n%10)+48; + buf[19-i]=0; + n/=10; + } + +} + +/// Global start time. Used as an absolute reference for timestamp conversion. +struct time_conv G_Start_Time = { + 0, + {0, 0}, +}; + +ULONG g_NumOpenedInstances = 0; + +BOOLEAN NPF_StartUsingBinding( + IN POPEN_INSTANCE pOpen) +{ + ASSERT(pOpen != NULL); + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + NdisAcquireSpinLock(&pOpen->AdapterHandleLock); + + if (pOpen->AdapterBindingStatus != ADAPTER_BOUND) + { + NdisReleaseSpinLock(&pOpen->AdapterHandleLock); + return FALSE; + } + + pOpen->AdapterHandleUsageCounter++; + + NdisReleaseSpinLock(&pOpen->AdapterHandleLock); + + return TRUE; +} + +VOID NPF_StopUsingBinding( + IN POPEN_INSTANCE pOpen) +{ + ASSERT(pOpen != NULL); +// +// There is no risk in calling this function from abobe passive level +// (i.e. DISPATCH, in this driver) as we acquire a spinlock and decrement a +// counter. +// +// ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + NdisAcquireSpinLock(&pOpen->AdapterHandleLock); + + ASSERT(pOpen->AdapterHandleUsageCounter > 0); + ASSERT(pOpen->AdapterBindingStatus == ADAPTER_BOUND); + + pOpen->AdapterHandleUsageCounter--; + + NdisReleaseSpinLock(&pOpen->AdapterHandleLock); +} + +VOID +NPF_CloseBinding( + IN POPEN_INSTANCE pOpen) +{ + NDIS_EVENT Event; + NDIS_STATUS Status; + + ASSERT(pOpen != NULL); + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + NdisInitializeEvent(&Event); + NdisResetEvent(&Event); + + NdisAcquireSpinLock(&pOpen->AdapterHandleLock); + + while(pOpen->AdapterHandleUsageCounter > 0) + { + NdisReleaseSpinLock(&pOpen->AdapterHandleLock); + NdisWaitEvent(&Event,1); + NdisAcquireSpinLock(&pOpen->AdapterHandleLock); + } + + // + // now the UsageCounter is 0 + // + + while(pOpen->AdapterBindingStatus == ADAPTER_UNBINDING) + { + NdisReleaseSpinLock(&pOpen->AdapterHandleLock); + NdisWaitEvent(&Event,1); + NdisAcquireSpinLock(&pOpen->AdapterHandleLock); + } + + // + // now the binding status is either bound or unbound + // + + if (pOpen->AdapterBindingStatus == ADAPTER_UNBOUND) + { + NdisReleaseSpinLock(&pOpen->AdapterHandleLock); + return; + } + + ASSERT(pOpen->AdapterBindingStatus == ADAPTER_BOUND); + + pOpen->AdapterBindingStatus = ADAPTER_UNBINDING; + + NdisReleaseSpinLock(&pOpen->AdapterHandleLock); + + // + // do the release procedure + // + NdisResetEvent(&pOpen->NdisOpenCloseCompleteEvent); + + // Close the adapter + NdisCloseAdapter( + &Status, + pOpen->AdapterHandle + ); + + if (Status == NDIS_STATUS_PENDING) + { + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Pending NdisCloseAdapter"); + NdisWaitEvent(&pOpen->NdisOpenCloseCompleteEvent, 0); + } + else + { + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Not Pending NdisCloseAdapter"); + } + + NdisAcquireSpinLock(&pOpen->AdapterHandleLock); + pOpen->AdapterBindingStatus = ADAPTER_UNBOUND; + NdisReleaseSpinLock(&pOpen->AdapterHandleLock); +} + +//------------------------------------------------------------------- + +NTSTATUS NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) +{ + + PDEVICE_EXTENSION DeviceExtension; + POPEN_INSTANCE Open; + PIO_STACK_LOCATION IrpSp; + NDIS_STATUS Status; + NDIS_STATUS ErrorStatus; + UINT i; + PUCHAR tpointer; + PLIST_ENTRY PacketListEntry; + NTSTATUS returnStatus; + +// +// Old registry based WinPcap names +// +// WCHAR EventPrefix[MAX_WINPCAP_KEY_CHARS]; +// UINT RegStrLen; + + TRACE_ENTER(); + + DeviceExtension = DeviceObject->DeviceExtension; + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + // allocate some memory for the open structure + Open=ExAllocatePoolWithTag(NonPagedPool, sizeof(OPEN_INSTANCE), '0OWA'); + + if (Open==NULL) { + // no memory + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory( + Open, + sizeof(OPEN_INSTANCE) + ); + +// +// Old registry based WinPcap names +// +// // +// // Get the Event names base from the registry +// // +// RegStrLen = sizeof(EventPrefix)/sizeof(EventPrefix[0]); +// +// NPF_QueryWinpcapRegistryString(NPF_EVENTS_NAMES_REG_KEY_WC, +// EventPrefix, +// RegStrLen, +// NPF_EVENTS_NAMES_WIDECHAR); +// + + Open->DeviceExtension=DeviceExtension; + + // Allocate a packet pool for our xmit and receive packets + NdisAllocatePacketPool( + &Status, + &Open->PacketPool, + TRANSMIT_PACKETS, + sizeof(PACKET_RESERVED)); + + if (Status != NDIS_STATUS_SUCCESS) { + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Failed to allocate packet pool"); + + ExFreePool(Open); + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INSUFFICIENT_RESOURCES; + } + + NdisInitializeEvent(&Open->WriteEvent); + NdisInitializeEvent(&Open->NdisRequestEvent); + NdisInitializeEvent(&Open->NdisWriteCompleteEvent); + NdisInitializeEvent(&Open->DumpEvent); + NdisAllocateSpinLock(&Open->MachineLock); + NdisAllocateSpinLock(&Open->WriteLock); + Open->WriteInProgress = FALSE; + + for (i = 0; i < g_NCpu; i++) + { + NdisAllocateSpinLock(&Open->CpuData[i].BufferLock); + } + + NdisInitializeEvent(&Open->NdisOpenCloseCompleteEvent); + + // list to hold irp's want to reset the adapter + InitializeListHead(&Open->ResetIrpList); + + // Initialize the request list + KeInitializeSpinLock(&Open->RequestSpinLock); + InitializeListHead(&Open->RequestList); + +#ifdef HAVE_BUGGY_TME_SUPPORT + // Initializes the extended memory of the NPF machine + Open->mem_ex.buffer = ExAllocatePoolWithTag(NonPagedPool, DEFAULT_MEM_EX_SIZE, '2OWA'); + if((Open->mem_ex.buffer) == NULL) + { + // + // no memory + // + ExFreePool(Open); + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Open->mem_ex.size = DEFAULT_MEM_EX_SIZE; + RtlZeroMemory(Open->mem_ex.buffer, DEFAULT_MEM_EX_SIZE); +#endif //HAVE_BUGGY_TME_SUPPORT + + + // + // Initialize the open instance + // + Open->bpfprogram = NULL; //reset the filter + Open->mode = MODE_CAPT; + Open->Nbytes.QuadPart = 0; + Open->Npackets.QuadPart = 0; + Open->Nwrites = 1; + Open->Multiple_Write_Counter = 0; + Open->MinToCopy = 0; + Open->TimeOut.QuadPart = (LONGLONG)1; + Open->DumpFileName.Buffer = NULL; + Open->DumpFileHandle = NULL; +#ifdef HAVE_BUGGY_TME_SUPPORT + Open->tme.active = TME_NONE_ACTIVE; +#endif // HAVE_BUGGY_TME_SUPPORT + Open->DumpLimitReached = FALSE; + Open->MaxFrameSize = 0; + Open->WriterSN=0; + Open->ReaderSN=0; + Open->Size=0; + Open->SkipSentPackets = FALSE; + Open->ReadEvent = NULL; + + // + // we need to keep a counter of the pending IRPs + // so that when the IRP_MJ_CLEANUP dispatcher gets called, + // we can wait for those IRPs to be completed + // + Open->NumPendingIrps = 0; + Open->ClosePending = FALSE; + NdisAllocateSpinLock(&Open->OpenInUseLock); + + // + //allocate the spinlock for the statistic counters + // + NdisAllocateSpinLock(&Open->CountersLock); + + // + // link up the request stored in our open block + // + for (i = 0 ; i < MAX_REQUESTS ; i++ ) + { + NdisInitializeEvent(&Open->Requests[i].InternalRequestCompletedEvent); + + ExInterlockedInsertTailList( + &Open->RequestList, + &Open->Requests[i].ListElement, + &Open->RequestSpinLock); + } + + NdisResetEvent(&Open->NdisOpenCloseCompleteEvent); + + // + // set the proper binding flags before trying to open the MAC + // + Open->AdapterBindingStatus = ADAPTER_BOUND; + Open->AdapterHandleUsageCounter = 0; + NdisAllocateSpinLock(&Open->AdapterHandleLock); + + // + // Try to open the MAC + // + TRACE_MESSAGE2(PACKET_DEBUG_LOUD,"Opening the device %ws, BindingContext=%p",DeviceExtension->AdapterName.Buffer, Open); + + returnStatus = STATUS_SUCCESS; + + NdisOpenAdapter( + &Status, + &ErrorStatus, + &Open->AdapterHandle, + &Open->Medium, + MediumArray, + NUM_NDIS_MEDIA, + g_NdisProtocolHandle, + Open, + &DeviceExtension->AdapterName, + 0, + NULL); + + TRACE_MESSAGE1(PACKET_DEBUG_LOUD,"Opened the device, Status=%x",Status); + + if (Status == NDIS_STATUS_PENDING) + { + NdisWaitEvent(&Open->NdisOpenCloseCompleteEvent, 0); + + if (!NT_SUCCESS(Open->OpenCloseStatus)) + { + returnStatus = Open->OpenCloseStatus; + } + else + { + returnStatus = STATUS_SUCCESS; + } + } + else + { + // + // request not pending, we know the result, and OpenComplete has not been called. + // + if (Status == NDIS_STATUS_SUCCESS) + { + returnStatus = STATUS_SUCCESS; + } + else + { + // + // this is not completely correct, as we are converting an NDIS_STATUS to a NTSTATUS + // + returnStatus = Status; + + } + } + + if (returnStatus == STATUS_SUCCESS) + { + ULONG localNumOpenedInstances; + // + // complete the open + // + localNumOpenedInstances = InterlockedIncrement(&g_NumOpenedInstances); + + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenedInstances); + + // Get the absolute value of the system boot time. + // This is used for timestamp conversion. + TIME_SYNCHRONIZE(&G_Start_Time); + + returnStatus = NPF_GetDeviceMTU(Open, Irp, &Open->MaxFrameSize); + + if (!NT_SUCCESS(returnStatus)) + { + // + // Close the binding + // + NPF_CloseBinding(Open); + } + } + + if (!NT_SUCCESS(returnStatus)) + { + NPF_ReleaseOpenInstanceResources(Open); + // + // Free the open instance itself + // + ExFreePool(Open); + + } + else + { + // Save or open here + IrpSp->FileObject->FsContext=Open; + } + + Irp->IoStatus.Status = returnStatus; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + TRACE_EXIT(); + return returnStatus; +} + +BOOLEAN +NPF_StartUsingOpenInstance( + IN POPEN_INSTANCE pOpen + ) +{ + BOOLEAN returnStatus; + + NdisAcquireSpinLock(&pOpen->OpenInUseLock); + if (pOpen->ClosePending) + { + returnStatus = FALSE; + } + else + { + returnStatus = TRUE; + pOpen->NumPendingIrps ++; + } + NdisReleaseSpinLock(&pOpen->OpenInUseLock); + + return returnStatus; +} + +VOID +NPF_StopUsingOpenInstance( + IN POPEN_INSTANCE pOpen + ) +{ + NdisAcquireSpinLock(&pOpen->OpenInUseLock); + ASSERT(pOpen->NumPendingIrps > 0); + pOpen->NumPendingIrps --; + NdisReleaseSpinLock(&pOpen->OpenInUseLock); +} + +VOID +NPF_CloseOpenInstance( + IN POPEN_INSTANCE pOpen + ) +{ + ULONG i = 0; + NDIS_EVENT Event; + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + NdisInitializeEvent(&Event); + NdisResetEvent(&Event); + + NdisAcquireSpinLock(&pOpen->OpenInUseLock); + + pOpen->ClosePending = TRUE; + + while(pOpen->NumPendingIrps > 0) + { + NdisReleaseSpinLock(&pOpen->OpenInUseLock); + NdisWaitEvent(&Event,1); + NdisAcquireSpinLock(&pOpen->OpenInUseLock); + } + + NdisReleaseSpinLock(&pOpen->OpenInUseLock); +} + + +VOID +NPF_ReleaseOpenInstanceResources(POPEN_INSTANCE pOpen) +{ + PKEVENT pEvent; + UINT i; + + TRACE_ENTER(); + + ASSERT(pOpen != NULL); + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open= %p", pOpen); + + NdisFreePacketPool(pOpen->PacketPool); + +#ifdef HAVE_BUGGY_TME_SUPPORT + // + // free mem_ex + // + pOpen->mem_ex.size = 0; + if(pOpen->mem_ex.buffer != NULL) + ExFreePool(pOpen->mem_ex.buffer); +#endif //HAVE_BUGGY_TME_SUPPORT + + // + // Free the filter if it's present + // + if(pOpen->bpfprogram != NULL) + ExFreePool(pOpen->bpfprogram); + +// +// Jitted filters are supported on x86 (32bit) only +// +#ifdef _X86_ + // Free the jitted filter if it's present + if(pOpen->Filter != NULL) + BPF_Destroy_JIT_Filter(pOpen->Filter); +#endif //_X86_ + + // + // Dereference the read event. + // + + if (pOpen->ReadEvent != NULL) + ObDereferenceObject(pOpen->ReadEvent); + + // + // free the buffer + // NOTE: the buffer is fragmented among the various CPUs, but the base pointer of the + // allocated chunk of memory is stored in the first slot (pOpen->CpuData[0]) + // + if (pOpen->Size > 0) + ExFreePool(pOpen->CpuData[0].Buffer); + + // + // free the per CPU spinlocks + // + for (i = 0; i < g_NCpu; i++) + { + NdisFreeSpinLock(&Open->CpuData[i].BufferLock); + } + + // + // Free the string with the name of the dump file + // + if(pOpen->DumpFileName.Buffer!=NULL) + ExFreePool(pOpen->DumpFileName.Buffer); + + TRACE_EXIT(); +} + + +//------------------------------------------------------------------- + +VOID NPF_OpenAdapterComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN NDIS_STATUS OpenErrorStatus) +{ + + POPEN_INSTANCE Open; + PLIST_ENTRY RequestListEntry; + PINTERNAL_REQUEST MaxSizeReq; + NDIS_STATUS ReqStatus; + + TRACE_ENTER(); + + Open = (POPEN_INSTANCE)ProtocolBindingContext; + + ASSERT(Open != NULL); + + if (Status != NDIS_STATUS_SUCCESS) + { + // + // this is not completely correct, as we are converting an NDIS_STATUS to a NTSTATUS + // + Open->OpenCloseStatus = Status; + } + else + { + Open->OpenCloseStatus = STATUS_SUCCESS; + } + + // + // wake up the caller of NdisOpen, that is NPF_Open + // + NdisSetEvent(&Open->NdisOpenCloseCompleteEvent); + + TRACE_EXIT(); +} + +NTSTATUS +NPF_GetDeviceMTU( + IN POPEN_INSTANCE pOpen, + IN PIRP pIrp, + OUT PUINT pMtu) +{ + PLIST_ENTRY RequestListEntry; + PINTERNAL_REQUEST MaxSizeReq; + NDIS_STATUS ReqStatus; + + TRACE_ENTER(); + + ASSERT(pOpen != NULL); + ASSERT(pIrp != NULL); + ASSERT(pMtu != NULL); + + // Extract a request from the list of free ones + RequestListEntry = ExInterlockedRemoveHeadList(&pOpen->RequestList, &pOpen->RequestSpinLock); + + if (RequestListEntry == NULL) + { + // + // THIS IS WRONG + // + + // + // Assume Ethernet + // + *pMtu = 1514; + TRACE_EXIT(); + return STATUS_SUCCESS; + } + + MaxSizeReq = CONTAINING_RECORD(RequestListEntry, INTERNAL_REQUEST, ListElement); + + MaxSizeReq->Request.RequestType = NdisRequestQueryInformation; + MaxSizeReq->Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE; + + MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBuffer = pMtu; + MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(*pMtu); + + NdisResetEvent(&MaxSizeReq->InternalRequestCompletedEvent); + + // submit the request + NdisRequest( + &ReqStatus, + pOpen->AdapterHandle, + &MaxSizeReq->Request); + + if (ReqStatus == NDIS_STATUS_PENDING) + { + NdisWaitEvent(&MaxSizeReq->InternalRequestCompletedEvent, 0); + ReqStatus = MaxSizeReq->RequestStatus; + } + + // + // Put the request in the list of the free ones + // + ExInterlockedInsertTailList(&pOpen->RequestList, &MaxSizeReq->ListElement, &pOpen->RequestSpinLock); + + if (ReqStatus == NDIS_STATUS_SUCCESS) + { + TRACE_EXIT(); + return STATUS_SUCCESS; + } + else + { + // + // THIS IS WRONG + // + + // + // Assume Ethernet + // + *pMtu = 1514; + + TRACE_EXIT(); + return STATUS_SUCCESS; + + // return ReqStatus; + } +} + + +//------------------------------------------------------------------- +NTSTATUS +NPF_Close(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) +{ + POPEN_INSTANCE pOpen; + PIO_STACK_LOCATION IrpSp; + TRACE_ENTER(); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + pOpen = IrpSp->FileObject->FsContext; + + ASSERT(pOpen != NULL); + // + // Free the open instance itself + // + ExFreePool(pOpen); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + TRACE_EXIT(); + return STATUS_SUCCESS; +} + +//------------------------------------------------------------------- +NTSTATUS +NPF_Cleanup(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) +{ + + POPEN_INSTANCE Open; + NDIS_STATUS Status; + PIO_STACK_LOCATION IrpSp; + LARGE_INTEGER ThreadDelay; + ULONG localNumOpenInstances; + + TRACE_ENTER(); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + Open = IrpSp->FileObject->FsContext; + + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open = %p\n", Open); + + ASSERT(Open != NULL); + + NPF_CloseOpenInstance(Open); + + if (Open->ReadEvent != NULL) + KeSetEvent(Open->ReadEvent,0,FALSE); + + NPF_CloseBinding(Open); + + // NOTE: + // code commented out because the kernel dump feature is disabled + // + //if (AdapterAlreadyClosing == FALSE) + //{ + + // + // Unfreeze the consumer + // + // if(Open->mode & MODE_DUMP) + // NdisSetEvent(&Open->DumpEvent); + // else + // KeSetEvent(Open->ReadEvent,0,FALSE); + + // // + // // If this instance is in dump mode, complete the dump and close the file + // // + // if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL) + // { + // NTSTATUS wres; + + // ThreadDelay.QuadPart = -50000000; + + // // + // // Wait the completion of the thread + // // + // wres = KeWaitForSingleObject(Open->DumpThreadObject, + // UserRequest, + // KernelMode, + // TRUE, + // &ThreadDelay); + + // ObDereferenceObject(Open->DumpThreadObject); + + // // + // // Flush and close the dump file + // // + // NPF_CloseDumpFile(Open); + // } + //} + + + // + // release all the resources + // + NPF_ReleaseOpenInstanceResources(Open); + +// IrpSp->FileObject->FsContext = NULL; + + // + // Decrease the counter of open instances + // + localNumOpenInstances = InterlockedDecrement(&g_NumOpenedInstances); + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenInstances); + + if(localNumOpenInstances == 0) + { + // + // Force a synchronization at the next NPF_Open(). + // This hopefully avoids the synchronization issues caused by hibernation or standby. + // + TIME_DESYNCHRONIZE(&G_Start_Time); + } + + + // + // and complete the IRP with status success + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + TRACE_EXIT(); + + return(STATUS_SUCCESS); +} + +//------------------------------------------------------------------- + +VOID +NPF_CloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status) +{ + POPEN_INSTANCE Open; + PIRP Irp; + + TRACE_ENTER(); + + Open = (POPEN_INSTANCE)ProtocolBindingContext; + + ASSERT(Open != NULL); + + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open= %p", Open); + + NdisSetEvent(&Open->NdisOpenCloseCompleteEvent); + + TRACE_EXIT(); + return; + +} +//------------------------------------------------------------------- + +#ifdef NDIS50 +NDIS_STATUS +NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent) +{ + TRACE_ENTER(); + + TIME_DESYNCHRONIZE(&G_Start_Time); + TIME_SYNCHRONIZE(&G_Start_Time); + + TRACE_EXIT(); + return STATUS_SUCCESS; +} +#endif + +//------------------------------------------------------------------- + +VOID +NPF_BindAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE BindContext, + IN PNDIS_STRING DeviceName, + IN PVOID SystemSpecific1, + IN PVOID SystemSpecific2 + ) +{ + TRACE_ENTER(); + TRACE_EXIT(); +} + +//------------------------------------------------------------------- + +VOID +NPF_UnbindAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE UnbindContext + ) +{ + POPEN_INSTANCE Open =(POPEN_INSTANCE)ProtocolBindingContext; + + TRACE_ENTER(); + + ASSERT(Open != NULL); + + // + // The following code has been disabled bcause the kernel dump feature has been disabled. + // + //// + //// Awake a possible pending read on this instance + //// TODO should be ok. + //// + // if(Open->mode & MODE_DUMP) + // NdisSetEvent(&Open->DumpEvent); + // else + if (Open->ReadEvent != NULL) + KeSetEvent(Open->ReadEvent,0,FALSE); + + // + // The following code has been disabled bcause the kernel dump feature has been disabled. + // + //// + //// If this instance is in dump mode, complete the dump and close the file + //// TODO needs to be checked again. + //// + // if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL) + // NPF_CloseDumpFile(Open); + + *Status = NDIS_STATUS_SUCCESS; + + NPF_CloseBinding(Open); + + TRACE_EXIT(); + return; +} + +//------------------------------------------------------------------- + +VOID +NPF_ResetComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status) + +{ + POPEN_INSTANCE Open; + PIRP Irp; + + PLIST_ENTRY ResetListEntry; + + TRACE_ENTER(); + + Open = (POPEN_INSTANCE)ProtocolBindingContext; + + // + // remove the reset IRP from the list + // + ResetListEntry=ExInterlockedRemoveHeadList( + &Open->ResetIrpList, + &Open->RequestSpinLock + ); + + Irp=CONTAINING_RECORD(ResetListEntry,IRP,Tail.Overlay.ListEntry); + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + TRACE_EXIT(); + + return; + +} diff --git a/drivers/3rdparty/npf/Packet.c b/drivers/3rdparty/npf/Packet.c new file mode 100644 index 0000000000000..cc1ca20e0958e --- /dev/null +++ b/drivers/3rdparty/npf/Packet.c @@ -0,0 +1,2115 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "debug.h" +#include "packet.h" +#include "win_bpf.h" +#include "ioctls.h" + +#ifdef HAVE_BUGGY_TME_SUPPORT +#include "win_bpf_filter_init.h" +#endif //HAVE_BUGGY_TME_SUPPORT + +#include "..\..\Common\WpcapNames.h" + + +#if DBG +// Declare the global debug flag for this driver. +ULONG PacketDebugFlag = PACKET_DEBUG_LOUD; + +#endif + +PDEVICE_EXTENSION GlobalDeviceExtension; + +// +// Global strings +// +WCHAR g_NPF_PrefixBuffer[MAX_WINPCAP_KEY_CHARS] = NPF_DEVICE_NAMES_PREFIX_WIDECHAR; +// +// Old registry based WinPcap names +// +//WCHAR g_NPF_PrefixBuffer[MAX_WINPCAP_KEY_CHARS]; +NDIS_STRING g_NPF_Prefix; +NDIS_STRING devicePrefix = NDIS_STRING_CONST("\\Device\\"); +NDIS_STRING symbolicLinkPrefix = NDIS_STRING_CONST("\\DosDevices\\"); +NDIS_STRING tcpLinkageKeyName = NDIS_STRING_CONST("\\Registry\\Machine\\System" + L"\\CurrentControlSet\\Services\\Tcpip\\Linkage"); +NDIS_STRING AdapterListKey = NDIS_STRING_CONST("\\Registry\\Machine\\System" + L"\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"); +NDIS_STRING bindValueName = NDIS_STRING_CONST("Bind"); +NDIS_STRING g_WinpcapGlobalKey = NDIS_STRING_CONST("\\Registry\\Machine\\" WINPCAP_INSTANCE_KEY_WIDECHAR); +//NDIS_STRING g_WinpcapGlobalKey = NDIS_STRING_CONST("\\Registry\\Machine\\" WINPCAP_GLOBAL_KEY_WIDECHAR); + +/// Global variable that points to the names of the bound adapters +WCHAR* bindP = NULL; + +NDIS_HANDLE g_NdisProtocolHandle = NULL; + +ULONG g_NCpu; + +ULONG TimestampMode; +UINT g_SendPacketFlags = 0; + +static VOID NPF_ResetBufferContents(POPEN_INSTANCE Open); + +// +// Packet Driver's entry routine. +// +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +{ + NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar; + UNICODE_STRING MacDriverName; + UNICODE_STRING UnicodeDeviceName; + PDEVICE_OBJECT DeviceObject = NULL; + PDEVICE_EXTENSION DeviceExtension = NULL; + NTSTATUS Status = STATUS_SUCCESS; + NTSTATUS ErrorCode = STATUS_SUCCESS; + NDIS_STRING ProtoName = NDIS_STRING_CONST("PacketDriver"); + ULONG DevicesCreated=0; + PWSTR BindString; + PWSTR ExportString; + PWSTR BindStringSave; + PWSTR ExportStringSave; + WCHAR* bindT; + PKEY_VALUE_PARTIAL_INFORMATION tcpBindingsP; + UNICODE_STRING macName; +// +// Old registry based WinPcap names +// +// UINT RegStrLen; + ULONG OsMajorVersion, OsMinorVersion; + + TRACE_ENTER(); + +#ifndef __NPF_NT4__ + + TRACE_MESSAGE(PACKET_DEBUG_INIT, "DriverEntry -- NT4"); + + // + // Get OS version and store it in a global variable. + // For the moment we use the deprecated PsGetVersion() because the suggested + // RtlGetVersion() doesn't seem to exist in Windows 2000, and we don't want + // to have two separated drivers just for this call. + // Morever, the NT4 version of the driver just excludes this, since those flags + // are not available. + // + // Note: both RtlGetVersion() and PsGetVersion() are documented to always return success. + // + // OsVersion.dwOSVersionInfoSize = sizeof(OsVersion); + // RtlGetVersion(&OsVersion); + PsGetVersion(&OsMajorVersion, &OsMinorVersion, NULL, NULL); + TRACE_MESSAGE2(PACKET_DEBUG_INIT, "OS Version: %d.%d\n", OsMajorVersion, OsMinorVersion); + + // + // Define the correct flag to skip the loopback packets, according to the OS + // + if((OsMajorVersion == 5) && (OsMinorVersion == 0)) + { + // Windows 2000 wants both NDIS_FLAGS_DONT_LOOPBACK and NDIS_FLAGS_SKIP_LOOPBACK + g_SendPacketFlags = NDIS_FLAGS_DONT_LOOPBACK | NDIS_FLAGS_SKIP_LOOPBACK_W2K; + } + else + { + // Windows XP, 2003 and follwing want only NDIS_FLAGS_DONT_LOOPBACK + g_SendPacketFlags = NDIS_FLAGS_DONT_LOOPBACK; + } +#endif //__NPF_NT4__ + + // + // Set timestamp gathering method getting it from the registry + // + ReadTimeStampModeFromRegistry(RegistryPath); + + TRACE_MESSAGE1(PACKET_DEBUG_INIT,"%ws",RegistryPath->Buffer); + +// +// Old registry based WinPcap names +// +// // +// // Get the device names prefix from the registry +// // +// RegStrLen = sizeof(g_NPF_PrefixBuffer) / sizeof(g_NPF_PrefixBuffer[0]); +// +// NPF_QueryWinpcapRegistryString(NPF_DEVICES_PREFIX_REG_KEY_WC, +// g_NPF_PrefixBuffer, +// RegStrLen, +// NPF_DEVICE_NAMES_PREFIX_WIDECHAR); +// + NdisInitUnicodeString(&g_NPF_Prefix, g_NPF_PrefixBuffer); + + + // + // Get number of CPUs and save it + // + g_NCpu = NdisSystemProcessorCount(); + + RtlZeroMemory(&ProtocolChar,sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); + + // + // Register as a protocol with NDIS + // +#ifdef NDIS50 + ProtocolChar.MajorNdisVersion = 5; +#else + ProtocolChar.MajorNdisVersion = 3; +#endif + ProtocolChar.MinorNdisVersion = 0; + ProtocolChar.Reserved = 0; + ProtocolChar.OpenAdapterCompleteHandler = NPF_OpenAdapterComplete; + ProtocolChar.CloseAdapterCompleteHandler = NPF_CloseAdapterComplete; + ProtocolChar.SendCompleteHandler = NPF_SendComplete; + ProtocolChar.TransferDataCompleteHandler = NPF_TransferDataComplete; + ProtocolChar.ResetCompleteHandler = NPF_ResetComplete; + ProtocolChar.RequestCompleteHandler = NPF_RequestComplete; + ProtocolChar.ReceiveHandler = NPF_tap; + ProtocolChar.ReceiveCompleteHandler = NPF_ReceiveComplete; + ProtocolChar.StatusHandler = NPF_Status; + ProtocolChar.StatusCompleteHandler = NPF_StatusComplete; +#ifdef NDIS50 + ProtocolChar.BindAdapterHandler = NPF_BindAdapter; + ProtocolChar.UnbindAdapterHandler = NPF_UnbindAdapter; + ProtocolChar.PnPEventHandler = NPF_PowerChange; + ProtocolChar.ReceivePacketHandler = NULL; +#endif + ProtocolChar.Name = ProtoName; + + NdisRegisterProtocol( + &Status, + &g_NdisProtocolHandle, + &ProtocolChar, + sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); + + if (Status != NDIS_STATUS_SUCCESS) { + + TRACE_MESSAGE(PACKET_DEBUG_INIT,"Failed to register protocol with NDIS"); + + TRACE_EXIT(); + return Status; + + } + + // + // Standard device driver entry points stuff. + // + DriverObject->MajorFunction[IRP_MJ_CREATE] = NPF_Open; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = NPF_Close; + DriverObject->MajorFunction[IRP_MJ_CLEANUP]= NPF_Cleanup; + DriverObject->MajorFunction[IRP_MJ_READ] = NPF_Read; + DriverObject->MajorFunction[IRP_MJ_WRITE] = NPF_Write; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NPF_IoControl; + DriverObject->DriverUnload = NPF_Unload; + + bindP = getAdaptersList(); + + if (bindP == NULL) + { + TRACE_MESSAGE(PACKET_DEBUG_INIT, "Adapters not found in the registry, try to copy the bindings of TCP-IP."); + + tcpBindingsP = getTcpBindings(); + + if (tcpBindingsP == NULL) + { + TRACE_MESSAGE(PACKET_DEBUG_INIT, "TCP-IP not found, quitting."); + goto RegistryError; + } + + bindP = (WCHAR*)tcpBindingsP; + bindT = (WCHAR*)(tcpBindingsP->Data); + + } + else + { + bindT = bindP; + } + + for (; *bindT != UNICODE_NULL; bindT += (macName.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR)) + { + RtlInitUnicodeString(&macName, bindT); + NPF_CreateDevice(DriverObject, &macName); + } + + TRACE_EXIT(); + return STATUS_SUCCESS; + +RegistryError: + + NdisDeregisterProtocol( + &Status, + g_NdisProtocolHandle + ); + + Status=STATUS_UNSUCCESSFUL; + + TRACE_EXIT(); + return(Status); +} + +//------------------------------------------------------------------- + +PWCHAR getAdaptersList(void) +{ + PKEY_VALUE_PARTIAL_INFORMATION result = NULL; + OBJECT_ATTRIBUTES objAttrs; + NTSTATUS status; + HANDLE keyHandle; + UINT BufPos=0; + UINT BufLen=4096; + + + PWCHAR DeviceNames = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen, '0PWA'); + + if (DeviceNames == NULL) { + IF_LOUD(DbgPrint("Unable the allocate the buffer for the list of the network adapters\n");) + return NULL; + } + + InitializeObjectAttributes(&objAttrs, &AdapterListKey, + OBJ_CASE_INSENSITIVE, NULL, NULL); + status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs); + if (!NT_SUCCESS(status)) { + IF_LOUD(DbgPrint("\n\nStatus of %x opening %ws\n", status, tcpLinkageKeyName.Buffer);) + } + else { //OK + + ULONG resultLength; + KEY_VALUE_PARTIAL_INFORMATION valueInfo; + CHAR AdapInfo[1024]; + UINT i=0; + + IF_LOUD(DbgPrint("getAdaptersList: scanning the list of the adapters in the registry, DeviceNames=%p\n",DeviceNames);) + + // Scan the list of the devices + while((status=ZwEnumerateKey(keyHandle,i,KeyBasicInformation,AdapInfo,sizeof(AdapInfo),&resultLength))==STATUS_SUCCESS) + { + WCHAR ExportKeyName [512]; + PWCHAR ExportKeyPrefix = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"; + UINT ExportKeyPrefixSize = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"); + PWCHAR LinkageKeyPrefix = L"\\Linkage"; + UINT LinkageKeyPrefixSize = sizeof(L"\\Linkage"); + NDIS_STRING FinalExportKey = NDIS_STRING_CONST("Export"); + PKEY_BASIC_INFORMATION tInfo= (PKEY_BASIC_INFORMATION)AdapInfo; + UNICODE_STRING AdapterKeyName; + HANDLE ExportKeyHandle; + + RtlCopyMemory(ExportKeyName, + ExportKeyPrefix, + ExportKeyPrefixSize); + + RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize, + tInfo->Name, + tInfo->NameLength+2); + + RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize+tInfo->NameLength, + LinkageKeyPrefix, + LinkageKeyPrefixSize); + + IF_LOUD(DbgPrint("Key name=%ws\n", ExportKeyName);) + + RtlInitUnicodeString(&AdapterKeyName, ExportKeyName); + + InitializeObjectAttributes(&objAttrs, &AdapterKeyName, + OBJ_CASE_INSENSITIVE, NULL, NULL); + + status=ZwOpenKey(&ExportKeyHandle,KEY_READ,&objAttrs); + + if (!NT_SUCCESS(status)) { + IF_LOUD(DbgPrint("OpenKey Failed, %d!\n",status);) + i++; + continue; + } + + status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey, + KeyValuePartialInformation, &valueInfo, + sizeof(valueInfo), &resultLength); + + if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW)) { + IF_LOUD(DbgPrint("\n\nStatus of %x querying key value for size\n", status);) + } + else { // We know how big it needs to be. + ULONG valueInfoLength = valueInfo.DataLength + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]); + PKEY_VALUE_PARTIAL_INFORMATION valueInfoP = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(PagedPool, valueInfoLength, '1PWA'); + if (valueInfoP != NULL) { + status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey, + KeyValuePartialInformation, + valueInfoP, + valueInfoLength, &resultLength); + if (!NT_SUCCESS(status)) { + IF_LOUD(DbgPrint("Status of %x querying key value\n", status);) + } + else{ + IF_LOUD(DbgPrint("Device %d = %ws\n", i, valueInfoP->Data);) + if( BufPos + valueInfoP->DataLength > BufLen ) { + // double the buffer size + PWCHAR DeviceNames2 = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen + << 1, '0PWA'); + if( DeviceNames2 ) { + RtlCopyMemory((PCHAR)DeviceNames2, (PCHAR)DeviceNames, BufLen); + BufLen <<= 1; + ExFreePool(DeviceNames); + DeviceNames = DeviceNames2; + } + } + if( BufPos + valueInfoP->DataLength < BufLen ) { + RtlCopyMemory((PCHAR)DeviceNames+BufPos, + valueInfoP->Data, + valueInfoP->DataLength); + BufPos+=valueInfoP->DataLength-2; + } + } + + ExFreePool(valueInfoP); + } + else { + IF_LOUD(DbgPrint("Error Allocating the buffer for the device name\n");) + } + + } + + // terminate the buffer + DeviceNames[BufPos/2]=0; + DeviceNames[BufPos/2+1]=0; + + ZwClose (ExportKeyHandle); + i++; + + } + + ZwClose (keyHandle); + + } + if(BufPos==0){ + ExFreePool(DeviceNames); + return NULL; + } + return DeviceNames; +} + +//------------------------------------------------------------------- + +PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(void) +{ + PKEY_VALUE_PARTIAL_INFORMATION result = NULL; + OBJECT_ATTRIBUTES objAttrs; + NTSTATUS status; + HANDLE keyHandle; + + InitializeObjectAttributes(&objAttrs, &tcpLinkageKeyName, + OBJ_CASE_INSENSITIVE, NULL, NULL); + status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs); + if (!NT_SUCCESS(status)) + { + IF_LOUD(DbgPrint("\n\nStatus of %x opening %ws\n", status, tcpLinkageKeyName.Buffer);) + } + else + { + ULONG resultLength; + KEY_VALUE_PARTIAL_INFORMATION valueInfo; + + IF_LOUD(DbgPrint("\n\nOpened %ws\n", tcpLinkageKeyName.Buffer);) + + status = ZwQueryValueKey(keyHandle, &bindValueName, + KeyValuePartialInformation, &valueInfo, + sizeof(valueInfo), &resultLength); + if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW)) + { + IF_LOUD(DbgPrint("\n\nStatus of %x querying key value for size\n", status);) + } + else + { // We know how big it needs to be. + ULONG valueInfoLength = valueInfo.DataLength + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]); + PKEY_VALUE_PARTIAL_INFORMATION valueInfoP = + (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(PagedPool, valueInfoLength, '2PWA'); + + if (valueInfoP != NULL) + { + status = ZwQueryValueKey(keyHandle, &bindValueName, + KeyValuePartialInformation, + valueInfoP, + valueInfoLength, &resultLength); + + if (!NT_SUCCESS(status)) + { + IF_LOUD(DbgPrint("\n\nStatus of %x querying key value\n", status);) + ExFreePool(valueInfoP); + } + else + { + if (valueInfoLength != resultLength) + { + IF_LOUD(DbgPrint("\n\nQuerying key value result len = %u " + "but previous len = %u\n", + resultLength, valueInfoLength);) + ExFreePool(valueInfoP); + } + else + { + if (valueInfoP->Type != REG_MULTI_SZ) + { + IF_LOUD(DbgPrint("\n\nTcpip bind value not REG_MULTI_SZ but %u\n", + valueInfoP->Type);) + ExFreePool(valueInfoP); + } + else + { // It's OK +#if DBG + ULONG i; + WCHAR* dataP = (WCHAR*)(&valueInfoP->Data[0]); + IF_LOUD(DbgPrint("\n\nBind value:\n");) + for (i = 0; *dataP != UNICODE_NULL; i++) { + UNICODE_STRING macName; + RtlInitUnicodeString(&macName, dataP); + IF_LOUD(DbgPrint("\n\nMac %u = %ws\n", i, macName.Buffer);) + dataP += + (macName.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR); + } +#endif // DBG + result = valueInfoP; + } + } + } + } + } + ZwClose(keyHandle); + } + return result; +} + +//------------------------------------------------------------------- + +BOOLEAN NPF_CreateDevice(IN OUT PDRIVER_OBJECT adriverObjectP, + IN PUNICODE_STRING amacNameP) +{ + NTSTATUS status; + PDEVICE_OBJECT devObjP; + UNICODE_STRING deviceName; + UNICODE_STRING deviceSymLink; + + IF_LOUD(DbgPrint("\n\ncreateDevice for MAC %ws\n", amacNameP->Buffer);); + if (RtlCompareMemory(amacNameP->Buffer, devicePrefix.Buffer, + devicePrefix.Length) < devicePrefix.Length) + { + return FALSE; + } + + deviceName.Length = 0; + deviceName.MaximumLength = (USHORT)(amacNameP->Length + g_NPF_Prefix.Length + sizeof(UNICODE_NULL)); + deviceName.Buffer = ExAllocatePoolWithTag(PagedPool, deviceName.MaximumLength, '3PWA'); + + if (deviceName.Buffer == NULL) + return FALSE; + + deviceSymLink.Length = 0; + deviceSymLink.MaximumLength =(USHORT)(amacNameP->Length-devicePrefix.Length + + symbolicLinkPrefix.Length + + g_NPF_Prefix.Length + + sizeof(UNICODE_NULL)); + + deviceSymLink.Buffer = ExAllocatePoolWithTag(NonPagedPool, deviceSymLink.MaximumLength, '3PWA'); + + if (deviceSymLink.Buffer == NULL) + { + ExFreePool(deviceName.Buffer); + return FALSE; + } + + RtlAppendUnicodeStringToString(&deviceName, &devicePrefix); + RtlAppendUnicodeStringToString(&deviceName, &g_NPF_Prefix); + RtlAppendUnicodeToString(&deviceName, amacNameP->Buffer + + devicePrefix.Length / sizeof(WCHAR)); + + RtlAppendUnicodeStringToString(&deviceSymLink, &symbolicLinkPrefix); + RtlAppendUnicodeStringToString(&deviceSymLink, &g_NPF_Prefix); + RtlAppendUnicodeToString(&deviceSymLink, amacNameP->Buffer + + devicePrefix.Length / sizeof(WCHAR)); + + IF_LOUD(DbgPrint("Creating device name: %ws\n", deviceName.Buffer);) + + status = IoCreateDevice(adriverObjectP, + sizeof(DEVICE_EXTENSION), + &deviceName, + FILE_DEVICE_TRANSPORT, +#ifdef __NPF_NT4__ + 0, +#else //__NPF_NT4__ + FILE_DEVICE_SECURE_OPEN, +#endif //__NPF_NT4__ + FALSE, + &devObjP); + + if (NT_SUCCESS(status)) + { + PDEVICE_EXTENSION devExtP = (PDEVICE_EXTENSION)devObjP->DeviceExtension; + + IF_LOUD(DbgPrint("Device created successfully\n");); + + devObjP->Flags |= DO_DIRECT_IO; + RtlInitUnicodeString(&devExtP->AdapterName,amacNameP->Buffer); + + IF_LOUD(DbgPrint("Trying to create SymLink %ws\n",deviceSymLink.Buffer);); + + if (IoCreateSymbolicLink(&deviceSymLink,&deviceName) != STATUS_SUCCESS) + { + IF_LOUD(DbgPrint("\n\nError creating SymLink %ws\nn", deviceSymLink.Buffer);); + + ExFreePool(deviceName.Buffer); + ExFreePool(deviceSymLink.Buffer); + + devExtP->ExportString = NULL; + + return FALSE; + } + + IF_LOUD(DbgPrint("SymLink %ws successfully created.\n\n", deviceSymLink.Buffer);); + + devExtP->ExportString = deviceSymLink.Buffer; + + ExFreePool(deviceName.Buffer); + + return TRUE; + } + + else + { + IF_LOUD(DbgPrint("\n\nIoCreateDevice status = %x\n", status);); + + ExFreePool(deviceName.Buffer); + ExFreePool(deviceSymLink.Buffer); + + return FALSE; + } +} +//------------------------------------------------------------------- + +VOID NPF_Unload(IN PDRIVER_OBJECT DriverObject) +{ + PDEVICE_OBJECT DeviceObject; + PDEVICE_OBJECT OldDeviceObject; + PDEVICE_EXTENSION DeviceExtension; + NDIS_STATUS Status; + NDIS_STRING SymLink; + + TRACE_ENTER(); + + DeviceObject = DriverObject->DeviceObject; + + while (DeviceObject != NULL) { + OldDeviceObject = DeviceObject; + + DeviceObject = DeviceObject->NextDevice; + + DeviceExtension = OldDeviceObject->DeviceExtension; + + TRACE_MESSAGE4(PACKET_DEBUG_LOUD,"Deleting Adapter %ws, Protocol Handle=%p, Device Obj=%p (%p)", + DeviceExtension->AdapterName.Buffer, + g_NdisProtocolHandle, + DeviceObject, + OldDeviceObject); + + if (DeviceExtension->ExportString) + { + RtlInitUnicodeString(&SymLink , DeviceExtension->ExportString); + + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Deleting SymLink at %p", SymLink.Buffer); + + IoDeleteSymbolicLink(&SymLink); + ExFreePool(DeviceExtension->ExportString); + } + + IoDeleteDevice(OldDeviceObject); + } + + NdisDeregisterProtocol( + &Status, + g_NdisProtocolHandle + ); + + // Free the adapters names + ExFreePool( bindP ); + + TRACE_EXIT(); + + // Free the device names string that was allocated in the DriverEntry +// NdisFreeString(g_NPF_Prefix); +} + +#define SET_FAILURE_BUFFER_SMALL() do{\ + Information = 0; \ + Status = STATUS_BUFFER_TOO_SMALL; \ +} while(FALSE) + +#define SET_RESULT_SUCCESS(__a__) do{\ + Information = __a__; \ + Status = STATUS_SUCCESS; \ +} while(FALSE) + +#define SET_FAILURE_INVALID_REQUEST() do{\ + Information = 0; \ + Status = STATUS_INVALID_DEVICE_REQUEST; \ +} while(FALSE) + +#define SET_FAILURE_UNSUCCESSFUL() do{\ + Information = 0; \ + Status = STATUS_UNSUCCESSFUL; \ +} while(FALSE) + +#define SET_FAILURE_NOMEM() do{\ + Information = 0; \ + Status = STATUS_INSUFFICIENT_RESOURCES; \ +} while(FALSE) + +//------------------------------------------------------------------- + +NTSTATUS NPF_IoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) +{ + POPEN_INSTANCE Open; + PIO_STACK_LOCATION IrpSp; + PLIST_ENTRY RequestListEntry; + PINTERNAL_REQUEST pRequest; + ULONG FunctionCode; + NDIS_STATUS Status; + ULONG Information = 0; + PLIST_ENTRY PacketListEntry; + UINT i; + PUCHAR tpointer; + ULONG dim,timeout; + struct bpf_insn* NewBpfProgram; + PPACKET_OID_DATA OidData; + int *StatsBuf; + PNDIS_PACKET pPacket; + ULONG mode; + PWSTR DumpNameBuff; + PUCHAR TmpBPFProgram; + INT WriteRes; + BOOLEAN SyncWrite = FALSE; + struct bpf_insn *initprogram; + ULONG insns; + ULONG cnt; + BOOLEAN IsExtendedFilter=FALSE; + ULONG StringLength; + ULONG NeededBytes; + BOOLEAN Flag; + PUINT pStats; + ULONG StatsLength; + + HANDLE hUserEvent; + PKEVENT pKernelEvent; +#ifdef _AMD64_ + VOID*POINTER_32 hUserEvent32Bit; +#endif //_AMD64_ + PMDL mdl; + + TRACE_ENTER(); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode; + Open=IrpSp->FileObject->FsContext; + + if (NPF_StartUsingOpenInstance(Open) == FALSE) + { + // + // an IRP_MJ_CLEANUP was received, just fail the request + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + TRACE_EXIT(); + return STATUS_CANCELLED; + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + + TRACE_MESSAGE3(PACKET_DEBUG_LOUD, + "Function code is %08lx Input size=%08lx Output size %08lx", + FunctionCode, + IrpSp->Parameters.DeviceIoControl.InputBufferLength, + IrpSp->Parameters.DeviceIoControl.OutputBufferLength); + + switch (FunctionCode){ + + case BIOCGSTATS: //function to get the capture stats + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCGSTATS"); + + StatsLength = 4*sizeof(UINT); + if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < StatsLength) + { + SET_FAILURE_BUFFER_SMALL(); + break; + } + + if (Irp->UserBuffer == NULL) + { + SET_FAILURE_UNSUCCESSFUL(); + break; + } + + // + // temp fix to a GIANT bug from LD. The CTL code has been defined as METHOD_NEITHER, so it + // might well be a dangling pointer. We need to probe and lock the address. + // + + mdl = NULL; + pStats = NULL; + + __try + { + mdl = IoAllocateMdl( + Irp->UserBuffer, + StatsLength, + FALSE, + TRUE, + NULL); + + if (mdl == NULL) + { + SET_FAILURE_UNSUCCESSFUL(); + break; + } + + MmProbeAndLockPages( + mdl, + UserMode, + IoWriteAccess); + + pStats = (PUINT)(Irp->UserBuffer); + } + __except(GetExceptionCode() == STATUS_ACCESS_VIOLATION) + { + pStats = NULL; + } + + if (pStats == NULL) + { + if (mdl != NULL) + { + IoFreeMdl(mdl); + } + + SET_FAILURE_UNSUCCESSFUL(); + break; + } + + pStats[3] = 0; + pStats[0] = 0; + pStats[1] = 0; + pStats[2] = 0; // Not yet supported + + for(i = 0 ; i < g_NCpu ; i++) + { + + pStats[3] += Open->CpuData[i].Accepted; + pStats[0] += Open->CpuData[i].Received; + pStats[1] += Open->CpuData[i].Dropped; + pStats[2] += 0; // Not yet supported + } + + MmUnlockPages(mdl); + IoFreeMdl(mdl); + + SET_RESULT_SUCCESS(StatsLength); + + break; + + case BIOCGEVNAME: //function to get the name of the event associated with the current instance + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCGEVNAME"); + + // + // Since 20060405, the event handling has been changed: + // we no longer use named events, instead the user level app creates an event, + // and passes it back to the kernel, that references it (ObReferenceObjectByHandle), and + // signals it. + // For the time being, we still leave this ioctl code here, and we simply fail. + // + SET_FAILURE_INVALID_REQUEST(); + break; + + case BIOCSENDPACKETSSYNC: + + SyncWrite = TRUE; + + case BIOCSENDPACKETSNOSYNC: + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSENDPACKETSNOSYNC"); + + NdisAcquireSpinLock(&Open->WriteLock); + if(Open->WriteInProgress) + { + NdisReleaseSpinLock(&Open->WriteLock); + // + // Another write operation is currently in progress + // + SET_FAILURE_UNSUCCESSFUL(); + break; + } + else + { + Open->WriteInProgress = TRUE; + } + NdisReleaseSpinLock(&Open->WriteLock); + + WriteRes = NPF_BufferedWrite(Irp, + (PUCHAR)Irp->AssociatedIrp.SystemBuffer, + IrpSp->Parameters.DeviceIoControl.InputBufferLength, + SyncWrite); + + NdisAcquireSpinLock(&Open->WriteLock); + Open->WriteInProgress = FALSE; + NdisReleaseSpinLock(&Open->WriteLock); + + if( WriteRes != -1) + { + SET_RESULT_SUCCESS(WriteRes); + } + else + { + SET_FAILURE_UNSUCCESSFUL(); + } + break; + + case BIOCSETF: + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETF"); + + // + // Get the pointer to the new program + // + NewBpfProgram = (struct bpf_insn*)Irp->AssociatedIrp.SystemBuffer; + + if(NewBpfProgram == NULL) + { + SET_FAILURE_BUFFER_SMALL(); + break; + } + + // + // Lock the machine. After this call we are at DISPATCH level + // + NdisAcquireSpinLock(&Open->MachineLock); + + do + { + + // Free the previous buffer if it was present + if(Open->bpfprogram != NULL) + { + TmpBPFProgram = Open->bpfprogram; + Open->bpfprogram = NULL; + ExFreePool(TmpBPFProgram); + } + +// +// Jitted filters are supported on x86 (32bit) only +// +#ifdef _X86_ + if (Open->Filter != NULL) + { + BPF_Destroy_JIT_Filter(Open->Filter); + Open->Filter = NULL; + } +#endif // _X86_ + + insns = (IrpSp->Parameters.DeviceIoControl.InputBufferLength)/sizeof(struct bpf_insn); + + //count the number of operative instructions + for (cnt = 0 ; (cnt < insns) &&(NewBpfProgram[cnt].code != BPF_SEPARATION); cnt++); + + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Operative instructions=%u", cnt); + +#ifdef HAVE_BUGGY_TME_SUPPORT + if ( (cnt != insns) && (insns != cnt+1) && (NewBpfProgram[cnt].code == BPF_SEPARATION)) + { + TRACE_MESSAGE1(PACKET_DEBUG_LOUD,"Initialization instructions = %u",insns-cnt-1); + + IsExtendedFilter = TRUE; + + initprogram = &NewBpfProgram[cnt+1]; + + if(bpf_filter_init(initprogram,&(Open->mem_ex),&(Open->tme), &G_Start_Time)!=INIT_OK) + { + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error initializing NPF machine (bpf_filter_init)"); + + SET_FAILURE_INVALID_REQUEST(); + break; + } + } +#else // HAVE_BUGGY_TME_SUPPORT + if ( cnt != insns) + { + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error installing the BPF filter. The filter contains TME extensions," + " not supported on 64bit platforms."); + + SET_FAILURE_INVALID_REQUEST(); + break; + } +#endif // HAVE_BUGGY_TME_SUPPORT + + //the NPF processor has been initialized, we have to validate the operative instructions + insns = cnt; + + //NOTE: the validation code checks for TME instructions, and fails if a TME instruction is + //encountered on 64 bit machines +#ifdef HAVE_BUGGY_TME_SUPPORT + if(bpf_validate(NewBpfProgram, cnt, Open->mem_ex.size) == 0) +#else //HAVE_BUGGY_TME_SUPPORT + if(bpf_validate(NewBpfProgram, cnt) == 0) +#endif //HAVE_BUGGY_TME_SUPPORT + { + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error validating program"); + //FIXME: the machine has been initialized(?), but the operative code is wrong. + //we have to reset the machine! + //something like: reallocate the mem_ex, and reset the tme_core + SET_FAILURE_INVALID_REQUEST(); + break; + } + + // Allocate the memory to contain the new filter program + // We could need the original BPF binary if we are forced to use bpf_filter_with_2_buffers() + TmpBPFProgram = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, cnt*sizeof(struct bpf_insn), '4PWA'); + if (TmpBPFProgram == NULL) + { + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error - No memory for filter"); + // no memory + + SET_FAILURE_NOMEM(); + break; + } + + // + // At the moment the JIT compiler works on x86 (32 bit) only + // +#ifdef _X86_ + // Create the new JIT filter function + if(!IsExtendedFilter) + { + if((Open->Filter = BPF_jitter(NewBpfProgram, cnt)) == NULL) + { + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error jittering filter"); + + ExFreePool(TmpBPFProgram); + + SET_FAILURE_UNSUCCESSFUL(); + break; + } + } +#endif //_X86_ + + //copy the program in the new buffer + RtlCopyMemory(TmpBPFProgram,NewBpfProgram,cnt*sizeof(struct bpf_insn)); + Open->bpfprogram = TmpBPFProgram; + + SET_RESULT_SUCCESS(0); + } + while(FALSE); + + // + // release the machine lock and then reset the buffer + // + NdisReleaseSpinLock(&Open->MachineLock); + + NPF_ResetBufferContents(Open); + + break; + + case BIOCSMODE: //set the capture mode + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSMODE"); + + if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) + { + SET_FAILURE_BUFFER_SMALL(); + break; + } + + mode=*((PULONG)Irp->AssociatedIrp.SystemBuffer); + +///////kernel dump does not work at the moment////////////////////////////////////////// + if (mode & MODE_DUMP) + { + SET_FAILURE_INVALID_REQUEST(); + break; + } +///////kernel dump does not work at the moment////////////////////////////////////////// + + if(mode == MODE_CAPT) + { + Open->mode = MODE_CAPT; + + SET_RESULT_SUCCESS(0); + break; + } + else if (mode == MODE_MON) + { + // + // The MONITOR_MODE (aka TME extensions) is not supported on + // 64 bit architectures + // + +#ifdef HAVE_BUGGY_TME_SUPPORT + Open->mode = MODE_MON; + SET_RESULT_SUCCESS(0); +#else // HAVE_BUGGY_TME_SUPPORT + SET_FAILURE_INVALID_REQUEST(); +#endif // HAVE_BUGGY_TME_SUPPORT + + break; + } + else{ + if(mode & MODE_STAT){ + Open->mode = MODE_STAT; + NdisAcquireSpinLock(&Open->CountersLock); + Open->Nbytes.QuadPart = 0; + Open->Npackets.QuadPart = 0; + NdisReleaseSpinLock(&Open->CountersLock); + + if(Open->TimeOut.QuadPart==0)Open->TimeOut.QuadPart = -10000000; + + } + + if(mode & MODE_DUMP){ + + Open->mode |= MODE_DUMP; +// Open->MinToCopy=(Open->BufSize<2000000)?Open->BufSize/2:1000000; + + } + + SET_RESULT_SUCCESS(0); + break; + } + + SET_FAILURE_INVALID_REQUEST(); + + break; + + case BIOCSETDUMPFILENAME: + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETDUMPFILENAME"); + +///////kernel dump does not work at the moment////////////////////////////////////////// + SET_FAILURE_INVALID_REQUEST(); + break; +///////kernel dump does not work at the moment////////////////////////////////////////// + + //if(Open->mode & MODE_DUMP) + //{ + // + // // Close current dump file + // if(Open->DumpFileHandle != NULL) + // { + // NPF_CloseDumpFile(Open); + // Open->DumpFileHandle = NULL; + // } + // + // if(IrpSp->Parameters.DeviceIoControl.InputBufferLength == 0){ + // EXIT_FAILURE(0); + // } + // + // // Allocate the buffer that will contain the string + // DumpNameBuff=ExAllocatePoolWithTag(NonPagedPool, IrpSp->Parameters.DeviceIoControl.InputBufferLength, '5PWA'); + // if(DumpNameBuff==NULL || Open->DumpFileName.Buffer!=NULL){ + // IF_LOUD(DbgPrint("NPF: unable to allocate the dump filename: not enough memory or name already set\n");) + // EXIT_FAILURE(0); + // } + // + // // Copy the buffer + // RtlCopyBytes((PVOID)DumpNameBuff, + // Irp->AssociatedIrp.SystemBuffer, + // IrpSp->Parameters.DeviceIoControl.InputBufferLength); + // + // // Force a \0 at the end of the filename to avoid that malformed strings cause RtlInitUnicodeString to crash the system + // ((PSHORT)DumpNameBuff)[IrpSp->Parameters.DeviceIoControl.InputBufferLength/2-1]=0; + // + // // Create the unicode string + // RtlInitUnicodeString(&Open->DumpFileName, DumpNameBuff); + // + // IF_LOUD(DbgPrint("NPF: dump file name set to %ws, len=%d\n", + // Open->DumpFileName.Buffer, + // IrpSp->Parameters.DeviceIoControl.InputBufferLength);) + // + // // Try to create the file + // if ( NT_SUCCESS( NPF_OpenDumpFile(Open,&Open->DumpFileName,FALSE)) && + // NT_SUCCESS( NPF_StartDump(Open))) + // { + // EXIT_SUCCESS(0); + // } + //} + // + //EXIT_FAILURE(0); + // + //break; + + case BIOCSETDUMPLIMITS: + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETDUMPLIMITS"); + +///////kernel dump does not work at the moment////////////////////////////////////////// + SET_FAILURE_INVALID_REQUEST(); + break; +///////kernel dump does not work at the moment////////////////////////////////////////// + + //if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < 2*sizeof(ULONG)) + //{ + // EXIT_FAILURE(0); + //} + // + //Open->MaxDumpBytes = *(PULONG)Irp->AssociatedIrp.SystemBuffer; + //Open->MaxDumpPacks = *((PULONG)Irp->AssociatedIrp.SystemBuffer + 1); + // + //IF_LOUD(DbgPrint("NPF: Set dump limits to %u bytes, %u packs\n", Open->MaxDumpBytes, Open->MaxDumpPacks);) + // + //EXIT_SUCCESS(0); + // + //break; + + case BIOCISDUMPENDED: + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCISDUMPENDED"); + +///////kernel dump does not work at the moment////////////////////////////////////////// + SET_FAILURE_INVALID_REQUEST(); + break; +///////kernel dump does not work at the moment////////////////////////////////////////// + + //if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT)) + //{ + // EXIT_FAILURE(0); + //} + + //*((UINT*)Irp->UserBuffer) = (Open->DumpLimitReached)?1:0; + + //EXIT_SUCCESS(4); + + //break; + + case BIOCISETLOBBEH: + + if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(INT)) + { + SET_FAILURE_BUFFER_SMALL(); + break; + } + +#ifdef __NPF_NT4__ + + // NT4 doesn't support loopback inhibition / activation + SET_FAILURE_INVALID_REQUEST(); + break; + +#else //not __NPF_NT4__ + // + // win2000/xp/2003/vista + // + if(*(PINT)Irp->AssociatedIrp.SystemBuffer == NPF_DISABLE_LOOPBACK) + { + Open->SkipSentPackets = TRUE; + + // + // Reset the capture buffers, since they could contain loopbacked packets + // + + NPF_ResetBufferContents(Open); + + SET_RESULT_SUCCESS(0); + break; + + } + else + if(*(PINT)Irp->AssociatedIrp.SystemBuffer == NPF_ENABLE_LOOPBACK) + { + Open->SkipSentPackets = FALSE; + + SET_RESULT_SUCCESS(0); + break; + } + else + { + // Unknown operation + SET_FAILURE_INVALID_REQUEST(); + break; + } + +#endif // !__NPF_NT4__ + break; + + case BIOCSETEVENTHANDLE: + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETEVENTHANDLE"); + +#ifdef _AMD64_ + if (IoIs32bitProcess(Irp)) + { + // + // validate the input + // + if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof (hUserEvent32Bit)) + { + SET_FAILURE_INVALID_REQUEST(); + break; + } + + hUserEvent32Bit = *(VOID*POINTER_32*)Irp->AssociatedIrp.SystemBuffer; + hUserEvent = hUserEvent32Bit; + } + else +#endif //_AMD64_ + { + // + // validate the input + // + if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof (hUserEvent)) + { + SET_FAILURE_INVALID_REQUEST(); + break; + } + + hUserEvent = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer; + } + + // + // NT4 doesn't seem to have EVENT_MODIFY_STATE, so on NT4 we request a wider set + // of privileges for the event handle + // +#ifdef __NPF_NT4__ + Status = ObReferenceObjectByHandle(hUserEvent, + OBJECT_TYPE_ALL_ACCESS, *ExEventObjectType, Irp->RequestorMode, + (PVOID*) &pKernelEvent, NULL); +#else //__NPF_NT4__ + Status = ObReferenceObjectByHandle(hUserEvent, + EVENT_MODIFY_STATE, *ExEventObjectType, Irp->RequestorMode, + (PVOID*) &pKernelEvent, NULL); +#endif //__NPF_NT4__ + + if (!NT_SUCCESS(Status)) + { + // Status = ??? already set + Information = 0; + break; + } + + + // + // NT4 does not have InterlockedCompareExchangePointer + // InterlockedCompareExchange on NT4 has the same prototype of InterlockedCompareExchange + // on NT5x, so we use this one. + // +#ifdef __NPF_NT4__ + if (InterlockedCompareExchange(&Open->ReadEvent, pKernelEvent, NULL) != NULL) +#else + if (InterlockedCompareExchangePointer(&Open->ReadEvent, pKernelEvent, NULL) != NULL) +#endif + { + // + // dereference the new pointer + // + + ObDereferenceObject(pKernelEvent); + SET_FAILURE_INVALID_REQUEST(); + break; + } + + KeResetEvent(Open->ReadEvent); + + SET_RESULT_SUCCESS(0); + break; + + case BIOCSETBUFFERSIZE: + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETBUFFERSIZE"); + + + if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) + { + SET_FAILURE_BUFFER_SMALL(); + break; + } + + // Get the number of bytes to allocate + dim = *((PULONG)Irp->AssociatedIrp.SystemBuffer); + + if (dim / g_NCpu < sizeof(struct PacketHeader)) + { + dim = 0; + } + else + { + tpointer = ExAllocatePoolWithTag(NonPagedPool, dim, '6PWA'); + if (tpointer == NULL) + { + // no memory + SET_FAILURE_NOMEM(); + break; + } + } + + // + // acquire the locks for all the buffers + // + for (i = 0; i < g_NCpu ; i++) + { +#pragma prefast(suppress:8103, "There's no Spinlock leak here, as it's released some lines below.") + NdisAcquireSpinLock(&Open->CpuData[i].BufferLock); + } + + // + // free the old buffer, if any + // + if (Open->CpuData[0].Buffer != NULL) + { + ExFreePool(Open->CpuData[0].Buffer); + } + + for (i = 0 ; i < g_NCpu ; i++) + { + if (dim > 0) + Open->CpuData[i].Buffer=(PUCHAR)tpointer + (dim/g_NCpu)*i; + else + Open->CpuData[i].Buffer = NULL; + Open->CpuData[i].Free = dim/g_NCpu; + Open->CpuData[i].P = 0; + Open->CpuData[i].C = 0; + Open->CpuData[i].Accepted = 0; + Open->CpuData[i].Dropped = 0; + Open->CpuData[i].Received = 0; + } + + Open->ReaderSN=0; + Open->WriterSN=0; + + Open->Size = dim/g_NCpu; + + // + // acquire the locks for all the buffers + // + i = g_NCpu; + + do + { + i--; + +#pragma prefast(suppress:8107, "There's no Spinlock leak here, as it's acquired some lines above.") + NdisReleaseSpinLock(&Open->CpuData[i].BufferLock); + }while(i != 0); + + SET_RESULT_SUCCESS(0); + break; + + case BIOCSRTIMEOUT: //set the timeout on the read calls + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSRTIMEOUT"); + + if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) + { + SET_FAILURE_BUFFER_SMALL(); + break; + } + + timeout = *((PULONG)Irp->AssociatedIrp.SystemBuffer); + if(timeout == (ULONG)-1) + Open->TimeOut.QuadPart=(LONGLONG)IMMEDIATE; + else + { + Open->TimeOut.QuadPart = (LONGLONG)timeout; + Open->TimeOut.QuadPart *= 10000; + Open->TimeOut.QuadPart = -Open->TimeOut.QuadPart; + } + + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Read timeout set to %I64d",Open->TimeOut.QuadPart); + + SET_RESULT_SUCCESS(0); + break; + + case BIOCSWRITEREP: //set the writes repetition number + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSWRITEREP"); + + if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) + { + SET_FAILURE_BUFFER_SMALL(); + break; + } + + Open->Nwrites = *((PULONG)Irp->AssociatedIrp.SystemBuffer); + + SET_RESULT_SUCCESS(0); + break; + + case BIOCSMINTOCOPY: //set the minimum buffer's size to copy to the application + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSMINTOCOPY"); + + if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) + { + SET_FAILURE_BUFFER_SMALL(); + break; + } + + Open->MinToCopy = (*((PULONG)Irp->AssociatedIrp.SystemBuffer))/g_NCpu; //An hack to make the NCPU-buffers behave like a larger one + + SET_RESULT_SUCCESS(0); + break; + +// case IOCTL_PROTOCOL_RESET: +// +// TRACE_MESSAGE(PACKET_DEBUG_LOUD, "IOCTL_PROTOCOL_RESET"); +// +// IoMarkIrpPending(Irp); +// Irp->IoStatus.Status = STATUS_SUCCESS; +// +// ExInterlockedInsertTailList(&Open->ResetIrpList,&Irp->Tail.Overlay.ListEntry,&Open->RequestSpinLock); +// NdisReset(&Status,Open->AdapterHandle); +// if (Status != NDIS_STATUS_PENDING) +// { +// IF_LOUD(DbgPrint("NPF: IoControl - ResetComplete being called\n");) +// NPF_ResetComplete(Open,Status); +// } +// +// break; + + case BIOCSETOID: + case BIOCQUERYOID: + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETOID - BIOCQUERYOID"); + + // + // gain ownership of the Ndis Handle + // + if (NPF_StartUsingBinding(Open) == FALSE) + { + // + // MAC unbindind or unbound + // + SET_FAILURE_INVALID_REQUEST(); + break; + } + + + // Extract a request from the list of free ones + RequestListEntry=ExInterlockedRemoveHeadList(&Open->RequestList,&Open->RequestSpinLock); + if (RequestListEntry == NULL) + { + // + // Release ownership of the Ndis Handle + // + NPF_StopUsingBinding(Open); + + SET_FAILURE_NOMEM(); + break; + } + + pRequest=CONTAINING_RECORD(RequestListEntry,INTERNAL_REQUEST,ListElement); + + // + // See if it is an Ndis request + // + OidData=Irp->AssociatedIrp.SystemBuffer; + + if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength == IrpSp->Parameters.DeviceIoControl.OutputBufferLength) + && + (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(PACKET_OID_DATA)) + && + (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(PACKET_OID_DATA)-1+OidData->Length)) { + + TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "BIOCSETOID|BIOCQUERYOID Request: Oid=%08lx, Length=%08lx",OidData->Oid,OidData->Length); + + // + // The buffer is valid + // + if (FunctionCode == BIOCSETOID){ + + pRequest->Request.RequestType=NdisRequestSetInformation; + pRequest->Request.DATA.SET_INFORMATION.Oid=OidData->Oid; + + pRequest->Request.DATA.SET_INFORMATION.InformationBuffer=OidData->Data; + pRequest->Request.DATA.SET_INFORMATION.InformationBufferLength=OidData->Length; + + + } + else{ + + pRequest->Request.RequestType=NdisRequestQueryInformation; + pRequest->Request.DATA.QUERY_INFORMATION.Oid=OidData->Oid; + + pRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer=OidData->Data; + pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength=OidData->Length; + + } + + NdisResetEvent(&pRequest->InternalRequestCompletedEvent); + + // + // submit the request + // + NdisRequest( + &Status, + Open->AdapterHandle, + &pRequest->Request + ); + + } else { + // + // Release ownership of the Ndis Handle + // + NPF_StopUsingBinding(Open); + + // + // buffer too small + // + SET_FAILURE_BUFFER_SMALL(); + break; + } + + if (Status == NDIS_STATUS_PENDING) + { + NdisWaitEvent(&pRequest->InternalRequestCompletedEvent, 0); + Status = pRequest->RequestStatus; + } + + // + // Release ownership of the Ndis Handle + // + NPF_StopUsingBinding(Open); + + // + // Complete the request + // + if (FunctionCode == BIOCSETOID) + { + OidData->Length = pRequest->Request.DATA.SET_INFORMATION.BytesRead; + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "BIOCSETOID completed, BytesRead = %u",OidData->Length); + } + else + { + if (FunctionCode == BIOCQUERYOID) + { + OidData->Length = pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten; + + if (Status == NDIS_STATUS_SUCCESS) + { + // + // check for the stupid bug of the Nortel driver ipsecw2k.sys v. 4.10.0.0 that doesn't set the BytesWritten correctly + // The driver is the one shipped with Nortel client Contivity VPN Client V04_65.18, and the MD5 for the buggy (unsigned) driver + // is 3c2ff8886976214959db7d7ffaefe724 *ipsecw2k.sys (there are multiple copies of this binary with the same exact version info!) + // + // The (certified) driver shipped with Nortel client Contivity VPN Client V04_65.320 doesn't seem affected by the bug. + // + if (pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten > pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength) + { + TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "Bogus return from NdisRequest (query): Bytes Written (%u) > InfoBufferLength (%u)!!", + pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten, + pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength); + + Status = NDIS_STATUS_INVALID_DATA; + } + } + + TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "BIOCQUERYOID completed, BytesWritten = %u",OidData->Length); + } + } + + + ExInterlockedInsertTailList( + &Open->RequestList, + &pRequest->ListElement, + &Open->RequestSpinLock); + + if (Status == NDIS_STATUS_SUCCESS) + { + SET_RESULT_SUCCESS(sizeof(PACKET_OID_DATA) - 1 + OidData->Length); + } + else + { + SET_FAILURE_INVALID_REQUEST(); + } + + break; + + + default: + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Unknown IOCTL code"); + SET_FAILURE_INVALID_REQUEST(); + break; + } + + + // + // release the Open structure + // + NPF_StopUsingOpenInstance(Open); + + // + // complete the IRP + // + Irp->IoStatus.Information = Information; + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + + TRACE_EXIT(); + + return Status; +} + +//------------------------------------------------------------------- + +VOID +NPF_RequestComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_REQUEST NdisRequest, + IN NDIS_STATUS Status + ) + +{ + PINTERNAL_REQUEST pRequest; + + TRACE_ENTER(); + + pRequest = CONTAINING_RECORD(NdisRequest,INTERNAL_REQUEST,Request); + + // + // Set the request result + // + pRequest->RequestStatus = Status; + + // + // and awake the caller + // + NdisSetEvent(&pRequest->InternalRequestCompletedEvent); + + TRACE_EXIT(); + return; + +} + +//------------------------------------------------------------------- + +VOID +NPF_Status( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN PVOID StatusBuffer, + IN UINT StatusBufferSize + ) + +{ + + IF_LOUD(DbgPrint("NPF: Status Indication\n");) + + return; + +} + +//------------------------------------------------------------------- + +VOID +NPF_StatusComplete( + IN NDIS_HANDLE ProtocolBindingContext + ) + +{ + + IF_LOUD(DbgPrint("NPF: StatusIndicationComplete\n");) + + return; + +} + +//------------------------------------------------------------------- + +NTSTATUS +NPF_ReadRegistry( + IN PWSTR *MacDriverName, + IN PWSTR *PacketDriverName, + IN PUNICODE_STRING RegistryPath + ) + +{ + NTSTATUS Status; + + RTL_QUERY_REGISTRY_TABLE ParamTable[4]; + + PWSTR Bind = L"Bind"; + PWSTR Export = L"Export"; + PWSTR Parameters = L"Parameters"; + PWSTR Linkage = L"Linkage"; + + PWCHAR Path; + + + + Path=ExAllocatePoolWithTag(PagedPool, RegistryPath->Length+sizeof(WCHAR), '7PWA'); + + if (Path == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory( + Path, + RegistryPath->Length+sizeof(WCHAR) + ); + + RtlCopyMemory( + Path, + RegistryPath->Buffer, + RegistryPath->Length + ); + + IF_LOUD(DbgPrint("NPF: Reg path is %ws\n",RegistryPath->Buffer);) + + RtlZeroMemory( + ParamTable, + sizeof(ParamTable) + ); + + + + // + // change to the linkage key + // + + ParamTable[0].QueryRoutine = NULL; + ParamTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; + ParamTable[0].Name = Linkage; + + + // + // Get the name of the mac driver we should bind to + // + + ParamTable[1].QueryRoutine = NPF_QueryRegistryRoutine; + ParamTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | + RTL_QUERY_REGISTRY_NOEXPAND; + + ParamTable[1].Name = Bind; + ParamTable[1].EntryContext = (PVOID)MacDriverName; + ParamTable[1].DefaultType = REG_MULTI_SZ; + + // + // Get the name that we should use for the driver object + // + + ParamTable[2].QueryRoutine = NPF_QueryRegistryRoutine; + ParamTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | + RTL_QUERY_REGISTRY_NOEXPAND; + + ParamTable[2].Name = Export; + ParamTable[2].EntryContext = (PVOID)PacketDriverName; + ParamTable[2].DefaultType = REG_MULTI_SZ; + + + Status=RtlQueryRegistryValues( + RTL_REGISTRY_ABSOLUTE, + Path, + ParamTable, + NULL, + NULL + ); + + + ExFreePool(Path); + + return Status; +} + +//------------------------------------------------------------------- + +NTSTATUS +NPF_QueryRegistryRoutine( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) + +{ + + PUCHAR Buffer; + + IF_LOUD(DbgPrint("Perf: QueryRegistryRoutine\n");) + + if (ValueType != REG_MULTI_SZ) { + + return STATUS_OBJECT_NAME_NOT_FOUND; + + } + + Buffer=ExAllocatePoolWithTag(NonPagedPool, ValueLength, '8PWA'); + + if (Buffer==NULL) { + + return STATUS_INSUFFICIENT_RESOURCES; + + } + + RtlCopyMemory( + Buffer, + ValueData, + ValueLength + ); + + *((PUCHAR *)EntryContext)=Buffer; + + return STATUS_SUCCESS; + +} + +VOID NPF_ResetBufferContents(POPEN_INSTANCE Open) +{ + UINT i; + + // + // lock all the buffers + // + for (i = 0 ; i < g_NCpu ; i++) + { +//#pragma prefast(suppress:8103, "There's no Spinlock leak here, as it's released some lines below.") + NdisAcquireSpinLock(&Open->CpuData[i].BufferLock); + } + + Open->ReaderSN = 0; + Open->WriterSN = 0; + + // + // reset their pointers + // + for (i = 0 ; i < g_NCpu ; i++) + { + Open->CpuData[i].C=0; + Open->CpuData[i].P=0; + Open->CpuData[i].Free = Open->Size; + Open->CpuData[i].Accepted = 0; + Open->CpuData[i].Dropped = 0; + Open->CpuData[i].Received = 0; + } + + // + // release the locks in reverse order + // + i = g_NCpu; + + do + { + i--; +#pragma prefast(suppress:8107, "There's no Spinlock leak here, as it's allocated some lines above.") + NdisReleaseSpinLock(&Open->CpuData[i].BufferLock); + + } + while (i != 0); +} + +#if 0 +// +// Old registry based WinPcap names +// + +//------------------------------------------------------------------- + +//NOTE: ValueLen is the length of Value in characters + +VOID NPF_QueryWinpcapRegistryString(PWSTR SubKeyName, + WCHAR *Value, + UINT ValueLen, + WCHAR *DefaultValue) +{ + UINT CharsToCopy; + +#ifdef WPCAP_OEM + OBJECT_ATTRIBUTES objAttrs; + NTSTATUS status; + HANDLE keyHandle; + UNICODE_STRING SubKeyToQueryU; + CHAR kvpiBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR) * MAX_WINPCAP_KEY_CHARS]; + ULONG QvkResultLength; + PKEY_VALUE_PARTIAL_INFORMATION pKeyValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)kvpiBuffer; + PWCHAR pResultingKeyValue; + + // + // Create subkey string + // + RtlInitUnicodeString(&SubKeyToQueryU, SubKeyName); + + // + // Init Attributes + // + InitializeObjectAttributes(&objAttrs, + &g_WinpcapGlobalKey, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + // + // Open the key + // + status = ZwOpenKey(&keyHandle, + KEY_QUERY_VALUE, + &objAttrs); + + if(!NT_SUCCESS(status)) + { + IF_LOUD(DbgPrint("NPF_QueryWinpcapRegistryKey: ZwOpenKey error %x\n", status);) + + //copy the default value and return + CharsToCopy = wcslen(DefaultValue) + 1; + if (CharsToCopy > ValueLen) + { + RtlCopyMemory(Value, DefaultValue, ValueLen * 2); + Value[ValueLen - 1] = 0; + } + else + { + RtlCopyMemory(Value, DefaultValue, CharsToCopy * 2); + } + return; + } + + // + // Query the requested value + // + status = ZwQueryValueKey(keyHandle, + &SubKeyToQueryU, + KeyValuePartialInformation, + pKeyValuePartialInformation, + sizeof(kvpiBuffer), + &QvkResultLength); + + if(!NT_SUCCESS(status)) + { + IF_LOUD(DbgPrint("NPF_QueryWinpcapRegistryKey: Status of %x querying key value %ws\n", + status, + SubKeyToQueryU.Buffer);) + + ZwClose(keyHandle); + + //copy the default value and return + CharsToCopy = wcslen(DefaultValue) + 1; + if (CharsToCopy > ValueLen) + { + RtlCopyMemory(Value, DefaultValue, ValueLen * 2); + Value[ValueLen - 1] = 0; + } + else + { + RtlCopyMemory(Value, DefaultValue, CharsToCopy * 2); + } + return; + } + + // + // Check that the resulting value is of the correct type + // + if (pKeyValuePartialInformation->Type != REG_SZ) + { + IF_LOUD(DbgPrint("NPF_QueryWinpcapRegistryKey: the reg key has the wrong type (%u)\n", pKeyValuePartialInformation->Type);) + + ZwClose(keyHandle); + + //copy the default value and return + CharsToCopy = wcslen(DefaultValue) + 1; + if (CharsToCopy > ValueLen) + { + RtlCopyMemory(Value, DefaultValue, ValueLen * 2); + Value[ValueLen - 1] = 0; + } + else + { + RtlCopyMemory(Value, DefaultValue, CharsToCopy * 2); + } + return; + } + + pResultingKeyValue = (PWCHAR)pKeyValuePartialInformation->Data; + + // + // Check we have enough space for the result. We include 1 to account for the UNICODE NULL terminator + // + if(wcslen(pResultingKeyValue) + 1 > ValueLen) + { + IF_LOUD(DbgPrint("NPF_QueryWinpcapRegistryKey: storage buffer too small\n");) + + ZwClose(keyHandle); + + //copy the default value and return + CharsToCopy = wcslen(DefaultValue) + 1; + if (CharsToCopy > ValueLen) + { + RtlCopyMemory(Value, DefaultValue, ValueLen * 2); + Value[ValueLen - 1] = 0; + } + else + { + RtlCopyMemory(Value, DefaultValue, CharsToCopy * 2); + } + return; + } + + // + // Copy the value to the user-provided values + // + wcscpy(Value, pResultingKeyValue); + + // + // Free the key + // + ZwClose(keyHandle); + + return; + +#else // WPCAP_OEM + + //copy the default value and return + CharsToCopy = wcslen(DefaultValue) + 1; + if (CharsToCopy > ValueLen) + { + RtlCopyMemory(Value, DefaultValue, ValueLen * 2); + Value[ValueLen - 1] = 0; + } + else + { + RtlCopyMemory(Value, DefaultValue, CharsToCopy * 2); + } + return; + +#endif // WPCAP_OEM +} + +#endif \ No newline at end of file diff --git a/drivers/3rdparty/npf/Packet.h b/drivers/3rdparty/npf/Packet.h new file mode 100644 index 0000000000000..9367a832015db --- /dev/null +++ b/drivers/3rdparty/npf/Packet.h @@ -0,0 +1,941 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/** @addtogroup NPF + * @{ + */ + +/** @defgroup NPF_include NPF structures and definitions + * @{ + */ + +#ifndef __PACKET_INCLUDE______ +#define __PACKET_INCLUDE______ + +#if !defined(NDIS30) && !defined(NDIS50) +#error NDIS30 or NDIS50 should be defined +#endif + +#ifdef _X86_ +#define NTKERNEL ///< Forces the compilation of the jitter with kernel calls +#include "jitter.h" +#endif + +#ifdef HAVE_BUGGY_TME_SUPPORT +#ifndef _X86_ +#error TME support is available only on x86 architectures +#endif // _X86_ +#endif //HAVE_BUGGY_TME_SUPPORT + + +// +// Needed to disable a warning due to the #pragma prefast directives, +// that are ignored by the normal DDK compiler +// +#ifndef _PREFAST_ +#pragma warning(disable:4068) +#endif + +#include "win_bpf.h" + +#define MAX_REQUESTS 32 ///< Maximum number of simultaneous IOCTL requests. + +#define Packet_ALIGNMENT sizeof(int) ///< Alignment macro. Defines the alignment size. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) ///< Alignment macro. Rounds up to the next + ///< even multiple of Packet_ALIGNMENT. + +#define KERNEL_EVENT_NAMESPACE L"\\BaseNamedObjects\\" + + +// Working modes +#define MODE_CAPT 0x0 ///< Capture working mode +#define MODE_STAT 0x1 ///< Statistical working mode +#define MODE_MON 0x2 ///< Kernel monitoring mode +#define MODE_DUMP 0x10 ///< Kernel dump working mode + + +#define IMMEDIATE 1 ///< Immediate timeout. Forces a read call to return immediately. + +#define NDIS_FLAGS_SKIP_LOOPBACK_W2K 0x400 ///< This is an undocumented flag for NdisSetPacketFlags() that allows to disable loopback reception. + +// The following definitions are used to provide compatibility +// of the dump files with the ones of libpcap +#define TCPDUMP_MAGIC 0xa1b2c3d4 ///< Libpcap magic number. Used by programs like tcpdump to recognize a driver's generated dump file. +#define PCAP_VERSION_MAJOR 2 ///< Major libpcap version of the dump file. Used by programs like tcpdump to recognize a driver's generated dump file. +#define PCAP_VERSION_MINOR 4 ///< Minor libpcap version of the dump file. Used by programs like tcpdump to recognize a driver's generated dump file. + +// Loopback behaviour definitions +#define NPF_DISABLE_LOOPBACK 1 ///< Tells the driver to drop the packets sent by itself. This is usefult when building applications like bridges. +#define NPF_ENABLE_LOOPBACK 2 ///< Tells the driver to capture the packets sent by itself. + +/*! + \brief Header of a libpcap dump file. + + Used when a driver instance is set in dump mode to create a libpcap-compatible file. +*/ +struct packet_file_header +{ + UINT magic; ///< Libpcap magic number + USHORT version_major; ///< Libpcap major version + USHORT version_minor; ///< Libpcap minor version + UINT thiszone; ///< Gmt to local correction + UINT sigfigs; ///< Accuracy of timestamps + UINT snaplen; ///< Length of the max saved portion of each packet + UINT linktype; ///< Data link type (DLT_*). See win_bpf.h for details. +}; + +/*! + \brief Header associated to a packet in the driver's buffer when the driver is in dump mode. + Similar to the bpf_hdr structure, but simpler. +*/ +struct sf_pkthdr { + struct timeval ts; ///< time stamp + UINT 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 len; ///< Length of the original packet (off wire). +}; + +// +// NT4 DDK doesn't have C_ASSERT +// +#ifndef C_ASSERT +#define C_ASSERT(a) +#endif + +/*! + \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. +*/ +typedef 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. +} + PACKET_OID_DATA, *PPACKET_OID_DATA; + +C_ASSERT(sizeof(PACKET_OID_DATA) == 12); + +/*! + \brief Stores an OID request. + + This structure is used by the driver to perform OID query or set operations on the underlying NIC driver. + The OID operations be performed usually only by network drivers, but NPF exports this mechanism to user-level + applications through an IOCTL interface. The driver uses this structure to wrap a NDIS_REQUEST structure. + This allows to handle correctly the callback structure of NdisRequest(), handling multiple requests and + maintaining information about the IRPs to complete. +*/ +typedef struct _INTERNAL_REQUEST { + LIST_ENTRY ListElement; ///< Used to handle lists of requests. +// PIRP Irp; ///< Irp that performed the request +// BOOLEAN Internal; ///< True if the request is for internal use of npf.sys. False if the request is performed by the user through an IOCTL. + NDIS_EVENT InternalRequestCompletedEvent; + NDIS_REQUEST Request; ///< The structure with the actual request, that will be passed to NdisRequest(). + NDIS_STATUS RequestStatus; + +} INTERNAL_REQUEST, *PINTERNAL_REQUEST; + +/*! + \brief Contains a NDIS packet. + + The driver uses this structure to wrap a NDIS_PACKET structure. + This allows to handle correctly the callback structure of NdisTransferData(), handling multiple requests and + maintaining information about the IRPs to complete. +*/ +typedef struct _PACKET_RESERVED { + LIST_ENTRY ListElement; ///< Used to handle lists of packets. + PIRP Irp; ///< Irp that performed the request + PMDL pMdl; ///< MDL mapping the buffer of the packet. + BOOLEAN FreeBufAfterWrite; ///< True if the memory buffer associated with the packet must be freed + ///< after a call to NdisSend(). + ULONG Cpu; ///< The CPU on which the packet was pulled out of the linked list of free packets +} PACKET_RESERVED, *PPACKET_RESERVED; + +#define RESERVED(_p) ((PPACKET_RESERVED)((_p)->ProtocolReserved)) ///< Macro to obtain a NDIS_PACKET from a PACKET_RESERVED + +/*! + \brief Port device extension. + + Structure containing some data relative to every adapter on which NPF is bound. +*/ +typedef struct _DEVICE_EXTENSION { + NDIS_STRING AdapterName; ///< Name of the adapter. + PWSTR ExportString; ///< Name of the exported device, i.e. name that the applications will use + ///< to open this adapter through WinPcap. +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +/*! + \brief Kernel buffer of each CPU. + + Structure containing the kernel buffer (and other CPU related fields) used to capture packets. +*/ +typedef struct __CPU_Private_Data +{ + ULONG P; ///< Zero-based index of the producer in the buffer. It indicates the first free byte to be written. + ULONG C; ///< Zero-based index of the consumer in the buffer. It indicates the first free byte to be read. + ULONG Free; ///< Number of the free bytes in the buffer + PUCHAR Buffer; ///< Pointer to the kernel buffer used to capture packets. + ULONG Accepted; ///< Number of packet that current capture instance acepted, from its opening. A packet + ///< is accepted if it passes the filter and fits in the buffer. Accepted packets are the + ///< ones that reach the application. + ///< This number is related to the particular CPU this structure is referring to. + ULONG Received; ///< Number of packets received by current instance from its opening, i.e. number of + ///< packet received by the network adapter since the beginning of the + ///< capture/monitoring/dump session. + ///< This number is related to the particular CPU this structure is referring to. + ULONG Dropped; ///< Number of packet that current instance had to drop, from its opening. A packet + ///< is dropped if there is no more space to store it in the circular buffer that the + ///< driver associates to current instance. + ///< This number is related to the particular CPU this structure is referring to. + NDIS_SPIN_LOCK BufferLock; ///< It protects the buffer associated with this CPU. + PMDL TransferMdl1; ///< MDL used to map the portion of the buffer that will contain an incoming packet. + PMDL TransferMdl2; ///< Second MDL used to map the portion of the buffer that will contain an incoming packet. + ULONG NewP; ///< Used by NdisTransferData() (when we call NdisTransferData, p index must be updated only in the TransferDataComplete. +} + CpuPrivateData; + + +/*! + \brief Contains the state of a running instance of the NPF driver. + + This is the most important structure of NPF: it is used by almost all the functions of the driver. An + _OPEN_INSTANCE structure is associated with every user-level session, allowing concurrent access + to the driver. +*/ +typedef struct _OPEN_INSTANCE +{ + PDEVICE_EXTENSION DeviceExtension; ///< Pointer to the _DEVICE_EXTENSION structure of the device on which + ///< the instance is bound. + NDIS_HANDLE AdapterHandle; ///< NDIS idetifier of the adapter used by this instance. + UINT Medium; ///< Type of physical medium the underlying NDIS driver uses. See the + ///< documentation of NdisOpenAdapter in the MS DDK for details. + NDIS_HANDLE PacketPool; ///< Pool of NDIS_PACKET structures used to transfer the packets from and to the NIC driver. + KSPIN_LOCK RequestSpinLock; ///< SpinLock used to synchronize the OID requests. + LIST_ENTRY RequestList; ///< List of pending OID requests. + LIST_ENTRY ResetIrpList; ///< List of pending adapter reset requests. + INTERNAL_REQUEST Requests[MAX_REQUESTS]; ///< Array of structures that wrap every single OID request. + PMDL BufferMdl; ///< Pointer to a Memory descriptor list (MDL) that maps the circular buffer's memory. + PKEVENT ReadEvent; ///< Pointer to the event on which the read calls on this instance must wait. + PUCHAR bpfprogram; ///< Pointer to the filtering pseudo-code associated with current instance of the driver. + ///< This code is used only in particular situations (for example when the packet received + ///< from the NIC driver is stored in two non-consecutive buffers. In normal situations + ///< the filtering routine created by the JIT compiler and pointed by the next field + ///< is used. See \ref NPF for details on the filtering process. +#ifdef _X86_ + JIT_BPF_Filter *Filter; ///< Pointer to the native filtering function created by the jitter. + ///< See BPF_jitter() for details. +#endif //_X86_ + UINT MinToCopy; ///< Minimum amount of data in the circular buffer that unlocks a read. Set with the + ///< BIOCSMINTOCOPY IOCTL. + LARGE_INTEGER TimeOut; ///< Timeout after which a read is released, also if the amount of data in the buffer is + ///< less than MinToCopy. Set with the BIOCSRTIMEOUT IOCTL. + + int mode; ///< Working mode of the driver. See PacketSetMode() for details. + LARGE_INTEGER Nbytes; ///< Amount of bytes accepted by the filter when this instance is in statistical mode. + LARGE_INTEGER Npackets; ///< Number of packets accepted by the filter when this instance is in statistical mode. + NDIS_SPIN_LOCK CountersLock; ///< SpinLock that protects the statistical mode counters. + UINT Nwrites; ///< Number of times a single write must be physically repeated. See \ref NPF for an + ///< explanation + ULONG Multiple_Write_Counter; ///< Counts the number of times a single write has already physically repeated. + NDIS_EVENT WriteEvent; ///< Event used to synchronize the multiple write process. + BOOLEAN WriteInProgress; ///< True if a write is currently in progress. NPF currently allows a single wite on + ///< the same open instance. + NDIS_SPIN_LOCK WriteLock; ///< SpinLock that protects the WriteInProgress variable. + NDIS_EVENT NdisRequestEvent; ///< Event used to synchronize I/O requests with the callback structure of NDIS. + BOOLEAN SkipSentPackets; ///< True if this instance should not capture back the packets that it transmits. + NDIS_STATUS IOStatus; ///< Maintains the status of and OID request call, that will be passed to the application. + HANDLE DumpFileHandle; ///< Handle of the file used in dump mode. + PFILE_OBJECT DumpFileObject; ///< Pointer to the object of the file used in dump mode. + PKTHREAD DumpThreadObject; ///< Pointer to the object of the thread used in dump mode. + HANDLE DumpThreadHandle; ///< Handle of the thread created by dump mode to asynchronously move the buffer to disk. + NDIS_EVENT DumpEvent; ///< Event used to synchronize the dump thread with the tap when the instance is in dump mode. + LARGE_INTEGER DumpOffset; ///< Current offset in the dump file. + UNICODE_STRING DumpFileName; ///< String containing the name of the dump file. + UINT MaxDumpBytes; ///< Maximum dimension in bytes of the dump file. If the dump file reaches this size it + ///< will be closed. A value of 0 means unlimited size. + UINT MaxDumpPacks; ///< Maximum number of packets that will be saved in the dump file. If this number of + ///< packets is reached the dump will be closed. A value of 0 means unlimited number of + ///< packets. + BOOLEAN DumpLimitReached; ///< TRUE if the maximum dimension of the dump file (MaxDumpBytes or MaxDumpPacks) is + ///< reached. +#ifdef HAVE_BUGGY_TME_SUPPORT + MEM_TYPE mem_ex; ///< Memory used by the TME virtual co-processor + TME_CORE tme; ///< Data structure containing the virtualization of the TME co-processor +#endif //HAVE_BUGGY_TME_SUPPORT + + NDIS_SPIN_LOCK MachineLock; ///< SpinLock that protects the BPF filter and the TME engine, if in use. + UINT MaxFrameSize; ///< Maximum frame size that the underlying MAC acceptes. Used to perform a check on the + ///< size of the frames sent with NPF_Write() or NPF_BufferedWrite(). + // + // KAFFINITY is used as a bit mask for the affinity in the system. So on every supported OS is big enough for all the CPUs on the system (32 bits on x86, 64 on x64?). + // We use its size to compute the max number of CPUs. + // + CpuPrivateData CpuData[sizeof(KAFFINITY) * 8]; ///< Pool of kernel buffer structures, one for each CPU. + ULONG ReaderSN; ///< Sequence number of the next packet to be read from the pool of kernel buffers. + ULONG WriterSN; ///< Sequence number of the next packet to be written in the pool of kernel buffers. + ///< These two sequence numbers are unique for each capture instance. + ULONG Size; ///< Size of each kernel buffer contained in the CpuData field. + ULONG AdapterHandleUsageCounter; + NDIS_SPIN_LOCK AdapterHandleLock; + ULONG AdapterBindingStatus; ///< Specifies if NPF is still bound to the adapter used by this instance, it's unbinding or it's not bound. + + NDIS_EVENT NdisOpenCloseCompleteEvent; + NDIS_EVENT NdisWriteCompleteEvent; ///< Event that is signalled when all the packets have been successfully sent by NdisSend (and corresponfing sendComplete has been called) + NTSTATUS OpenCloseStatus; + ULONG TransmitPendingPackets; ///< Specifies the number of packets that are pending to be transmitted, i.e. have been submitted to NdisSendXXX but the SendComplete has not been called yet. + ULONG NumPendingIrps; + BOOLEAN ClosePending; + NDIS_SPIN_LOCK OpenInUseLock; +} +OPEN_INSTANCE, *POPEN_INSTANCE; + +enum ADAPTER_BINDING_STATUS +{ + ADAPTER_UNBOUND, + ADAPTER_BOUND, + ADAPTER_UNBINDING, +}; + +/*! + \brief Structure prepended to each packet in the kernel buffer pool. + + Each packet in one of the kernel buffers is prepended by this header. It encapsulates the bpf_header, + which will be passed to user level programs, as well as the sequence number of the packet, set by the producer (the tap function), + and used by the consumer (the read function) to "reorder" the packets contained in the various kernel buffers. +*/ +struct PacketHeader +{ + ULONG SN; ///< Sequence number of the packet. + struct bpf_hdr header; ///< bpf header, created by the tap, and copied unmodified to user level programs. +}; + +extern ULONG g_NCpu; +extern NDIS_HANDLE g_NdisProtocolHandle; +extern struct time_conv G_Start_Time; // from openclos.c +extern UINT g_SendPacketFlags; + +#define TRANSMIT_PACKETS 256 ///< Maximum number of packets in the transmit packet pool. This value is an upper bound to the number + ///< of packets that can be transmitted at the same time or with a single call to NdisSendPackets. + + +/// Macro used in the I/O routines to return the control to user-mode with a success status. +#define EXIT_SUCCESS(quantity) Irp->IoStatus.Information=quantity;\ + Irp->IoStatus.Status = STATUS_SUCCESS;\ + IoCompleteRequest(Irp, IO_NO_INCREMENT);\ + return STATUS_SUCCESS;\ + +/// Macro used in the I/O routines to return the control to user-mode with a failure status. +#define EXIT_FAILURE(quantity) Irp->IoStatus.Information=quantity;\ + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;\ + IoCompleteRequest(Irp, IO_NO_INCREMENT);\ + return STATUS_UNSUCCESSFUL;\ + +/** + * @} + */ + + +/***************************/ +/* Prototypes */ +/***************************/ + +/** @defgroup NPF_code NPF functions + * @{ + */ + + +/*! + \brief The initialization routine of the driver. + \param DriverObject The driver object of NPF created by the system. + \param RegistryPath The registry path containing the keys related to the driver. + \return A string containing a list of network adapters. + + DriverEntry is a mandatory function in a device driver. Like the main() of a user level program, it is called + by the system when the driver is loaded in memory and started. Its purpose is to initialize the driver, + performing all the allocations and the setup. In particular, DriverEntry registers all the driver's I/O + callbacks, creates the devices, defines NPF as a protocol inside NDIS. +*/ +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +/*! + \brief Returns the list of the MACs available on the system. + \return A string containing a list of network adapters. + + The list of adapters is retrieved from the + SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318} registry key. + NPF tries to create its bindings from this list. In this way it is possible to be loaded + and unloaded dynamically without passing from the control panel. +*/ +PWCHAR getAdaptersList(VOID); + +/*! + \brief Returns the MACs that bind to TCP/IP. + \return Pointer to the registry key containing the list of adapters on which TCP/IP is bound. + + If getAdaptersList() fails, NPF tries to obtain the TCP/IP bindings through this function. +*/ +PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(VOID); + +/*! + \brief Creates a device for a given MAC. + \param adriverObjectP The driver object that will be associated with the device, i.e. the one of NPF. + \param amacNameP The name of the network interface that the device will point. + \return If the function succeeds, the return value is nonzero. + + NPF creates a device for every valid network adapter. The new device points to the NPF driver, but contains + information about the original device. In this way, when the user opens the new device, NPF will be able to + determine the correct adapter to use. +*/ +BOOLEAN NPF_CreateDevice( + IN OUT PDRIVER_OBJECT adriverObjectP, + IN PUNICODE_STRING amacNameP + ); +/*! + \brief Opens a new instance of the driver. + \param DeviceObject Pointer to the device object utilized by the user. + \param Irp Pointer to the IRP containing the user request. + \return The status of the operation. See ntstatus.h in the DDK. + + This function is called by the OS when a new instance of the driver is opened, i.e. when a user application + performs a CreateFile on a device created by NPF. NPF_Open allocates and initializes variables, objects + and buffers needed by the new instance, fills the OPEN_INSTANCE structure associated with it and opens the + adapter with a call to NdisOpenAdapter. +*/ +NTSTATUS +NPF_Open( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +/*! + \brief Ends the opening of an adapter. + \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance. + \param Status Status of the opening operation performed by NDIS. + \param OpenErrorStatus not used by NPF. + + Callback function associated with the NdisOpenAdapter() NDIS function. It is invoked by NDIS when the NIC + driver has finished an open operation that was previously started by NPF_Open(). +*/ +VOID +NPF_OpenAdapterComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN NDIS_STATUS OpenErrorStatus + ); + +/*! + \brief Closes an instance of the driver. + \param DeviceObject Pointer to the device object utilized by the user. + \param Irp Pointer to the IRP containing the user request. + \return The status of the operation. See ntstatus.h in the DDK. + + This function is called when a running instance of the driver is closed by the user with a CloseHandle(). + It stops the capture/monitoring/dump process, deallocates the memory and the objects associated with the + instance and closing the files. The network adapter is then closed with a call to NdisCloseAdapter. +*/ +NTSTATUS +NPF_Cleanup( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +NPF_Close( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + + + +/*! + \brief Ends the closing of an adapter. + \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance. + \param Status Status of the close operation performed by NDIS. + + Callback function associated with the NdisCloseAdapter() NDIS function. It is invoked by NDIS when the NIC + driver has finished a close operation that was previously started by NPF_Close(). +*/ +VOID +NPF_CloseAdapterComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status + ); + +/*! + \brief Callback invoked by NDIS when a packet arrives from the network. + \param ProtocolBindingContext Context of the function. Points to a OPEN_INSTANCE structure that identifies + the NPF instance to which the packets are destined. + \param MacReceiveContext Handle that identifies the underlying NIC driver that generated the request. + This value must be used when the packet is transferred from the NIC driver with NdisTransferData(). + \param HeaderBuffer Pointer to the buffer in the NIC driver memory that contains the header of the packet. + \param HeaderBufferSize Size in bytes of the header. + \param LookAheadBuffer Pointer to the buffer in the NIC driver's memory that contains the incoming packet's + data available to NPF. This value does not necessarily coincide with the actual size of the packet, + since only a portion can be available at this time. The remaining portion can be obtained with the + NdisTransferData() NDIS function. + \param LookaheadBufferSize Size in bytes of the lookahead buffer. + \param PacketSize Total size of the incoming packet, excluded the header. + \return The status of the operation. See ntstatus.h in the DDK. + + NPF_tap() is called by the underlying NIC for every incoming packet. It is the most important and one of + the most complex functions of NPF: it executes the filter, runs the statistical engine (if the instance is in + statistical mode), gathers the timestamp, moves the packet in the buffer. NPF_tap() is the only function, + along with the filtering ones, that is executed for every incoming packet, therefore it is carefully + optimized. +*/ +NDIS_STATUS +NPF_tap( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookAheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +/*! + \brief Ends the transfer of a packet. + \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance. + \param Packet Pointer to the NDIS_PACKET structure that received the packet data. + \param Status Status of the transfer operation. + \param BytesTransferred Amount of bytes transferred. + + Callback function associated with the NdisTransferData() NDIS function. It is invoked by NDIS when the NIC + driver has finished the transfer of a packet from the NIC driver memory to the NPF circular buffer. +*/ +VOID +NPF_TransferDataComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status, + IN UINT BytesTransferred + ); + +/*! + \brief Callback function that signals the end of a packet reception. + \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance. + + does nothing in NPF +*/ +VOID +NPF_ReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext); + +/*! + \brief Handles the IOCTL calls. + \param DeviceObject Pointer to the device object utilized by the user. + \param Irp Pointer to the IRP containing the user request. + \return The status of the operation. See ntstatus.h in the DDK. + + Once the packet capture driver is opened it can be configured from user-level applications with IOCTL commands + using the DeviceIoControl() system call. NPF_IoControl receives and serves all the IOCTL calls directed to NPF. + The following commands are recognized: + - #BIOCSETBUFFERSIZE + - #BIOCSETF + - #BIOCGSTATS + - #BIOCSRTIMEOUT + - #BIOCSMODE + - #BIOCSWRITEREP + - #BIOCSMINTOCOPY + - #BIOCSETOID + - #BIOCQUERYOID + - #BIOCSETDUMPFILENAME + - #BIOCGEVNAME + - #BIOCSENDPACKETSSYNC + - #BIOCSENDPACKETSNOSYNC +*/ +NTSTATUS +NPF_IoControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +VOID + +/*! + \brief Ends an OID request. + \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance. + \param pRequest Pointer to the completed OID request. + \param Status Status of the operation. + + Callback function associated with the NdisRequest() NDIS function. It is invoked by NDIS when the NIC + driver has finished an OID request operation that was previously started by NPF_IoControl(). +*/ +NPF_RequestComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_REQUEST pRequest, + IN NDIS_STATUS Status + ); + +/*! + \brief Writes a raw packet to the network. + \param DeviceObject Pointer to the device object on which the user wrote the packet. + \param Irp Pointer to the IRP containing the user request. + \return The status of the operation. See ntstatus.h in the DDK. + + This function is called by the OS in consequence of user WriteFile() call, with the data of the packet that must + be sent on the net. The data is contained in the buffer associated with Irp, NPF_Write takes it and + delivers it to the NIC driver via the NdisSend() function. The Nwrites field of the OPEN_INSTANCE structure + associated with Irp indicates the number of copies of the packet that will be sent: more than one copy of the + packet can be sent for performance reasons. +*/ +NTSTATUS +NPF_Write( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + + +/*! + \brief Writes a buffer of raw packets to the network. + \param Irp Pointer to the IRP containing the user request. + \param UserBuff Pointer to the buffer containing the packets to send. + \param UserBuffSize Size of the buffer with the packets. + \param sync If set to TRUE, the packets are transmitted respecting their timestamps. + \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 an adapter problem or by an + inconsistent/bogus user buffer. + + This function is called by the OS in consequence of a BIOCSENDPACKETSNOSYNC or a BIOCSENDPACKETSSYNC IOCTL. + The buffer received as input parameter contains an arbitrary number of packets, each of which preceded by a + sf_pkthdr structure. NPF_BufferedWrite() scans the buffer and sends every packet via the NdisSend() function. + When Sync is set to TRUE, the packets are synchronized with the KeQueryPerformanceCounter() function. + This requires a remarkable amount of CPU, but allows to respect the timestamps associated with packets with a precision + of some microseconds (depending on the precision of the performance counter of the machine). + If Sync is false, the timestamps are ignored and the packets are sent as fat as possible. +*/ + +INT NPF_BufferedWrite(IN PIRP Irp, + IN PCHAR UserBuff, + IN ULONG UserBuffSize, + BOOLEAN sync); + +/*! + \brief Waits the completion of all the sends performed by NPF_BufferedWrite. + + \param Open Pointer to open context structure + + Used by NPF_BufferedWrite to wait the completion of all the sends before returning the control to the user. +*/ +VOID NPF_WaitEndOfBufferedWrite(POPEN_INSTANCE Open); + +/*! + \brief Ends a send operation. + \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance. + \param pPacket Pointer to the NDIS PACKET structure used by NPF_Write() to send the packet. + \param Status Status of the operation. + + Callback function associated with the NdisSend() NDIS function. It is invoked by NDIS when the NIC + driver has finished an OID request operation that was previously started by NPF_Write(). +*/ +VOID +NPF_SendComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET pPacket, + IN NDIS_STATUS Status + ); + +/*! + \brief Ends a reset of the adapter. + \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance. + \param Status Status of the operation. + + Callback function associated with the NdisReset() NDIS function. It is invoked by NDIS when the NIC + driver has finished an OID request operation that was previously started by NPF_IoControl(), in an IOCTL_PROTOCOL_RESET + command. +*/ +VOID +NPF_ResetComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status + ); + +/*! + \brief Callback for NDIS StatusHandler. Not used by NPF +*/ +VOID +NPF_Status( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN PVOID StatusBuffer, + IN UINT StatusBufferSize + ); + + +/*! + \brief Callback for NDIS StatusCompleteHandler. Not used by NPF +*/ +VOID +NPF_StatusComplete(IN NDIS_HANDLE ProtocolBindingContext); + +/*! + \brief Function called by the OS when NPF is unloaded. + \param DriverObject The driver object of NPF created by the system. + + This is the last function executed when the driver is unloaded from the system. It frees global resources, + delete the devices and deregisters the protocol. The driver can be unloaded by the user stopping the NPF + service (from control panel or with a console 'net stop npf'). +*/ +VOID +NPF_Unload(IN PDRIVER_OBJECT DriverObject); + + +/*! + \brief Function that serves the user's reads. + \param DeviceObject Pointer to the device used by the user. + \param Irp Pointer to the IRP containing the user request. + \return The status of the operation. See ntstatus.h in the DDK. + + This function is called by the OS in consequence of user ReadFile() call. It moves the data present in the + kernel buffer to the user buffer associated with Irp. + First of all, NPF_Read checks the amount of data in kernel buffer associated with current NPF instance. + - If the instance is in capture mode and the buffer contains more than OPEN_INSTANCE::MinToCopy bytes, + NPF_Read moves the data in the user buffer and returns immediatly. In this way, the read performed by the + user is not blocking. + - If the buffer contains less than MinToCopy bytes, the application's request isn't + satisfied immediately, but it's blocked until at least MinToCopy bytes arrive from the net + or the timeout on this read expires. The timeout is kept in the OPEN_INSTANCE::TimeOut field. + - If the instance is in statistical mode or in dump mode, the application's request is blocked until the + timeout kept in OPEN_INSTANCE::TimeOut expires. +*/ +NTSTATUS +NPF_Read( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +/*! + \brief Reads the registry keys associated woth NPF if the driver is manually installed via the control panel. + + Normally not used in recent versions of NPF. +*/ +NTSTATUS +NPF_ReadRegistry( + IN PWSTR *MacDriverName, + IN PWSTR *PacketDriverName, + IN PUNICODE_STRING RegistryPath + ); + +/*! + \brief Function used by NPF_ReadRegistry() to quesry the registry keys associated woth NPF if the driver + is manually installed via the control panel. + + Normally not used in recent versions of NPF. +*/ +NTSTATUS +NPF_QueryRegistryRoutine( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +/*! + \brief Callback for NDIS BindAdapterHandler. Not used by NPF. + + Function called by NDIS when a new adapter is installed on the machine With Plug and Play. +*/ +VOID NPF_BindAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE BindContext, + IN PNDIS_STRING DeviceName, + IN PVOID SystemSpecific1, + IN PVOID SystemSpecific2 + ); + +/*! + \brief Callback for NDIS UnbindAdapterHandler. + \param Status out variable filled by NPF_UnbindAdapter with the status of the unbind operation. + \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with current instance. + \param UnbindContext Specifies a handle, supplied by NDIS, that NPF can use to complete the opration. + + Function called by NDIS when a new adapter is removed from the machine without shutting it down. + NPF_UnbindAdapter closes the adapter calling NdisCloseAdapter() and frees the memory and the structures + associated with it. It also releases the waiting user-level app and closes the dump thread if the instance + is in dump mode. +*/ +VOID +NPF_UnbindAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE UnbindContext + ); + + +/*! + \brief Creates the file that will receive the packets when the driver is in dump mode. + \param Open The NPF instance that opens the file. + \param fileName Pointer to a UNICODE string containing the name of the file. + \param append Boolean value that specifies if the data must be appended to the file. + \return The status of the operation. See ntstatus.h in the DDK. +*/ +NTSTATUS NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN append); + +/*! + \brief Starts dump to file. + \param Open The NPF instance that opens the file. + \return The status of the operation. See ntstatus.h in the DDK. + + This function performs two operations. First, it writes the libpcap header at the beginning of the file. + Second, it starts the thread that asynchronously dumps the network data to the file. +*/ +NTSTATUS NPF_StartDump(POPEN_INSTANCE Open); + +/*! + \brief The dump thread. + \param Open The NPF instance that creates the thread. + + This function moves the content of the NPF kernel buffer to file. It runs in the user context, so at lower + priority than the TAP. +*/ +VOID NPF_DumpThread(PVOID Open); + +/*! + \brief Saves the content of the packet buffer to the file associated with current instance. + \param Open The NPF instance that creates the thread. + + Used by NPF_DumpThread() and NPF_CloseDumpFile(). +*/ +NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open); + +/*! + \brief Writes a block of packets on the dump file. + \param FileObject The file object that will receive the packets. + \param Offset The offset in the file where the packets will be put. + \param Length The amount of bytes to write. + \param Mdl MDL mapping the memory buffer that will be written to disk. + \param IoStatusBlock Used by the function to return the status of the operation. + \return The status of the operation. See ntstatus.h in the DDK. + + NPF_WriteDumpFile addresses directly the file system, creating a custom IRP and using it to send a portion + of the NPF circular buffer to disk. This function is used by NPF_DumpThread(). +*/ +VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject, + PLARGE_INTEGER Offset, + ULONG Length, + PMDL Mdl, + PIO_STATUS_BLOCK IoStatusBlock); + + + +/*! + \brief Closes the dump file associated with an instance of the driver. + \param Open The NPF instance that closes the file. + \return The status of the operation. See ntstatus.h in the DDK. +*/ +NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open); + +BOOLEAN +NPF_StartUsingBinding( + IN POPEN_INSTANCE pOpen); + +VOID +NPF_StopUsingBinding( + IN POPEN_INSTANCE pOpen); + +VOID +NPF_CloseBinding( + IN POPEN_INSTANCE pOpen); + +BOOLEAN +NPF_StartUsingOpenInstance( + IN POPEN_INSTANCE pOpen); + +VOID +NPF_StopUsingOpenInstance( + IN POPEN_INSTANCE pOpen); + +VOID +NPF_CloseOpenInstance( + IN POPEN_INSTANCE pOpen); + +NTSTATUS +NPF_GetDeviceMTU( + IN POPEN_INSTANCE pOpen, + IN PIRP pIrp, + OUT PUINT pMtu); + +/*! + \brief Returns the amount of bytes present in the packet buffer. + \param Open The NPF instance that closes the file. +*/ +UINT GetBuffOccupation(POPEN_INSTANCE Open); + +/*! + \brief Called by NDIS to notify us of a PNP event. The most significant one for us is power state change. + + \param ProtocolBindingContext Pointer to open context structure. This is NULL for global reconfig + events. + \param pNetPnPEvent Pointer to the PnP event + + If there is a power state change, the driver is forced to resynchronize the global timer. + This hopefully avoids the synchronization issues caused by hibernation or standby. + This function is excluded from the NT4 driver, where PnP is not supported +*/ +#ifdef NDIS50 +NDIS_STATUS NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent); +#endif + +// +// Old registry based WinPcap names +// +///*! +// \brief Helper function to query a value from the global WinPcap registry key +//*/ +//VOID NPF_QueryWinpcapRegistryString(PWSTR SubKeyName, +// WCHAR *Value, +// UINT ValueLen, +// WCHAR *DefaultValue); +// + + +/** + * @} + */ + +/** + * @} + */ + +#endif /*main ifndef/define*/ \ No newline at end of file diff --git a/drivers/3rdparty/npf/Read.c b/drivers/3rdparty/npf/Read.c new file mode 100644 index 0000000000000..00f684523ee2f --- /dev/null +++ b/drivers/3rdparty/npf/Read.c @@ -0,0 +1,1052 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "debug.h" +#include "packet.h" +#include "win_bpf.h" +#include "time_calls.h" + +#ifdef HAVE_BUGGY_TME_SUPPORT +#include "tme.h" +#endif //HAVE_BUGGY_TME_SUPPORT + +NTSTATUS NPF_Read(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) +{ + POPEN_INSTANCE Open; + PIO_STACK_LOCATION IrpSp; + PUCHAR packp; + ULONG Input_Buffer_Length; + UINT Thead; + UINT Ttail; + UINT TLastByte; + PUCHAR CurrBuff; + LARGE_INTEGER CapTime; + LARGE_INTEGER TimeFreq; + struct bpf_hdr *header; + KIRQL Irql; + PUCHAR UserPointer; + ULONG bytecopy; + UINT SizeToCopy; + UINT PktLen; + ULONG copied,count,current_cpu,av,plen,increment,ToCopy,available; + CpuPrivateData *LocalData; + ULONG i; + ULONG Occupation; + + IF_LOUD(DbgPrint("NPF: Read\n");) + + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + Open=IrpSp->FileObject->FsContext; + + + if (NPF_StartUsingOpenInstance(Open) == FALSE) + { + // + // an IRP_MJ_CLEANUP was received, just fail the request + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + TRACE_EXIT(); + return STATUS_CANCELLED; + } + + + // + // we need to test if the device is still bound to the Network adapter, + // so we perform a start/stop using binding. + // This is not critical, since we just want to have a quick way to have the + // dispatch read fail in case the adapter has been unbound + + if(NPF_StartUsingBinding(Open) == FALSE) + { + NPF_StopUsingOpenInstance(Open); + // The Network adapter has been removed or diasabled + EXIT_FAILURE(0); + } + NPF_StopUsingBinding(Open); + + if (Open->Size == 0) + { + NPF_StopUsingOpenInstance(Open); + EXIT_FAILURE(0); + } + + if( Open->mode & MODE_DUMP && Open->DumpFileHandle == NULL ){ + // this instance is in dump mode, but the dump file has still not been opened + NPF_StopUsingOpenInstance(Open); + EXIT_FAILURE(0); + } + + Occupation=0; + + for(i=0;iSize - Open->CpuData[i].Free); + + //See if the buffer is full enough to be copied + if( Occupation <= Open->MinToCopy*g_NCpu || Open->mode & MODE_DUMP ) + { + if (Open->ReadEvent != NULL) + { + //wait until some packets arrive or the timeout expires + if(Open->TimeOut.QuadPart != (LONGLONG)IMMEDIATE) + KeWaitForSingleObject(Open->ReadEvent, + UserRequest, + KernelMode, + TRUE, + (Open->TimeOut.QuadPart == (LONGLONG)0)? NULL: &(Open->TimeOut)); + + KeClearEvent(Open->ReadEvent); + } + + if(Open->mode & MODE_STAT) + { //this capture instance is in statistics mode +#ifdef NDIS50 + CurrBuff=(PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); +#else + CurrBuff=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress); +#endif + + if (CurrBuff == NULL) + { + NPF_StopUsingOpenInstance(Open); + EXIT_FAILURE(0); + } + + if (Open->mode & MODE_DUMP) + { + if (IrpSp->Parameters.Read.Length < sizeof(struct bpf_hdr) + 24) + { + NPF_StopUsingOpenInstance(Open); + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + } + else + { + if (IrpSp->Parameters.Read.Length < sizeof(struct bpf_hdr) + 16) + { + NPF_StopUsingOpenInstance(Open); + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + } + + //fill the bpf header for this packet + header=(struct bpf_hdr*)CurrBuff; + GET_TIME(&header->bh_tstamp,&G_Start_Time); + + if(Open->mode & MODE_DUMP){ + *(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+16)=Open->DumpOffset.QuadPart; + header->bh_caplen=24; + header->bh_datalen=24; + Irp->IoStatus.Information = 24 + sizeof(struct bpf_hdr); + } + else{ + header->bh_caplen=16; + header->bh_datalen=16; + header->bh_hdrlen=sizeof(struct bpf_hdr); + Irp->IoStatus.Information = 16 + sizeof(struct bpf_hdr); + } + + *(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr))=Open->Npackets.QuadPart; + *(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+8)=Open->Nbytes.QuadPart; + + //reset the countetrs + NdisAcquireSpinLock( &Open->CountersLock ); + Open->Npackets.QuadPart=0; + Open->Nbytes.QuadPart=0; + NdisReleaseSpinLock( &Open->CountersLock ); + + NPF_StopUsingOpenInstance(Open); + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; + } + +// +// The MONITOR_MODE (aka TME extensions) is not supported on +// 64 bit architectures +// +#ifdef HAVE_BUGGY_TME_SUPPORT + + if(Open->mode==MODE_MON) //this capture instance is in monitor mode + { + PTME_DATA data; + ULONG cnt; + ULONG block_size; + PUCHAR tmp; + +#ifdef NDIS50 + UserPointer=MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); +#else + UserPointer=MmGetSystemAddressForMdl(Irp->MdlAddress); +#endif + + if (UserPointer == NULL) + { + NPF_StopUsingOpenInstance(Open); + EXIT_FAILURE(0); + } + + if ((!IS_VALIDATED(Open->tme.validated_blocks,Open->tme.active_read))||(IrpSp->Parameters.Read.Lengthbh_tstamp,&G_Start_Time); + + + header->bh_hdrlen=sizeof(struct bpf_hdr); + + + //moves user memory pointer + UserPointer+=sizeof(struct bpf_hdr); + + //calculus of data to be copied + //if the user buffer is smaller than data to be copied, + //only some data will be copied + data=&Open->tme.block_data[Open->tme.active_read]; + + if (data->last_read.tv_sec!=0) + data->last_read=header->bh_tstamp; + + + bytecopy=data->block_size*data->filled_blocks; + + if ((IrpSp->Parameters.Read.Length-sizeof(struct bpf_hdr))Parameters.Read.Length-sizeof(struct bpf_hdr))/ data->block_size; + else + bytecopy=data->filled_blocks; + + tmp=data->shared_memory_base_address; + block_size=data->block_size; + + for (cnt=0;cntMachineLock); + RtlCopyMemory(UserPointer,tmp,block_size); + NdisReleaseSpinLock(&Open->MachineLock); + tmp+=block_size; + UserPointer+=block_size; + } + + bytecopy*=block_size; + + header->bh_caplen=bytecopy; + header->bh_datalen=header->bh_caplen; + + NPF_StopUsingOpenInstance(Open); + EXIT_SUCCESS(bytecopy+sizeof(struct bpf_hdr)); + } + + Occupation=0; + + for(i=0;iSize - Open->CpuData[i].Free); + + + if ( Occupation == 0 || Open->mode & MODE_DUMP) + // The timeout has expired, but the buffer is still empty (or the packets must be written to file). + // We must awake the application, returning an empty buffer. + { + NPF_StopUsingOpenInstance(Open); + EXIT_SUCCESS(0); + } + +#else // not HAVE_BUGGY_TME_SUPPORT + if(Open->mode==MODE_MON) //this capture instance is in monitor mode + { + NPF_StopUsingOpenInstance(Open); + EXIT_FAILURE(0); + } +#endif // HAVE_BUGGY_TME_SUPPORT + + } + + + +//------------------------------------------------------------------------------ + copied=0; + count=0; + current_cpu=0; + available = IrpSp->Parameters.Read.Length; +#ifdef NDIS50 + packp=(PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); +#else + packp=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress); +#endif + + if (packp == NULL) + { + NPF_StopUsingOpenInstance(Open); + EXIT_FAILURE(0); + } + + if (Open->ReadEvent != NULL) + KeClearEvent(Open->ReadEvent); + + while (count < g_NCpu) //round robin on the CPUs, if count = NCpu there are no packets left to be copied + { + if (available == copied) + { + NPF_StopUsingOpenInstance(Open); + EXIT_SUCCESS(copied); + } + + LocalData = &Open->CpuData[current_cpu]; + + if (LocalData->Free < Open->Size) + { //there are some packets in the selected (aka LocalData) buffer + struct PacketHeader *Header = (struct PacketHeader*)(LocalData->Buffer + LocalData->C); + + if ( Header->SN == Open->ReaderSN) + { //check if it the next one to be copied + plen = Header->header.bh_caplen; + if (plen + sizeof (struct bpf_hdr) > available - copied) + { //if the packet does not fit into the user buffer, we've ended copying packets + NPF_StopUsingOpenInstance(Open); + EXIT_SUCCESS(copied); + } + +// FIX_TIMESTAMPS(&Header->header.bh_tstamp); + + *((struct bpf_hdr*)(&packp[copied]))=Header->header; + + copied += sizeof(struct bpf_hdr); + LocalData->C += sizeof(struct PacketHeader); + + if (LocalData->C == Open->Size) + LocalData->C = 0; + + if (Open->Size - LocalData->C < plen) + { + //the packet is fragmented in the buffer (i.e. it skips the buffer boundary) + ToCopy = Open->Size - LocalData->C; + RtlCopyMemory(packp + copied,LocalData->Buffer + LocalData->C,ToCopy); + RtlCopyMemory(packp + copied + ToCopy,LocalData->Buffer,plen-ToCopy); + LocalData->C = plen-ToCopy; + } + else + { + //the packet is not fragmented + RtlCopyMemory(packp + copied ,LocalData->Buffer + LocalData->C ,plen); + LocalData->C += plen; + // if (c==size) inutile, contemplato nell "header atomico" + // c=0; + } + + Open->ReaderSN++; + copied+=Packet_WORDALIGN(plen); + + increment = plen + sizeof(struct PacketHeader); + if ( Open->Size - LocalData->C < sizeof(struct PacketHeader)) + { //the next packet would be saved at the end of the buffer, but the NewHeader struct would be fragmented + //so the producer (--> the consumer) skips to the beginning of the buffer + increment += Open->Size-LocalData->C; + LocalData->C=0; + } + InterlockedExchangeAdd(&Open->CpuData[current_cpu].Free,increment); + count=0; + } + else + { + current_cpu=(current_cpu+1)%g_NCpu; + count++; + } + + } + else + { + current_cpu=(current_cpu+1)%g_NCpu; + count++; + } + } + + { + NPF_StopUsingOpenInstance(Open); + EXIT_SUCCESS(copied); + } + +//------------------------------------------------------------------------------ + +} + +NDIS_STATUS NPF_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer,IN UINT HeaderBufferSize,IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize,IN UINT PacketSize) +{ + POPEN_INSTANCE Open; + PNDIS_PACKET pPacket; + ULONG SizeToTransfer; + NDIS_STATUS Status; + UINT BytesTransfered; + ULONG BufferLength; + PMDL pMdl1,pMdl2; + LARGE_INTEGER CapTime; + LARGE_INTEGER TimeFreq; + UINT fres; + USHORT NPFHdrSize; + + CpuPrivateData *LocalData; + ULONG Cpu; + struct PacketHeader *Header; + ULONG ToCopy; + ULONG increment; + ULONG i; + BOOLEAN ShouldReleaseBufferLock; + + IF_VERY_LOUD(DbgPrint("NPF: tap\n");) + IF_VERY_LOUD(DbgPrint("HeaderBufferSize=%u, LookAheadBuffer=%p, LookaheadBufferSize=%u, PacketSize=%u\n", + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize);) + + Open= (POPEN_INSTANCE)ProtocolBindingContext; + + Cpu = KeGetCurrentProcessorNumber(); + LocalData = &Open->CpuData[Cpu]; + + LocalData->Received++; + IF_LOUD(DbgPrint("Received on CPU %d \t%d\n",Cpu,LocalData->Received);) +// Open->Received++; // Number of packets received by filter ++ + + + NdisAcquireSpinLock(&Open->MachineLock); + + // + //Check if the lookahead buffer follows the mac header. + //If the data follow the header (i.e. there is only a buffer) a normal bpf_filter() is + //executed on the packet. + //Otherwise if there are 2 separate buffers (this could be the case of LAN emulation or + //things like this) bpf_filter_with_2_buffers() is executed. + // + if((UINT)((PUCHAR)LookaheadBuffer-(PUCHAR)HeaderBuffer) != HeaderBufferSize) + { +#ifdef HAVE_BUGGY_TME_SUPPORT + fres=bpf_filter_with_2_buffers((struct bpf_insn*)(Open->bpfprogram), + HeaderBuffer, + LookaheadBuffer, + HeaderBufferSize, + PacketSize+HeaderBufferSize, + LookaheadBufferSize+HeaderBufferSize, + &Open->mem_ex, + &Open->tme, + &G_Start_Time); +#else // HAVE_BUGGY_TME_SUPPORT + fres=bpf_filter_with_2_buffers((struct bpf_insn*)(Open->bpfprogram), + HeaderBuffer, + LookaheadBuffer, + HeaderBufferSize, + PacketSize+HeaderBufferSize, + LookaheadBufferSize+HeaderBufferSize); +#endif // HAVE_BUGGY_TME_SUPPORT + } + else +// +// the jit filter is available on x86 (32 bit) only +// +#ifdef _X86_ + + if(Open->Filter != NULL) + { + if (Open->bpfprogram != NULL) + { + fres=Open->Filter->Function(HeaderBuffer, + PacketSize+HeaderBufferSize, + LookaheadBufferSize+HeaderBufferSize); + } + else + fres = -1; + } + else +#endif //_X86_ + +#ifdef HAVE_BUGGY_TME_SUPPORT + fres=bpf_filter((struct bpf_insn*)(Open->bpfprogram), + HeaderBuffer, + PacketSize+HeaderBufferSize, + LookaheadBufferSize+HeaderBufferSize, + &Open->mem_ex, + &Open->tme, + &G_Start_Time); +#else //HAVE_BUGGY_TME_SUPPORT + fres=bpf_filter((struct bpf_insn*)(Open->bpfprogram), + HeaderBuffer, + PacketSize+HeaderBufferSize, + LookaheadBufferSize+HeaderBufferSize); +#endif //HAVE_BUGGY_TME_SUPPORT + + NdisReleaseSpinLock(&Open->MachineLock); + +// +// The MONITOR_MODE (aka TME extensions) is not supported on +// 64 bit architectures +// +#ifdef HAVE_BUGGY_TME_SUPPORT + if(Open->mode==MODE_MON) + // we are in monitor mode + { + if (fres==1) + { + if (Open->ReadEvent != NULL) + { + KeSetEvent(Open->ReadEvent,0,FALSE); + } + } + return NDIS_STATUS_NOT_ACCEPTED; + + } +#endif //HAVE_BUGGY_TME_SUPPORT + + if(fres==0) + { + // Packet not accepted by the filter, ignore it. + return NDIS_STATUS_NOT_ACCEPTED; + } + + //if the filter returns -1 the whole packet must be accepted + if(fres == -1 || fres > PacketSize+HeaderBufferSize) + fres = PacketSize+HeaderBufferSize; + + if(Open->mode & MODE_STAT) + { + // we are in statistics mode + NdisAcquireSpinLock( &Open->CountersLock ); + + Open->Npackets.QuadPart++; + + if(PacketSize+HeaderBufferSize<60) + Open->Nbytes.QuadPart+=60; + else + Open->Nbytes.QuadPart+=PacketSize+HeaderBufferSize; + // add preamble+SFD+FCS to the packet + // these values must be considered because are not part of the packet received from NDIS + Open->Nbytes.QuadPart+=12; + + NdisReleaseSpinLock( &Open->CountersLock ); + + if(!(Open->mode & MODE_DUMP)) + { + return NDIS_STATUS_NOT_ACCEPTED; + } + } + + if(Open->Size == 0) + { + LocalData->Dropped++; + return NDIS_STATUS_NOT_ACCEPTED; + } + + if(Open->mode & MODE_DUMP && Open->MaxDumpPacks) + { + ULONG Accepted=0; + for(i=0;iCpuData[i].Accepted; + + if( Accepted > Open->MaxDumpPacks) + { + // Reached the max number of packets to save in the dump file. Discard the packet and stop the dump thread. + Open->DumpLimitReached = TRUE; // This stops the thread + // Awake the dump thread + NdisSetEvent(&Open->DumpEvent); + + // Awake the application + if (Open->ReadEvent != NULL) + KeSetEvent(Open->ReadEvent,0,FALSE); + + return NDIS_STATUS_NOT_ACCEPTED; + } + } + + //////////////////////////////COPIA.C//////////////////////////////////////////77 + + ShouldReleaseBufferLock = TRUE; + NdisDprAcquireSpinLock(&LocalData->BufferLock); + + do + { + + if (fres + sizeof(struct PacketHeader) > LocalData->Free) + { + LocalData->Dropped++; + break; + } + + if (LocalData->TransferMdl1 != NULL) + { + // + //if TransferMdl is not NULL, there is some TransferData pending (i.e. not having called TransferDataComplete, yet) + //in order to avoid buffer corruption, we drop the packet + // + LocalData->Dropped++; + break; + } + + + if (LookaheadBufferSize + HeaderBufferSize >= fres) + { + + // + // we do not need to call NdisTransferData, either because we need only the HeaderBuffer, or because the LookaheadBuffer + // contains what we need + // + + Header = (struct PacketHeader*)(LocalData->Buffer + LocalData->P); + LocalData->Accepted++; + GET_TIME(&Header->header.bh_tstamp,&G_Start_Time); + Header->SN = InterlockedIncrement(&Open->WriterSN) - 1; + + Header->header.bh_caplen = fres; + Header->header.bh_datalen = PacketSize + HeaderBufferSize; + Header->header.bh_hdrlen=sizeof(struct bpf_hdr); + + LocalData->P +=sizeof(struct PacketHeader); + if (LocalData->P == Open->Size) + LocalData->P = 0; + + if ( fres <= HeaderBufferSize || (UINT)( (PUCHAR)LookaheadBuffer - (PUCHAR)HeaderBuffer ) == HeaderBufferSize ) + { + // + //we can consider the buffer contiguous, either because we use only the data + //present in the HeaderBuffer, or because HeaderBuffer and LookaheadBuffer are contiguous + // ;-)))))) + // + if (Open->Size - LocalData->P < fres) + { + //the packet will be fragmented in the buffer (aka, it will skip the buffer boundary) + //two copies!! + ToCopy = Open->Size - LocalData->P; + NdisMoveMappedMemory(LocalData->Buffer + LocalData->P,HeaderBuffer, ToCopy); + NdisMoveMappedMemory(LocalData->Buffer + 0 , (PUCHAR)HeaderBuffer + ToCopy, fres - ToCopy); + LocalData->P = fres-ToCopy; + } + else + { + //the packet does not need to be fragmented in the buffer (aka, it doesn't skip the buffer boundary) + // ;-)))))) only ONE copy + NdisMoveMappedMemory(LocalData->Buffer + LocalData->P, HeaderBuffer, fres); + LocalData->P += fres; + } + } + else + { + //HeaderBuffer and LookAhead buffer are NOT contiguous, + //AND, we need some bytes from the LookaheadBuffer, too + if (Open->Size - LocalData->P < fres) + { + //the packet will be fragmented in the buffer (aka, it will skip the buffer boundary) + if (Open->Size - LocalData->P >= HeaderBufferSize) + { + //HeaderBuffer is NOT fragmented + NdisMoveMappedMemory(LocalData->Buffer + LocalData->P, HeaderBuffer, HeaderBufferSize); + LocalData->P += HeaderBufferSize; + + if (LocalData->P == Open->Size) + { + //the fragmentation of the packet in the buffer is the same fragmentation + //in HeaderBuffer+LookaheadBuffer + LocalData->P=0; + NdisMoveMappedMemory(LocalData->Buffer + 0, LookaheadBuffer, fres - HeaderBufferSize); + LocalData->P += (fres - HeaderBufferSize); + } + else + { + //LookAheadBuffer is fragmented, two copies + ToCopy = Open->Size - LocalData->P; + NdisMoveMappedMemory(LocalData->Buffer + LocalData->P, LookaheadBuffer, ToCopy); + LocalData->P=0; + NdisMoveMappedMemory(LocalData->Buffer + 0, (PUCHAR)LookaheadBuffer+ ToCopy, fres - HeaderBufferSize - ToCopy); + LocalData->P = fres - HeaderBufferSize - ToCopy; + } + } + else + { + //HeaderBuffer is fragmented in the buffer (aka, it will skip the buffer boundary) + //two copies to copy the HeaderBuffer + ToCopy = Open->Size - LocalData->P; + NdisMoveMappedMemory(LocalData->Buffer + LocalData->P, HeaderBuffer, ToCopy); + LocalData->P = 0; + NdisMoveMappedMemory(LocalData->Buffer + 0, (PUCHAR)HeaderBuffer + ToCopy, HeaderBufferSize - ToCopy); + LocalData->P = HeaderBufferSize - ToCopy; + + //only one copy to copy the LookaheadBuffer + NdisMoveMappedMemory(LocalData->Buffer + LocalData->P, LookaheadBuffer, fres- HeaderBufferSize); + LocalData->P += (fres - HeaderBufferSize); + } + } + else + { + //the packet won't be fragmented in the destination buffer (aka, it won't skip the buffer boundary) + //two copies, the former to copy the HeaderBuffer, the latter to copy the LookaheadBuffer + NdisMoveMappedMemory(LocalData->Buffer + LocalData->P, HeaderBuffer, HeaderBufferSize); + LocalData->P += HeaderBufferSize; + NdisMoveMappedMemory(LocalData->Buffer + LocalData->P, LookaheadBuffer, fres - HeaderBufferSize); + LocalData->P += (fres - HeaderBufferSize); + } + } + + increment = fres + sizeof(struct PacketHeader); + if (Open->Size - LocalData->P < sizeof(struct PacketHeader)) //we check that the available, AND contiguous, space in the buffer will fit + { //the NewHeader structure, at least, otherwise we skip the producer + increment += Open->Size-LocalData->P; //at the beginning of the buffer (p = 0), and decrement the free bytes appropriately + LocalData->P = 0; + } + + InterlockedExchangeAdd(&LocalData->Free, (ULONG)(-(LONG)increment)); + if(Open->Size - LocalData->Free >= Open->MinToCopy) + { + if(Open->mode & MODE_DUMP) + NdisSetEvent(&Open->DumpEvent); + else + { + if (Open->ReadEvent != NULL) + { + KeSetEvent(Open->ReadEvent,0,FALSE); + } + } + } + + break; + } + else + { + IF_LOUD(DbgPrint("TransferData!!\n");) + //ndisTransferData required + LocalData->NewP = LocalData->P; + + LocalData->NewP +=sizeof(struct PacketHeader); + if (LocalData->NewP == Open->Size) + LocalData->NewP = 0; + + //first of all, surely the header must be copied + if (Open->Size-LocalData->NewP >= HeaderBufferSize) + { + //1 copy! + NdisMoveMappedMemory(LocalData->Buffer + LocalData->NewP, HeaderBuffer, HeaderBufferSize); + LocalData->NewP += HeaderBufferSize; + if (LocalData->NewP == Open->Size) + LocalData->NewP = 0; + } + else + { + ToCopy = Open->Size - LocalData->NewP; + NdisMoveMappedMemory(LocalData->Buffer + LocalData->NewP, HeaderBuffer, ToCopy); + NdisMoveMappedMemory(LocalData->Buffer + 0, (PUCHAR)HeaderBuffer + ToCopy, HeaderBufferSize - ToCopy); + LocalData->NewP = HeaderBufferSize - ToCopy; + } + + //then we copy the Lookahead buffer + + if (Open->Size-LocalData->NewP >= LookaheadBufferSize) + { + //1 copy! + NdisMoveMappedMemory(LocalData->Buffer + LocalData->NewP, LookaheadBuffer, LookaheadBufferSize); + LocalData->NewP += LookaheadBufferSize; + if (LocalData->NewP == Open->Size) + LocalData->NewP = 0; + } + else + { + ToCopy = Open->Size - LocalData->NewP; + NdisMoveMappedMemory(LocalData->Buffer + LocalData->NewP, LookaheadBuffer, ToCopy); + NdisMoveMappedMemory(LocalData->Buffer + 0, (PUCHAR)LookaheadBuffer + ToCopy, LookaheadBufferSize - ToCopy); + LocalData->NewP = LookaheadBufferSize - ToCopy; + } + + //Now we must prepare the buffer(s) for the NdisTransferData + if ((Open->Size - LocalData->NewP) >= (fres - HeaderBufferSize - LookaheadBufferSize)) + { + //only 1 buffer + pMdl1 = IoAllocateMdl( + LocalData->Buffer + LocalData->NewP, + fres - HeaderBufferSize - LookaheadBufferSize, + FALSE, + FALSE, + NULL); + + if (pMdl1 == NULL) + { + IF_LOUD(DbgPrint("Error allocating Mdl1\n");) + LocalData->Dropped++; + break; + } + + MmBuildMdlForNonPagedPool(pMdl1); + pMdl2=NULL; + LocalData->NewP += fres - HeaderBufferSize - LookaheadBufferSize; + + + } + else + { + //2 buffers + pMdl1 = IoAllocateMdl( + LocalData->Buffer + LocalData->NewP, + Open->Size - LocalData->NewP, + FALSE, + FALSE, + NULL); + + if (pMdl1 == NULL) + { + IF_LOUD(DbgPrint("Error allocating Mdl1\n");) + LocalData->Dropped++; + break; + } + + pMdl2 = IoAllocateMdl( + LocalData->Buffer + 0, + fres - HeaderBufferSize - LookaheadBufferSize - (Open->Size - LocalData->NewP), + FALSE, + FALSE, + NULL); + + if (pMdl2 == NULL) + { + IF_LOUD(DbgPrint("Error allocating Mdl2\n");) + IoFreeMdl(pMdl1); + LocalData->Dropped++; + break; + } + + LocalData->NewP = fres - HeaderBufferSize - LookaheadBufferSize - (Open->Size - LocalData->NewP); + + MmBuildMdlForNonPagedPool(pMdl1); + MmBuildMdlForNonPagedPool(pMdl2); + } + + + NdisAllocatePacket(&Status, &pPacket, Open->PacketPool); + + if (Status != NDIS_STATUS_SUCCESS) + { + IF_LOUD(DbgPrint("NPF: Tap - No free packets\n");) + IoFreeMdl(pMdl1); + if (pMdl2 != NULL) + IoFreeMdl(pMdl2); + LocalData->Dropped++; + break; + } + + if (pMdl2 != NULL) + NdisChainBufferAtFront(pPacket,pMdl2); + + NdisChainBufferAtFront(pPacket,pMdl1); + + RESERVED(pPacket)->Cpu = Cpu; + + LocalData->TransferMdl1 = pMdl1; + LocalData->TransferMdl2 = pMdl2; + + + Header = (struct PacketHeader*)(LocalData->Buffer + LocalData->P); + Header->header.bh_caplen = fres; + Header->header.bh_datalen = PacketSize + HeaderBufferSize; + Header->header.bh_hdrlen=sizeof(struct bpf_hdr); + + NdisTransferData( + &Status, + Open->AdapterHandle, + MacReceiveContext, + LookaheadBufferSize, + fres - HeaderBufferSize - LookaheadBufferSize, + pPacket, + &BytesTransfered); + + if (Status != NDIS_STATUS_PENDING) + { + IF_LOUD(DbgPrint("NdisTransferData, not pending!\n");) + LocalData->TransferMdl1 = NULL; + LocalData->TransferMdl2 = NULL; + + IoFreeMdl(pMdl1); + if ( pMdl2 != NULL ) + IoFreeMdl(pMdl2); + + NdisReinitializePacket(pPacket); + // Put the packet on the free queue + NdisFreePacket(pPacket); + + LocalData->P = LocalData->NewP; + + LocalData->Accepted++; + GET_TIME(&Header->header.bh_tstamp,&G_Start_Time); + Header->SN = InterlockedIncrement(&Open->WriterSN) - 1; + + increment = fres + sizeof(struct PacketHeader); + if (Open->Size - LocalData->P < sizeof(struct PacketHeader)) + { + increment += Open->Size-LocalData->P; + LocalData->P = 0; + } + + InterlockedExchangeAdd(&LocalData->Free, (ULONG)(-(LONG)increment)); + + if(Open->Size - LocalData->Free >= Open->MinToCopy) + { + if(Open->mode & MODE_DUMP) + NdisSetEvent(&Open->DumpEvent); + else + { + if (Open->ReadEvent != NULL) + { + KeSetEvent(Open->ReadEvent,0,FALSE); + } + } + } + + break; + } + else + { + IF_LOUD(DbgPrint("NdisTransferData, pending!\n");) + ShouldReleaseBufferLock = FALSE; + } + } + } + while(FALSE); + + if (ShouldReleaseBufferLock) + { + NdisDprReleaseSpinLock(&LocalData->BufferLock); + } + + return NDIS_STATUS_NOT_ACCEPTED; + +} + +//------------------------------------------------------------------- + +VOID NPF_TransferDataComplete (IN NDIS_HANDLE ProtocolBindingContext,IN PNDIS_PACKET pPacket, + IN NDIS_STATUS Status,IN UINT BytesTransfered) +{ + POPEN_INSTANCE Open; + ULONG Cpu; + CpuPrivateData *LocalData; + struct PacketHeader* Header; + ULONG increment; + + IF_LOUD(DbgPrint("NPF: TransferDataComplete\n");) + + Open = (POPEN_INSTANCE)ProtocolBindingContext; + + Cpu = RESERVED(pPacket)->Cpu; + + LocalData = &Open->CpuData[Cpu]; + + IoFreeMdl(LocalData->TransferMdl1); + if ( LocalData->TransferMdl2 != NULL ) + IoFreeMdl(LocalData->TransferMdl2); + + NdisReinitializePacket(pPacket); + // Put the packet on the free queue + NdisFreePacket(pPacket); + + //the packet has been successfully copied to the kernel buffer, we can prepend it with the PacketHeader, + //and obtain the sequence number and the timestamp + + LocalData->Accepted++; + Header = (struct PacketHeader*)(LocalData->Buffer + LocalData->P); + GET_TIME(&Header->header.bh_tstamp,&G_Start_Time); + Header->SN = InterlockedIncrement(&Open->WriterSN) - 1; + + LocalData->P = LocalData->NewP; + + increment = Header->header.bh_caplen + sizeof(struct PacketHeader); + if (Open->Size - LocalData->P < sizeof(struct PacketHeader)) + { + increment += Open->Size-LocalData->P; + LocalData->P = 0; + } + + InterlockedExchangeAdd(&LocalData->Free, (ULONG)(-(LONG)increment)); + + if(Open->Size - LocalData->Free >= Open->MinToCopy) + { + if(Open->mode & MODE_DUMP) + NdisSetEvent(&Open->DumpEvent); + else + { + if (Open->ReadEvent != NULL) + { + KeSetEvent(Open->ReadEvent,0,FALSE); + } + } + } + + LocalData->TransferMdl1 = NULL; + LocalData->TransferMdl2 = NULL; + +// +// NOTE: this is really bad practice. +// a better approach would be performing the entire copy here. +// +#pragma prefast(suppress:8107, "There's no Spinlock leak here, as it's acquired by the tap.") + NdisDprReleaseSpinLock(&LocalData->BufferLock); + +// Unfreeze the consumer + if(Open->Size - LocalData->Free > Open->MinToCopy) + { + if(Open->mode & MODE_DUMP) + NdisSetEvent(&Open->DumpEvent); + else + { + if (Open->ReadEvent != NULL) + { + KeSetEvent(Open->ReadEvent,0,FALSE); + } + } + } + return; +} + +//------------------------------------------------------------------- + +VOID NPF_ReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext) +{ + IF_VERY_LOUD(DbgPrint("NPF: NPF_ReceiveComplete\n");) + return; +} diff --git a/drivers/3rdparty/npf/Sources b/drivers/3rdparty/npf/Sources new file mode 100644 index 0000000000000..78de4edf0a5fd --- /dev/null +++ b/drivers/3rdparty/npf/Sources @@ -0,0 +1,22 @@ +TARGETNAME=npf + +TARGETPATH=bin$(TARGETSUFFIX) + +TARGETTYPE=DRIVER + +TARGETLIBS=$(DDK_LIB_PATH)\ndis.lib + +C_DEFINES=$(C_DEFINES) -DWIN_NT_DRIVER -DWIN32_EXT $(NPF_C_DEFINES) + +INCLUDES=..\..\common + +SOURCES=packet.c \ + openclos.c \ + read.c \ + write.c \ + dump.c \ + win_bpf_filter.c \ + NPF.rc \ + $(NPF_TME_FILES) + +I386_SOURCES = jitter.c diff --git a/drivers/3rdparty/npf/WinPcap NTx Driver_2003.vcproj b/drivers/3rdparty/npf/WinPcap NTx Driver_2003.vcproj new file mode 100644 index 0000000000000..88369a9aef0ad --- /dev/null +++ b/drivers/3rdparty/npf/WinPcap NTx Driver_2003.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/3rdparty/npf/Write.c b/drivers/3rdparty/npf/Write.c new file mode 100644 index 0000000000000..6a2ad5334652f --- /dev/null +++ b/drivers/3rdparty/npf/Write.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "debug.h" +#include "packet.h" + +//------------------------------------------------------------------- + +NTSTATUS +NPF_Write( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) + +{ + POPEN_INSTANCE Open; + PIO_STACK_LOCATION IrpSp; + PNDIS_PACKET pPacket; + NDIS_STATUS Status; + ULONG NumSends; + ULONG numSentPackets; + + TRACE_ENTER(); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + Open=IrpSp->FileObject->FsContext; + + if (NPF_StartUsingOpenInstance(Open) == FALSE) + { + // + // an IRP_MJ_CLEANUP was received, just fail the request + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + TRACE_EXIT(); + return STATUS_CANCELLED; + } + + NumSends = Open->Nwrites; + + // + // validate the send parameters set by the IOCTL + // + if (NumSends == 0) + { + NPF_StopUsingOpenInstance(Open); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + TRACE_EXIT(); + return STATUS_SUCCESS; + } + + // + // Validate input parameters: + // 1. The packet size should be greater than 0, + // 2. less-equal than max frame size for the link layer and + // 3. the maximum frame size of the link layer should not be zero. + // + if(IrpSp->Parameters.Write.Length == 0 || // Check that the buffer provided by the user is not empty + Open->MaxFrameSize == 0 || // Check that the MaxFrameSize is correctly initialized + Irp->MdlAddress == NULL || + IrpSp->Parameters.Write.Length > Open->MaxFrameSize) // Check that the fame size is smaller that the MTU + { + TRACE_MESSAGE(PACKET_DEBUG_LOUD,"Frame size out of range, or maxFrameSize = 0. Send aborted"); + + NPF_StopUsingOpenInstance(Open); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + TRACE_EXIT(); + return STATUS_UNSUCCESSFUL; + } + + // + // Increment the ref counter of the binding handle, if possible + // + if(NPF_StartUsingBinding(Open) == FALSE) + { + TRACE_MESSAGE(PACKET_DEBUG_LOUD,"Adapter is probably unbinding, cannot send packets"); + + NPF_StopUsingOpenInstance(Open); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + TRACE_EXIT(); + return STATUS_INVALID_DEVICE_REQUEST; + } + + NdisAcquireSpinLock(&Open->WriteLock); + if(Open->WriteInProgress) + { + // Another write operation is currently in progress + NdisReleaseSpinLock(&Open->WriteLock); + + NPF_StopUsingBinding(Open); + + TRACE_MESSAGE(PACKET_DEBUG_LOUD,"Another Send operation is in progress, aborting."); + + NPF_StopUsingOpenInstance(Open); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + TRACE_EXIT(); + + return STATUS_UNSUCCESSFUL; + } + else + { + Open->WriteInProgress = TRUE; + NdisResetEvent(&Open->NdisWriteCompleteEvent); + } + + NdisReleaseSpinLock(&Open->WriteLock); + + TRACE_MESSAGE2(PACKET_DEBUG_LOUD,"Max frame size = %u, packet size = %u", Open->MaxFrameSize, IrpSp->Parameters.Write.Length); + + // + // reset the number of packets pending the SendComplete + // + Open->TransmitPendingPackets = 0; + + NdisResetEvent(&Open->WriteEvent); + + numSentPackets = 0; + + while( numSentPackets < NumSends ) + { + NdisAllocatePacket( + &Status, + &pPacket, + Open->PacketPool + ); + + if (Status == NDIS_STATUS_SUCCESS) + { + // + // packet is available, prepare it and send it with NdisSend. + // + + // + // If asked, set the flags for this packet. + // Currently, the only situation in which we set the flags is to disable the reception of loopback + // packets, i.e. of the packets sent by us. + // + if(Open->SkipSentPackets) + { + NdisSetPacketFlags( + pPacket, + g_SendPacketFlags); + } + + + // The packet hasn't a buffer that needs not to be freed after every single write + RESERVED(pPacket)->FreeBufAfterWrite = FALSE; + +// // Save the IRP associated with the packet +// RESERVED(pPacket)->Irp=Irp; + + // Attach the writes buffer to the packet + NdisChainBufferAtFront(pPacket,Irp->MdlAddress); + + InterlockedIncrement(&Open->TransmitPendingPackets); + + NdisResetEvent(&Open->NdisWriteCompleteEvent); + + // + // Call the MAC + // + NdisSend( + &Status, + Open->AdapterHandle, + pPacket); + + if (Status != NDIS_STATUS_PENDING) + { + // The send didn't pend so call the completion handler now + NPF_SendComplete( + Open, + pPacket, + Status + ); + } + + numSentPackets ++; + } + else + { + // + // no packets are available in the Transmit pool, wait some time. The + // event gets signalled when at least half of the TX packet pool packets + // are available + // + NdisWaitEvent(&Open->WriteEvent,1); + } + } + + // + // when we reach this point, all the packets have been enqueued to NdisSend, + // we just need to wait for all the packets to be completed by the SendComplete + // (if any of the NdisSend requests returned STATUS_PENDING) + // + NdisWaitEvent(&Open->NdisWriteCompleteEvent, 0); + + // + // all the packets have been transmitted, release the use of the adapter binding + // + NPF_StopUsingBinding(Open); + + // + // no more writes are in progress + // + NdisAcquireSpinLock(&Open->WriteLock); + Open->WriteInProgress = FALSE; + NdisReleaseSpinLock(&Open->WriteLock); + + NPF_StopUsingOpenInstance(Open); + + // + // Complete the Irp and return success + // + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = IrpSp->Parameters.Write.Length; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + TRACE_EXIT(); + + return STATUS_SUCCESS; +} + +//------------------------------------------------------------------- + +INT +NPF_BufferedWrite( + IN PIRP Irp, + IN PCHAR UserBuff, + IN ULONG UserBuffSize, + BOOLEAN Sync) +{ + POPEN_INSTANCE Open; + PIO_STACK_LOCATION IrpSp; + PNDIS_PACKET pPacket; + UINT i; + NDIS_STATUS Status; + LARGE_INTEGER StartTicks, CurTicks, TargetTicks; + LARGE_INTEGER TimeFreq; + struct timeval BufStartTime; + struct sf_pkthdr *pWinpcapHdr; + PMDL TmpMdl; + ULONG Pos = 0; +// PCHAR CurPos; +// PCHAR EndOfUserBuff = UserBuff + UserBuffSize; + INT result; + + IF_LOUD(DbgPrint("NPF: BufferedWrite, UserBuff=%p, Size=%u\n", UserBuff, UserBuffSize);) + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + Open=IrpSp->FileObject->FsContext; + + if( NPF_StartUsingBinding(Open) == FALSE) + { + // The Network adapter was removed. + return 0; + } + + // Sanity check on the user buffer + if(UserBuff == NULL) + { + // + // release ownership of the NdisAdapter binding + // + NPF_StopUsingBinding(Open); + + return 0; + } + + // Check that the MaxFrameSize is correctly initialized + if(Open->MaxFrameSize == 0) + { + IF_LOUD(DbgPrint("BufferedWrite: Open->MaxFrameSize not initialized, probably because of a problem in the OID query\n");) + + // + // release ownership of the NdisAdapter binding + // + NPF_StopUsingBinding(Open); + return 0; + } + + // Reset the event used to synchronize packet allocation + NdisResetEvent(&Open->WriteEvent); + + // Reset the pending packets counter + Open->Multiple_Write_Counter = 0; + + // Save the current time stamp counter + CurTicks = KeQueryPerformanceCounter(&TimeFreq); + + // + // Main loop: send the buffer to the wire + // + while(TRUE) + { + if (Pos == UserBuffSize) + { + // + // end of buffer + // + result = Pos; + break; + } + + if (UserBuffSize - Pos < sizeof(*pWinpcapHdr)) + { + // Malformed header + IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");) + + result = -1; + break; + } + + pWinpcapHdr = (struct sf_pkthdr*)(UserBuff + Pos); + + if(pWinpcapHdr->caplen ==0 || pWinpcapHdr->caplen > Open->MaxFrameSize) + { + // Malformed header + IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");) + + result = -1; + break; + } + + if (Pos == 0) + { + // Retrieve the time references + StartTicks = KeQueryPerformanceCounter(&TimeFreq); + BufStartTime.tv_sec = pWinpcapHdr->ts.tv_sec; + BufStartTime.tv_usec = pWinpcapHdr->ts.tv_usec; + } + + Pos += sizeof(*pWinpcapHdr); + + if (pWinpcapHdr->caplen > UserBuffSize - Pos) + { + // + // the packet is missing!! + // + IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");) + + result = -1; + break; + } + + // Allocate an MDL to map the packet data + TmpMdl = IoAllocateMdl(UserBuff + Pos, + pWinpcapHdr->caplen, + FALSE, + FALSE, + NULL); + + if (TmpMdl == NULL) + { + // Unable to map the memory: packet lost + IF_LOUD(DbgPrint("NPF_BufferedWrite: unable to allocate the MDL.\n");) + + result = -1; + break; + } + + MmBuildMdlForNonPagedPool(TmpMdl); // XXX can this line be removed? + + Pos += pWinpcapHdr->caplen; + + // Allocate a packet from our free list + NdisAllocatePacket( &Status, &pPacket, Open->PacketPool); + + if (Status != NDIS_STATUS_SUCCESS) + { + // No more free packets + IF_LOUD(DbgPrint("NPF_BufferedWrite: no more free packets, returning.\n");) + + NdisResetEvent(&Open->WriteEvent); + + NdisWaitEvent(&Open->WriteEvent, 1000); + + // Try again to allocate a packet + NdisAllocatePacket( &Status, &pPacket, Open->PacketPool); + + if (Status != NDIS_STATUS_SUCCESS) + { + // Second failure, report an error + IoFreeMdl(TmpMdl); + + result = -1; + break; + } + + } + + // If asked, set the flags for this packet. + // Currently, the only situation in which we set the flags is to disable the reception of loopback + // packets, i.e. of the packets sent by us. + if(Open->SkipSentPackets) + { + NdisSetPacketFlags( + pPacket, + g_SendPacketFlags); + } + + // The packet has a buffer that needs to be freed after every single write + RESERVED(pPacket)->FreeBufAfterWrite = TRUE; + + TmpMdl->Next = NULL; + + // Attach the MDL to the packet + NdisChainBufferAtFront(pPacket, TmpMdl); + + // Increment the number of pending sends + InterlockedIncrement(&Open->Multiple_Write_Counter); + + // Call the MAC + NdisSend( &Status, Open->AdapterHandle, pPacket); + + if (Status != NDIS_STATUS_PENDING) { + // The send didn't pend so call the completion handler now + NPF_SendComplete( + Open, + pPacket, + Status + ); + } + + if( Sync ){ + + if (Pos == UserBuffSize) + { + result = Pos; + break; + } + + if ((UserBuffSize - Pos) < sizeof(*pWinpcapHdr)) + { + // Malformed header + IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");) + + result = -1; + break; + } + + pWinpcapHdr = (struct sf_pkthdr*)(UserBuff + Pos); + + if(pWinpcapHdr->caplen ==0 || pWinpcapHdr->caplen > Open->MaxFrameSize || pWinpcapHdr->caplen > (UserBuffSize - Pos - sizeof(*pWinpcapHdr))) + { + // Malformed header + IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");) + + result = -1; + break; + } + + // Release the application if it has been blocked for approximately more than 1 seconds + if( pWinpcapHdr->ts.tv_sec - BufStartTime.tv_sec > 1 ) + { + IF_LOUD(DbgPrint("NPF_BufferedWrite: timestamp elapsed, returning.\n");) + + result = Pos; + break; + } + + // Calculate the time interval to wait before sending the next packet + TargetTicks.QuadPart = StartTicks.QuadPart + + (LONGLONG)((pWinpcapHdr->ts.tv_sec - BufStartTime.tv_sec) * 1000000 + + pWinpcapHdr->ts.tv_usec - BufStartTime.tv_usec) * + (TimeFreq.QuadPart) / 1000000; + + // Wait until the time interval has elapsed + while( CurTicks.QuadPart <= TargetTicks.QuadPart ) + CurTicks = KeQueryPerformanceCounter(NULL); + } + + } + + // Wait the completion of pending sends + NPF_WaitEndOfBufferedWrite(Open); + + // + // release ownership of the NdisAdapter binding + // + NPF_StopUsingBinding(Open); + + return result; +} + +//------------------------------------------------------------------- + +VOID NPF_WaitEndOfBufferedWrite(POPEN_INSTANCE Open) +{ + UINT i; + + NdisResetEvent(&Open->WriteEvent); + + for(i=0; Open->Multiple_Write_Counter > 0 && i < TRANSMIT_PACKETS; i++) + { + NdisWaitEvent(&Open->WriteEvent, 100); + NdisResetEvent(&Open->WriteEvent); + } + + return; +} + +//------------------------------------------------------------------- + +VOID +NPF_SendComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET pPacket, + IN NDIS_STATUS Status + ) + +{ + POPEN_INSTANCE Open; + PMDL TmpMdl; + + TRACE_ENTER(); + + Open= (POPEN_INSTANCE)ProtocolBindingContext; + + if( RESERVED(pPacket)->FreeBufAfterWrite ) + { + // + // Packet sent by NPF_BufferedWrite() + // + + + // Free the MDL associated with the packet + NdisUnchainBufferAtFront(pPacket, &TmpMdl); + + IoFreeMdl(TmpMdl); + + // recyle the packet + // NdisReinitializePacket(pPacket); + + NdisFreePacket(pPacket); + + // Increment the number of pending sends + InterlockedDecrement(&Open->Multiple_Write_Counter); + + NdisSetEvent(&Open->WriteEvent); + + TRACE_EXIT(); + return; + } + else + { + // + // Packet sent by NPF_Write() + // + + ULONG stillPendingPackets = InterlockedDecrement(&Open->TransmitPendingPackets); + + // + // Put the packet back on the free list + // + NdisFreePacket(pPacket); + + // + // if the number of packets submitted to NdisSend and not acknoledged is less than half the + // packets in the TX pool, wake up any transmitter waiting for available packets in the TX + // packet pool + // + if (stillPendingPackets < TRANSMIT_PACKETS/2) + { + NdisSetEvent(&Open->WriteEvent); + } + else + { + // + // otherwise, reset the event, so that we are sure that the NPF_Write will eventually block to + // waitg for availability of packets in the TX packet pool + // + NdisResetEvent(&Open->WriteEvent); + } + + if(stillPendingPackets == 0) + { + NdisSetEvent(&Open->NdisWriteCompleteEvent); + } + + TRACE_EXIT(); + return; + } + +} diff --git a/drivers/3rdparty/npf/bucket_lookup.c b/drivers/3rdparty/npf/bucket_lookup.c new file mode 100644 index 0000000000000..562a8ca62aa45 --- /dev/null +++ b/drivers/3rdparty/npf/bucket_lookup.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef WIN32 +#include "tme.h" +#include "bucket_lookup.h" +#endif + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#endif + +#endif + +#ifndef UNUSED +#define UNUSED(_x) (_x) +#endif + + +/* the key is represented by the initial and final value */ +/* of the bucket. At the moment bucket_lookup is able to */ +/* manage values of 16, 32 bits. */ +uint32 bucket_lookup(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref) +{ + uint32 value; + uint32 i,j; + int found=-1; + uint32 blocks; + uint32 block_size; + uint8 *temp; + + UNUSED(mem_ex); + + if ((data->key_len!=1)&& /*16 bit value*/ + (data->key_len!=2)) /*32 bit value*/ + return TME_ERROR; + + /*32 bit values*/ + blocks=data->filled_blocks-1; + block_size=data->block_size; + i=blocks/2; /*relative shift*/ + j=i; + temp=data->shared_memory_base_address+block_size; + + if (data->key_len==2) + { + value=SW_ULONG_AT(key,0); + + if((valueSW_ULONG_AT(temp+block_size*(blocks-1),4))) + { + uint32 *key32=(uint32*) key; + key32[0]=key32[1]=0; + + GET_TIME((struct timeval *)(data->shared_memory_base_address+8),time_ref); + + data->last_found=NULL; + return TME_FALSE; + } + + while(found==-1) /* search routine */ + { + i=(i==1)? 1:i>>1; + if (SW_ULONG_AT(temp+block_size*j,0)>value) + if (SW_ULONG_AT(temp+block_size*(j-1),4)value) + found=-2; + else + j+=i; + else found=j; + } + if (found<0) + { + uint32 *key32=(uint32*) key; + key32[0]=key32[1]=0; + + GET_TIME((struct timeval *)(data->shared_memory_base_address+8),time_ref); + + data->last_found=NULL; + return TME_FALSE; + } + + data->last_found=data->lut_base_address+found*sizeof(RECORD); + + COPY_MEMORY(key,temp+block_size*found,8); + + GET_TIME((struct timeval *)(temp+block_size*found+8),time_ref); + + return TME_TRUE; + } + else + { + value=SW_USHORT_AT(key,0); + + if((valueSW_USHORT_AT(temp+block_size*(blocks-1),2))) + { + uint16 *key16=(uint16*) key; + key16[0]=key16[1]=0; + + GET_TIME((struct timeval *)(data->shared_memory_base_address+4),time_ref); + + data->last_found=NULL; + return TME_FALSE; + } + + while(found==-1) /* search routine */ + { + i=(i==1)? 1:i>>1; + if (SW_USHORT_AT(temp+block_size*j,0)>value) + if (SW_USHORT_AT(temp+block_size*(j-1),2)value) + found=-2; + else + j+=i; + else found=j; + } + + if (found<0) + { + uint16 *key16=(uint16*) key; + key16[0]=key16[1]=0; + + GET_TIME((struct timeval *)(data->shared_memory_base_address+4),time_ref); + + data->last_found=NULL; + return TME_FALSE; + } + + data->last_found=data->lut_base_address+found*sizeof(RECORD); + + GET_TIME((struct timeval *)(temp+block_size*found+4),time_ref); + + COPY_MEMORY(key,temp+block_size*found,4); + + return TME_TRUE; + } + +} + +uint32 bucket_lookup_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref) +{ + RECORD *records=(RECORD*)data->lut_base_address; + + if ((data->key_len!=1)&& /*16 bit value*/ + (data->key_len!=2)) /*32 bit value*/ + return TME_ERROR; + + if(data->key_len==2) + { + uint32 start,stop; + uint8 *tmp; + + start=SW_ULONG_AT(key,0); + stop=SW_ULONG_AT(key,4); + + if (start>stop) + return TME_ERROR; + if (data->filled_entries>0) + { + tmp=mem_ex->buffer+SW_ULONG_AT(&records[data->filled_entries-1].block,0); + /*check if it is coherent with the previous block*/ + if (SW_ULONG_AT(tmp,4)>=start) + return TME_ERROR; + } + + if (data->filled_blocks==data->shared_memory_blocks) + return TME_ERROR; + + if (data->filled_entries==data->lut_entries) + return TME_ERROR; + + tmp=data->shared_memory_base_address+data->block_size*data->filled_blocks; + + COPY_MEMORY(tmp,key,8); + + SW_ULONG_ASSIGN(&records[data->filled_entries].block,tmp-mem_ex->buffer); + SW_ULONG_ASSIGN(&records[data->filled_entries].exec_fcn,data->default_exec); + + GET_TIME((struct timeval *)(tmp+8),time_ref); + + data->filled_blocks++; + data->filled_entries++; + + return TME_TRUE; + } + else + { + uint16 start,stop; + uint8 *tmp; + + start=SW_USHORT_AT(key,0); + stop=SW_USHORT_AT(key,2); + + if (start>stop) + return TME_ERROR; + if (data->filled_entries>0) + { + tmp=mem_ex->buffer+SW_ULONG_AT(&records[data->filled_entries-1].block,0); + /*check if it is coherent with the previous block*/ + if (SW_USHORT_AT(tmp,2)>=start) + return TME_ERROR; + } + + if (data->filled_blocks==data->shared_memory_blocks) + return TME_ERROR; + + if (data->filled_entries==data->lut_entries) + return TME_ERROR; + + tmp=mem_ex->buffer+SW_ULONG_AT(&records[data->filled_entries].block,0); + + COPY_MEMORY(tmp,key,4); + + SW_ULONG_ASSIGN(&records[data->filled_entries].block,tmp-mem_ex->buffer); + SW_ULONG_ASSIGN(&records[data->filled_entries].exec_fcn,data->default_exec); + + GET_TIME((struct timeval *)(tmp+4),time_ref); + + data->filled_blocks++; + data->filled_entries++; + + return TME_TRUE; + } +} \ No newline at end of file diff --git a/drivers/3rdparty/npf/bucket_lookup.h b/drivers/3rdparty/npf/bucket_lookup.h new file mode 100644 index 0000000000000..e614e45d94cd1 --- /dev/null +++ b/drivers/3rdparty/npf/bucket_lookup.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __bucket_lookup +#define __bucket_lookup +#ifdef WIN32 +#include "tme.h" +#endif + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#else +#include +#endif + +#endif + +#define BUCKET_LOOKUP_INSERT 0x00000011 +uint32 bucket_lookup_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref); +#define BUCKET_LOOKUP 0x00000010 +uint32 bucket_lookup(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref); + +#endif \ No newline at end of file diff --git a/drivers/3rdparty/npf/count_packets.c b/drivers/3rdparty/npf/count_packets.c new file mode 100644 index 0000000000000..972e1bb9b7d5f --- /dev/null +++ b/drivers/3rdparty/npf/count_packets.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef WIN32 +#include "tme.h" +#include "count_packets.h" +#endif + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#endif + +#endif + +#ifndef UNUSED +#define UNUSED(_x) (_x) +#endif + + +uint32 count_packets(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data) +{ + c_p_data *counters; + + UNUSED(mem_data); + UNUSED(mem_ex); + + counters = (c_p_data*)(block+data->key_len*4); + + counters->bytes+=pkt_size; + counters->packets++; + + return TME_SUCCESS; + +} diff --git a/drivers/3rdparty/npf/count_packets.h b/drivers/3rdparty/npf/count_packets.h new file mode 100644 index 0000000000000..2cd1af59793b9 --- /dev/null +++ b/drivers/3rdparty/npf/count_packets.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __count_packets +#define __count_packets + +#ifdef WIN32 +#include "tme.h" +#endif + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#else +#include +#endif + +#endif + +typedef struct __c_p_data +{ + struct timeval timestamp; + uint64 packets; + uint64 bytes; +} + c_p_data; + +#define COUNT_PACKETS 0x00000000 +uint32 count_packets(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data); + +#endif + diff --git a/drivers/3rdparty/npf/dump.c b/drivers/3rdparty/npf/dump.c new file mode 100644 index 0000000000000..b7cfe1e90088e --- /dev/null +++ b/drivers/3rdparty/npf/dump.c @@ -0,0 +1,608 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "debug.h" +#include "packet.h" +#include "win_bpf.h" + +#ifdef __NPF_NT4__ +extern POBJECT_TYPE *PsThreadType; +#endif + +//------------------------------------------------------------------- + +NTSTATUS +NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append) +{ + NTSTATUS ntStatus; + IO_STATUS_BLOCK IoStatus; + OBJECT_ATTRIBUTES ObjectAttributes; + PWCHAR PathPrefix; + USHORT PathLen; + UNICODE_STRING FullFileName; + ULONG FullFileNameLength; + PDEVICE_OBJECT fsdDevice; + + FILE_STANDARD_INFORMATION StandardInfo; + + IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");) + + if(fileName->Buffer[0] == L'\\' && + fileName->Buffer[1] == L'?' && + fileName->Buffer[2] == L'?' && + fileName->Buffer[3] == L'\\' + ){ + PathLen = 0; + } + else{ + PathPrefix = L"\\??\\"; + PathLen = 8; + } + + // Insert the correct path prefix. + FullFileNameLength = PathLen + fileName->MaximumLength; + + FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool, + FullFileNameLength, + '0DWA'); + + if (FullFileName.Buffer == NULL) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + return ntStatus; + } + + FullFileName.Length = PathLen; + FullFileName.MaximumLength = (USHORT)FullFileNameLength; + + if(PathLen) + RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen); + + RtlAppendUnicodeStringToString (&FullFileName, fileName); + + IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);) + + InitializeObjectAttributes ( &ObjectAttributes, + &FullFileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL ); + + // Create the dump file + ntStatus = ZwCreateFile( &Open->DumpFileHandle, + SYNCHRONIZE | FILE_WRITE_DATA, + &ObjectAttributes, + &IoStatus, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + (Append)?FILE_OPEN_IF:FILE_SUPERSEDE, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 ); + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus);) + + ExFreePool(FullFileName.Buffer); + Open->DumpFileHandle=NULL; + ntStatus = STATUS_NO_SUCH_FILE; + return ntStatus; + } + + ExFreePool(FullFileName.Buffer); + + ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle, + FILE_WRITE_ACCESS, + *IoFileObjectType, + KernelMode, + &Open->DumpFileObject, + 0); + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);) + + ZwClose( Open->DumpFileHandle ); + Open->DumpFileHandle=NULL; + + ntStatus = STATUS_NO_SUCH_FILE; + return ntStatus; + } + + fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject); + + IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);) + + return ntStatus; +} + +//------------------------------------------------------------------- + +NTSTATUS +NPF_StartDump(POPEN_INSTANCE Open) +{ + NTSTATUS ntStatus; + struct packet_file_header hdr; + IO_STATUS_BLOCK IoStatus; + NDIS_REQUEST pRequest; + ULONG MediaType; + OBJECT_ATTRIBUTES ObjectAttributes; + + IF_LOUD(DbgPrint("NPF: StartDump.\n");) + + // Init the file header + hdr.magic = TCPDUMP_MAGIC; + hdr.version_major = PCAP_VERSION_MAJOR; + hdr.version_minor = PCAP_VERSION_MINOR; + hdr.thiszone = 0; /*Currently not set*/ + hdr.snaplen = 1514; + hdr.sigfigs = 0; + + // Detect the medium type + switch (Open->Medium){ + + case NdisMediumWan: + hdr.linktype = DLT_EN10MB; + break; + + case NdisMedium802_3: + hdr.linktype = DLT_EN10MB; + break; + + case NdisMediumFddi: + hdr.linktype = DLT_FDDI; + break; + + case NdisMedium802_5: + hdr.linktype = DLT_IEEE802; + break; + + case NdisMediumArcnet878_2: + hdr.linktype = DLT_ARCNET; + break; + + case NdisMediumAtm: + hdr.linktype = DLT_ATM_RFC1483; + break; + + default: + hdr.linktype = DLT_EN10MB; + } + + // Write the header. + // We can use ZwWriteFile because we are in the context of the application + ntStatus = ZwWriteFile(Open->DumpFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + &hdr, + sizeof(hdr), + NULL, + NULL ); + + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);) + + ZwClose( Open->DumpFileHandle ); + Open->DumpFileHandle=NULL; + + ntStatus = STATUS_NO_SUCH_FILE; + return ntStatus; + } + + Open->DumpOffset.QuadPart=24; + + ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle, + THREAD_ALL_ACCESS, + (ACCESS_MASK)0L, + 0, + 0, + NPF_DumpThread, + Open); + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);) + + ZwClose( Open->DumpFileHandle ); + Open->DumpFileHandle=NULL; + + return ntStatus; + } + + ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle, + THREAD_ALL_ACCESS, + *PsThreadType, + KernelMode, + &Open->DumpThreadObject, + 0); + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);) + + ObDereferenceObject(Open->DumpFileObject); + ZwClose( Open->DumpFileHandle ); + Open->DumpFileHandle=NULL; + + return ntStatus; + } + + + return ntStatus; + +} + +//------------------------------------------------------------------- +// Dump Thread +//------------------------------------------------------------------- + +VOID NPF_DumpThread(POPEN_INSTANCE Open) +{ + ULONG FrozenNic; + + IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%p\n",Open);) + + while(TRUE){ + + // Wait until some packets arrive or the timeout expires + NdisWaitEvent(&Open->DumpEvent, 5000); + + IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");) + + if(Open->DumpLimitReached || + Open->Size==0){ // BufSize=0 means that this instance was closed, or that the buffer is too + // small for any capture. In both cases it is better to end the dump + + IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");) + IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open->DumpOffset.QuadPart);) + + PsTerminateSystemThread(STATUS_SUCCESS); + return; + } + + NdisResetEvent(&Open->DumpEvent); + + // Write the content of the buffer to the file + if(NPF_SaveCurrentBuffer(Open) != STATUS_SUCCESS){ + PsTerminateSystemThread(STATUS_SUCCESS); + return; + } + + } + +} + +//------------------------------------------------------------------- + +NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open) +{ + UINT Thead; + UINT Ttail; + UINT TLastByte; + PUCHAR CurrBuff; + NTSTATUS ntStatus; + IO_STATUS_BLOCK IoStatus; + PMDL lMdl; + UINT SizeToDump; + +#if 0 + + Thead=Open->Bhead; + Ttail=Open->Btail; + TLastByte=Open->BLastByte; + + IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");) + + // Get the address of the buffer + CurrBuff=Open->Buffer; + // + // Fill the application buffer + // + if( Ttail < Thead ) + { + if(Open->MaxDumpBytes && + (UINT)Open->DumpOffset.QuadPart /*+ GetBuffOccupation(Open)*/ > Open->MaxDumpBytes) + { + // Size limit reached + UINT PktLen; + + SizeToDump = 0; + + // Scan the buffer to detect the exact amount of data to save + while(TRUE){ + PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr); + + if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes) + break; + + SizeToDump += PktLen; + } + + } + else + SizeToDump = TLastByte-Thead; + + lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL); + if (lMdl == NULL) + { + // No memory: stop dump + IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");) + return STATUS_UNSUCCESSFUL; + } + + MmBuildMdlForNonPagedPool(lMdl); + + // Write to disk + NPF_WriteDumpFile(Open->DumpFileObject, + &Open->DumpOffset, + SizeToDump, + lMdl, + &IoStatus); + + IoFreeMdl(lMdl); + + if(!NT_SUCCESS(IoStatus.Status)){ + // Error + return STATUS_UNSUCCESSFUL; + } + + if(SizeToDump != TLastByte-Thead){ + // Size limit reached. + Open->DumpLimitReached = TRUE; + + // Awake the application + KeSetEvent(Open->ReadEvent,0,FALSE); + + return STATUS_UNSUCCESSFUL; + } + + // Update the packet buffer + Open->DumpOffset.QuadPart+=(TLastByte-Thead); + Open->BLastByte=Ttail; + Open->Bhead=0; + } + + if( Ttail > Thead ){ + + if(Open->MaxDumpBytes && + (UINT)Open->DumpOffset.QuadPart /* +GetBuffOccupation(Open)*/ > Open->MaxDumpBytes) + { + // Size limit reached + UINT PktLen; + + SizeToDump = 0; + + // Scan the buffer to detect the exact amount of data to save + while(Thead + SizeToDump < Ttail){ + + PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr); + + if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes) + break; + + SizeToDump += PktLen; + } + + } + else + SizeToDump = Ttail-Thead; + + lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL); + if (lMdl == NULL) + { + // No memory: stop dump + IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");) + return STATUS_UNSUCCESSFUL; + } + + MmBuildMdlForNonPagedPool(lMdl); + + // Write to disk + NPF_WriteDumpFile(Open->DumpFileObject, + &Open->DumpOffset, + SizeToDump, + lMdl, + &IoStatus); + + IoFreeMdl(lMdl); + + if(!NT_SUCCESS(IoStatus.Status)){ + // Error + return STATUS_UNSUCCESSFUL; + } + + if(SizeToDump != Ttail-Thead){ + // Size limit reached. + Open->DumpLimitReached = TRUE; + + // Awake the application + KeSetEvent(Open->ReadEvent,0,FALSE); + + return STATUS_UNSUCCESSFUL; + } + + // Update the packet buffer + Open->DumpOffset.QuadPart+=(Ttail-Thead); + Open->Bhead=Ttail; + + } +#endif + return STATUS_SUCCESS; +} + +//------------------------------------------------------------------- + +NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){ + NTSTATUS ntStatus; + IO_STATUS_BLOCK IoStatus; + PMDL WriteMdl; + PUCHAR VMBuff; + UINT VMBufLen; + +#if 0 + IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");) + IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);) + +DbgPrint("1\n"); + // Consistency check + if(Open->DumpFileHandle == NULL) + return STATUS_UNSUCCESSFUL; + +DbgPrint("2\n"); + ZwClose( Open->DumpFileHandle ); + + ObDereferenceObject(Open->DumpFileObject); +/* + if(Open->DumpLimitReached == TRUE) + // Limit already reached: don't save the rest of the buffer. + return STATUS_SUCCESS; +*/ +DbgPrint("3\n"); + + NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE); + + // Flush the buffer to file + NPF_SaveCurrentBuffer(Open); + + // Close The file + ObDereferenceObject(Open->DumpFileObject); + ZwClose( Open->DumpFileHandle ); + + Open->DumpFileHandle = NULL; + + ObDereferenceObject(Open->DumpFileObject); +#endif + return STATUS_SUCCESS; +} + +//------------------------------------------------------------------- + +static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Context) +{ + + // + // From Sebastian Gottschalk, + // Wednesday, May 07, 2008 4:55 PM + // + // The issue is within dump.c!PacketDumpCompletion. As an I/O completion + // routine it is bound to the contract that every pending IRP passed to this + // routine has to be marked as pending in case that is wasn't yet. Since the + // device returning this IRP is a filesystem device (PacketDumpCompletion is + // setup by WriteDumpFile), such cases might happen and would then hang the + // filesystem, soon hanging up then entire system. + // + // Solution: (TO BE TESTED) + // + if (Irp->PendingReturned) + IoMarkIrpPending(Irp); + + // Copy the status information back into the "user" IOSB + *Irp->UserIosb = Irp->IoStatus; + + // Wake up the mainline code + KeSetEvent(Irp->UserEvent, 0, FALSE); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +//------------------------------------------------------------------- + +VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject, + PLARGE_INTEGER Offset, + ULONG Length, + PMDL Mdl, + PIO_STATUS_BLOCK IoStatusBlock) +{ + PIRP irp; + KEVENT event; + PIO_STACK_LOCATION ioStackLocation; + PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject); + NTSTATUS Status; + + // Set up the event we'll use + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + + // Allocate and build the IRP we'll be sending to the FSD + irp = IoAllocateIrp(fsdDevice->StackSize, FALSE); + + if (!irp) { + // Allocation failed, presumably due to memory allocation failure + IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES; + IoStatusBlock->Information = 0; + + return; + } + + irp->MdlAddress = Mdl; + irp->UserEvent = &event; + irp->UserIosb = IoStatusBlock; + irp->Tail.Overlay.Thread = PsGetCurrentThread(); + irp->Tail.Overlay.OriginalFileObject= FileObject; + irp->RequestorMode = KernelMode; + + // Indicate that this is a WRITE operation + irp->Flags = IRP_WRITE_OPERATION; + + // Set up the next I/O stack location + ioStackLocation = IoGetNextIrpStackLocation(irp); + ioStackLocation->MajorFunction = IRP_MJ_WRITE; + ioStackLocation->MinorFunction = 0; + ioStackLocation->DeviceObject = fsdDevice; + ioStackLocation->FileObject = FileObject; + IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE); + ioStackLocation->Parameters.Write.Length = Length; + ioStackLocation->Parameters.Write.ByteOffset = *Offset; + + + // Send it on. Ignore the return code + (void) IoCallDriver(fsdDevice, irp); + + // Wait for the I/O to complete. + KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0); + + // Free the IRP now that we are done with it + IoFreeIrp(irp); + + return; + +} diff --git a/drivers/3rdparty/npf/functions.c b/drivers/3rdparty/npf/functions.c new file mode 100644 index 0000000000000..b4d5d0f46adf2 --- /dev/null +++ b/drivers/3rdparty/npf/functions.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1999 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef WIN32 +#include "tme.h" +#include "functions.h" +#endif + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#include +#include +#else +#include +#include +#include +#endif + +#endif + + + +lut_fcn lut_fcn_mapper(uint32 index) +{ + + switch (index) + { + case NORMAL_LUT_W_INSERT: + return (lut_fcn) normal_lut_w_insert; + + case NORMAL_LUT_WO_INSERT: + return (lut_fcn) normal_lut_wo_insert; + + case BUCKET_LOOKUP: + return (lut_fcn) bucket_lookup; + + case BUCKET_LOOKUP_INSERT: + return (lut_fcn) bucket_lookup_insert; + + default: + return NULL; + } + +} + +exec_fcn exec_fcn_mapper(uint32 index) +{ + switch (index) + { + case COUNT_PACKETS: + return (exec_fcn) count_packets; + + case TCP_SESSION: + return (exec_fcn) tcp_session; + default: + return NULL; + } +} diff --git a/drivers/3rdparty/npf/functions.h b/drivers/3rdparty/npf/functions.h new file mode 100644 index 0000000000000..3808a03bed4d2 --- /dev/null +++ b/drivers/3rdparty/npf/functions.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1999 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __FUNCTIONS +#define __FUNCTIONS + +#ifdef WIN32 +#include "tme.h" +#endif + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#else +#include +#endif + +#endif +/*function mappers */ + +lut_fcn lut_fcn_mapper(uint32 index); +exec_fcn exec_fcn_mapper(uint32 index); + +/* lookup functions */ + +#ifdef WIN32 +#include "bucket_lookup.h" +#include "normal_lookup.h" +#endif + +#ifdef __FreeBSD__ +#include +#include +#endif + +/* execution functions */ + +#ifdef WIN32 +#include "count_packets.h" +#include "tcp_session.h" +#endif + +#ifdef __FreeBSD__ +#include +#include +#endif + +#endif \ No newline at end of file diff --git a/drivers/3rdparty/npf/ioctls.h b/drivers/3rdparty/npf/ioctls.h new file mode 100644 index 0000000000000..88ccf270d0732 --- /dev/null +++ b/drivers/3rdparty/npf/ioctls.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2007 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CACE Technologies nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __NPF_IOCTLS_H__ +#define __NPF_IOCTLS_H__ + +/***************************/ +/* IOCTLs */ +/***************************/ + +/** @addtogroup NPF + * @{ + */ + +/** @defgroup NPF_ioctl NPF I/O control codes + * @{ + */ + +/*! + \brief IOCTL code: set kernel buffer size. + + This IOCTL is used to set a new size of the circular buffer associated with an instance of NPF. + When a BIOCSETBUFFERSIZE command is received, the driver frees the old buffer, allocates the new one + and resets all the parameters associated with the buffer in the OPEN_INSTANCE structure. The currently + buffered packets are lost. +*/ +#define BIOCSETBUFFERSIZE 9592 + +/*! + \brief IOCTL code: set packet filtering program. + + This IOCTL sets a new packet filter in the driver. Before allocating any memory for the new filter, the + bpf_validate() function is called to check the correctness of the filter. If this function returns TRUE, + the filter is copied to the driver's memory, its address is stored in the bpfprogram field of the + OPEN_INSTANCE structure associated with current instance of the driver, and the filter will be applied to + every incoming packet. This command also empties the circular buffer used by current instance + to store packets. This is done to avoid the presence in the buffer of packets that do not match the filter. +*/ +#define BIOCSETF 9030 + +/*! + \brief IOCTL code: get the capture stats + + This command returns to the application the number of packets received and the number of packets dropped by + an instance of the driver. +*/ +#define BIOCGSTATS 9031 + +/*! + \brief IOCTL code: set the read timeout + + This command sets the maximum timeout after which a read is released, also if no data packets were received. +*/ +#define BIOCSRTIMEOUT 7416 + +/*! + \brief IOCTL code: set working mode + + This IOCTL can be used to set the working mode of a NPF instance. The new mode, received by the driver in the + buffer associated with the IOCTL command, can be #MODE_CAPT for capture mode (the default), #MODE_STAT for + statistical mode or #MODE_DUMP for dump mode. +*/ +#define BIOCSMODE 7412 + +/*! + \brief IOCTL code: set number of physical repetions of every packet written by the app + + Sets the number of times a single write call must be repeated. This command sets the OPEN_INSTANCE::Nwrites + member, and is used to implement the 'multiple write' feature of the driver. +*/ +#define BIOCSWRITEREP 7413 + +/*! + \brief IOCTL code: set minimum amount of data in the kernel buffer that unlocks a read call + + This command sets the OPEN_INSTANCE::MinToCopy member. +*/ +#define BIOCSMINTOCOPY 7414 + +/*! + \brief IOCTL code: set an OID value + + This IOCTL is used to perform an OID set operation on the NIC driver. +*/ +#define BIOCSETOID 0x80000000 + +/*! + \brief IOCTL code: get an OID value + + This IOCTL is used to perform an OID get operation on the NIC driver. +*/ +#define BIOCQUERYOID 0x80000004 + +/*! + \brief IOCTL code: set the name of a the file used by kernel dump mode + + This command opens a file whose name is contained in the IOCTL buffer and associates it with current NPf instance. + The dump thread uses it to copy the content of the circular buffer to file. + If a file was already opened, the driver closes it before opening the new one. +*/ +#define BIOCSETDUMPFILENAME 9029 + +/*! + \brief IOCTL code: get the name of the event that the driver signals when some data is present in the buffer + + Command used by the application to retrieve the name of the global event associated with a NPF instance. + The event is signaled by the driver when the kernel buffer contains enough data for a transfer. +*/ +#define BIOCGEVNAME 7415 + +/*! + \brief IOCTL code: Send a buffer containing multiple packets to the network, ignoring the timestamps. + + Command used to send a buffer of packets in a single system call. Every packet in the buffer is preceded by + a sf_pkthdr structure. The timestamps of the packets are ignored, i.e. the packets are sent as fast as + possible. The NPF_BufferedWrite() function is invoked to send the packets. +*/ +#define BIOCSENDPACKETSNOSYNC 9032 + +/*! + \brief IOCTL code: Send a buffer containing multiple packets to the network, considering the timestamps. + + Command used to send a buffer of packets in a single system call. Every packet in the buffer is preceded by + a sf_pkthdr structure. The timestamps of the packets are used to synchronize the write, i.e. the packets + are sent to the network respecting the intervals specified in the sf_pkthdr structure assiciated with each + packet. NPF_BufferedWrite() function is invoked to send the packets. +*/ +#define BIOCSENDPACKETSSYNC 9033 + +/*! + \brief IOCTL code: Set the dump file limits. + + This IOCTL sets the limits (maximum size and maximum number of packets) of the dump file created when the + driver works in dump mode. +*/ +#define BIOCSETDUMPLIMITS 9034 + +/*! + \brief IOCTL code: Get the status of the kernel dump process. + + This command returns TRUE if the kernel dump is ended, i.e if one of the limits set with BIOCSETDUMPLIMITS + (amount of bytes or number of packets) has been reached. +*/ +#define BIOCISDUMPENDED 7411 + +/*! + \brief IOCTL code: set the loopback behavior. + + This IOCTL sets the loopback behavior of the driver with packets sent by itself: capture or drop. +*/ +#define BIOCISETLOBBEH 7410 + +/*! + \brief This IOCTL passes the read event HANDLE allocated by the user (packet.dll) to kernel level + + Parameter: HANDLE + Parameter size: sizeof(HANDLE). If the caller is 32 bit, the parameter size is 4 bytes, even if sizeof(HANDLE) at kernel level + is 8 bytes. That's why in this IOCTL code handler we detect a 32bit calling process and do the necessary thunking. + + TODO GV:I will go to hell for this ugly IOCTL definition. We should use CTL_CODE!! +*/ +#define BIOCSETEVENTHANDLE 7920 + +/** + * @} + */ + +/** + * @} + */ + + + + +#endif //__NPF_IOCTLS_H__ diff --git a/drivers/3rdparty/npf/jitter.c b/drivers/3rdparty/npf/jitter.c new file mode 100644 index 0000000000000..b8e1fafeb4e35 --- /dev/null +++ b/drivers/3rdparty/npf/jitter.c @@ -0,0 +1,692 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "stdarg.h" +#include "ntddk.h" +#include "ntiologc.h" +#include "ndis.h" + +#include "packet.h" +#include "win_bpf.h" + +// +// emit routine to update the jump table +// +void emit_lenght(binary_stream *stream, ULONG value, UINT len) +{ + (stream->refs)[stream->bpf_pc]+=len; + stream->cur_ip+=len; +} + +// +// emit routine to output the actual binary code +// +void emit_code(binary_stream *stream, ULONG value, UINT len) +{ + + switch (len){ + + case 1: + stream->ibuf[stream->cur_ip]=(UCHAR)value; + stream->cur_ip++; + break; + + case 2: + *((USHORT*)(stream->ibuf+stream->cur_ip))=(USHORT)value; + stream->cur_ip+=2; + break; + + case 4: + *((ULONG*)(stream->ibuf+stream->cur_ip))=value; + stream->cur_ip+=4; + break; + + default:; + + } + + return; + +} + +// +// Function that does the real stuff +// +BPF_filter_function BPFtoX86(struct bpf_insn *prog, UINT nins, INT *mem) +{ + struct bpf_insn *ins; + UINT i, pass; + binary_stream stream; + + //NOTE: do not modify the name of this variable, as it's used by the macros to emit code. + emit_func emitm; + + + // Allocate the reference table for the jumps +#ifdef NTKERNEL + stream.refs=(UINT *)ExAllocatePoolWithTag(NonPagedPool, (nins + 1)*sizeof(UINT), '0JWA'); +#else + stream.refs=(UINT *)malloc((nins + 1)*sizeof(UINT)); +#endif + if(stream.refs==NULL) + { + return NULL; + } + + // Reset the reference table + for(i=0; i< nins + 1; i++) + stream.refs[i]=0; + + stream.cur_ip=0; + stream.bpf_pc=0; + + // the first pass will emit the lengths of the instructions + // to create the reference table + emitm=emit_lenght; + + for(pass=0;;){ + + ins = prog; + + /* create the procedure header */ + PUSH(EBP) + MOVrd(EBP,ESP) + PUSH(EBX) + PUSH(ECX) + PUSH(EDX) + PUSH(ESI) + PUSH(EDI) + MOVodd(EBX, EBP, 8) + + for(i=0;icode) { + + default: + + return NULL; + + case BPF_RET|BPF_K: + + MOVid(EAX,ins->k) + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + RET() + + break; + + + case BPF_RET|BPF_A: + + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + RET() + + break; + + + case BPF_LD|BPF_W|BPF_ABS: + + MOVid(ECX,ins->k) + CMPodd(ECX, EBP, 0x10) + JAb(10) + MOVrd(ESI,ECX) + ADDib(ECX,sizeof(INT)) + CMPodd(ECX, EBP, 0x10) + JBEb(12) + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + MOVid(EAX,0) //this can be optimized with xor eax,eax + RET() + MOVobd(EAX, EBX, ESI) + BSWAP(EAX) + + break; + + case BPF_LD|BPF_H|BPF_ABS: + + MOVid(ECX,ins->k) + CMPodd(ECX, EBP, 0x10) + JAb(10) + MOVrd(ESI,ECX) + ADDib(ECX,sizeof(SHORT)) + CMPodd(ECX, EBP, 0x10) + JBEb(12) + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + MOVid(EAX,0) + RET() + MOVid(EAX,0) + MOVobw(AX, EBX, ESI) + SWAP_AX() + + break; + + case BPF_LD|BPF_B|BPF_ABS: + + MOVid(ECX,ins->k) + CMPodd(ECX, EBP, 0x10) + JBb(12) + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + MOVid(EAX,0) + RET() + MOVid(EAX,0) + MOVobb(AL,EBX,ECX) + + break; + + case BPF_LD|BPF_W|BPF_LEN: + + MOVodd(EAX, EBP, 0xc) + + break; + + case BPF_LDX|BPF_W|BPF_LEN: + + MOVodd(EDX, EBP, 0xc) + + break; + + case BPF_LD|BPF_W|BPF_IND: + + MOVid(ECX,ins->k) + ADDrd(ECX,EDX) + CMPodd(ECX, EBP, 0x10) + JAb(10) + MOVrd(ESI,ECX) + ADDib(ECX,sizeof(INT)) + CMPodd(ECX, EBP, 0x10) + JBEb(12) + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + MOVid(EAX,0) + RET() + MOVobd(EAX, EBX, ESI) + BSWAP(EAX) + + break; + + case BPF_LD|BPF_H|BPF_IND: + + MOVid(ECX,ins->k) + ADDrd(ECX,EDX) + CMPodd(ECX, EBP, 0x10) + JAb(10) + MOVrd(ESI,ECX) + ADDib(ECX,sizeof(SHORT)) + CMPodd(ECX, EBP, 0x10) + JBEb(12) + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + MOVid(EAX,0) + RET() + MOVid(EAX,0) + MOVobw(AX, EBX, ESI) + SWAP_AX() + + break; + + case BPF_LD|BPF_B|BPF_IND: + + MOVid(ECX,ins->k) + ADDrd(ECX,EDX) + CMPodd(ECX, EBP, 0x10) + JBb(12) + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + MOVid(EAX,0) + RET() + MOVid(EAX,0) + MOVobb(AL,EBX,ECX) + + break; + + case BPF_LDX|BPF_MSH|BPF_B: + + MOVid(ECX,ins->k) + CMPodd(ECX, EBP, 0x10) + JBb(12) + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + MOVid(EAX,0) + RET() + MOVid(EDX,0) + MOVobb(DL,EBX,ECX) + ANDib(DL, 0xf) + SHLib(EDX, 2) + + break; + + case BPF_LD|BPF_IMM: + + MOVid(EAX,ins->k) + + break; + + case BPF_LDX|BPF_IMM: + + MOVid(EDX,ins->k) + + break; + + case BPF_LD|BPF_MEM: + + MOVid(ECX,(INT)mem) + MOVid(ESI,ins->k*4) + MOVobd(EAX, ECX, ESI) + + break; + + case BPF_LDX|BPF_MEM: + + MOVid(ECX,(INT)mem) + MOVid(ESI,ins->k*4) + MOVobd(EDX, ECX, ESI) + + break; + + case BPF_ST: + + // XXX: this command and the following could be optimized if the previous + // instruction was already of this type + MOVid(ECX,(INT)mem) + MOVid(ESI,ins->k*4) + MOVomd(ECX, ESI, EAX) + + break; + + case BPF_STX: + + MOVid(ECX,(INT)mem) + MOVid(ESI,ins->k*4) + MOVomd(ECX, ESI, EDX) + break; + + case BPF_JMP|BPF_JA: + + JMP(stream.refs[stream.bpf_pc+ins->k]-stream.refs[stream.bpf_pc]) + + break; + + case BPF_JMP|BPF_JGT|BPF_K: + + CMPid(EAX, ins->k) + JG(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5) // 5 is the size of the following JMP + JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]) + break; + + case BPF_JMP|BPF_JGE|BPF_K: + + CMPid(EAX, ins->k) + JGE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5) + JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]) + + break; + + case BPF_JMP|BPF_JEQ|BPF_K: + + CMPid(EAX, ins->k) + JE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5) + JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]) + + break; + + case BPF_JMP|BPF_JSET|BPF_K: + + MOVrd(ECX,EAX) + ANDid(ECX,ins->k) + JE(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]+5) + JMP(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]) + + break; + + case BPF_JMP|BPF_JGT|BPF_X: + + CMPrd(EAX, EDX) + JA(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5) + JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]) + break; + + case BPF_JMP|BPF_JGE|BPF_X: + + CMPrd(EAX, EDX) + JAE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5) + JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]) + + break; + + case BPF_JMP|BPF_JEQ|BPF_X: + + CMPrd(EAX, EDX) + JE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5) + JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]) + + break; + + case BPF_JMP|BPF_JSET|BPF_X: + + MOVrd(ECX,EAX) + ANDrd(ECX,EDX) + JE(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]+5) + JMP(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]) + + break; + + case BPF_ALU|BPF_ADD|BPF_X: + + ADDrd(EAX,EDX) + + break; + + case BPF_ALU|BPF_SUB|BPF_X: + + SUBrd(EAX,EDX) + + break; + + case BPF_ALU|BPF_MUL|BPF_X: + + MOVrd(ECX,EDX) + MULrd(EDX) + MOVrd(EDX,ECX) + break; + + case BPF_ALU|BPF_DIV|BPF_X: + + CMPid(EDX, 0) + JNEb(12) + POP(EDI) + POP(ESI) + POP(EDX) + POP(ECX) + POP(EBX) + POP(EBP) + MOVid(EAX,0) + RET() + MOVrd(ECX,EDX) + MOVid(EDX,0) + DIVrd(ECX) + MOVrd(EDX,ECX) + + break; + + case BPF_ALU|BPF_AND|BPF_X: + + ANDrd(EAX,EDX) + + break; + + case BPF_ALU|BPF_OR|BPF_X: + + ORrd(EAX,EDX) + + break; + + case BPF_ALU|BPF_LSH|BPF_X: + + MOVrd(ECX,EDX) + SHL_CLrb(EAX) + + break; + + case BPF_ALU|BPF_RSH|BPF_X: + + MOVrd(ECX,EDX) + SHR_CLrb(EAX) + + break; + + case BPF_ALU|BPF_ADD|BPF_K: + + ADD_EAXi(ins->k) + + break; + + case BPF_ALU|BPF_SUB|BPF_K: + + SUB_EAXi(ins->k) + + break; + + case BPF_ALU|BPF_MUL|BPF_K: + + MOVrd(ECX,EDX) + MOVid(EDX,ins->k) + MULrd(EDX) + MOVrd(EDX,ECX) + + break; + + case BPF_ALU|BPF_DIV|BPF_K: + + MOVrd(ECX,EDX) + MOVid(EDX,0) + MOVid(ESI,ins->k) + DIVrd(ESI) + MOVrd(EDX,ECX) + + break; + + case BPF_ALU|BPF_AND|BPF_K: + + ANDid(EAX, ins->k) + + break; + + case BPF_ALU|BPF_OR|BPF_K: + + ORid(EAX, ins->k) + + break; + + case BPF_ALU|BPF_LSH|BPF_K: + + SHLib(EAX, (ins->k) & 255) + + break; + + case BPF_ALU|BPF_RSH|BPF_K: + + SHRib(EAX, (ins->k) & 255) + + break; + + case BPF_ALU|BPF_NEG: + + NEGd(EAX) + + break; + + case BPF_MISC|BPF_TAX: + + MOVrd(EDX,EAX) + + break; + + case BPF_MISC|BPF_TXA: + + MOVrd(EAX,EDX) + + break; + + + + } + + ins++; + } + + pass++; + if(pass == 2) break; + +#ifdef NTKERNEL + stream.ibuf=(CHAR*)ExAllocatePoolWithTag(NonPagedPool, stream.cur_ip, '1JWA'); +#else + stream.ibuf=(CHAR*)malloc(stream.cur_ip); +#endif + if(stream.ibuf==NULL) + { +#ifdef NTKERNEL + ExFreePool(stream.refs); +#else + free(stream.refs); +#endif + return NULL; + } + + // modify the reference table to contain the offsets and not the lengths of the instructions + for(i=1; i< nins + 1; i++) + stream.refs[i]+=stream.refs[i-1]; + + // Reset the counters + stream.cur_ip=0; + stream.bpf_pc=0; + // the second pass creates the actual code + emitm=emit_code; + + } + + // the reference table is needed only during compilation, now we can free it +#ifdef NTKERNEL + ExFreePool(stream.refs); +#else + free(stream.refs); +#endif + return (BPF_filter_function)stream.ibuf; + +} + + +JIT_BPF_Filter* BPF_jitter(struct bpf_insn *fp, INT nins) +{ + JIT_BPF_Filter *Filter; + + + // Allocate the filter structure +#ifdef NTKERNEL + Filter=(struct JIT_BPF_Filter*)ExAllocatePoolWithTag(NonPagedPool, sizeof(struct JIT_BPF_Filter), '2JWA'); +#else + Filter=(struct JIT_BPF_Filter*)malloc(sizeof(struct JIT_BPF_Filter)); +#endif + if(Filter==NULL) + { + return NULL; + } + + // Allocate the filter's memory +#ifdef NTKERNEL + Filter->mem=(INT*)ExAllocatePoolWithTag(NonPagedPool, BPF_MEMWORDS*sizeof(INT), '3JWA'); +#else + Filter->mem=(INT*)malloc(BPF_MEMWORDS*sizeof(INT)); +#endif + if(Filter->mem==NULL) + { +#ifdef NTKERNEL + ExFreePool(Filter); +#else + free(Filter); +#endif + return NULL; + } + + // Create the binary + if((Filter->Function = BPFtoX86(fp, nins, Filter->mem))==NULL) + { +#ifdef NTKERNEL + ExFreePool(Filter->mem); + ExFreePool(Filter); +#else + free(Filter->mem); + free(Filter); +#endif + return NULL; + } + + return Filter; + +} + +////////////////////////////////////////////////////////////// + +void BPF_Destroy_JIT_Filter(JIT_BPF_Filter *Filter){ + +#ifdef NTKERNEL + ExFreePool(Filter->mem); + ExFreePool(Filter->Function); + ExFreePool(Filter); +#else + free(Filter->mem); + free(Filter->Function); + free(Filter); +#endif + +} diff --git a/drivers/3rdparty/npf/jitter.h b/drivers/3rdparty/npf/jitter.h new file mode 100644 index 0000000000000..42fe38a3bd5d7 --- /dev/null +++ b/drivers/3rdparty/npf/jitter.h @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/** @addtogroup NPF + * @{ + */ + +/** @defgroup NPF_jitter NPF Just-in-time compiler definitions + * @{ + */ + +// +// Registers +// +#define EAX 0 +#define ECX 1 +#define EDX 2 +#define EBX 3 +#define ESP 4 +#define EBP 5 +#define ESI 6 +#define EDI 7 + +#define AX 0 +#define CX 1 +#define DX 2 +#define BX 3 +#define SP 4 +#define BP 5 +#define SI 6 +#define DI 7 + +#define AL 0 +#define CL 1 +#define DL 2 +#define BL 3 + +/*! \brief A stream of X86 binary code.*/ +typedef struct binary_stream{ + INT cur_ip; ///< Current X86 instruction pointer. + INT bpf_pc; ///< Current BPF instruction pointer, i.e. position in the BPF program reached by the jitter. + PCHAR ibuf; ///< Instruction buffer, contains the X86 generated code. + PUINT refs; ///< Jumps reference table. +}binary_stream; + + +/*! \brief Prototype of a filtering function created by the jitter. + + The syntax and the meaning of the parameters is analogous to the one of bpf_filter(). Notice that the filter + is not among the parameters, because it is hardwired in the function. +*/ +typedef UINT (__cdecl *BPF_filter_function)( PVOID *, ULONG, UINT); + +/*! \brief Prototype of the emit functions. + + Different emit functions are used to create the reference table and to generate the actual filtering code. + This allows to have simpler instruction macros. + The first parameter is the stream that will receive the data. The secon one is a variable containing + the data, the third one is the length, that can be 1,2 or 4 since it is possible to emit a byte, a short + or a work at a time. +*/ +typedef void (*emit_func)(binary_stream *stream, ULONG value, UINT n); + +/*! \brief Structure describing a x86 filtering program created by the jitter.*/ +typedef struct JIT_BPF_Filter{ + BPF_filter_function Function; ///< The x86 filtering binary, in the form of a BPF_filter_function. + PINT mem; +} +JIT_BPF_Filter; + + + + +/**************************/ +/* X86 INSTRUCTION MACROS */ +/**************************/ + +/// mov r32,i32 +#define MOVid(r32, i32) \ + emitm(&stream, 11 << 4 | 1 << 3 | r32 & 0x7, 1); emitm(&stream, i32, 4); + +/// mov dr32,sr32 +#define MOVrd(dr32, sr32) \ + emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1); + +/// mov dr32,sr32[off] +#define MOVodd(dr32, sr32, off) \ + emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); \ + emitm(&stream, 1 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);\ + emitm(&stream, off, 1); + +/// mov dr32,sr32[or32] +#define MOVobd(dr32, sr32, or32) \ + emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); \ + emitm(&stream, (dr32 & 0x7) << 3 | 4 , 1);\ + emitm(&stream, (or32 & 0x7) << 3 | (sr32 & 0x7) , 1); + +/// mov dr16,sr32[or32] +#define MOVobw(dr32, sr32, or32) \ + emitm(&stream, 0x66, 1); \ + emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); \ + emitm(&stream, (dr32 & 0x7) << 3 | 4 , 1);\ + emitm(&stream, (or32 & 0x7) << 3 | (sr32 & 0x7) , 1); + +/// mov dr8,sr32[or32] +#define MOVobb(dr8, sr32, or32) \ + emitm(&stream, 0x8a, 1); \ + emitm(&stream, (dr8 & 0x7) << 3 | 4 , 1);\ + emitm(&stream, (or32 & 0x7) << 3 | (sr32 & 0x7) , 1); + +/// mov [dr32][or32],sr32 +#define MOVomd(dr32, or32, sr32) \ + emitm(&stream, 0x89, 1); \ + emitm(&stream, (sr32 & 0x7) << 3 | 4 , 1);\ + emitm(&stream, (or32 & 0x7) << 3 | (dr32 & 0x7) , 1); + +/// bswap dr32 +#define BSWAP(dr32) \ + emitm(&stream, 0xf, 1); \ + emitm(&stream, 0x19 << 3 | dr32 , 1); + +/// xchg al,ah +#define SWAP_AX() \ + emitm(&stream, 0x86, 1); \ + emitm(&stream, 0xc4 , 1); + +/// push r32 +#define PUSH(r32) \ + emitm(&stream, 5 << 4 | 0 << 3 | r32 & 0x7, 1); + +/// pop r32 +#define POP(r32) \ + emitm(&stream, 5 << 4 | 1 << 3 | r32 & 0x7, 1); + +/// ret +#define RET() \ + emitm(&stream, 12 << 4 | 0 << 3 | 3, 1); + +/// add dr32,sr32 +#define ADDrd(dr32, sr32) \ + emitm(&stream, 0x03, 1);\ + emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | (sr32 & 0x7), 1); + +/// add eax,i32 +#define ADD_EAXi(i32) \ + emitm(&stream, 0x05, 1);\ + emitm(&stream, i32, 4); + +/// add r32,i32 +#define ADDid(r32, i32) \ + emitm(&stream, 0x81, 1);\ + emitm(&stream, 24 << 3 | r32, 1);\ + emitm(&stream, i32, 4); + +/// add r32,i8 +#define ADDib(r32, i8) \ + emitm(&stream, 0x83, 1);\ + emitm(&stream, 24 << 3 | r32, 1);\ + emitm(&stream, i8, 1); + +/// sub dr32,sr32 +#define SUBrd(dr32, sr32) \ + emitm(&stream, 0x2b, 1);\ + emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | (sr32 & 0x7), 1); + +/// sub eax,i32 +#define SUB_EAXi(i32) \ + emitm(&stream, 0x2d, 1);\ + emitm(&stream, i32, 4); + +/// mul r32 +#define MULrd(r32) \ + emitm(&stream, 0xf7, 1);\ + emitm(&stream, 7 << 5 | (r32 & 0x7), 1); + +/// div r32 +#define DIVrd(r32) \ + emitm(&stream, 0xf7, 1);\ + emitm(&stream, 15 << 4 | (r32 & 0x7), 1); + +/// and r8,i8 +#define ANDib(r8, i8) \ + emitm(&stream, 0x80, 1);\ + emitm(&stream, 7 << 5 | r8, 1);\ + emitm(&stream, i8, 1); + +/// and r32,i32 +#define ANDid(r32, i32) \ + if (r32 == EAX){ \ + emitm(&stream, 0x25, 1);\ + emitm(&stream, i32, 4);}\ + else{ \ + emitm(&stream, 0x81, 1);\ + emitm(&stream, 7 << 5 | r32, 1);\ + emitm(&stream, i32, 4);} + +/// and dr32,sr32 +#define ANDrd(dr32, sr32) \ + emitm(&stream, 0x23, 1);\ + emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1); + +/// or dr32,sr32 +#define ORrd(dr32, sr32) \ + emitm(&stream, 0x0b, 1);\ + emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1); + +/// or r32,i32 +#define ORid(r32, i32) \ + if (r32 == EAX){ \ + emitm(&stream, 0x0d, 1);\ + emitm(&stream, i32, 4);}\ + else{ \ + emitm(&stream, 0x81, 1);\ + emitm(&stream, 25 << 3 | r32, 1);\ + emitm(&stream, i32, 4);} + +/// shl r32,i8 +#define SHLib(r32, i8) \ + emitm(&stream, 0xc1, 1);\ + emitm(&stream, 7 << 5 | r32 & 0x7, 1);\ + emitm(&stream, i8, 1); + +/// shl dr32,cl +#define SHL_CLrb(dr32) \ + emitm(&stream, 0xd3, 1);\ + emitm(&stream, 7 << 5 | dr32 & 0x7, 1); + +/// shr r32,i8 +#define SHRib(r32, i8) \ + emitm(&stream, 0xc1, 1);\ + emitm(&stream, 29 << 3 | r32 & 0x7, 1);\ + emitm(&stream, i8, 1); + +/// shr dr32,cl +#define SHR_CLrb(dr32) \ + emitm(&stream, 0xd3, 1);\ + emitm(&stream, 29 << 3 | dr32 & 0x7, 1); + +/// neg r32 +#define NEGd(r32) \ + emitm(&stream, 0xf7, 1);\ + emitm(&stream, 27 << 3 | r32 & 0x7, 1); + +/// cmp dr32,sr32[off] +#define CMPodd(dr32, sr32, off) \ + emitm(&stream, 3 << 4 | 3 | 1 << 3, 1); \ + emitm(&stream, 1 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);\ + emitm(&stream, off, 1); + +/// cmp dr32,sr32 +#define CMPrd(dr32, sr32) \ + emitm(&stream, 0x3b, 1); \ + emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1); + +/// cmp dr32,i32 +#define CMPid(dr32, i32) \ + if (dr32 == EAX){ \ + emitm(&stream, 0x3d, 1); \ + emitm(&stream, i32, 4);} \ + else{ \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, 0x1f << 3 | (dr32 & 0x7), 1);\ + emitm(&stream, i32, 4);} + +/// jne off32 +#define JNEb(off8) \ + emitm(&stream, 0x75, 1);\ + emitm(&stream, off8, 1); + +/// ja off32 +#define JAb(off8) \ + emitm(&stream, 0x77, 1);\ + emitm(&stream, off8, 1); + +/// je off32 +#define JE(off32) \ + emitm(&stream, 0x0f, 1);\ + emitm(&stream, 0x84, 1);\ + emitm(&stream, off32, 4); + +/// jle off32 +#define JLE(off32) \ + emitm(&stream, 0x0f, 1);\ + emitm(&stream, 0x8e, 1);\ + emitm(&stream, off32, 4); + +/// jle off8 +#define JLEb(off8) \ + emitm(&stream, 0x7e, 1);\ + emitm(&stream, off8, 1); + +/// jbe off8 +#define JBEb(off8) \ + emitm(&stream, 0x76, 1);\ + emitm(&stream, off8, 1); + +/// jb off8 +#define JBb(off8) \ + emitm(&stream, 0x72, 1);\ + emitm(&stream, off8, 1); + +/// ja off32 +#define JA(off32) \ + emitm(&stream, 0x0f, 1);\ + emitm(&stream, 0x87, 1);\ + emitm(&stream, off32, 4); + +/// jae off32 +#define JAE(off32) \ + emitm(&stream, 0x0f, 1);\ + emitm(&stream, 0x83, 1);\ + emitm(&stream, off32, 4); + +/// jg off32 +#define JG(off32) \ + emitm(&stream, 0x0f, 1);\ + emitm(&stream, 0x8f, 1);\ + emitm(&stream, off32, 4); + +/// jge off32 +#define JGE(off32) \ + emitm(&stream, 0x0f, 1);\ + emitm(&stream, 0x8d, 1);\ + emitm(&stream, off32, 4); + +/// jmp off32 +#define JMP(off32) \ + emitm(&stream, 0xe9, 1);\ + emitm(&stream, off32, 4); + +/** + * @} + */ + +/**************************/ +/* Prototypes */ +/**************************/ + +/** @addtogroup NPF_code + * @{ + */ + +/*! + \brief BPF jitter, builds an x86 function from a BPF program. + \param fp The BPF pseudo-assembly filter that will be translated into x86 code. + \param nins Number of instructions of the input filter. + \return The JIT_BPF_Filter structure containing the x86 filtering binary. + + BPF_jitter allocates the buffers for the new native filter and then translates the program pointed by fp + calling BPFtoX86(). +*/ +JIT_BPF_Filter* BPF_jitter(struct bpf_insn *fp, INT nins); + +/*! + \brief Translates a set of BPF instructions in a set of x86 ones. + \param ins Pointer to the BPF instructions that will be translated into x86 code. + \param nins Number of instructions to translate. + \param mem Memory used by the x86 function to emulate the RAM of the BPF pseudo processor. + \return The x86 filtering function. + + This function does the hard work for the JIT compilation. It takes a group of BPF pseudo instructions and + through the instruction macros defined in jitter.h it is able to create an function directly executable + by NPF. +*/ +BPF_filter_function BPFtoX86(struct bpf_insn *ins, UINT nins, INT *mem); +/*! + \brief Deletes a filtering function that was previously created by BPF_jitter(). + \param Filter The filter to destroy. + + This function frees the variuos buffers (code, memory, etc.) associated with a filtering function. +*/ +void BPF_Destroy_JIT_Filter(JIT_BPF_Filter *Filter); + +/** + * @} + */ + +/** + * @} + */ diff --git a/drivers/3rdparty/npf/memory_t.h b/drivers/3rdparty/npf/memory_t.h new file mode 100644 index 0000000000000..b4200168a41c1 --- /dev/null +++ b/drivers/3rdparty/npf/memory_t.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2001 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __memory_t +#define __memory_t + +#define uint8 UCHAR +#define int8 CHAR +#define uint16 USHORT +#define int16 SHORT +#define uint32 ULONG +#define int32 LONG +#define uint64 ULONGLONG +#define int64 LONGLONG + +/*memory type*/ +typedef struct __MEM_TYPE +{ + uint8 *buffer; + uint32 size; +} MEM_TYPE, *PMEM_TYPE; + +#define LONG_AT(base,offset) (*(int32*)((uint8*)base+(uint32)offset)) + +#define ULONG_AT(base,offset) (*(uint32*)((uint8*)base+(uint32)offset)) + +#define SHORT_AT(base,offset) (*(int16*)((uint8*)base+(uint32)offset)) + +#define USHORT_AT(base,offset) (*(uint16*)((uint8*)base+(uint32)offset)) + +__inline int32 SW_LONG_AT(void *b, uint32 c) +{ + return ((int32)*((uint8 *)b+c)<<24| + (int32)*((uint8 *)b+c+1)<<16| + (int32)*((uint8 *)b+c+2)<<8| + (int32)*((uint8 *)b+c+3)<<0); +} + + +__inline uint32 SW_ULONG_AT(void *b, uint32 c) +{ + return ((uint32)*((uint8 *)b+c)<<24| + (uint32)*((uint8 *)b+c+1)<<16| + (uint32)*((uint8 *)b+c+2)<<8| + (uint32)*((uint8 *)b+c+3)<<0); +} + +__inline int16 SW_SHORT_AT(void *b, uint32 os) +{ + return ((int16) + ((int16)*((uint8 *)b+os+0)<<8| + (int16)*((uint8 *)b+os+1)<<0)); +} + +__inline uint16 SW_USHORT_AT(void *b, uint32 os) +{ + return ((uint16) + ((uint16)*((uint8 *)b+os+0)<<8| + (uint16)*((uint8 *)b+os+1)<<0)); +} + +__inline VOID SW_ULONG_ASSIGN(void *dst, uint32 src) +{ + *((uint8*)dst+0)=*((uint8*)&src+3); + *((uint8*)dst+1)=*((uint8*)&src+2); + *((uint8*)dst+2)=*((uint8*)&src+1); + *((uint8*)dst+3)=*((uint8*)&src+0); + +} + +#ifdef WIN_NT_DRIVER + +#define ALLOCATE_MEMORY(dest,type,amount) \ + (dest)=ExAllocatePoolWithTag(NonPagedPool,sizeof(type)*(amount), '0TWA'); +#define ALLOCATE_ZERO_MEMORY(dest,type,amount) \ + { \ + (dest)=ExAllocatePoolWithTag(NonPagedPool,sizeof(type)*(amount), '1TWA'); \ + if ((dest)!=NULL) \ + RtlZeroMemory((dest),sizeof(type)*(amount)); \ + } + +#define FREE_MEMORY(dest) ExFreePool(dest); +#define ZERO_MEMORY(dest,amount) RtlZeroMemory(dest,amount); +#define COPY_MEMORY(dest,src,amount) RtlCopyMemory(dest,src,amount); + +#else + +#define ALLOCATE_MEMORY(dest,type,amount) \ + (dest)=(type*)GlobalAlloc(GPTR, sizeof(type)*(amount)); +#define ALLOCATE_ZERO_MEMORY(dest,type,amount) \ + (dest)=(type*)GlobalAlloc(GPTR, sizeof(type)*(amount)); + +#define FREE_MEMORY(dest) GlobalFree(dest); +#define ZERO_MEMORY(dest,amount) RtlZeroMemory(dest,amount); +#define COPY_MEMORY(dest,src,amount) RtlCopyMemory(dest,src,amount); + + +#endif /*WIN_NT_DRIVER*/ + + + +#endif + diff --git a/drivers/3rdparty/npf/normal_lookup.c b/drivers/3rdparty/npf/normal_lookup.c new file mode 100644 index 0000000000000..20f057ca34ac1 --- /dev/null +++ b/drivers/3rdparty/npf/normal_lookup.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef WIN32 +#include "tme.h" +#include "normal_lookup.h" +#endif + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#endif + +#endif + + +/* lookup in the table, seen as an hash */ +/* if not found, inserts an element */ +/* returns TME_TRUE if the entry is found or created, */ +/* returns TME_FALSE if no more blocks are available */ +uint32 normal_lut_w_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref) +{ + uint32 i; + uint32 tocs=0; + uint32 *key32=(uint32*) key; + uint32 shrinked_key=0; + uint32 index; + RECORD *records=(RECORD*)data->lut_base_address; + uint8 *offset; + uint32 key_len=data->key_len; + /*the key is shrinked into a 32-bit value */ + for (i=0; ilut_entries; + + while (tocs<=data->filled_entries) + { + + if (records[index].block==0) + { /*creation of a new entry*/ + + if (data->filled_blocks==data->shared_memory_blocks) + { + /*no more free blocks*/ + GET_TIME((struct timeval *)(data->shared_memory_base_address+4*key_len),time_ref); + data->last_found=NULL; + return TME_FALSE; + } + + /*offset=absolute pointer to the block associated*/ + /*with the newly created entry*/ + offset=data->shared_memory_base_address+ + data->block_size*data->filled_blocks; + + /*copy the key in the block*/ + COPY_MEMORY(offset,key32,key_len*4); + GET_TIME((struct timeval *)(offset+4*key_len),time_ref); + /*assign the block relative offset to the entry, in NBO*/ + SW_ULONG_ASSIGN(&records[index].block,offset-mem_ex->buffer); + + data->filled_blocks++; + + /*assign the exec function ID to the entry, in NBO*/ + SW_ULONG_ASSIGN(&records[index].exec_fcn,data->default_exec); + data->filled_entries++; + + data->last_found=(uint8*)&records[index]; + + return TME_TRUE; + } + /*offset contains the absolute pointer to the block*/ + /*associated with the current entry */ + offset=mem_ex->buffer+SW_ULONG_AT(&records[index].block,0); + + for (i=0; (ilast_found=(uint8*)&records[index]; + return TME_TRUE; + } + else + { + /* wrong entry, rehashing */ + if (IS_DELETABLE(offset+key_len*4,data)) + { + ZERO_MEMORY(offset,data->block_size); + COPY_MEMORY(offset,key32,key_len*4); + SW_ULONG_ASSIGN(&records[index].exec_fcn,data->default_exec); + GET_TIME((struct timeval*)(offset+key_len*4),time_ref); + data->last_found=(uint8*)&records[index]; + return TME_TRUE; + } + else + { + index=(index+data->rehashing_value) % data->lut_entries; + tocs++; + } + } + } + + /* nothing found, last found= out of lut */ + GET_TIME((struct timeval *)(data->shared_memory_base_address+4*key_len),time_ref); + data->last_found=NULL; + return TME_FALSE; + +} + +/* lookup in the table, seen as an hash */ +/* if not found, returns out of count entry index */ +/* returns TME_TRUE if the entry is found */ +/* returns TME_FALSE if the entry is not found */ +uint32 normal_lut_wo_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref) +{ + uint32 i; + uint32 tocs=0; + uint32 *key32=(uint32*) key; + uint32 shrinked_key=0; + uint32 index; + RECORD *records=(RECORD*)data->lut_base_address; + uint8 *offset; + uint32 key_len=data->key_len; + /*the key is shrinked into a 32-bit value */ + for (i=0; ilut_entries; + + while (tocs<=data->filled_entries) + { + + if (records[index].block==0) + { /*out of table, insertion is not allowed*/ + GET_TIME((struct timeval *)(data->shared_memory_base_address+4*key_len),time_ref); + data->last_found=NULL; + return TME_FALSE; + } + /*offset contains the absolute pointer to the block*/ + /*associated with the current entry */ + + offset=mem_ex->buffer+SW_ULONG_AT(&records[index].block,0); + + for (i=0; (ilast_found=(uint8*)&records[index]; + return TME_TRUE; + } + else + { + /*wrong entry, rehashing*/ + index=(index+data->rehashing_value) % data->lut_entries; + tocs++; + } + } + + /*nothing found, last found= out of lut*/ + GET_TIME((struct timeval *)(data->shared_memory_base_address+4*key_len),time_ref); + data->last_found=NULL; + return TME_FALSE; + +} diff --git a/drivers/3rdparty/npf/normal_lookup.h b/drivers/3rdparty/npf/normal_lookup.h new file mode 100644 index 0000000000000..62e75f467db30 --- /dev/null +++ b/drivers/3rdparty/npf/normal_lookup.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __normal_lookup +#define __normal_lookup + +#ifdef WIN32 +#include "tme.h" +#endif + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#else +#include +#endif + +#endif + +#define NORMAL_LUT_W_INSERT 0x00000000 +uint32 normal_lut_w_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref); +#define NORMAL_LUT_WO_INSERT 0x00000001 +uint32 normal_lut_wo_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref); +#define DUMMY_INSERT 1234 + +#endif \ No newline at end of file diff --git a/drivers/3rdparty/npf/resource.h b/drivers/3rdparty/npf/resource.h new file mode 100644 index 0000000000000..d704ecaaf4149 --- /dev/null +++ b/drivers/3rdparty/npf/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by NPF.RC +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/drivers/3rdparty/npf/tcp_session.c b/drivers/3rdparty/npf/tcp_session.c new file mode 100644 index 0000000000000..1848ccf8f32a1 --- /dev/null +++ b/drivers/3rdparty/npf/tcp_session.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef WIN32 +#include "tme.h" +#include "tcp_session.h" +#endif + +#ifdef __FreeBSD + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#endif + +#endif + +uint32 tcp_session(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data) + +{ + + uint32 next_status; + uint32 direction=ULONG_AT(mem_data,12); + uint8 flags=mem_ex->buffer[25]; + tcp_data *session=(tcp_data*)(block+data->key_len*4); + + session->last_timestamp=session->timestamp_block; + session->timestamp_block.tv_sec=0x7fffffff; + + if (direction==session->direction) + { + session->pkts_cln_to_srv++; + session->bytes_cln_to_srv+=pkt_size; + } + else + { + session->pkts_srv_to_cln++; + session->bytes_srv_to_cln+=pkt_size; + } + /* we use only thes four flags, we don't need PSH or URG */ + flags&=(ACK|FIN|SYN|RST); + + switch (session->status) + { + case ERROR_TCP: + next_status=ERROR_TCP; + break; + + case UNKNOWN: + if (flags==SYN) + { + if (SW_ULONG_AT(mem_ex->buffer,20)!=0) + { + + next_status=ERROR_TCP; + break; + } + next_status=SYN_RCV; + session->syn_timestamp=session->last_timestamp; + + session->direction=direction; + session->seq_n_0_cln=SW_ULONG_AT(mem_ex->buffer,16); + } + else + next_status=UNKNOWN; + break; + + case SYN_RCV: + if ((flags&RST)&&(direction!=session->direction)) + { + next_status=CLOSED_RST; + break; + } + if ((flags==SYN)&&(direction==session->direction)) + { /* two syns... */ + next_status=SYN_RCV; + session->seq_n_0_cln=SW_ULONG_AT(mem_ex->buffer,16); + break; + } + + if ((flags==(SYN|ACK))&&(direction!=session->direction)) + { + if (SW_ULONG_AT(mem_ex->buffer,20)!=session->seq_n_0_cln+1) + { + next_status=ERROR_TCP; + break; + } + next_status=SYN_ACK_RCV; + + session->syn_ack_timestamp=session->last_timestamp; + + session->seq_n_0_srv=SW_ULONG_AT(mem_ex->buffer,16); + session->ack_cln=session->seq_n_0_cln+1; + } + else + { + next_status=ERROR_TCP; + } + break; + + case SYN_ACK_RCV: + if ((flags&ACK)&&(flags&RST)&&(direction==session->direction)) + { + next_status=CLOSED_RST; + session->ack_srv=SW_ULONG_AT(mem_ex->buffer,20); + break; + } + + if ((flags==ACK)&&(!(flags&(SYN|FIN|RST)))&&(direction==session->direction)) + { + if (SW_ULONG_AT(mem_ex->buffer,20)!=session->seq_n_0_srv+1) + { + next_status=ERROR_TCP; + break; + } + next_status=ESTABLISHED; + session->ack_srv=session->seq_n_0_srv+1; + break; + } + if ((flags&ACK)&&(flags&SYN)&&(direction!=session->direction)) + { + next_status=SYN_ACK_RCV; + break; + } + + next_status=ERROR_TCP; + break; + + case ESTABLISHED: + if (flags&SYN) + { + if ((flags&ACK)&& + (direction!=session->direction)&& + ((session->ack_cln-SW_ULONG_AT(mem_ex->buffer,20))direction)&& + (SW_ULONG_AT(mem_ex->buffer,16)==session->seq_n_0_cln)&& + (ULONG_AT(mem_ex->buffer,20)==0) + ) + { /* syn duplicato */ + next_status=ESTABLISHED; + break; + } + + next_status=ERROR_TCP; + break; + } + if (flags&ACK) + if (direction==session->direction) + { + uint32 new_ack=SW_ULONG_AT(mem_ex->buffer,20); + if (new_ack-session->ack_srvack_srv=new_ack; + } + else + { + uint32 new_ack=SW_ULONG_AT(mem_ex->buffer,20); + if (new_ack-session->ack_clnack_cln=new_ack; + } + if (flags&RST) + { + next_status=CLOSED_RST; + break; + } + if (flags&FIN) + if (direction==session->direction) + { /* an hack to make all things work */ + session->ack_cln=SW_ULONG_AT(mem_ex->buffer,16); + next_status=FIN_CLN_RCV; + break; + } + else + { + session->ack_srv=SW_ULONG_AT(mem_ex->buffer,16); + next_status=FIN_SRV_RCV; + break; + } + next_status=ESTABLISHED; + break; + + case CLOSED_RST: + next_status=CLOSED_RST; + break; + + case FIN_SRV_RCV: + if (flags&SYN) + { + next_status=ERROR_TCP; + break; + } + + next_status=FIN_SRV_RCV; + + if (flags&ACK) + { + uint32 new_ack=SW_ULONG_AT(mem_ex->buffer,20); + if (direction!=session->direction) + if ((new_ack-session->ack_cln)ack_cln=new_ack; + } + + if (flags&RST) + next_status=CLOSED_RST; + else + if ((flags&FIN)&&(direction==session->direction)) + { + session->ack_cln=SW_ULONG_AT(mem_ex->buffer,16); + next_status=CLOSED_FIN; + } + + break; + + case FIN_CLN_RCV: + if (flags&SYN) + { + next_status=ERROR_TCP; + break; + } + + next_status=FIN_CLN_RCV; + + if (flags&ACK) + { + uint32 new_ack=SW_ULONG_AT(mem_ex->buffer,20); + if (direction==session->direction) + if (new_ack-session->ack_srvack_srv=new_ack; + } + + if (flags&RST) + next_status=CLOSED_RST; + else + if ((flags&FIN)&&(direction!=session->direction)) + { + session->ack_srv=SW_ULONG_AT(mem_ex->buffer,16); + next_status=CLOSED_FIN; + } + + break; + + case CLOSED_FIN: + next_status=CLOSED_FIN; + break; + default: + next_status=ERROR_TCP; + + } + + session->status=next_status; + + if ((next_status==CLOSED_FIN)||(next_status==UNKNOWN)||(next_status==CLOSED_RST)||(next_status==ERROR_TCP)) + session->timestamp_block=session->last_timestamp; + + return TME_SUCCESS; +} \ No newline at end of file diff --git a/drivers/3rdparty/npf/tcp_session.h b/drivers/3rdparty/npf/tcp_session.h new file mode 100644 index 0000000000000..73d6bc3573873 --- /dev/null +++ b/drivers/3rdparty/npf/tcp_session.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __tcp_session +#define __tcp_session + +#ifdef WIN32 +#include "tme.h" +#endif + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#else +#include +#endif + +#endif + +#define UNKNOWN 0 +#define SYN_RCV 1 +#define SYN_ACK_RCV 2 +#define ESTABLISHED 3 +#define CLOSED_RST 4 +#define FIN_CLN_RCV 5 +#define FIN_SRV_RCV 6 +#define CLOSED_FIN 7 +#define ERROR_TCP 8 +#define FIRST_IS_CLN 0 +#define FIRST_IS_SRV 0xffffffff +#define FIN_CLN 1 +#define FIN_SRV 2 + +#define MAX_WINDOW 65536 + +typedef struct __tcp_data +{ + struct timeval timestamp_block; /*DO NOT MOVE THIS VALUE*/ + struct timeval syn_timestamp; + struct timeval last_timestamp; + struct timeval syn_ack_timestamp; + uint32 direction; + uint32 seq_n_0_srv; + uint32 seq_n_0_cln; + uint32 ack_srv; /* acknowledge of (data sent by server) */ + uint32 ack_cln; /* acknowledge of (data sent by client) */ + uint32 status; + uint32 pkts_cln_to_srv; + uint32 pkts_srv_to_cln; + uint32 bytes_srv_to_cln; + uint32 bytes_cln_to_srv; + uint32 close_state; +} + tcp_data; + +#define FIN 1 +#define SYN 2 +#define RST 4 +#define PSH 8 +#define ACK 16 +#define URG 32 + +#define TCP_SESSION 0x00000800 +uint32 tcp_session(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data); + +#endif \ No newline at end of file diff --git a/drivers/3rdparty/npf/time_calls.h b/drivers/3rdparty/npf/time_calls.h new file mode 100644 index 0000000000000..cb378dcfd79fb --- /dev/null +++ b/drivers/3rdparty/npf/time_calls.h @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2001 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _time_calls +#define _time_calls + +#ifdef WIN_NT_DRIVER + +#include "debug.h" +#include "ndis.h" + +#define DEFAULT_TIMESTAMPMODE 0 + +#define TIMESTAMPMODE_SINGLE_SYNCHRONIZATION 0 +#define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP 1 +#define TIMESTAMPMODE_QUERYSYSTEMTIME 2 +#define TIMESTAMPMODE_RDTSC 3 + +#define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP 99 + +#define TIMESTAMPMODE_REGKEY L"TimestampMode" + +extern ULONG TimestampMode; + +/*! + \brief A microsecond precise timestamp. + + included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet. +*/ + +struct timeval { + long tv_sec; ///< seconds + long tv_usec; ///< microseconds +}; + +#endif /*WIN_NT_DRIVER*/ + +struct time_conv +{ + ULONGLONG reference; + struct timeval start[32]; +}; + +#ifdef WIN_NT_DRIVER + +__inline void TIME_DESYNCHRONIZE(struct time_conv *data) +{ + data->reference = 0; +// data->start.tv_sec = 0; +// data->start.tv_usec = 0; +} + + +__inline void ReadTimeStampModeFromRegistry(PUNICODE_STRING RegistryPath) +{ + ULONG NewLength; + PWSTR NullTerminatedString; + RTL_QUERY_REGISTRY_TABLE Queries[2]; + ULONG DefaultTimestampMode = DEFAULT_TIMESTAMPMODE; + + NewLength = RegistryPath->Length/2; + + NullTerminatedString = ExAllocatePoolWithTag(PagedPool, (NewLength+1) *sizeof(WCHAR), '2TWA'); + + if (NullTerminatedString != NULL) + { + RtlCopyMemory(NullTerminatedString, RegistryPath->Buffer, RegistryPath->Length); + + NullTerminatedString[NewLength]=0; + + RtlZeroMemory(Queries, sizeof(Queries)); + + Queries[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + Queries[0].Name = TIMESTAMPMODE_REGKEY; + Queries[0].EntryContext = &TimestampMode; + Queries[0].DefaultType = REG_DWORD; + Queries[0].DefaultData = &DefaultTimestampMode; + Queries[0].DefaultLength = sizeof(ULONG); + + if(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, NullTerminatedString, Queries, NULL, NULL) != STATUS_SUCCESS) + { + TimestampMode = DEFAULT_TIMESTAMPMODE; + } + + RtlWriteRegistryValue( RTL_REGISTRY_ABSOLUTE, NullTerminatedString, TIMESTAMPMODE_REGKEY, REG_DWORD, &TimestampMode,sizeof(ULONG)); + ExFreePool(NullTerminatedString); + } + else + TimestampMode = DEFAULT_TIMESTAMPMODE; +} + +#pragma optimize ("g",off) //Due to some weird behaviour of the optimizer of DDK build 2600 + +/* KeQueryPerformanceCounter TimeStamps */ +__inline void SynchronizeOnCpu(struct timeval *start) +{ +// struct timeval *start = (struct timeval*)Data; + + struct timeval tmp; + LARGE_INTEGER SystemTime; + LARGE_INTEGER i; + ULONG tmp2; + LARGE_INTEGER TimeFreq,PTime; + + // get the absolute value of the system boot time. + + PTime = KeQueryPerformanceCounter(&TimeFreq); + KeQuerySystemTime(&SystemTime); + + start->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600); + + start->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10); + + start->tv_sec -= (ULONG)(PTime.QuadPart/TimeFreq.QuadPart); + + start->tv_usec -= (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart); + + if (start->tv_usec < 0) + { + start->tv_sec --; + start->tv_usec += 1000000; + } +} + +// +// inline assembler is not supported with the current AMD64 compilers +// At the moment we simply disable this timestamping mode on AMD64. +// A solution would be to allocate a small memory from the non-paged +// pool, dump the instructions on that buffer, and then execute them. +// The non paged pool is needed since it's the only area of kernel +// data memory that is not subject to the NX protection. +// Or use some lower level trick, like using an assembler to assemble +// a small function for this. +// + +#ifdef _X86_ +/*RDTSC timestamps */ +/* callers must be at IRQL=PASSIVE_LEVEL*/ +__inline VOID TimeSynchronizeRDTSC(struct time_conv *data) +{ + struct timeval tmp; + LARGE_INTEGER system_time; + ULONGLONG curr_ticks; + KIRQL old; + LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq; + ULONGLONG start_ticks,stop_ticks; + ULONGLONG delta,delta2; + KEVENT event; + LARGE_INTEGER i; + ULONGLONG reference; + + if (data->reference!=0) + return; + + KeInitializeEvent(&event,NotificationEvent,FALSE); + + i.QuadPart=-3500000; + + KeRaiseIrql(HIGH_LEVEL,&old); + start_kqpc=KeQueryPerformanceCounter(&start_freq); + __asm + { + push eax + push edx + push ecx + rdtsc + lea ecx, start_ticks + mov [ecx+4], edx + mov [ecx], eax + pop ecx + pop edx + pop eax + } + + KeLowerIrql(old); + + KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i); + + KeRaiseIrql(HIGH_LEVEL,&old); + stop_kqpc=KeQueryPerformanceCounter(&stop_freq); + __asm + { + push eax + push edx + push ecx + rdtsc + lea ecx, stop_ticks + mov [ecx+4], edx + mov [ecx], eax + pop ecx + pop edx + pop eax + } + KeLowerIrql(old); + + delta=stop_ticks-start_ticks; + delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart; + if (delta>10000000000) + { + delta/=16; + delta2/=16; + } + + reference=delta*(start_freq.QuadPart)/delta2; + + data->reference=reference/1000; + + if (reference%1000>500) + data->reference++; + + data->reference*=1000; + + reference=data->reference; + + KeQuerySystemTime(&system_time); + + __asm + { + push eax + push edx + push ecx + rdtsc + lea ecx, curr_ticks + mov [ecx+4], edx + mov [ecx], eax + pop ecx + pop edx + pop eax + } + + tmp.tv_sec=-(LONG)(curr_ticks/reference); + + tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference); + + system_time.QuadPart-=116444736000000000; + + tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000); + tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10); + + if (tmp.tv_usec<0) + { + tmp.tv_sec--; + tmp.tv_usec+=1000000; + } + + data->start[0] = tmp; + + IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);) +} +#endif //_X86_ + +#pragma optimize ("g",on) //Due to some weird behaviour of the optimizer of DDK build 2600 + +__inline VOID TIME_SYNCHRONIZE(struct time_conv *data) +{ + ULONG NumberOfCpus, i; + KAFFINITY AffinityMask; + + if (data->reference != 0) + return; + + NumberOfCpus = NdisSystemProcessorCount(); + + if ( TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP) + { + for (i = 0 ; i < NumberOfCpus ; i++ ) + { + // + // the following cast is needed because KAFFINITY is defined as a 32bit value on x86 and a 64bit integer on x64. + // The constant 1 is implicitely 32bit only, so a shift won't work properly on x64. + // + AffinityMask = ((KAFFINITY)1 << i); + ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY)); + SynchronizeOnCpu(&(data->start[i])); + } + AffinityMask = 0xFFFFFFFF; + ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY)); + data->reference = 1; + } + else + if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME ) + { + //do nothing + data->reference = 1; + } + else +// +// This timestamp mode is supported on x86 (32 bit) only +// +#ifdef _X86_ + if ( TimestampMode == TIMESTAMPMODE_RDTSC ) + { + TimeSynchronizeRDTSC(data); + } + else +#endif // _X86_ + { //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION + SynchronizeOnCpu(data->start); + data->reference = 1; + } + return; +} + + +#pragma optimize ("g",off) //Due to some weird behaviour of the optimizer of DDK build 2600 + +__inline void GetTimeKQPC(struct timeval *dst, struct time_conv *data) +{ + LARGE_INTEGER PTime, TimeFreq; + LONG tmp; + ULONG CurrentCpu; + static struct timeval old_ts={0,0}; + + + PTime = KeQueryPerformanceCounter(&TimeFreq); + tmp = (LONG)(PTime.QuadPart/TimeFreq.QuadPart); + + if (TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP) + { + //actually this code is ok only if we are guaranteed that no thread scheduling will take place. + CurrentCpu = KeGetCurrentProcessorNumber(); + + dst->tv_sec = data->start[CurrentCpu].tv_sec + tmp; + dst->tv_usec = data->start[CurrentCpu].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart); + + if (dst->tv_usec >= 1000000) + { + dst->tv_sec ++; + dst->tv_usec -= 1000000; + } + + if (TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP) + { + if (old_ts.tv_sec > dst->tv_sec || (old_ts.tv_sec == dst->tv_sec && old_ts.tv_usec > dst->tv_usec) ) + *dst = old_ts; + + else + old_ts = *dst; + } + } + else + { //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION + dst->tv_sec = data->start[0].tv_sec + tmp; + dst->tv_usec = data->start[0].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart); + + if (dst->tv_usec >= 1000000) + { + dst->tv_sec ++; + dst->tv_usec -= 1000000; + } + } +} + +// +// inline assembler is not supported with the current AMD64 compilers +// At the moment we simply disable this timestamping mode on AMD64. +// A solution would be to allocate a small memory from the non-paged +// pool, dump the instructions on that buffer, and then execute them. +// The non paged pool is needed since it's the only area of kernel +// data memory that is not subject to the NX protection. +// Or use some lower level trick, like using an assembler to assemble +// a small function for this. +// + +#ifdef _X86_ +__inline void GetTimeRDTSC(struct timeval *dst, struct time_conv *data) +{ + + ULONGLONG tmp = 0; + __asm + { + push eax + push edx + push ecx + rdtsc + lea ecx, tmp + mov [ecx+4], edx + mov [ecx], eax + pop ecx + pop edx + pop eax + } + + if (data->reference==0) + { + return; + } + dst->tv_sec=(LONG)(tmp/data->reference); + + dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference); + + dst->tv_sec+=data->start[0].tv_sec; + + dst->tv_usec+=data->start[0].tv_usec; + + if (dst->tv_usec>=1000000) + { + dst->tv_sec++; + dst->tv_usec-=1000000; + } + + +} +#endif //_X86_ + +__inline void GetTimeQST(struct timeval *dst, struct time_conv *data) +{ + LARGE_INTEGER SystemTime; + + KeQuerySystemTime(&SystemTime); + + dst->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600); + dst->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10); + +} + +#pragma optimize ("g",on) //Due to some weird behaviour of the optimizer of DDK build 2600 + + +__inline void GET_TIME(struct timeval *dst, struct time_conv *data) +{ + +// +// This timestamp mode is supported on x86 (32 bit) only +// +#ifdef _X86_ + if ( TimestampMode == TIMESTAMPMODE_RDTSC ) + { + GetTimeRDTSC(dst,data); + } + else +#endif // _X86_ + if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME ) + { + GetTimeQST(dst,data); + } + else + { + GetTimeKQPC(dst,data); + } +} + + +#else /*WIN_NT_DRIVER*/ + +__inline void FORCE_TIME(struct timeval *src, struct time_conv *dest) +{ + dest->start[0]=*src; +} + +__inline void GET_TIME(struct timeval *dst, struct time_conv *data) +{ + *dst=data->start[0]; +} + +#endif /*WIN_NT_DRIVER*/ + + +#endif /*_time_calls*/ diff --git a/drivers/3rdparty/npf/tme.c b/drivers/3rdparty/npf/tme.c new file mode 100644 index 0000000000000..92a8644b95bf0 --- /dev/null +++ b/drivers/3rdparty/npf/tme.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "tme.h" + +#ifndef UNUSED +#define UNUSED(_x) (_x) +#endif + +/* resizes extended memory */ +uint32 init_extended_memory(uint32 size, MEM_TYPE *mem_ex) +{ + uint8 *tmp; + + if ((mem_ex==NULL)||(mem_ex->buffer==NULL)||(size==0)) + return TME_ERROR; /* awfully never reached!!!! */ + + tmp=mem_ex->buffer; + mem_ex->buffer=NULL; + FREE_MEMORY(tmp); + + ALLOCATE_MEMORY(tmp,uint8,size); + if (tmp==NULL) + return TME_ERROR; /* no memory */ + + mem_ex->size=size; + mem_ex->buffer=tmp; + return TME_SUCCESS; + +} + +/* activates a block of the TME */ +uint32 set_active_tme_block(TME_CORE *tme, uint32 block) +{ + + if ((block>=MAX_TME_DATA_BLOCKS)||(!IS_VALIDATED(tme->validated_blocks,block))) + return TME_ERROR; + tme->active=block; + tme->working=block; + return TME_SUCCESS; + +} + +/* simply inserts default values in a TME block */ +/* it DOESN'T initialize the block in the core!! */ +/* FIXME default values are defined at compile time, */ +/* it will be useful to store them in the registry */ +uint32 init_tme_block(TME_CORE *tme, uint32 block) +{ + + TME_DATA *data; + if (block>=MAX_TME_DATA_BLOCKS) + return TME_ERROR; + data=&(tme->block_data[block]); + tme->working=block; + + ZERO_MEMORY(data,sizeof(TME_DATA)); + + /* entries in LUT */ + data->lut_entries=TME_LUT_ENTRIES_DEFAULT; + /* blocks */ + data->shared_memory_blocks=TME_SHARED_MEMORY_BLOCKS_DEFAULT; + /* block size */ + data->block_size=TME_BLOCK_SIZE_DEFAULT; + /* lookup function */ + data->lookup_code=lut_fcn_mapper(TME_LOOKUP_CODE_DEFAULT); + /* rehashing value */ + data->rehashing_value=TME_REHASHING_VALUE_DEFAULT; + /* out lut function */ + data->out_lut_exec=TME_OUT_LUT_EXEC_DEFAULT; + /* default function */ + data->default_exec=TME_DEFAULT_EXEC_DEFAULT; + /* extra segment size */ + data->extra_segment_size=TME_EXTRA_SEGMENT_SIZE_DEFAULT; + + + data->enable_deletion=FALSE; + data->last_read.tv_sec=0; + data->last_read.tv_usec=0; + return TME_SUCCESS; + +} +/* it validates a TME block and */ +/* (on OK) inserts the block in the core */ +uint32 validate_tme_block(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 block, uint32 mem_ex_offset) +{ + uint32 required_memory; + uint8 *base=mem_ex_offset+mem_ex->buffer; + TME_DATA *data; + + /* FIXME soluzione un po' posticcia... */ + if (mem_ex_offset==0) + return TME_ERROR; + + if (block>=MAX_TME_DATA_BLOCKS) + return TME_ERROR; + data=&tme->block_data[block]; + + if (data->lut_entries==0) + return TME_ERROR; + + if (data->key_len==0) + return TME_ERROR; + + if (data->shared_memory_blocks==0) + return TME_ERROR; + + if (data->block_size==0) + return TME_ERROR; + + /* checks if the lookup function is valid */ + if (data->lookup_code==NULL) + return TME_ERROR; + + /* checks if the out lut exec function is valid */ + if (exec_fcn_mapper(data->out_lut_exec)==NULL) + return TME_ERROR; + + /* checks if the default exec function is valid */ + if (exec_fcn_mapper(data->default_exec)==NULL) + return TME_ERROR; + + /* let's calculate memory needed */ + required_memory=data->lut_entries*sizeof(RECORD); /*LUT*/ + required_memory+=data->block_size*data->shared_memory_blocks; /*shared segment*/ + required_memory+=data->extra_segment_size; /*extra segment*/ + + if (required_memory>(mem_ex->size-mem_ex_offset)) + return TME_ERROR; /*not enough memory*/ + + /* the TME block can be initialized */ + ZERO_MEMORY(base,required_memory); + + data->lut_base_address=base; + + data->shared_memory_base_address= + data->lut_base_address+ + data->lut_entries*sizeof(RECORD); + + data->extra_segment_base_address= + data->shared_memory_base_address+ + data->block_size*data->shared_memory_blocks; + data->filled_blocks=1; + VALIDATE(tme->validated_blocks,block); + tme->active=block; + tme->working=block; + return TME_SUCCESS; +} + +/* I/F between the bpf machine and the callbacks, just some checks */ +uint32 lookup_frontend(MEM_TYPE *mem_ex, TME_CORE *tme,uint32 mem_ex_offset, struct time_conv *time_ref) +{ + if (tme->active==TME_NONE_ACTIVE) + return TME_FALSE; + + return (tme->block_data[tme->active].lookup_code)(mem_ex_offset+mem_ex->buffer,&tme->block_data[tme->active],mem_ex, time_ref); +} + +/* I/F between the bpf machine and the callbacks, just some checks */ +uint32 execute_frontend(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 pkt_size, uint32 offset) +{ + + exec_fcn tmp; + TME_DATA *data; + uint8 *block; + uint8 *mem_data; + + if (tme->active==TME_NONE_ACTIVE) + return TME_ERROR; + + data=&tme->block_data[tme->active]; + + if (data->last_found==NULL) + { /*out lut exec */ + tmp=exec_fcn_mapper(data->out_lut_exec); + block=data->shared_memory_base_address; + } + else + { /*checks if last_found is valid */ + if ((data->last_foundlut_base_address)||(data->last_found>=data->shared_memory_base_address)) + return TME_ERROR; + else + { + tmp=exec_fcn_mapper(SW_ULONG_AT(&((RECORD*)data->last_found)->exec_fcn,0)); + if (tmp==NULL) + return TME_ERROR; + block=SW_ULONG_AT(&((RECORD*)data->last_found)->block,0)+mem_ex->buffer; + if ((blockshared_memory_base_address)||(block>=data->extra_segment_base_address)) + return TME_ERROR; + } + } + + if (offset>=mem_ex->size) + return TME_ERROR; + + mem_data=mem_ex->buffer+offset; + + return tmp(block,pkt_size,data,mem_ex,mem_data); +} + +/*resets all the TME core*/ +uint32 reset_tme(TME_CORE *tme) +{ + if (tme==NULL) + return TME_ERROR; + ZERO_MEMORY(tme, sizeof(TME_CORE)); + return TME_SUCCESS; +} + +/* returns a register value of the active TME block */ +/* FIXME last found in maniera elegante e veloce ?!?! */ +uint32 get_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 *rval) +{ + switch(rgstr) + { + case TME_LUT_ENTRIES: + *rval=data->lut_entries; + return TME_SUCCESS; + case TME_MAX_FILL_STATE: + *rval=data->max_fill_state; + return TME_SUCCESS; + case TME_REHASHING_VALUE: + *rval=data->rehashing_value; + return TME_SUCCESS; + case TME_KEY_LEN: + *rval=data->key_len; + return TME_SUCCESS; + case TME_SHARED_MEMORY_BLOCKS: + *rval=data->shared_memory_blocks; + return TME_SUCCESS; + case TME_FILLED_ENTRIES: + *rval=data->filled_entries; + return TME_SUCCESS; + case TME_BLOCK_SIZE: + *rval=data->block_size; + return TME_SUCCESS; + case TME_EXTRA_SEGMENT_SIZE: + *rval=data->extra_segment_size; + return TME_SUCCESS; + case TME_FILLED_BLOCKS: + *rval=data->filled_blocks; + return TME_SUCCESS; + case TME_DEFAULT_EXEC: + *rval=data->default_exec; + return TME_SUCCESS; + case TME_OUT_LUT_EXEC: + *rval=data->out_lut_exec; + return TME_SUCCESS; + case TME_SHARED_MEMORY_BASE_ADDRESS: + *rval=data->shared_memory_base_address-mem_ex->buffer; + return TME_SUCCESS; + case TME_LUT_BASE_ADDRESS: + *rval=data->lut_base_address-mem_ex->buffer; + return TME_SUCCESS; + case TME_EXTRA_SEGMENT_BASE_ADDRESS: + *rval=data->extra_segment_base_address-mem_ex->buffer; + return TME_SUCCESS; + case TME_LAST_FOUND_BLOCK: + if (data->last_found==NULL) + *rval=0; + else + *rval=data->last_found-mem_ex->buffer; + return TME_SUCCESS; + + default: + return TME_ERROR; + } +} + +/* sets a register value in the active block */ +/* FIXME last found in maniera elegante e veloce ?!?! */ +uint32 set_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 value, int32 init) +{ /* very very very dangerous!!!!!!!!!!! */ + lut_fcn tmp; + + UNUSED(mem_ex); + + switch(rgstr) + { + case TME_MAX_FILL_STATE: + data->max_fill_state=value; + return TME_SUCCESS; + case TME_REHASHING_VALUE: + data->rehashing_value=value; + return TME_SUCCESS; + case TME_FILLED_ENTRIES: + data->filled_entries=value; + return TME_SUCCESS; + case TME_FILLED_BLOCKS: + if (value<=data->shared_memory_blocks) + { + data->filled_blocks=value; + return TME_SUCCESS; + } + else + return TME_ERROR; + case TME_DEFAULT_EXEC: + data->default_exec=value; + return TME_SUCCESS; + case TME_OUT_LUT_EXEC: + data->out_lut_exec=value; + return TME_SUCCESS; + case TME_LOOKUP_CODE: + tmp=lut_fcn_mapper(value); + if (tmp==NULL) + return TME_ERROR; + else + data->lookup_code=tmp; + return TME_SUCCESS; + default: + break; + } + + if (init) + switch (rgstr) + { + + case TME_LUT_ENTRIES: + data->lut_entries=value; + return TME_SUCCESS; + case TME_KEY_LEN: + data->key_len=value; + return TME_SUCCESS; + case TME_SHARED_MEMORY_BLOCKS: + data->shared_memory_blocks=value; + return TME_SUCCESS; + case TME_BLOCK_SIZE: + data->block_size=value; + return TME_SUCCESS; + case TME_EXTRA_SEGMENT_SIZE: + data->extra_segment_size=value; + return TME_SUCCESS; + default: + return TME_ERROR; + } + else + return TME_ERROR; + +} + +/* chooses the TME block for read */ +uint32 set_active_read_tme_block(TME_CORE *tme, uint32 block) +{ + + if ((block>=MAX_TME_DATA_BLOCKS)||(!IS_VALIDATED(tme->validated_blocks,block))) + return TME_ERROR; + tme->active_read=block; + return TME_SUCCESS; + +} + +/* chooses if the autodeletion must be used */ +uint32 set_autodeletion(TME_DATA *data, uint32 value) +{ + if (value==0) /* no autodeletion */ + data->enable_deletion=FALSE; + else + data->enable_deletion=TRUE; + + return TME_SUCCESS; +} \ No newline at end of file diff --git a/drivers/3rdparty/npf/tme.h b/drivers/3rdparty/npf/tme.h new file mode 100644 index 0000000000000..41e46326ba2f7 --- /dev/null +++ b/drivers/3rdparty/npf/tme.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __tme_include_ +#define __tme_include_ + +#ifdef WIN_NT_DRIVER +#include "ndis.h" +#else +#include +#endif /*WIN_NT_DRIVER*/ + +#include "memory_t.h" +#include "time_calls.h" + + +/* error codes */ +#define TME_ERROR 0 +#define TME_SUCCESS 1 +#define TME_TRUE 2 +#define TME_FALSE 3 + +/* some constants */ +#define DEFAULT_MEM_EX_SIZE 65536 +#define MAX_TME_DATA_BLOCKS 4 +#define TME_NONE_ACTIVE 0xffffffff +#define DELTA_READ 2 /* secs */ + +#define TME_LUT_ENTRIES 0x00000000 +#define TME_MAX_FILL_STATE 0x00000001 /*potrebbe servire per un thread a passive level!?!?! */ +#define TME_REHASHING_VALUE 0x00000002 +#define TME_KEY_LEN 0x00000003 +#define TME_SHARED_MEMORY_BLOCKS 0x00000004 +#define TME_FILLED_ENTRIES 0x00000005 +#define TME_BLOCK_SIZE 0x00000006 +#define TME_EXTRA_SEGMENT_SIZE 0x00000007 +#define TME_LOOKUP_CODE 0x00000008 +#define TME_OUT_LUT_EXEC 0x00000009 +#define TME_FILLED_BLOCKS 0x0000000a +#define TME_DEFAULT_EXEC 0x0000000b +#define TME_LUT_BASE_ADDRESS 0x0000000c +#define TME_SHARED_MEMORY_BASE_ADDRESS 0x0000000d +#define TME_EXTRA_SEGMENT_BASE_ADDRESS 0x0000000e +#define TME_LAST_FOUND 0x0000000f /* contains the offset of the last found entry */ +#define TME_LAST_FOUND_BLOCK 0x00000010 +/* TME default values */ +#define TME_LUT_ENTRIES_DEFAULT 32007 +#define TME_REHASHING_VALUE_DEFAULT 1 +#define TME_SHARED_MEMORY_BLOCKS_DEFAULT 16000 +#define TME_BLOCK_SIZE_DEFAULT 64 +#define TME_EXTRA_SEGMENT_SIZE_DEFAULT 0 +#define TME_LOOKUP_CODE_DEFAULT 0 +#define TME_OUT_LUT_EXEC_DEFAULT 0 +#define TME_DEFAULT_EXEC_DEFAULT 0 +#define TME_MAX_FILL_STATE_DEFAULT 15000 + +#define IS_VALIDATED(src,index) (src&(1<tv_sec=0x7fffffff; + +struct __TME_DATA; + +/* TME callback prototypes */ +typedef uint32 (*lut_fcn)(uint8 *key, struct __TME_DATA *data,MEM_TYPE *mem_ex, struct time_conv *time_ref ); +typedef uint32 (*exec_fcn)(uint8 *block, uint32 pkt_size, struct __TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data); + +/* DO NOT MODIFY THIS STRUCTURE!!!! GV */ +typedef struct __RECORD + +{ + uint32 block; + uint32 exec_fcn; +} + RECORD, *PRECORD; + +/* TME data registers */ +struct __TME_DATA +{ + uint32 lut_entries; + uint32 max_fill_state; + uint32 rehashing_value; + uint32 key_len; + uint32 shared_memory_blocks; + uint32 filled_entries; + uint32 block_size; + uint32 extra_segment_size; + uint32 filled_blocks; + lut_fcn lookup_code; + uint32 default_exec; + uint32 out_lut_exec; + uint8 *lut_base_address; + uint8 *shared_memory_base_address; + uint8 *extra_segment_base_address; + struct timeval last_read; + uint32 enable_deletion; + uint8 *last_found; +}; + +typedef struct __TME_DATA TME_DATA,*PTME_DATA; + + + +/* TME core */ +typedef struct __TME_CORE +{ + uint32 working; + uint32 active; + uint32 validated_blocks; + TME_DATA block_data[MAX_TME_DATA_BLOCKS]; + uint32 active_read; + +} TME_CORE, *PTME_CORE; + +static __inline int32 IS_DELETABLE(void *timestamp, TME_DATA *data) +{ + struct timeval *ts=(struct timeval*)timestamp; + + if (data->enable_deletion==FALSE) + return FALSE; + if (data->filled_entriesmax_fill_state) + return FALSE; + if ((ts->tv_sec+DELTA_READ)last_read.tv_sec) + return TRUE; + return FALSE; +} + +/* functions to manage TME */ +uint32 init_tme_block(TME_CORE *tme, uint32 block); +uint32 validate_tme_block(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 block, uint32 mem_ex_offset); +uint32 lookup_frontend(MEM_TYPE *mem_ex, TME_CORE *tme,uint32 mem_ex_offset, struct time_conv *time_ref); +uint32 execute_frontend(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 pkt_size,uint32 offset); +uint32 set_active_tme_block(TME_CORE *tme, uint32 block); +uint32 init_extended_memory(uint32 size, MEM_TYPE *mem_ex); +uint32 reset_tme(TME_CORE *tme); +uint32 get_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 *rval); +uint32 set_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 value, int32 init); +uint32 set_active_read_tme_block(TME_CORE *tme, uint32 block); +uint32 set_autodeletion(TME_DATA *data, uint32 value); + +/* function mappers */ +lut_fcn lut_fcn_mapper(uint32 index); +exec_fcn exec_fcn_mapper(uint32 index); + +#endif \ No newline at end of file diff --git a/drivers/3rdparty/npf/valid_insns.h b/drivers/3rdparty/npf/valid_insns.h new file mode 100644 index 0000000000000..a1c0e0410eab5 --- /dev/null +++ b/drivers/3rdparty/npf/valid_insns.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2001 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +u_short valid_instructions[]= + { + BPF_RET|BPF_K, + BPF_RET|BPF_A, + BPF_LD|BPF_IMM, + BPF_LDX|BPF_IMM, + BPF_LD|BPF_MEM, + BPF_LDX|BPF_MEM, + +#ifdef HAVE_BUGGY_TME_SUPPORT + BPF_LD|BPF_MEM_EX_IMM|BPF_B, + BPF_LD|BPF_MEM_EX_IMM|BPF_H, + BPF_LD|BPF_MEM_EX_IMM|BPF_W, + BPF_LD|BPF_MEM_EX_IND|BPF_B, + BPF_LD|BPF_MEM_EX_IND|BPF_H, + BPF_LD|BPF_MEM_EX_IND|BPF_W, +#endif //HAVE_BUGGY_TME_SUPPORT + BPF_LD|BPF_W|BPF_ABS, + BPF_LD|BPF_H|BPF_ABS, + BPF_LD|BPF_B|BPF_ABS, + BPF_LDX|BPF_W|BPF_ABS, + BPF_LDX|BPF_H|BPF_ABS, + BPF_LDX|BPF_B|BPF_ABS, + BPF_LD|BPF_W|BPF_LEN, + BPF_LDX|BPF_W|BPF_LEN, + BPF_LD|BPF_W|BPF_IND, + BPF_LD|BPF_H|BPF_IND, + BPF_LD|BPF_B|BPF_IND, + BPF_LDX|BPF_MSH|BPF_B, + BPF_ST, + BPF_STX, + +#ifdef HAVE_BUGGY_TME_SUPPORT + BPF_ST|BPF_MEM_EX_IMM|BPF_B, + BPF_STX|BPF_MEM_EX_IMM|BPF_B, + BPF_ST|BPF_MEM_EX_IMM|BPF_W, + BPF_STX|BPF_MEM_EX_IMM|BPF_W, + BPF_ST|BPF_MEM_EX_IMM|BPF_H, + BPF_STX|BPF_MEM_EX_IMM|BPF_H, + BPF_ST|BPF_MEM_EX_IND|BPF_B, + BPF_ST|BPF_MEM_EX_IND|BPF_W, + BPF_ST|BPF_MEM_EX_IND|BPF_H, +#endif // HAVE_BUGGY_TME_SUPPORT + + BPF_JMP|BPF_JA, + BPF_JMP|BPF_JGT|BPF_K, + BPF_JMP|BPF_JGE|BPF_K, + BPF_JMP|BPF_JEQ|BPF_K, + BPF_JMP|BPF_JSET|BPF_K, + BPF_JMP|BPF_JGT|BPF_X, + BPF_JMP|BPF_JGE|BPF_X, + BPF_JMP|BPF_JEQ|BPF_X, + BPF_JMP|BPF_JSET|BPF_X, + BPF_ALU|BPF_ADD|BPF_X, + BPF_ALU|BPF_SUB|BPF_X, + BPF_ALU|BPF_MUL|BPF_X, + BPF_ALU|BPF_DIV|BPF_X, + BPF_ALU|BPF_AND|BPF_X, + BPF_ALU|BPF_OR|BPF_X, + BPF_ALU|BPF_LSH|BPF_X, + BPF_ALU|BPF_RSH|BPF_X, + BPF_ALU|BPF_ADD|BPF_K, + BPF_ALU|BPF_SUB|BPF_K, + BPF_ALU|BPF_MUL|BPF_K, + BPF_ALU|BPF_DIV|BPF_K, + BPF_ALU|BPF_AND|BPF_K, + BPF_ALU|BPF_OR|BPF_K, + BPF_ALU|BPF_LSH|BPF_K, + BPF_ALU|BPF_RSH|BPF_K, + BPF_ALU|BPF_NEG, + BPF_MISC|BPF_TAX, + BPF_MISC|BPF_TXA, + +#ifdef HAVE_BUGGY_TME_SUPPORT + BPF_MISC|BPF_TME|BPF_LOOKUP, + BPF_MISC|BPF_TME|BPF_EXECUTE, + BPF_MISC|BPF_TME|BPF_SET_ACTIVE, + BPF_MISC|BPF_TME|BPF_GET_REGISTER_VALUE, + BPF_MISC|BPF_TME|BPF_SET_REGISTER_VALUE +#endif //HAVE_BUGGY_TME_SUPPORT + + }; + +#define VALID_INSTRUCTIONS_LEN (sizeof(valid_instructions)/sizeof(u_short)) diff --git a/drivers/3rdparty/npf/win_bpf.h b/drivers/3rdparty/npf/win_bpf.h new file mode 100644 index 0000000000000..ed5d4bceed46f --- /dev/null +++ b/drivers/3rdparty/npf/win_bpf.h @@ -0,0 +1,436 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /usr/cvsroot_private/winpcap/packetNtx/driver/win_bpf.h,v 1.4 2007/11/12 23:12:12 gianlucav Exp $ (LBL) + */ + +#ifndef BPF_MAJOR_VERSION + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef WIN_NT_DRIVER +#include +#endif + +#ifdef HAVE_BUGGY_TME_SUPPORT +#include "tme.h" +#endif +#include "time_calls.h" + +typedef UCHAR u_char; +typedef USHORT u_short; + +#ifdef WIN_NT_DRIVER +typedef ULONG u_int; +#endif + +typedef LONG bpf_int32; +typedef ULONG bpf_u_int32; +typedef ULONG u_int32; + +#define BPF_MAXINSNS 512 +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Structure for BIOCSETF. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct returned by BIOCGSTATS. + */ +struct bpf_stat { + 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. +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + + +/* + * Structure prepended to each packet. + */ +struct bpf_hdr { + struct timeval bh_tstamp; /* time stamp */ + bpf_u_int32 bh_caplen; /* length of captured portion */ + bpf_u_int32 bh_datalen; /* original length of packet */ + u_short bh_hdrlen; /* length of bpf header (this struct + plus alignment padding) */ +}; + +/* + * Data-link level type codes. + */ + +/* + * These are the types that are the same on all platforms; on other + * platforms, a should be supplied that defines the additional + * DLT_* codes appropriately for that platform (the BSDs, for example, + * should not just pick up this version of "bpf.h"; they should also define + * the additional DLT_* codes used by their kernels, as well as the values + * defined here - and, if the values they use for particular DLT_ types + * differ from those here, they should use their values, not the ones + * here). + */ +#define DLT_NULL 0 /* no link-layer encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* IEEE 802 Networks */ +#define DLT_ARCNET 7 /* ARCNET */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are values from the traditional libpcap "bpf.h". + * Ports of this to particular platforms should replace these definitions + * with the ones appropriate to that platform, if the values are + * different on that platform. + */ +#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */ +#define DLT_RAW 12 /* raw IP */ + +/* + * These are values from BSD/OS's "bpf.h". + * These are not the same as the values from the traditional libpcap + * "bpf.h"; however, these values shouldn't be generated by any + * OS other than BSD/OS, so the correct values to use here are the + * BSD/OS values. + * + * Platforms that have already assigned these values to other + * DLT_ codes, however, should give these codes the values + * from that platform, so that programs that use these codes will + * continue to compile - even though they won't correctly read + * files of these types. + */ +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * This value is defined by NetBSD; other platforms should refrain from + * using it for other purposes, so that NetBSD savefiles with a link + * type of 50 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +/* + * Reserved for future use. + * Do not pick other numerical value for these unless you have also + * picked up the tcpdump.org top-of-CVS-tree version of "savefile.c", + * which will arrange that capture files for these DLT_ types have + * the same "network" value on all platforms, regardless of what + * value is chosen for their DLT_ type (thus allowing captures made + * on one platform to be read on other platforms, even if the two + * platforms don't use the same numerical values for all DLT_ types). + */ +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * Values between 106 and 107 are used in capture file headers as + * link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * OpenBSD defines it as 12, but that collides with DLT_RAW, so we + * define it as 108 here. If OpenBSD picks up this file, it should + * define DLT_LOOP as 12 in its version, as per the comment above - + * and should not use 108 for any purpose. + */ +#define DLT_LOOP 108 + +/* + * Values between 109 and 112 are used in capture file headers as + * link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* TME instructions */ +#define BPF_TME 0x08 + +#define BPF_LOOKUP 0x90 +#define BPF_EXECUTE 0xa0 +#define BPF_INIT 0xb0 +#define BPF_VALIDATE 0xc0 +#define BPF_SET_ACTIVE 0xd0 +#define BPF_RESET 0xe0 +#define BPF_SET_MEMORY 0x80 +#define BPF_GET_REGISTER_VALUE 0x70 +#define BPF_SET_REGISTER_VALUE 0x60 +#define BPF_SET_WORKING 0x50 +#define BPF_SET_ACTIVE_READ 0x40 +#define BPF_SET_AUTODELETION 0x30 +#define BPF_SEPARATION 0xff + +#define BPF_MEM_EX_IMM 0xc0 +#define BPF_MEM_EX_IND 0xe0 +/*used for ST */ +#define BPF_MEM_EX 0xc0 + + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*! + \brief Validates a filtering program arriving from the user-level app. + \param f The filter. + \param len Its length, in pseudo instructions. + \param mem_ex_size The length of the extended memory, used to validate LD/ST to that memory + \return true if f is a valid filter program.. + + The kernel needs to be able to verify an application's filter code. Otherwise, a bogus program could easily + crash the system. + This function returns true if f is a valid filter program. The constraints are that each jump be forward and + to a valid code. The code must terminate with either an accept or reject. +*/ +#ifdef HAVE_BUGGY_TME_SUPPORT +int bpf_validate(struct bpf_insn *f,int len, uint32 mem_ex_size); +#else //HAVE_BUGGY_TME_SUPPORT +int bpf_validate(struct bpf_insn *f,int len); +#endif //HAVE_BUGGY_TME_SUPPORT + +/*! + \brief The filtering pseudo-machine interpreter. + \param pc The filter. + \param p Pointer to a memory buffer containing the packet on which the filter will be executed. + \param wirelen Original length of the packet. + \param buflen Current length of the packet. In some cases (for example when the transfer of the packet to the RAM + has not yet finished), bpf_filter can be executed on a portion of the packet. + \param mem_ex The extended memory. + \param tme The virtualization of the TME co-processor + \param time_ref Data structure needed by the TME co-processor to timestamp data + \return The portion of the packet to keep, in bytes. 0 means that the packet must be rejected, -1 means that + the whole packet must be kept. + + \note this function is not used in normal situations, because the jitter creates a native filtering function + that is faster than the interpreter. +*/ +#ifdef HAVE_BUGGY_TME_SUPPORT +u_int bpf_filter(register struct bpf_insn *pc, + register UCHAR *p, + u_int wirelen, + register u_int buflen , + PMEM_TYPE mem_ex, + PTME_CORE tme , + struct time_conv *time_ref); +#else //HAVE_BUGGY_TME_SUPPORT +u_int bpf_filter(register struct bpf_insn *pc, + register UCHAR *p, + u_int wirelen, + register u_int buflen); +#endif //HAVE_BUGGY_TME_SUPPORT +/*! + \brief The filtering pseudo-machine interpreter with two buffers. This function is slower than bpf_filter(), + but works correctly also if the MAC header and the data of the packet are in two different buffers. + \param pc The filter. + \param p Pointer to a memory buffer containing the MAC header of the packet. + \param pd Pointer to a memory buffer containing the data of the packet. + \param wirelen Original length of the packet. + \param buflen Current length of the packet. In some cases (for example when the transfer of the packet to the RAM + has not yet finished), bpf_filter can be executed on a portion of the packet. + \param mem_ex The extended memory. + \param tme The virtualization of the TME co-processor + \param time_ref Data structure needed by the TME co-processor to timestamp data + \return The portion of the packet to keep, in bytes. 0 means that the packet must be rejected, -1 means that + the whole packet must be kept. + + This function is used when NDIS passes the packet to NPF_tap() in two buffers instaed than in a single one. +*/ +#ifdef HAVE_BUGGY_TME_SUPPORT +u_int bpf_filter_with_2_buffers(register struct bpf_insn *pc, + register u_char *p, + register u_char *pd, + register int headersize, + u_int wirelen, + register u_int buflen, + PMEM_TYPE mem_ex, + PTME_CORE tme, + struct time_conv *time_ref); +#else //HAVE_BUGGY_TME_SUPPORT +u_int bpf_filter_with_2_buffers(register struct bpf_insn *pc, + register u_char *p, + register u_char *pd, + register int headersize, + u_int wirelen, + register u_int buflen); +#endif +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/drivers/3rdparty/npf/win_bpf_filter.c b/drivers/3rdparty/npf/win_bpf_filter.c new file mode 100644 index 0000000000000..eb0bb958cc4ee --- /dev/null +++ b/drivers/3rdparty/npf/win_bpf_filter.c @@ -0,0 +1,1149 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WIN_NT_DRIVER +#include +#else +#include +#endif + +#pragma warning(disable : 4131) //old style function declaration +#pragma warning(disable : 4127) // conditional expr is constant (used for while(1) loops) +#pragma warning(disable : 4213) //cast on l-value + +#ifndef UNUSED +#define UNUSED(_x) (_x) +#endif + +#include "win_bpf.h" + +#include "debug.h" + +#include "valid_insns.h" + +#define EXTRACT_SHORT(p)\ + ((((u_short)(((u_char*)p)[0])) << 8) |\ + (((u_short)(((u_char*)p)[1])) << 0)) + +#define EXTRACT_LONG(p)\ + ((((u_int32)(((u_char*)p)[0])) << 24) |\ + (((u_int32)(((u_char*)p)[1])) << 16) |\ + (((u_int32)(((u_char*)p)[2])) << 8 ) |\ + (((u_int32)(((u_char*)p)[3])) << 0 )) + +#ifdef HAVE_BUGGY_TME_SUPPORT +u_int bpf_filter(pc, p, wirelen, buflen,mem_ex,tme,time_ref) + register struct bpf_insn *pc; + register u_char *p; + u_int wirelen; + register u_int buflen; + PMEM_TYPE mem_ex; + PTME_CORE tme; + struct time_conv *time_ref; +#else //HAVE_BUGGY_TME_SUPPORT +u_int bpf_filter(pc, p, wirelen, buflen) + register struct bpf_insn *pc; + register u_char *p; + u_int wirelen; + register u_int buflen; +#endif //HAVE_BUGGY_TME_SUPPORT + +{ + register u_int32 A, X; + register bpf_u_int32 k; + +#ifdef HAVE_BUGGY_TME_SUPPORT + u_int32 j,tmp; + u_short tmp2; +#endif //HAVE_BUGGY_TME_SUPPORT + + int mem[BPF_MEMWORDS]; + + RtlZeroMemory(mem, sizeof(mem)); + + if (pc == 0) + /* + * No filter means accept all. + */ + return (u_int)-1; + A = 0; + X = 0; + --pc; + while (1) { + ++pc; + switch (pc->code) { + + default: + + return 0; + + case BPF_RET|BPF_K: + return (u_int)pc->k; + + case BPF_RET|BPF_A: + return (u_int)A; + + case BPF_LD|BPF_W|BPF_ABS: + k = pc->k; + if (k >= buflen || k + sizeof(int) > buflen) { + return 0; + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_ABS: + k = pc->k; + if (k >= buflen || k + sizeof(short) > buflen) { + return 0; + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_ABS: + k = pc->k; + if (k >= buflen) { + return 0; + } + A = p[k]; + continue; + + case BPF_LD|BPF_W|BPF_LEN: + A = wirelen; + continue; + + case BPF_LDX|BPF_W|BPF_LEN: + X = wirelen; + continue; + + case BPF_LD|BPF_W|BPF_IND: + k = X + pc->k; + if (k >= buflen || k + sizeof(int) > buflen) { + return 0; + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_IND: + k = X + pc->k; + if (k >= buflen || k + sizeof(short) > buflen) { + return 0; + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_IND: + k = X + pc->k; + if (k >= buflen) { + return 0; + } + A = p[k]; + continue; + + case BPF_LDX|BPF_MSH|BPF_B: + k = pc->k; + if (k >= buflen) { + return 0; + } + X = (p[pc->k] & 0xf) << 2; + continue; + + case BPF_LD|BPF_IMM: + A = pc->k; + continue; + + case BPF_LDX|BPF_IMM: + X = pc->k; + continue; + + case BPF_LD|BPF_MEM: + A = mem[pc->k]; + continue; + + case BPF_LDX|BPF_MEM: + X = mem[pc->k]; + continue; + +#ifdef HAVE_BUGGY_TME_SUPPORT + // + // these instructions use the TME extensions, + // not supported on x86-64 and IA64 architectures. + // + + /* LD NO PACKET INSTRUCTIONS */ + + case BPF_LD|BPF_MEM_EX_IMM|BPF_B: + A= mem_ex->buffer[pc->k]; + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_B: + X= mem_ex->buffer[pc->k]; + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_H: + A = EXTRACT_SHORT(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_H: + X = EXTRACT_SHORT(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_W: + A = EXTRACT_LONG(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_W: + X = EXTRACT_LONG(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_B: + k = X + pc->k; + if ((int32)k>= (int32)mem_ex->size) { + return 0; + } + A= mem_ex->buffer[k]; + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_H: + k = X + pc->k; + if ((int32)(k+1)>= (int32)mem_ex->size) { + return 0; + } + A=EXTRACT_SHORT((uint32*)&mem_ex->buffer[k]); + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_W: + k = X + pc->k; + if ((int32)(k+3)>= (int32)mem_ex->size) { + return 0; + } + A=EXTRACT_LONG((uint32*)&mem_ex->buffer[k]); + continue; + /* END LD NO PACKET INSTRUCTIONS */ + +#endif //HAVE_BUGGY_TME_SUPPORT + + case BPF_ST: + mem[pc->k] = A; + continue; + + case BPF_STX: + mem[pc->k] = X; + continue; + +#ifdef HAVE_BUGGY_TME_SUPPORT + // + // these instructions use the TME extensions, + // not supported on x86-64 and IA64 architectures. + // + + /* STORE INSTRUCTIONS */ + + case BPF_ST|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)A; + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)X; + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_W: + tmp=A; + *(uint32*)&(mem_ex->buffer[pc->k])=EXTRACT_LONG(&tmp); + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_W: + tmp=X; + *(uint32*)&(mem_ex->buffer[pc->k])=EXTRACT_LONG(&tmp); + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16)A; + *(uint16*)&mem_ex->buffer[pc->k]=EXTRACT_SHORT(&tmp2); + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16)X; + *(uint16*)&mem_ex->buffer[pc->k]=EXTRACT_SHORT(&tmp2); + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_B: + mem_ex->buffer[pc->k+X]=(uint8)A; + + case BPF_ST|BPF_MEM_EX_IND|BPF_W: + tmp=A; + *(uint32*)&mem_ex->buffer[pc->k+X]=EXTRACT_LONG(&tmp); + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_H: + tmp2=(uint16)A; + *(uint16*)&mem_ex->buffer[pc->k+X]=EXTRACT_SHORT(&tmp2); + continue; + + /* END STORE INSTRUCTIONS */ + +#endif //HAVE_BUGGY_TME_SUPPORT + + case BPF_JMP|BPF_JA: + pc += pc->k; + continue; + + case BPF_JMP|BPF_JGT|BPF_K: + pc += ((int)A > (int)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_K: + pc += ((int)A >= (int)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_K: + pc += ((int)A == (int)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? pc->jt : pc->jf; + continue; + + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + + case BPF_ALU|BPF_LSH|BPF_X: + A <<= X; + continue; + + case BPF_ALU|BPF_RSH|BPF_X: + A >>= X; + continue; + + case BPF_ALU|BPF_ADD|BPF_K: + A += pc->k; + continue; + + case BPF_ALU|BPF_SUB|BPF_K: + A -= pc->k; + continue; + + case BPF_ALU|BPF_MUL|BPF_K: + A *= pc->k; + continue; + + case BPF_ALU|BPF_DIV|BPF_K: + A /= pc->k; + continue; + + case BPF_ALU|BPF_AND|BPF_K: + A &= pc->k; + continue; + + case BPF_ALU|BPF_OR|BPF_K: + A |= pc->k; + continue; + + case BPF_ALU|BPF_LSH|BPF_K: + A <<= pc->k; + continue; + + case BPF_ALU|BPF_RSH|BPF_K: + A >>= pc->k; + continue; + + case BPF_ALU|BPF_NEG: + (int)A = -((int)A); + continue; + + case BPF_MISC|BPF_TAX: + X = A; + continue; + + case BPF_MISC|BPF_TXA: + A = X; + continue; + +#ifdef HAVE_BUGGY_TME_SUPPORT + // + // these instructions use the TME extensions, + // not supported on x86-64 and IA64 architectures. + // + + /* TME INSTRUCTIONS */ + + case BPF_MISC|BPF_TME|BPF_LOOKUP: + j=lookup_frontend(mem_ex,tme,pc->k,time_ref); + if (j==TME_ERROR) + return 0; + pc += (j == TME_TRUE) ? pc->jt : pc->jf; + continue; + + case BPF_MISC|BPF_TME|BPF_EXECUTE: + if (execute_frontend(mem_ex,tme,wirelen,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_ACTIVE: + if (set_active_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_GET_REGISTER_VALUE: + if (get_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,&j)==TME_ERROR) + return 0; + A=j; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_REGISTER_VALUE: + if (set_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,A,FALSE)==TME_ERROR) + return 0; + continue; + + /* END TME INSTRUCTIONS */ +#endif //HAVE_BUGGY_TME_SUPPORT + + + } + } +} + +//------------------------------------------------------------------- + +#ifdef HAVE_BUGGY_TME_SUPPORT +u_int bpf_filter_with_2_buffers(pc, p, pd, headersize, wirelen, buflen, mem_ex,tme,time_ref) + register struct bpf_insn *pc; + register u_char *p; + register u_char *pd; + register int headersize; + u_int wirelen; + register u_int buflen; + PMEM_TYPE mem_ex; + PTME_CORE tme; + struct time_conv *time_ref; +#else //HAVE_BUGGY_TME_SUPPORT +u_int bpf_filter_with_2_buffers(pc, p, pd, headersize, wirelen, buflen) + register struct bpf_insn *pc; + register u_char *p; + register u_char *pd; + register int headersize; + u_int wirelen; + register u_int buflen; +#endif //HAVE_BUGGY_TME_SUPPORT + { + register u_int32 A, X; + register int k; + int mem[BPF_MEMWORDS]; +#ifdef HAVE_BUGGY_TME_SUPPORT + u_int32 j,tmp; + u_short tmp2; +#endif //HAVE_BUGGY_TME_SUPPORT + + RtlZeroMemory(mem, sizeof(mem)); + + if (pc == 0) + /* + * No filter means accept all. + */ + return (u_int)-1; + A = 0; + X = 0; + --pc; + while (1) { + ++pc; + switch (pc->code) { + + default: + + return 0; + + case BPF_RET|BPF_K: + return (u_int)pc->k; + + case BPF_RET|BPF_A: + return (u_int)A; + + case BPF_LD|BPF_W|BPF_ABS: + k = pc->k; + if (k + 4 > (int)buflen) { + return 0; + } + + if(k + 4 <= headersize) + A = EXTRACT_LONG(&p[k]); + else if(k + 3 == headersize) + { + A= (u_int32)*((u_char *)p+k)<<24| + (u_int32)*((u_char *)p+k+1)<<16| + (u_int32)*((u_char *)p+k+2)<<8| + (u_int32)*((u_char *)pd+k-headersize); + } + else if(k + 2 == headersize) + { + A= (u_int32)*((u_char *)p+k)<<24| + (u_int32)*((u_char *)p+k+1)<<16| + (u_int32)*((u_char *)pd+k-headersize)<<8| + (u_int32)*((u_char *)pd+k-headersize+1); + } + else if(k + 1 == headersize){ + A= (u_int32)*((u_char *)p+k)<<24| + (u_int32)*((u_char *)pd+k-headersize+1)<<16| + (u_int32)*((u_char *)pd+k-headersize+2)<<8| + (u_int32)*((u_char *)pd+k-headersize+3); + } + else + A = EXTRACT_LONG(&pd[k-headersize]); + + continue; + + case BPF_LD|BPF_H|BPF_ABS: + k = pc->k; + if (k + sizeof(short) > buflen) + { + return 0; + } + + if(k + 2 <= headersize) + A = EXTRACT_SHORT(&p[k]); + else if(k + 1 == headersize) + { + A= (u_short)*((u_char *)p+k)<<8| + (u_short)*((u_char *)pd+k-headersize); + } + else + A = EXTRACT_SHORT(&pd[k-headersize]); + + continue; + + case BPF_LD|BPF_B|BPF_ABS: + k = pc->k; + if ((int)k >= (int)buflen) { + return 0; + } + + if(k +(int) sizeof(char) <= headersize) + A = p[k]; + else + A = pd[k-headersize]; + + continue; + + case BPF_LD|BPF_W|BPF_LEN: + A = wirelen; + continue; + + case BPF_LDX|BPF_W|BPF_LEN: + X = wirelen; + continue; + + case BPF_LD|BPF_W|BPF_IND: + k = X + pc->k; + if (k + sizeof(int) > buflen) { + return 0; + } + + if(k + 4 <= headersize) + A = EXTRACT_LONG(&p[k]); + else if(k + 3 == headersize) + { + A= (u_int32)*((u_char *)p+k)<<24| + (u_int32)*((u_char *)p+k+1)<<16| + (u_int32)*((u_char *)p+k+2)<<8| + (u_int32)*((u_char *)pd+k-headersize); + } + else if(k + 2 == headersize) + { + A= (u_int32)*((u_char *)p+k)<<24| + (u_int32)*((u_char *)p+k+1)<<16| + (u_int32)*((u_char *)pd+k-headersize)<<8| + (u_int32)*((u_char *)pd+k-headersize+1); + } + else if(k + 1 == headersize) + { + A= (u_int32)*((u_char *)p+k)<<24| + (u_int32)*((u_char *)pd+k-headersize+1)<<16| + (u_int32)*((u_char *)pd+k-headersize+2)<<8| + (u_int32)*((u_char *)pd+k-headersize+3); + } + else + A = EXTRACT_LONG(&pd[k-headersize]); + + continue; + + case BPF_LD|BPF_H|BPF_IND: + k = X + pc->k; + if (k + 2 > (int)buflen) { + return 0; + } + + if(k + 2 <= headersize) + A = EXTRACT_SHORT(&p[k]); + else if(k +1 == headersize) + { + A= (u_short)*((u_char *)p+k)<<8| + (u_short)*((u_char *)pd+k-headersize); + } + else + A = EXTRACT_SHORT(&pd[k-headersize]); + + continue; + + case BPF_LD|BPF_B|BPF_IND: + k = X + pc->k; + if ((int)k >= (int)buflen) { + return 0; + } + + if( k + 1 <= headersize) + A = p[k]; + else + A = pd[k-headersize]; + + continue; + + case BPF_LDX|BPF_MSH|BPF_B: + k = pc->k; + if ((int)k >= (int)buflen) { + return 0; + } + + if( k + 1 <= headersize) + X = (p[k] & 0xf) << 2; + else + X = (pd[k-headersize] & 0xf) << 2; + + continue; + + case BPF_LD|BPF_IMM: + A = pc->k; + continue; + + case BPF_LDX|BPF_IMM: + X = pc->k; + continue; + + case BPF_LD|BPF_MEM: + A = mem[pc->k]; + continue; + + case BPF_LDX|BPF_MEM: + X = mem[pc->k]; + continue; + +#ifdef HAVE_BUGGY_TME_SUPPORT + // + // these instructions use the TME extensions, + // not supported on x86-64 and IA64 architectures. + // + + /* LD NO PACKET INSTRUCTIONS */ + + case BPF_LD|BPF_MEM_EX_IMM|BPF_B: + A= mem_ex->buffer[pc->k]; + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_B: + X= mem_ex->buffer[pc->k]; + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_H: + A = EXTRACT_SHORT(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_H: + X = EXTRACT_SHORT(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_W: + A = EXTRACT_LONG(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_W: + X = EXTRACT_LONG(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_B: + k = X + pc->k; + if ((int32)k>= (int32)mem_ex->size) { + return 0; + } + A= mem_ex->buffer[k]; + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_H: + k = X + pc->k; + if ((int32)(k+1)>= (int32)mem_ex->size) { + return 0; + } + A=EXTRACT_SHORT((uint32*)&mem_ex->buffer[k]); + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_W: + k = X + pc->k; + if ((int32)(k+3)>= (int32)mem_ex->size) { + return 0; + } + A=EXTRACT_LONG((uint32*)&mem_ex->buffer[k]); + continue; + + /* END LD NO PACKET INSTRUCTIONS */ + +#endif //HAVE_BUGGY_TME_SUPPORT + + case BPF_ST: + mem[pc->k] = A; + continue; + + case BPF_STX: + mem[pc->k] = X; + continue; + +#ifdef HAVE_BUGGY_TME_SUPPORT + // + // these instructions use the TME extensions, + // not supported on x86-64 and IA64 architectures. + // + + /* STORE INSTRUCTIONS */ + + case BPF_ST|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)A; + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)X; + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_W: + tmp=A; + *(uint32*)&(mem_ex->buffer[pc->k])=EXTRACT_LONG(&tmp); + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_W: + tmp=X; + *(uint32*)&(mem_ex->buffer[pc->k])=EXTRACT_LONG(&tmp); + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16)A; + *(uint16*)&mem_ex->buffer[pc->k]=EXTRACT_SHORT(&tmp2); + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16)X; + *(uint16*)&mem_ex->buffer[pc->k]=EXTRACT_SHORT(&tmp2); + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_B: + mem_ex->buffer[pc->k+X]=(uint8)A; + + case BPF_ST|BPF_MEM_EX_IND|BPF_W: + tmp=A; + *(uint32*)&mem_ex->buffer[pc->k+X]=EXTRACT_LONG(&tmp); + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_H: + tmp2=(uint16)A; + *(uint16*)&mem_ex->buffer[pc->k+X]=EXTRACT_SHORT(&tmp2); + continue; + + /* END STORE INSTRUCTIONS */ + +#endif //HAVE_BUGGY_TME_SUPPORT + + case BPF_JMP|BPF_JA: + pc += pc->k; + continue; + + case BPF_JMP|BPF_JGT|BPF_K: + pc += ((int)A > (int)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_K: + pc += ((int)A >= (int)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_K: + pc += ((int)A == (int)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? pc->jt : pc->jf; + continue; + + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + + case BPF_ALU|BPF_LSH|BPF_X: + A <<= X; + continue; + + case BPF_ALU|BPF_RSH|BPF_X: + A >>= X; + continue; + + case BPF_ALU|BPF_ADD|BPF_K: + A += pc->k; + continue; + + case BPF_ALU|BPF_SUB|BPF_K: + A -= pc->k; + continue; + + case BPF_ALU|BPF_MUL|BPF_K: + A *= pc->k; + continue; + + case BPF_ALU|BPF_DIV|BPF_K: + A /= pc->k; + continue; + + case BPF_ALU|BPF_AND|BPF_K: + A &= pc->k; + continue; + + case BPF_ALU|BPF_OR|BPF_K: + A |= pc->k; + continue; + + case BPF_ALU|BPF_LSH|BPF_K: + A <<= pc->k; + continue; + + case BPF_ALU|BPF_RSH|BPF_K: + A >>= pc->k; + continue; + + case BPF_ALU|BPF_NEG: + (int)A = -((int)A); + continue; + + case BPF_MISC|BPF_TAX: + X = A; + continue; + + case BPF_MISC|BPF_TXA: + A = X; + continue; + +#ifdef HAVE_BUGGY_TME_SUPPORT + // + // these instructions use the TME extensions, + // not supported on x86-64 and IA64 architectures. + // + + /* TME INSTRUCTIONS */ + + case BPF_MISC|BPF_TME|BPF_LOOKUP: + j=lookup_frontend(mem_ex,tme,pc->k,time_ref); + if (j==TME_ERROR) + return 0; + pc += (j == TME_TRUE) ? pc->jt : pc->jf; + continue; + + case BPF_MISC|BPF_TME|BPF_EXECUTE: + if (execute_frontend(mem_ex,tme,wirelen,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_ACTIVE: + if (set_active_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_GET_REGISTER_VALUE: + if (get_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,&j)==TME_ERROR) + return 0; + A=j; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_REGISTER_VALUE: + if (set_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,A,FALSE)==TME_ERROR) + return 0; + continue; + + /* END TME INSTRUCTIONS */ + +#endif //HAVE_BUGGY_TME_SUPPORT + + } + } +} + +#ifdef HAVE_BUGGY_TME_SUPPORT +int +bpf_validate(f, len,mem_ex_size) + struct bpf_insn *f; + int len; + uint32 mem_ex_size; +#else +int +bpf_validate(f, len) + struct bpf_insn *f; + int len; +#endif //HAVE_BUGGY_TME_SUPPORT + { + register u_int32 i, from; + register int j; + register struct bpf_insn *p; + int flag; + + if (len < 1) + return 0; + + for (i = 0; i < (u_int32)len; ++i) { + p = &f[i]; + + TRACE_MESSAGE(PACKET_DEBUG_LOUD,"Validating program"); + + flag=0; + for(j=0;jcode==valid_instructions[j]) + flag=1; + if (flag==0) + return 0; + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Validating program: no unknown instructions"); + + switch (BPF_CLASS(p->code)) { + /* + * Check that memory operations use valid addresses. + */ + case BPF_LD: + case BPF_LDX: + switch (BPF_MODE(p->code)) { + case BPF_IMM: + break; + case BPF_ABS: + case BPF_IND: + case BPF_MSH: + break; + case BPF_MEM: + if (p->k >= BPF_MEMWORDS) + return 0; + break; + case BPF_LEN: + break; + default: + return 0; + } + + TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Validating program: no wrong LD memory locations"); + break; + + case BPF_ST: + case BPF_STX: + +#ifdef HAVE_BUGGY_TME_SUPPORT + // + // these instructions use the TME extensions, + // not supported on x86-64 and IA64 architectures. + // + if ((p->code &BPF_MEM_EX_IMM) == BPF_MEM_EX_IMM) + { + /* + * Check if key stores use valid addresses + */ + switch (BPF_SIZE(p->code)) { + + case BPF_W: + if (p->k+3 >= mem_ex_size) + return 0; + break; + + case BPF_H: + if (p->k+1 >= mem_ex_size) + return 0; + break; + + case BPF_B: + if (p->k >= mem_ex_size) + return 0; + break; + } + } + else + { + if ((p->code & BPF_MEM_EX_IND) != BPF_MEM_EX_IND) + { + if (p->k >= BPF_MEMWORDS) + return 0; + } + } +#else // ! HAVE_BUGGY_TME_SUPPORT + if (p->k >= BPF_MEMWORDS) + return 0; +#endif // HAVE_BUGGY_TME_SUPPORT + + TRACE_MESSAGE(PACKET_DEBUG_LOUD,"Validating program: no wrong ST memory locations"); + break; + + case BPF_ALU: + switch (BPF_OP(p->code)) { + case BPF_ADD: + case BPF_SUB: + case BPF_MUL: + case BPF_OR: + case BPF_AND: + case BPF_LSH: + case BPF_RSH: + case BPF_NEG: + break; + case BPF_DIV: + /* + * Check for constant division by 0. + */ + if (BPF_SRC(p->code) == BPF_K && p->k == 0) + return 0; + break; + default: + return 0; + } + break; + case BPF_JMP: + /* + * Check that jumps are within the code block, + * and that unconditional branches don't go + * backwards as a result of an overflow. + * Unconditional branches have a 32-bit offset, + * so they could overflow; we check to make + * sure they don't. Conditional branches have + * an 8-bit offset, and the from address is <= + * BPF_MAXINSNS, and we assume that BPF_MAXINSNS + * is sufficiently small that adding 255 to it + * won't overflow. + * + * We know that len is <= BPF_MAXINSNS, and we + * assume that BPF_MAXINSNS is < the maximum size + * of a u_int, so that i + 1 doesn't overflow. + */ + from = i + 1; + switch (BPF_OP(p->code)) { + case BPF_JA: + if (from + p->k < from || from + p->k >= (u_int32)len) + return 0; + break; + case BPF_JEQ: + case BPF_JGT: + case BPF_JGE: + case BPF_JSET: + if (from + p->jt >= (u_int32)len || from + p->jf >= (u_int32)len) + return 0; + break; + default: + return 0; + } + IF_LOUD(DbgPrint("Validating program: no wrong JUMPS");) + break; + case BPF_RET: + break; + case BPF_MISC: + break; + default: + return 0; + } + } + return BPF_CLASS(f[len - 1].code) == BPF_RET; +} \ No newline at end of file diff --git a/drivers/3rdparty/npf/win_bpf_filter_init.c b/drivers/3rdparty/npf/win_bpf_filter_init.c new file mode 100644 index 0000000000000..36a496120e6be --- /dev/null +++ b/drivers/3rdparty/npf/win_bpf_filter_init.c @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "tme.h" +#include "win_bpf.h" + +#pragma warning(disable : 4131) //old style function declaration +#pragma warning(disable : 4127) // conditional expr is constant (used for while(1) loops) +#pragma warning(disable : 4213) //cast on l-value + +/* + * Initialize the filter machine + */ +uint32 bpf_filter_init(register struct bpf_insn *pc, MEM_TYPE *mem_ex, TME_CORE *tme, struct time_conv *time_ref) +{ + register uint32 A, X; + int32 mem[BPF_MEMWORDS]; + register int32 k; + uint32 *tmp; + uint16 *tmp2; + uint32 j; + if (pc == 0) + /* + * No filter means accept all. + */ + return (uint32)-1; + + RtlZeroMemory(mem, sizeof(mem)); + + A = 0; + X = 0; + --pc; + while (1) { + ++pc; + switch (pc->code) { + + default: + return 0; + +/* RET INSTRUCTIONS */ + case BPF_RET|BPF_K: + return (uint32)pc->k; + + case BPF_RET|BPF_A: + return (uint32)A; +/* END RET INSTRUCTIONS */ + +/* LD NO PACKET INSTRUCTIONS */ + case BPF_LD|BPF_IMM: + A = pc->k; + continue; + + case BPF_LDX|BPF_IMM: + X = pc->k; + continue; + + case BPF_LD|BPF_MEM: + A = mem[pc->k]; + continue; + + case BPF_LDX|BPF_MEM: + X = mem[pc->k]; + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_B: + A= mem_ex->buffer[pc->k]; + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_B: + X= mem_ex->buffer[pc->k]; + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k]; + __asm + { + push eax + push ebx + mov ebx,tmp2 + xor eax, eax + mov ax, [ebx] + bswap eax + mov A, eax + pop ebx + pop eax + } + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k]; + __asm + { + push eax + push ebx + mov ebx,tmp2 + xor eax, eax + mov ax, [ebx] + bswap eax + mov X, eax + pop ebx + pop eax + } + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k]; + __asm + { + push eax + push ebx + mov ebx,tmp + mov eax, [ebx] + bswap eax + mov A, eax + pop ebx + pop eax + } + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k]; + __asm + { + push eax + push ebx + mov ebx,tmp + mov eax, [ebx] + bswap eax + mov X, eax + pop ebx + pop eax + } + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_B: + k = X + pc->k; + if ((int32)k>= (int32)mem_ex->size) { + return 0; + } + A= mem_ex->buffer[k]; + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_H: + k = X + pc->k; + if ((int32)(k+1)>= (int32)mem_ex->size) { + return 0; + } + tmp2=(uint16*)&mem_ex->buffer[k]; + __asm + { + push eax + push ebx + mov ebx,tmp2 + xor eax, eax + mov ax, [ebx] + bswap eax + mov A, eax + pop ebx + pop eax + } + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_W: + k = X + pc->k; + if ((int32)(k+3)>= (int32)mem_ex->size) { + return 0; + } + tmp=(uint32*)&mem_ex->buffer[k]; + __asm + { + push eax + push ebx + mov ebx,tmp + mov eax, [ebx] + bswap eax + mov A, eax + pop ebx + pop eax + } + continue; +/* END LD NO PACKET INSTRUCTIONS */ + +/* STORE INSTRUCTIONS */ + case BPF_ST: + mem[pc->k] = A; + continue; + + case BPF_STX: + mem[pc->k] = X; + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)A; + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)X; + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k]; + __asm + { + push eax + push ebx + mov ebx, tmp + mov eax, A + bswap eax + mov [ebx], eax + pop ebx + pop eax + } + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k]; + __asm + { + push eax + push ebx + mov ebx, tmp + mov eax, X + bswap eax + mov [ebx], eax + pop ebx + pop eax + } + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k]; + __asm + { + push eax + push ebx + mov ebx, tmp2 + mov eax, A + xchg ah, al + mov [ebx], ax + pop ebx + pop eax + } + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k]; + __asm + { + push eax + push ebx + mov ebx, tmp2 + mov eax, X + xchg ah, al + mov [ebx], ax + pop ebx + pop eax + } + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_B: + mem_ex->buffer[pc->k+X]=(uint8)A; + + case BPF_ST|BPF_MEM_EX_IND|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k+X]; + __asm + { + push eax + push ebx + mov ebx, tmp + mov eax, A + bswap eax + mov [ebx], eax + pop ebx + pop eax + } + + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k+X]; + __asm + { + push eax + push ebx + mov ebx, tmp2 + mov eax, A + xchg ah, al + mov [ebx], ax + pop ebx + pop eax + } + continue; +/* END STORE INSTRUCTIONS */ + +/* JUMP INSTRUCTIONS */ + case BPF_JMP|BPF_JA: + pc += pc->k; + continue; + + case BPF_JMP|BPF_JGT|BPF_K: + pc += ((int32)A > (int32)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_K: + pc += ((int32)A >= (int32)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_K: + pc += ((int32)A == (int32)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? pc->jt : pc->jf; + continue; +/* END JUMP INSTRUCTIONS */ + +/* ARITHMETIC INSTRUCTIONS */ + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + + case BPF_ALU|BPF_LSH|BPF_X: + A <<= X; + continue; + + case BPF_ALU|BPF_RSH|BPF_X: + A >>= X; + continue; + + case BPF_ALU|BPF_ADD|BPF_K: + A += pc->k; + continue; + + case BPF_ALU|BPF_SUB|BPF_K: + A -= pc->k; + continue; + + case BPF_ALU|BPF_MUL|BPF_K: + A *= pc->k; + continue; + + case BPF_ALU|BPF_DIV|BPF_K: + A /= pc->k; + continue; + + case BPF_ALU|BPF_AND|BPF_K: + A &= pc->k; + continue; + + case BPF_ALU|BPF_OR|BPF_K: + A |= pc->k; + continue; + + case BPF_ALU|BPF_LSH|BPF_K: + A <<= pc->k; + continue; + + case BPF_ALU|BPF_RSH|BPF_K: + A >>= pc->k; + continue; + + case BPF_ALU|BPF_NEG: + (int32)A = -((int32)A); + continue; +/* ARITHMETIC INSTRUCTIONS */ + +/* MISC INSTRUCTIONS */ + case BPF_MISC|BPF_TAX: + X = A; + continue; + + case BPF_MISC|BPF_TXA: + A = X; + continue; +/* END MISC INSTRUCTIONS */ + +/* TME INSTRUCTIONS */ + case BPF_MISC|BPF_TME|BPF_LOOKUP: + j=lookup_frontend(mem_ex,tme,pc->k,time_ref); + if (j==TME_ERROR) + return 0; + pc += (j == TME_TRUE) ? pc->jt : pc->jf; + continue; + + case BPF_MISC|BPF_TME|BPF_EXECUTE: + if (execute_frontend(mem_ex,tme,0,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_INIT: + if (init_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_VALIDATE: + if (validate_tme_block(mem_ex,tme,A,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_MEMORY: + if (init_extended_memory(pc->k,mem_ex)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_ACTIVE: + if (set_active_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_ACTIVE_READ: + if (set_active_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + case BPF_MISC|BPF_TME|BPF_SET_WORKING: + if (pc->k>=MAX_TME_DATA_BLOCKS) + return 0; + tme->working=pc->k; + continue; + + + + case BPF_MISC|BPF_TME|BPF_RESET: + if (reset_tme(tme)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_GET_REGISTER_VALUE: + if (get_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,&j)==TME_ERROR) + return 0; + A=j; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_REGISTER_VALUE: + if (set_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,A,TRUE)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_AUTODELETION: + set_autodeletion(&tme->block_data[tme->working],pc->k); + continue; + +/* END TME INSTRUCTIONS */ + + } + } +} + diff --git a/drivers/3rdparty/npf/win_bpf_filter_init.h b/drivers/3rdparty/npf/win_bpf_filter_init.h new file mode 100644 index 0000000000000..20de2b1b29bce --- /dev/null +++ b/drivers/3rdparty/npf/win_bpf_filter_init.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2001 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __FILTER_INIT +#define __FILTER_INIT + +#include "tme.h" + +#define INIT_OK 1 +#define INIT_ERROR 0 + +#ifdef __cplusplus +extern "C" +{ +#endif +uint32 bpf_filter_init(register struct bpf_insn *pc,MEM_TYPE *mem_ex, TME_CORE *tme, struct time_conv *time_ref); +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file