|
|
/*++
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); }
|