windows-nt/Source/XPSP1/NT/net/ndis/sys/verify.c
2020-09-26 16:20:57 +08:00

429 lines
11 KiB
C

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
verify.c
Abstract:
verifer support routines for Ndis wrapper
Author:
Alireza Dabagh (alid) 8-9-1999
Environment:
Kernel mode, FSD
Revision History:
8-9-99 alid: initial version
--*/
#include <precomp.h>
#pragma hdrstop
#define MODULE_NUMBER MODULE_VERIFY
LARGE_INTEGER VerifierRequiredTimeSinceBoot = {(ULONG)(40 * 1000 * 1000 * 10), 1};
#define VERIFIERFUNC(pfn) ((PDRIVER_VERIFIER_THUNK_ROUTINE)(pfn))
const DRIVER_VERIFIER_THUNK_PAIRS ndisVerifierFunctionTable[] =
{
{VERIFIERFUNC(NdisAllocateMemory ), VERIFIERFUNC(ndisVerifierAllocateMemory)},
{VERIFIERFUNC(NdisAllocateMemoryWithTag ), VERIFIERFUNC(ndisVerifierAllocateMemoryWithTag)},
{VERIFIERFUNC(NdisAllocatePacketPool ), VERIFIERFUNC(ndisVerifierAllocatePacketPool)},
{VERIFIERFUNC(NdisAllocatePacketPoolEx ), VERIFIERFUNC(ndisVerifierAllocatePacketPoolEx)},
{VERIFIERFUNC(NdisFreePacketPool ), VERIFIERFUNC(ndisVerifierFreePacketPool)},
{VERIFIERFUNC(NdisQueryMapRegisterCount ), VERIFIERFUNC(ndisVerifierQueryMapRegisterCount)},
{VERIFIERFUNC(NdisFreeMemory ), VERIFIERFUNC(ndisVerifierFreeMemory)}
};
BOOLEAN
ndisVerifierInitialization(
VOID
)
{
NTSTATUS Status;
BOOLEAN cr = FALSE;
ULONG Level;
Status = MmIsVerifierEnabled (&Level);
if (NT_SUCCESS(Status))
{
ndisVerifierLevel = Level;
//
// combine what we read from registry for ndis with the global flags
//
if (ndisFlags & NDIS_GFLAG_INJECT_ALLOCATION_FAILURE)
ndisVerifierLevel |= DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES;
if (ndisFlags & NDIS_GFLAG_SPECIAL_POOL_ALLOCATION)
ndisVerifierLevel |= DRIVER_VERIFIER_SPECIAL_POOLING;
Status = MmAddVerifierThunks ((VOID *) ndisVerifierFunctionTable,
sizeof(ndisVerifierFunctionTable));
if (NT_SUCCESS(Status))
{
InitializeListHead(&ndisMiniportTrackAllocList);
InitializeListHead(&ndisDriverTrackAllocList);
INITIALIZE_SPIN_LOCK(&ndisTrackMemLock);
cr = TRUE;
}
}
return cr;
}
NDIS_STATUS
ndisVerifierAllocateMemory(
OUT PVOID * VirtualAddress,
IN UINT Length,
IN UINT MemoryFlags,
IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
)
{
PVOID Address;
#if DBG
if ((ndisFlags & NDIS_GFLAG_WARNING_LEVEL_MASK) >= NDIS_GFLAG_WARN_LEVEL_1)
{
DbgPrint("Driver is using NdisAllocateMemory instead of NdisAllocateMemoryWithTag\n");
if (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING)
DbgBreakPoint();
}
#endif
if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
{
Length += sizeof(NDIS_TRACK_MEM);
}
ndisFlags |= NDIS_GFLAG_ABORT_TRACK_MEM_ALLOCATION;
ndisMiniportTrackAlloc = NULL;
ndisDriverTrackAlloc = NULL;
if (ndisVerifierInjectResourceFailure(TRUE))
{
Address = NULL;
}
else
{
if (MemoryFlags != 0)
{
NdisAllocateMemory(
&Address,
Length,
MemoryFlags,
HighestAcceptableAddress);
}
else
{
if (ndisVerifierLevel & DRIVER_VERIFIER_SPECIAL_POOLING)
{
Address = ExAllocatePoolWithTagPriority(
NonPagedPool,
Length,
NDIS_TAG_ALLOC_MEM_VERIFY_ON,
NormalPoolPrioritySpecialPoolOverrun); // most common problem
}
else
{
Address = ALLOC_FROM_POOL(Length, NDIS_TAG_ALLOC_MEM);
}
}
}
*VirtualAddress = Address;
if ((Address != NULL) && (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION))
{
*VirtualAddress = (PVOID)((PUCHAR)Address + sizeof(NDIS_TRACK_MEM));
}
return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
ndisVerifierAllocateMemoryWithTag(
OUT PVOID * VirtualAddress,
IN UINT Length,
IN ULONG Tag
)
{
PVOID Caller, CallersCaller;
PVOID Address;
PNDIS_TRACK_MEM TrackMem;
KIRQL OldIrql;
if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
{
RtlGetCallersAddress(&Caller, &CallersCaller);
Length += sizeof(NDIS_TRACK_MEM);
}
if (ndisVerifierInjectResourceFailure(TRUE))
{
Address = NULL;
}
else
{
if (ndisVerifierLevel & DRIVER_VERIFIER_SPECIAL_POOLING)
{
Address = ExAllocatePoolWithTagPriority(
NonPagedPool,
Length,
Tag,
NormalPoolPrioritySpecialPoolOverrun); // most common problem
}
else
{
Address = ALLOC_FROM_POOL(Length, Tag);
}
}
if ((Address != NULL) && (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION))
{
*VirtualAddress = (PVOID)((PUCHAR)Address + sizeof(NDIS_TRACK_MEM));
TrackMem = (PNDIS_TRACK_MEM)Address;
RtlZeroMemory(TrackMem, sizeof(NDIS_TRACK_MEM));
TrackMem->Tag = Tag;
TrackMem->Length = Length;
TrackMem->Caller = Caller;
TrackMem->CallersCaller = CallersCaller;
ACQUIRE_SPIN_LOCK(&ndisTrackMemLock, &OldIrql);
if (ndisMiniportTrackAlloc)
{
//
// charge it against miniport
//
InsertHeadList(&ndisMiniportTrackAllocList, &TrackMem->List);
}
else
{
//
// charge it against driver
//
InsertHeadList(&ndisDriverTrackAllocList, &TrackMem->List);
}
RELEASE_SPIN_LOCK(&ndisTrackMemLock, OldIrql);
}
else
{
*VirtualAddress = Address;
}
return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
}
VOID
ndisVerifierAllocatePacketPool(
OUT PNDIS_STATUS Status,
OUT PNDIS_HANDLE PoolHandle,
IN UINT NumberOfDescriptors,
IN UINT ProtocolReservedLength
)
{
PVOID Caller, CallersCaller;
RtlGetCallersAddress(&Caller, &CallersCaller);
if (ndisVerifierInjectResourceFailure(TRUE))
{
*PoolHandle = NULL;
*Status = NDIS_STATUS_RESOURCES;
}
else
{
NdisAllocatePacketPool(
Status,
PoolHandle,
NumberOfDescriptors,
ProtocolReservedLength);
if (*Status == NDIS_STATUS_SUCCESS)
{
PNDIS_PKT_POOL Pool = *PoolHandle;
Pool->Allocator = Caller;
}
}
}
VOID
ndisVerifierAllocatePacketPoolEx(
OUT PNDIS_STATUS Status,
OUT PNDIS_HANDLE PoolHandle,
IN UINT NumberOfDescriptors,
IN UINT NumberOfOverflowDescriptors,
IN UINT ProtocolReservedLength
)
{
PVOID Caller, CallersCaller;
RtlGetCallersAddress(&Caller, &CallersCaller);
if (ndisVerifierInjectResourceFailure(TRUE))
{
*PoolHandle = NULL;
*Status = NDIS_STATUS_RESOURCES;
}
else
{
NdisAllocatePacketPoolEx(
Status,
PoolHandle,
NumberOfDescriptors,
NumberOfOverflowDescriptors,
ProtocolReservedLength);
if (*Status == NDIS_STATUS_SUCCESS)
{
PNDIS_PKT_POOL Pool = *PoolHandle;
Pool->Allocator = Caller;
}
}
}
VOID
ndisVerifierFreePacketPool(
IN NDIS_HANDLE PoolHandle
)
{
ndisFreePacketPool(PoolHandle, TRUE);
}
BOOLEAN
ndisVerifierInjectResourceFailure(
BOOLEAN fDelayFailure
)
/*++
Routine Description:
This function determines whether a resource allocation should be
deliberately failed. This may be a pool allocation, MDL creation,
system PTE allocation, etc.
Arguments:
None.
Return Value:
TRUE if the allocation should be failed. FALSE otherwise.
Environment:
Kernel mode. DISPATCH_LEVEL or below.
--*/
{
LARGE_INTEGER CurrentTime;
if (!(ndisVerifierLevel & DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES))
{
return FALSE;
}
if (fDelayFailure)
{
//
// Don't fail any requests in the first 7 or 8 minutes as we want to
// give the system enough time to boot.
//
if (VerifierSystemSufficientlyBooted == FALSE)
{
KeQuerySystemTime (&CurrentTime);
if (CurrentTime.QuadPart > KeBootTime.QuadPart + VerifierRequiredTimeSinceBoot.QuadPart)
{
VerifierSystemSufficientlyBooted = TRUE;
}
}
}
if (!fDelayFailure || (VerifierSystemSufficientlyBooted == TRUE))
{
KeQueryTickCount(&CurrentTime);
if ((CurrentTime.LowPart & 0x7) == 0)
{
//
// Deliberately fail this request.
//
InterlockedIncrement(&ndisVeriferFailedAllocations);
return TRUE;
}
}
return FALSE;
}
NDIS_STATUS
ndisVerifierQueryMapRegisterCount(
IN NDIS_INTERFACE_TYPE BusType,
OUT PUINT MapRegisterCount
)
{
#if DBG
DbgPrint("NdisQueryMapRegisterCount: Driver is using an obsolete API.\n");
if (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING)
DbgBreakPoint();
#endif
*MapRegisterCount = 0;
return NDIS_STATUS_NOT_SUPPORTED;
}
VOID
ndisVerifierFreeMemory(
IN PVOID VirtualAddress,
IN UINT Length,
IN UINT MemoryFlags
)
{
if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
{
PNDIS_TRACK_MEM TrackMem;
KIRQL OldIrql;
Length += sizeof(NDIS_TRACK_MEM);
VirtualAddress = (PVOID)((PUCHAR)VirtualAddress - sizeof(NDIS_TRACK_MEM));
TrackMem = (PNDIS_TRACK_MEM)VirtualAddress;
if(!(ndisFlags & NDIS_GFLAG_ABORT_TRACK_MEM_ALLOCATION))
{
ACQUIRE_SPIN_LOCK(&ndisTrackMemLock, &OldIrql);
RemoveEntryList(&TrackMem->List);
RELEASE_SPIN_LOCK(&ndisTrackMemLock, OldIrql);
}
}
NdisFreeMemory(VirtualAddress, Length, MemoryFlags);
}