Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

428 lines
11 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. verify.c
  5. Abstract:
  6. verifer support routines for Ndis wrapper
  7. Author:
  8. Alireza Dabagh (alid) 8-9-1999
  9. Environment:
  10. Kernel mode, FSD
  11. Revision History:
  12. 8-9-99 alid: initial version
  13. --*/
  14. #include <precomp.h>
  15. #pragma hdrstop
  16. #define MODULE_NUMBER MODULE_VERIFY
  17. LARGE_INTEGER VerifierRequiredTimeSinceBoot = {(ULONG)(40 * 1000 * 1000 * 10), 1};
  18. #define VERIFIERFUNC(pfn) ((PDRIVER_VERIFIER_THUNK_ROUTINE)(pfn))
  19. const DRIVER_VERIFIER_THUNK_PAIRS ndisVerifierFunctionTable[] =
  20. {
  21. {VERIFIERFUNC(NdisAllocateMemory ), VERIFIERFUNC(ndisVerifierAllocateMemory)},
  22. {VERIFIERFUNC(NdisAllocateMemoryWithTag ), VERIFIERFUNC(ndisVerifierAllocateMemoryWithTag)},
  23. {VERIFIERFUNC(NdisAllocatePacketPool ), VERIFIERFUNC(ndisVerifierAllocatePacketPool)},
  24. {VERIFIERFUNC(NdisAllocatePacketPoolEx ), VERIFIERFUNC(ndisVerifierAllocatePacketPoolEx)},
  25. {VERIFIERFUNC(NdisFreePacketPool ), VERIFIERFUNC(ndisVerifierFreePacketPool)},
  26. {VERIFIERFUNC(NdisQueryMapRegisterCount ), VERIFIERFUNC(ndisVerifierQueryMapRegisterCount)},
  27. {VERIFIERFUNC(NdisFreeMemory ), VERIFIERFUNC(ndisVerifierFreeMemory)}
  28. };
  29. BOOLEAN
  30. ndisVerifierInitialization(
  31. VOID
  32. )
  33. {
  34. NTSTATUS Status;
  35. BOOLEAN cr = FALSE;
  36. ULONG Level;
  37. Status = MmIsVerifierEnabled (&Level);
  38. if (NT_SUCCESS(Status))
  39. {
  40. ndisVerifierLevel = Level;
  41. //
  42. // combine what we read from registry for ndis with the global flags
  43. //
  44. if (ndisFlags & NDIS_GFLAG_INJECT_ALLOCATION_FAILURE)
  45. ndisVerifierLevel |= DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES;
  46. if (ndisFlags & NDIS_GFLAG_SPECIAL_POOL_ALLOCATION)
  47. ndisVerifierLevel |= DRIVER_VERIFIER_SPECIAL_POOLING;
  48. Status = MmAddVerifierThunks ((VOID *) ndisVerifierFunctionTable,
  49. sizeof(ndisVerifierFunctionTable));
  50. if (NT_SUCCESS(Status))
  51. {
  52. InitializeListHead(&ndisMiniportTrackAllocList);
  53. InitializeListHead(&ndisDriverTrackAllocList);
  54. INITIALIZE_SPIN_LOCK(&ndisTrackMemLock);
  55. cr = TRUE;
  56. }
  57. }
  58. return cr;
  59. }
  60. NDIS_STATUS
  61. ndisVerifierAllocateMemory(
  62. OUT PVOID * VirtualAddress,
  63. IN UINT Length,
  64. IN UINT MemoryFlags,
  65. IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
  66. )
  67. {
  68. PVOID Address;
  69. #if DBG
  70. if ((ndisFlags & NDIS_GFLAG_WARNING_LEVEL_MASK) >= NDIS_GFLAG_WARN_LEVEL_1)
  71. {
  72. DbgPrint("Driver is using NdisAllocateMemory instead of NdisAllocateMemoryWithTag\n");
  73. if (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING)
  74. DbgBreakPoint();
  75. }
  76. #endif
  77. if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
  78. {
  79. Length += sizeof(NDIS_TRACK_MEM);
  80. }
  81. ndisFlags |= NDIS_GFLAG_ABORT_TRACK_MEM_ALLOCATION;
  82. ndisMiniportTrackAlloc = NULL;
  83. ndisDriverTrackAlloc = NULL;
  84. if (ndisVerifierInjectResourceFailure(TRUE))
  85. {
  86. Address = NULL;
  87. }
  88. else
  89. {
  90. if (MemoryFlags != 0)
  91. {
  92. NdisAllocateMemory(
  93. &Address,
  94. Length,
  95. MemoryFlags,
  96. HighestAcceptableAddress);
  97. }
  98. else
  99. {
  100. if (ndisVerifierLevel & DRIVER_VERIFIER_SPECIAL_POOLING)
  101. {
  102. Address = ExAllocatePoolWithTagPriority(
  103. NonPagedPool,
  104. Length,
  105. NDIS_TAG_ALLOC_MEM_VERIFY_ON,
  106. NormalPoolPrioritySpecialPoolOverrun); // most common problem
  107. }
  108. else
  109. {
  110. Address = ALLOC_FROM_POOL(Length, NDIS_TAG_ALLOC_MEM);
  111. }
  112. }
  113. }
  114. *VirtualAddress = Address;
  115. if ((Address != NULL) && (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION))
  116. {
  117. *VirtualAddress = (PVOID)((PUCHAR)Address + sizeof(NDIS_TRACK_MEM));
  118. }
  119. return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
  120. }
  121. NDIS_STATUS
  122. ndisVerifierAllocateMemoryWithTag(
  123. OUT PVOID * VirtualAddress,
  124. IN UINT Length,
  125. IN ULONG Tag
  126. )
  127. {
  128. PVOID Caller, CallersCaller;
  129. PVOID Address;
  130. PNDIS_TRACK_MEM TrackMem;
  131. KIRQL OldIrql;
  132. if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
  133. {
  134. RtlGetCallersAddress(&Caller, &CallersCaller);
  135. Length += sizeof(NDIS_TRACK_MEM);
  136. }
  137. if (ndisVerifierInjectResourceFailure(TRUE))
  138. {
  139. Address = NULL;
  140. }
  141. else
  142. {
  143. if (ndisVerifierLevel & DRIVER_VERIFIER_SPECIAL_POOLING)
  144. {
  145. Address = ExAllocatePoolWithTagPriority(
  146. NonPagedPool,
  147. Length,
  148. Tag,
  149. NormalPoolPrioritySpecialPoolOverrun); // most common problem
  150. }
  151. else
  152. {
  153. Address = ALLOC_FROM_POOL(Length, Tag);
  154. }
  155. }
  156. if ((Address != NULL) && (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION))
  157. {
  158. *VirtualAddress = (PVOID)((PUCHAR)Address + sizeof(NDIS_TRACK_MEM));
  159. TrackMem = (PNDIS_TRACK_MEM)Address;
  160. RtlZeroMemory(TrackMem, sizeof(NDIS_TRACK_MEM));
  161. TrackMem->Tag = Tag;
  162. TrackMem->Length = Length;
  163. TrackMem->Caller = Caller;
  164. TrackMem->CallersCaller = CallersCaller;
  165. ACQUIRE_SPIN_LOCK(&ndisTrackMemLock, &OldIrql);
  166. if (ndisMiniportTrackAlloc)
  167. {
  168. //
  169. // charge it against miniport
  170. //
  171. InsertHeadList(&ndisMiniportTrackAllocList, &TrackMem->List);
  172. }
  173. else
  174. {
  175. //
  176. // charge it against driver
  177. //
  178. InsertHeadList(&ndisDriverTrackAllocList, &TrackMem->List);
  179. }
  180. RELEASE_SPIN_LOCK(&ndisTrackMemLock, OldIrql);
  181. }
  182. else
  183. {
  184. *VirtualAddress = Address;
  185. }
  186. return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
  187. }
  188. VOID
  189. ndisVerifierAllocatePacketPool(
  190. OUT PNDIS_STATUS Status,
  191. OUT PNDIS_HANDLE PoolHandle,
  192. IN UINT NumberOfDescriptors,
  193. IN UINT ProtocolReservedLength
  194. )
  195. {
  196. PVOID Caller, CallersCaller;
  197. RtlGetCallersAddress(&Caller, &CallersCaller);
  198. if (ndisVerifierInjectResourceFailure(TRUE))
  199. {
  200. *PoolHandle = NULL;
  201. *Status = NDIS_STATUS_RESOURCES;
  202. }
  203. else
  204. {
  205. NdisAllocatePacketPool(
  206. Status,
  207. PoolHandle,
  208. NumberOfDescriptors,
  209. ProtocolReservedLength);
  210. if (*Status == NDIS_STATUS_SUCCESS)
  211. {
  212. PNDIS_PKT_POOL Pool = *PoolHandle;
  213. Pool->Allocator = Caller;
  214. }
  215. }
  216. }
  217. VOID
  218. ndisVerifierAllocatePacketPoolEx(
  219. OUT PNDIS_STATUS Status,
  220. OUT PNDIS_HANDLE PoolHandle,
  221. IN UINT NumberOfDescriptors,
  222. IN UINT NumberOfOverflowDescriptors,
  223. IN UINT ProtocolReservedLength
  224. )
  225. {
  226. PVOID Caller, CallersCaller;
  227. RtlGetCallersAddress(&Caller, &CallersCaller);
  228. if (ndisVerifierInjectResourceFailure(TRUE))
  229. {
  230. *PoolHandle = NULL;
  231. *Status = NDIS_STATUS_RESOURCES;
  232. }
  233. else
  234. {
  235. NdisAllocatePacketPoolEx(
  236. Status,
  237. PoolHandle,
  238. NumberOfDescriptors,
  239. NumberOfOverflowDescriptors,
  240. ProtocolReservedLength);
  241. if (*Status == NDIS_STATUS_SUCCESS)
  242. {
  243. PNDIS_PKT_POOL Pool = *PoolHandle;
  244. Pool->Allocator = Caller;
  245. }
  246. }
  247. }
  248. VOID
  249. ndisVerifierFreePacketPool(
  250. IN NDIS_HANDLE PoolHandle
  251. )
  252. {
  253. ndisFreePacketPool(PoolHandle, TRUE);
  254. }
  255. BOOLEAN
  256. ndisVerifierInjectResourceFailure(
  257. BOOLEAN fDelayFailure
  258. )
  259. /*++
  260. Routine Description:
  261. This function determines whether a resource allocation should be
  262. deliberately failed. This may be a pool allocation, MDL creation,
  263. system PTE allocation, etc.
  264. Arguments:
  265. None.
  266. Return Value:
  267. TRUE if the allocation should be failed. FALSE otherwise.
  268. Environment:
  269. Kernel mode. DISPATCH_LEVEL or below.
  270. --*/
  271. {
  272. LARGE_INTEGER CurrentTime;
  273. if (!(ndisVerifierLevel & DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES))
  274. {
  275. return FALSE;
  276. }
  277. if (fDelayFailure)
  278. {
  279. //
  280. // Don't fail any requests in the first 7 or 8 minutes as we want to
  281. // give the system enough time to boot.
  282. //
  283. if (VerifierSystemSufficientlyBooted == FALSE)
  284. {
  285. KeQuerySystemTime (&CurrentTime);
  286. if (CurrentTime.QuadPart > KeBootTime.QuadPart + VerifierRequiredTimeSinceBoot.QuadPart)
  287. {
  288. VerifierSystemSufficientlyBooted = TRUE;
  289. }
  290. }
  291. }
  292. if (!fDelayFailure || (VerifierSystemSufficientlyBooted == TRUE))
  293. {
  294. KeQueryTickCount(&CurrentTime);
  295. if ((CurrentTime.LowPart & 0x7) == 0)
  296. {
  297. //
  298. // Deliberately fail this request.
  299. //
  300. InterlockedIncrement(&ndisVeriferFailedAllocations);
  301. return TRUE;
  302. }
  303. }
  304. return FALSE;
  305. }
  306. NDIS_STATUS
  307. ndisVerifierQueryMapRegisterCount(
  308. IN NDIS_INTERFACE_TYPE BusType,
  309. OUT PUINT MapRegisterCount
  310. )
  311. {
  312. #if DBG
  313. DbgPrint("NdisQueryMapRegisterCount: Driver is using an obsolete API.\n");
  314. if (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING)
  315. DbgBreakPoint();
  316. #endif
  317. *MapRegisterCount = 0;
  318. return NDIS_STATUS_NOT_SUPPORTED;
  319. }
  320. VOID
  321. ndisVerifierFreeMemory(
  322. IN PVOID VirtualAddress,
  323. IN UINT Length,
  324. IN UINT MemoryFlags
  325. )
  326. {
  327. if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
  328. {
  329. PNDIS_TRACK_MEM TrackMem;
  330. KIRQL OldIrql;
  331. Length += sizeof(NDIS_TRACK_MEM);
  332. VirtualAddress = (PVOID)((PUCHAR)VirtualAddress - sizeof(NDIS_TRACK_MEM));
  333. TrackMem = (PNDIS_TRACK_MEM)VirtualAddress;
  334. if(!(ndisFlags & NDIS_GFLAG_ABORT_TRACK_MEM_ALLOCATION))
  335. {
  336. ACQUIRE_SPIN_LOCK(&ndisTrackMemLock, &OldIrql);
  337. RemoveEntryList(&TrackMem->List);
  338. RELEASE_SPIN_LOCK(&ndisTrackMemLock, OldIrql);
  339. }
  340. }
  341. NdisFreeMemory(VirtualAddress, Length, MemoryFlags);
  342. }