Leaked source code of windows server 2003
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.

1367 lines
45 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. spxmem.c
  5. Abstract:
  6. This module contains code which implements the memory allocation wrappers.
  7. Author:
  8. Nikhil Kamkolkar (nikhilk) 11-November-1993
  9. Jameel Hyder (jameelh) Initial Version
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text( INIT, SpxInitMemorySystem)
  18. #pragma alloc_text( PAGE, SpxDeInitMemorySystem)
  19. #endif
  20. #if !defined SPX_OWN_PACKETS
  21. typedef struct NdisResEntry {
  22. struct NdisResEntry *nre_next;
  23. NDIS_HANDLE nre_handle;
  24. uchar *nre_buffer;
  25. } NdisResEntry;
  26. NdisResEntry *SendPacketPoolList = NULL;
  27. SLIST_HEADER SendPacketList;
  28. NdisResEntry *RecvPacketPoolList = NULL;
  29. SLIST_HEADER RecvPacketList;
  30. DEFINE_LOCK_STRUCTURE(SendHeaderLock);
  31. DEFINE_LOCK_STRUCTURE(RecvHeaderLock);
  32. uint CurrentSendPacketCount = 0;
  33. uint CurrentRecvPacketCount = 0;
  34. uint MaxPacketCount = 0x0ffffff;
  35. #define PACKET_GROW_COUNT 16
  36. #endif // SPX_OWN_PACKETS
  37. // Define module number for event logging entries
  38. #define FILENUM SPXMEM
  39. // Globals for this module
  40. // Some block sizes (like NDISSEND/NDISRECV are filled in after binding with IPX)
  41. USHORT spxBlkSize[NUM_BLKIDS] = // Size of each block
  42. {
  43. sizeof(BLK_HDR)+sizeof(TIMERLIST), // BLKID_TIMERLIST
  44. 0, // BLKID_NDISSEND
  45. 0 // BLKID_NDISRECV
  46. };
  47. USHORT spxChunkSize[NUM_BLKIDS] = // Size of each Chunk
  48. {
  49. 512-BC_OVERHEAD, // BLKID_TIMERLIST
  50. 512-BC_OVERHEAD, // BLKID_NDISSEND
  51. 512-BC_OVERHEAD // BLKID_NDISRECV
  52. };
  53. // Filled in after binding with IPX
  54. // Reference for below.
  55. // ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
  56. // (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
  57. USHORT spxNumBlks[NUM_BLKIDS] = // Number of blocks per chunk
  58. {
  59. ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
  60. (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
  61. 0, // BLKID_NDISSEND
  62. 0 // BLKID_NDISRECV
  63. };
  64. CTELock spxBPLock[NUM_BLKIDS] = { 0 };
  65. PBLK_CHUNK spxBPHead[NUM_BLKIDS] = { 0 };
  66. NTSTATUS
  67. SpxInitMemorySystem(
  68. IN PDEVICE pSpxDevice
  69. )
  70. /*++
  71. Routine Description:
  72. !!! MUST BE CALLED AFTER BINDING TO IPX!!!
  73. Arguments:
  74. Return Value:
  75. --*/
  76. {
  77. LONG i;
  78. NDIS_STATUS ndisStatus;
  79. // Try to allocate the ndis buffer pool.
  80. NdisAllocateBufferPool(
  81. &ndisStatus,
  82. &pSpxDevice->dev_NdisBufferPoolHandle,
  83. 20);
  84. if (ndisStatus != NDIS_STATUS_SUCCESS)
  85. return(STATUS_INSUFFICIENT_RESOURCES);
  86. for (i = 0; i < NUM_BLKIDS; i++)
  87. CTEInitLock (&spxBPLock[i]);
  88. // Set the sizes in the block id info arrays.
  89. for (i = 0; i < NUM_BLKIDS; i++)
  90. {
  91. switch (i)
  92. {
  93. case BLKID_NDISSEND:
  94. #ifdef SPX_OWN_PACKETS
  95. spxBlkSize[i] = sizeof(BLK_HDR) +
  96. sizeof(SPX_SEND_RESD) +
  97. NDIS_PACKET_SIZE +
  98. IpxMacHdrNeeded +
  99. MIN_IPXSPX2_HDRSIZE;
  100. #else
  101. spxBlkSize[i] = sizeof(PNDIS_PACKET);
  102. #endif
  103. //
  104. // Round the block size up to the next 8-byte boundary.
  105. //
  106. spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
  107. // Set number blocks
  108. spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
  109. break;
  110. case BLKID_NDISRECV:
  111. #ifdef SPX_OWN_PACKETS
  112. spxBlkSize[i] = sizeof(BLK_HDR) +
  113. sizeof(SPX_RECV_RESD) +
  114. NDIS_PACKET_SIZE;
  115. #else
  116. spxBlkSize[i] = sizeof(PNDIS_PACKET);
  117. #endif
  118. //
  119. // Round the block size up to the next 8-byte boundary.
  120. //
  121. spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
  122. // Set number blocks
  123. spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
  124. break;
  125. default:
  126. break;
  127. }
  128. }
  129. SpxTimerScheduleEvent((TIMER_ROUTINE)spxBPAgePool,
  130. BLOCK_POOL_TIMER,
  131. NULL);
  132. return STATUS_SUCCESS;
  133. }
  134. VOID
  135. SpxDeInitMemorySystem(
  136. IN PDEVICE pSpxDevice
  137. )
  138. /*++
  139. Routine Description:
  140. Arguments:
  141. Return Value:
  142. --*/
  143. {
  144. LONG i, j, NumBlksPerChunk;
  145. PBLK_CHUNK pChunk, pFree;
  146. for (i = 0; i < NUM_BLKIDS; i++)
  147. {
  148. NumBlksPerChunk = spxNumBlks[i];
  149. for (pChunk = spxBPHead[i];
  150. pChunk != NULL; )
  151. {
  152. DBGPRINT(RESOURCES, ERR,
  153. ("SpxInitMemorySystem: Freeing %lx\n", pChunk));
  154. CTEAssert (pChunk->bc_NumFrees == NumBlksPerChunk);
  155. if ((pChunk->bc_BlkId == BLKID_NDISSEND) ||
  156. (pChunk->bc_BlkId == BLKID_NDISRECV))
  157. {
  158. PBLK_HDR pBlkHdr;
  159. // We need to free the Ndis stuff for these guys
  160. for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
  161. j < NumBlksPerChunk;
  162. j++, pBlkHdr = pBlkHdr->bh_Next)
  163. {
  164. PNDIS_PACKET pNdisPkt;
  165. PNDIS_BUFFER pNdisBuffer;
  166. #ifdef SPX_OWN_PACKETS
  167. // Only need to free the ndis buffer.
  168. pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
  169. if (pChunk->bc_BlkId == BLKID_NDISSEND)
  170. {
  171. NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
  172. if (pNdisBuffer == NULL)
  173. {
  174. // Something is terribly awry.
  175. KeBugCheck(0);
  176. }
  177. NdisFreeBuffer(pNdisBuffer);
  178. //
  179. // Free the second MDL also
  180. //
  181. NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
  182. if (pNdisBuffer == NULL)
  183. {
  184. // Something is terribly awry.
  185. KeBugCheck(0);
  186. }
  187. NdisFreeBuffer(pNdisBuffer);
  188. }
  189. #else
  190. /* // Need to free both the packet and the buffer.
  191. pNdisPkt = (PNDIS_PACKET *)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
  192. if (pChunk->bc_BlkId == BLKID_NDISSEND)
  193. {
  194. NdisUnchainBufferAtFront(*pNdisPkt, &pNdisBuffer);
  195. if (pNdisBuffer == NULL)
  196. {
  197. // Something is terribly awry.
  198. KeBugCheck(0);
  199. }
  200. NdisFreeBuffer(pNdisBuffer);
  201. }
  202. NdisFreePacket(*pNdisPkt);
  203. */
  204. #endif
  205. }
  206. }
  207. pFree = pChunk;
  208. pChunk = pChunk->bc_Next;
  209. #ifndef SPX_OWN_PACKETS
  210. /*
  211. // Free the ndis packet pool in chunk
  212. NdisFreePacketPool((NDIS_HANDLE)pFree->bc_ChunkCtx); */
  213. #endif
  214. SpxFreeMemory(pFree);
  215. }
  216. }
  217. // Free up the ndis buffer pool
  218. NdisFreeBufferPool(
  219. pSpxDevice->dev_NdisBufferPoolHandle);
  220. return;
  221. }
  222. PVOID
  223. SpxAllocMem(
  224. #ifdef TRACK_MEMORY_USAGE
  225. IN ULONG Size,
  226. IN ULONG FileLine
  227. #else
  228. IN ULONG Size
  229. #endif // TRACK_MEMORY_USAGE
  230. )
  231. /*++
  232. Routine Description:
  233. Allocate a block of non-paged memory. This is just a wrapper over ExAllocPool.
  234. Allocation failures are error-logged. We always allocate a ULONG more than
  235. the specified size to accomodate the size. This is used by SpxFreeMemory
  236. to update the statistics.
  237. Arguments:
  238. Return Value:
  239. --*/
  240. {
  241. PBYTE pBuf;
  242. BOOLEAN zeroed;
  243. // round up the size so that we can put a signature at the end
  244. // that is on a LARGE_INTEGER boundary
  245. zeroed = ((Size & ZEROED_MEMORY_TAG) == ZEROED_MEMORY_TAG);
  246. Size = QWORDSIZEBLOCK(Size & ~ZEROED_MEMORY_TAG);
  247. // Do the actual memory allocation. Allocate eight extra bytes so
  248. // that we can store the size of the allocation for the free routine
  249. // and still keep the buffer quadword aligned.
  250. if ((pBuf = ExAllocatePoolWithTag(NonPagedPool, Size + sizeof(LARGE_INTEGER)
  251. #if DBG
  252. + sizeof(ULONG)
  253. #endif
  254. ,SPX_TAG)) == NULL)
  255. {
  256. DBGPRINT(RESOURCES, FATAL,
  257. ("SpxAllocMemory: failed - size %lx\n", Size));
  258. TMPLOGERR();
  259. return NULL;
  260. }
  261. // Save the size of this block in the four extra bytes we allocated.
  262. *((PULONG)pBuf) = (Size + sizeof(LARGE_INTEGER));
  263. // Return a pointer to the memory after the size longword.
  264. pBuf += sizeof(LARGE_INTEGER);
  265. #if DBG
  266. *((PULONG)(pBuf+Size)) = SPX_MEMORY_SIGNATURE;
  267. DBGPRINT(RESOURCES, INFO,
  268. ("SpxAllocMemory: %p Allocated %lx bytes @%p\n",
  269. _ReturnAddress(), Size, pBuf));
  270. #endif
  271. SpxTrackMemoryUsage((PVOID)(pBuf - sizeof(LARGE_INTEGER)), TRUE, FileLine);
  272. if (zeroed)
  273. RtlZeroMemory(pBuf, Size);
  274. return (pBuf);
  275. }
  276. VOID
  277. SpxFreeMemory(
  278. IN PVOID pBuf
  279. )
  280. /*++
  281. Routine Description:
  282. Free the block of memory allocated via SpxAllocMemory. This is
  283. a wrapper around ExFreePool.
  284. Arguments:
  285. Return Value:
  286. --*/
  287. {
  288. PULONG pRealBuffer;
  289. // Get a pointer to the block allocated by ExAllocatePool --
  290. // we allocate a LARGE_INTEGER at the front.
  291. pRealBuffer = ((PULONG)pBuf - 2);
  292. SpxTrackMemoryUsage(pRealBuffer, FALSE, 0);
  293. #if DBG
  294. // Check the signature at the end
  295. if (*(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer)
  296. != SPX_MEMORY_SIGNATURE)
  297. {
  298. DBGPRINT(RESOURCES, FATAL,
  299. ("SpxFreeMemory: Memory overrun on block %lx\n", pRealBuffer));
  300. DBGBRK(FATAL);
  301. }
  302. *(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer) = 0;
  303. #endif
  304. #if DBG
  305. *pRealBuffer = 0;
  306. #endif
  307. // Free the pool and return.
  308. ExFreePool(pRealBuffer);
  309. }
  310. #ifdef TRACK_MEMORY_USAGE
  311. #define MAX_PTR_COUNT 4*1024
  312. #define MAX_MEM_USERS 512
  313. CTELock spxMemTrackLock = {0};
  314. CTELockHandle lockHandle = {0};
  315. struct
  316. {
  317. PVOID mem_Ptr;
  318. ULONG mem_FileLine;
  319. } spxMemPtrs[MAX_PTR_COUNT] = {0};
  320. struct
  321. {
  322. ULONG mem_FL;
  323. ULONG mem_Count;
  324. } spxMemUsage[MAX_MEM_USERS] = {0};
  325. VOID
  326. SpxTrackMemoryUsage(
  327. IN PVOID pMem,
  328. IN BOOLEAN Alloc,
  329. IN ULONG FileLine
  330. )
  331. /*++
  332. Routine Description:
  333. Keep track of memory usage by storing and clearing away pointers as and
  334. when they are allocated or freed. This helps in keeping track of memory
  335. leaks.
  336. Arguments:
  337. Return Value:
  338. --*/
  339. {
  340. static int i = 0;
  341. int j, k;
  342. CTEGetLock (&spxMemTrackLock, &lockHandle);
  343. if (Alloc)
  344. {
  345. for (j = 0; j < MAX_PTR_COUNT; i++, j++)
  346. {
  347. i = i & (MAX_PTR_COUNT-1);
  348. if (spxMemPtrs[i].mem_Ptr == NULL)
  349. {
  350. spxMemPtrs[i].mem_Ptr = pMem;
  351. spxMemPtrs[i++].mem_FileLine = FileLine;
  352. break;
  353. }
  354. }
  355. for (k = 0; k < MAX_MEM_USERS; k++)
  356. {
  357. if (spxMemUsage[k].mem_FL == FileLine)
  358. {
  359. spxMemUsage[k].mem_Count ++;
  360. break;
  361. }
  362. }
  363. if (k == MAX_MEM_USERS)
  364. {
  365. for (k = 0; k < MAX_MEM_USERS; k++)
  366. {
  367. if (spxMemUsage[k].mem_FL == 0)
  368. {
  369. spxMemUsage[k].mem_FL = FileLine;
  370. spxMemUsage[k].mem_Count = 1;
  371. break;
  372. }
  373. }
  374. }
  375. if (k == MAX_MEM_USERS)
  376. {
  377. DBGPRINT(RESOURCES, ERR,
  378. ("SpxTrackMemoryUsage: Out of space on spxMemUsage !!!\n"));
  379. DBGBRK(FATAL);
  380. }
  381. }
  382. else
  383. {
  384. for (j = 0, k = i; j < MAX_PTR_COUNT; j++, k--)
  385. {
  386. k = k & (MAX_PTR_COUNT-1);
  387. if (spxMemPtrs[k].mem_Ptr == pMem)
  388. {
  389. spxMemPtrs[k].mem_Ptr = 0;
  390. spxMemPtrs[k].mem_FileLine = 0;
  391. break;
  392. }
  393. }
  394. }
  395. CTEFreeLock (&spxMemTrackLock, lockHandle);
  396. if (j == MAX_PTR_COUNT)
  397. {
  398. DBGPRINT(RESOURCES, ERR,
  399. ("SpxTrackMemoryUsage: %s\n", Alloc ? "Table Full" : "Can't find"));
  400. DBGBRK(FATAL);
  401. }
  402. }
  403. #endif // TRACK_MEMORY_USAGE
  404. PVOID
  405. SpxBPAllocBlock(
  406. IN BLKID BlockId
  407. )
  408. /*++
  409. Routine Description:
  410. Alloc a block of memory from the block pool package. This is written to speed up
  411. operations where a lot of small fixed size allocations/frees happen. Going to
  412. ExAllocPool() in these cases is expensive.
  413. Arguments:
  414. Return Value:
  415. --*/
  416. {
  417. PBLK_HDR pBlk = NULL;
  418. PBLK_CHUNK pChunk, *ppChunkHead;
  419. USHORT BlkSize;
  420. CTELockHandle lockHandle;
  421. PSPX_SEND_RESD pSendResd;
  422. PSPX_RECV_RESD pRecvResd;
  423. PNDIS_PACKET pNdisPkt;
  424. PNDIS_BUFFER pNdisBuffer;
  425. PNDIS_BUFFER pNdisIpxSpxBuffer;
  426. CTEAssert (BlockId < NUM_BLKIDS);
  427. if (BlockId < NUM_BLKIDS)
  428. {
  429. BlkSize = spxBlkSize[BlockId];
  430. ppChunkHead = &spxBPHead[BlockId];
  431. CTEGetLock(&spxBPLock[BlockId], &lockHandle);
  432. for (pChunk = *ppChunkHead;
  433. pChunk != NULL;
  434. pChunk = pChunk->bc_Next)
  435. {
  436. CTEAssert(pChunk->bc_BlkId == BlockId);
  437. if (pChunk->bc_NumFrees > 0)
  438. {
  439. DBGPRINT(SYSTEM, INFO,
  440. ("SpxBPAllocBlock: Found space in Chunk %lx\n", pChunk));
  441. #ifdef PROFILING
  442. InterlockedIncrement( &SpxStatistics.stat_NumBPHits);
  443. #endif
  444. break;
  445. }
  446. }
  447. if (pChunk == NULL)
  448. {
  449. DBGPRINT(SYSTEM, INFO,
  450. ("SpxBPAllocBlock: Allocating a new chunk for Id %d\n", BlockId));
  451. #ifdef PROFILING
  452. InterlockedIncrement( &SpxStatistics.stat_NumBPMisses);
  453. #endif
  454. pChunk = SpxAllocateMemory(spxChunkSize[BlockId]);
  455. if (pChunk != NULL)
  456. {
  457. LONG i, j;
  458. PBLK_HDR pBlkHdr;
  459. USHORT NumBlksPerChunk;
  460. NumBlksPerChunk = spxNumBlks[BlockId];
  461. pChunk->bc_NumFrees = NumBlksPerChunk;
  462. pChunk->bc_BlkId = BlockId;
  463. pChunk->bc_FreeHead = (PBLK_HDR)((PBYTE)pChunk + sizeof(BLK_CHUNK));
  464. DBGPRINT(SYSTEM, INFO,
  465. ("SpxBPAllocBlock: Initializing chunk %lx\n", pChunk));
  466. // Initialize the blocks in the chunk
  467. for (i = 0, pBlkHdr = pChunk->bc_FreeHead;
  468. i < NumBlksPerChunk;
  469. i++, pBlkHdr = pBlkHdr->bh_Next)
  470. {
  471. NDIS_STATUS ndisStatus;
  472. pBlkHdr->bh_Next = (PBLK_HDR)((PBYTE)pBlkHdr + BlkSize);
  473. if (BlockId == BLKID_NDISSEND)
  474. {
  475. PBYTE pHdrMem;
  476. #ifdef SPX_OWN_PACKETS
  477. // Point to the ndis packet,initialize it.
  478. pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
  479. NdisReinitializePacket(pNdisPkt);
  480. // Allocate a ndis buffer descriptor describing hdr memory
  481. // and queue it in.
  482. pHdrMem = (PBYTE)pNdisPkt +
  483. NDIS_PACKET_SIZE +
  484. sizeof(SPX_SEND_RESD);
  485. NdisAllocateBuffer(
  486. &ndisStatus,
  487. &pNdisBuffer,
  488. SpxDevice->dev_NdisBufferPoolHandle,
  489. pHdrMem,
  490. IpxMacHdrNeeded);
  491. if (ndisStatus != NDIS_STATUS_SUCCESS)
  492. {
  493. break;
  494. }
  495. // Link the buffer descriptor into the packet descriptor
  496. NdisChainBufferAtBack(
  497. pNdisPkt,
  498. pNdisBuffer);
  499. NdisAllocateBuffer(
  500. &ndisStatus,
  501. &pNdisIpxSpxBuffer,
  502. SpxDevice->dev_NdisBufferPoolHandle,
  503. pHdrMem + IpxMacHdrNeeded,
  504. MIN_IPXSPX2_HDRSIZE);
  505. if (ndisStatus != NDIS_STATUS_SUCCESS)
  506. {
  507. break;
  508. }
  509. // Link the buffer descriptor into the packet descriptor
  510. NdisChainBufferAtBack(
  511. pNdisPkt,
  512. pNdisIpxSpxBuffer);
  513. pSendResd = (PSPX_SEND_RESD)pNdisPkt->ProtocolReserved;
  514. //#else
  515. // Allocate a ndis packet pool for this chunk
  516. // NdisAllocatePacketPool();
  517. // etc.
  518. // Initialize elements of the protocol reserved structure.
  519. pSendResd->sr_Id = IDENTIFIER_SPX;
  520. pSendResd->sr_Reserved1 = NULL;
  521. pSendResd->sr_Reserved2 = NULL;
  522. pSendResd->sr_State = SPX_SENDPKT_IDLE;
  523. #endif
  524. }
  525. else if (BlockId == BLKID_NDISRECV)
  526. {
  527. #ifdef SPX_OWN_PACKETS
  528. // Point to the ndis packet,initialize it.
  529. pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
  530. NdisReinitializePacket(pNdisPkt);
  531. pRecvResd = (PSPX_RECV_RESD)pNdisPkt->ProtocolReserved;
  532. //#else
  533. // Allocate a ndis packet pool for this chunk
  534. // NdisAllocatePacketPool();
  535. // etc.
  536. // Initialize elements of the protocol reserved structure.
  537. pRecvResd->rr_Id = IDENTIFIER_SPX;
  538. pRecvResd->rr_State = SPX_RECVPKT_IDLE;
  539. #endif
  540. }
  541. }
  542. if (i != NumBlksPerChunk)
  543. {
  544. // This has to be a failure from Ndis for send blocks!!!
  545. // Undo a bunch of stuff
  546. CTEAssert (BlockId == BLKID_NDISSEND);
  547. pBlkHdr = pChunk->bc_FreeHead;
  548. for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
  549. j < i; j++, pBlkHdr = pBlkHdr->bh_Next)
  550. {
  551. NdisUnchainBufferAtFront(
  552. (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
  553. &pNdisBuffer);
  554. CTEAssert(pNdisBuffer != NULL);
  555. NdisFreeBuffer(pNdisBuffer);
  556. NdisUnchainBufferAtFront(
  557. (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
  558. &pNdisIpxSpxBuffer);
  559. if (pNdisIpxSpxBuffer)
  560. {
  561. NdisFreeBuffer(pNdisIpxSpxBuffer);
  562. }
  563. }
  564. SpxFreeMemory(pChunk);
  565. pChunk = NULL;
  566. }
  567. else
  568. {
  569. // Successfully initialized the chunk, link it in
  570. pChunk->bc_Next = *ppChunkHead;
  571. *ppChunkHead = pChunk;
  572. }
  573. }
  574. }
  575. if (pChunk != NULL)
  576. {
  577. CTEAssert(pChunk->bc_BlkId == BlockId);
  578. DBGPRINT(RESOURCES, INFO,
  579. ("SpxBPAllocBlock: Allocating a block out of chunk %lx(%d) for Id %d\n",
  580. pChunk, pChunk->bc_NumFrees, BlockId));
  581. pChunk->bc_NumFrees --;
  582. pChunk->bc_Age = 0; // Reset age
  583. pBlk = pChunk->bc_FreeHead;
  584. pChunk->bc_FreeHead = pBlk->bh_Next;
  585. pBlk->bh_pChunk = pChunk;
  586. // Skip the block header!
  587. pBlk++;
  588. }
  589. CTEFreeLock(&spxBPLock[BlockId], lockHandle);
  590. }
  591. return pBlk;
  592. }
  593. VOID
  594. SpxBPFreeBlock(
  595. IN PVOID pBlock,
  596. IN BLKID BlockId
  597. )
  598. /*++
  599. Routine Description:
  600. Return a block to its owning chunk.
  601. Arguments:
  602. Return Value:
  603. --*/
  604. {
  605. PBLK_CHUNK pChunk;
  606. PBLK_HDR pBlkHdr = (PBLK_HDR)((PCHAR)pBlock - sizeof(BLK_HDR));
  607. CTELockHandle lockHandle;
  608. CTEGetLock(&spxBPLock[BlockId], &lockHandle);
  609. for (pChunk = spxBPHead[BlockId];
  610. pChunk != NULL;
  611. pChunk = pChunk->bc_Next)
  612. {
  613. CTEAssert(pChunk->bc_BlkId == BlockId);
  614. if (pBlkHdr->bh_pChunk == pChunk)
  615. {
  616. DBGPRINT(SYSTEM, INFO,
  617. ("SpxBPFreeBlock: Returning Block %lx to chunk %lx for Id %d\n",
  618. pBlkHdr, pChunk, BlockId));
  619. CTEAssert (pChunk->bc_NumFrees < spxNumBlks[BlockId]);
  620. pChunk->bc_NumFrees ++;
  621. pBlkHdr->bh_Next = pChunk->bc_FreeHead;
  622. pChunk->bc_FreeHead = pBlkHdr;
  623. break;
  624. }
  625. }
  626. CTEAssert ((pChunk != NULL) && (pChunk->bc_FreeHead == pBlkHdr));
  627. CTEFreeLock(&spxBPLock[BlockId], lockHandle);
  628. return;
  629. }
  630. ULONG
  631. spxBPAgePool(
  632. IN PVOID Context,
  633. IN BOOLEAN TimerShuttingDown
  634. )
  635. /*++
  636. Routine Description:
  637. Age out the block pool of unused blocks
  638. Arguments:
  639. Return Value:
  640. --*/
  641. {
  642. PBLK_CHUNK pChunk, *ppChunk, pFree = NULL;
  643. LONG i, j, NumBlksPerChunk;
  644. CTELockHandle lockHandle;
  645. PNDIS_PACKET pNdisPkt;
  646. PNDIS_BUFFER pNdisBuffer;
  647. if (TimerShuttingDown)
  648. {
  649. return TIMER_DONT_REQUEUE;
  650. }
  651. for (i = 0; i < NUM_BLKIDS; i++)
  652. {
  653. NumBlksPerChunk = spxNumBlks[i];
  654. CTEGetLock(&spxBPLock[i], &lockHandle);
  655. for (ppChunk = &spxBPHead[i];
  656. (pChunk = *ppChunk) != NULL; )
  657. {
  658. if ((pChunk->bc_NumFrees == NumBlksPerChunk) &&
  659. (++(pChunk->bc_Age) >= MAX_BLOCK_POOL_AGE))
  660. {
  661. DBGPRINT(SYSTEM, INFO,
  662. ("spxBPAgePool: freeing Chunk %lx, Id %d\n",
  663. pChunk, pChunk->bc_BlkId));
  664. *ppChunk = pChunk->bc_Next;
  665. #ifdef PROFILING
  666. InterlockedIncrement( &SpxStatistics.stat_NumBPAge);
  667. #endif
  668. if (pChunk->bc_BlkId == BLKID_NDISSEND)
  669. {
  670. PBLK_HDR pBlkHdr;
  671. // We need to free Ndis stuff for these guys
  672. pBlkHdr = pChunk->bc_FreeHead;
  673. for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
  674. j < NumBlksPerChunk;
  675. j++, pBlkHdr = pBlkHdr->bh_Next)
  676. {
  677. pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
  678. NdisUnchainBufferAtFront(
  679. pNdisPkt,
  680. &pNdisBuffer);
  681. NdisFreeBuffer(pNdisBuffer);
  682. NdisUnchainBufferAtFront(
  683. pNdisPkt,
  684. &pNdisBuffer);
  685. NdisFreeBuffer(pNdisBuffer);
  686. }
  687. }
  688. SpxFreeMemory(pChunk);
  689. }
  690. else
  691. {
  692. ppChunk = &pChunk->bc_Next;
  693. }
  694. }
  695. CTEFreeLock(&spxBPLock[i], lockHandle);
  696. }
  697. return TIMER_REQUEUE_CUR_VALUE;
  698. }
  699. #if !defined SPX_OWN_PACKETS
  700. //
  701. // GrowSPXSendPacketsList
  702. // Called when we dont have any free packets in the SendPacketsList.
  703. //
  704. // Allocate a packet pool, allocate all the packets for that pool and
  705. // store these on a list.
  706. //
  707. // Returns: Pointer to newly allocated packet, or NULL if this faild.
  708. //
  709. PNDIS_PACKET
  710. GrowSPXSendPacketList(void)
  711. {
  712. NdisResEntry *NewEntry;
  713. NDIS_STATUS Status;
  714. PNDIS_PACKET Packet, ReturnPacket;
  715. uint i;
  716. CTELockHandle Handle;
  717. CTEGetLock(&SendHeaderLock, &Handle);
  718. if (CurrentSendPacketCount >= MaxPacketCount)
  719. goto failure;
  720. // First, allocate a tracking structure.
  721. NewEntry = CTEAllocMem(sizeof(NdisResEntry));
  722. if (NewEntry == NULL)
  723. goto failure;
  724. NewEntry->nre_handle = (void *) NDIS_PACKET_POOL_TAG_FOR_NWLNKSPX;
  725. // Got a tracking structure. Now allocate a packet pool.
  726. NdisAllocatePacketPoolEx(
  727. &Status,
  728. &NewEntry->nre_handle,
  729. PACKET_GROW_COUNT,
  730. 0,
  731. sizeof(SPX_SEND_RESD)
  732. );
  733. if (Status != NDIS_STATUS_SUCCESS) {
  734. CTEFreeMem(NewEntry);
  735. goto failure;
  736. }
  737. NdisSetPacketPoolProtocolId(NewEntry->nre_handle,NDIS_PROTOCOL_ID_IPX);
  738. // We've allocated the pool. Now initialize the packets, and link them
  739. // on the free list.
  740. ReturnPacket = NULL;
  741. // Link the new NDIS resource tracker entry onto the list.
  742. NewEntry->nre_next = SendPacketPoolList;
  743. SendPacketPoolList = NewEntry;
  744. CurrentSendPacketCount += PACKET_GROW_COUNT;
  745. CTEFreeLock(&SendHeaderLock, Handle);
  746. for (i = 0; i < PACKET_GROW_COUNT; i++) {
  747. SPX_SEND_RESD *SendReserved;
  748. NdisAllocatePacket(&Status, &Packet, NewEntry->nre_handle);
  749. if (Status != NDIS_STATUS_SUCCESS) {
  750. CTEAssert(FALSE);
  751. break;
  752. }
  753. CTEMemSet(Packet->ProtocolReserved, 0, sizeof(SPX_SEND_RESD));
  754. SendReserved = (SPX_SEND_RESD *)Packet->ProtocolReserved;
  755. // store whatever's required in the reserved section.
  756. if (i != 0) {
  757. (void)SpxFreeSendPacket(SpxDevice, Packet);
  758. } else
  759. ReturnPacket = Packet;
  760. }
  761. // We've put all but the first one on the list. Return the first one.
  762. return ReturnPacket;
  763. failure:
  764. CTEFreeLock(&SendHeaderLock, Handle);
  765. return NULL;
  766. }
  767. //
  768. // GrowSPXRecvPacketsList
  769. // Called when we dont have any free packets in the RecvPacketsList.
  770. //
  771. // Allocate a packet pool, allocate all the packets for that pool and
  772. // store these on a list.
  773. //
  774. // Returns: Pointer to newly allocated packet, or NULL if this faild.
  775. //
  776. PNDIS_PACKET
  777. GrowSPXRecvPacketList(void)
  778. {
  779. NdisResEntry *NewEntry;
  780. NDIS_STATUS Status;
  781. PNDIS_PACKET Packet, ReturnPacket;
  782. uint i;
  783. CTELockHandle Handle;
  784. CTEGetLock(&RecvHeaderLock, &Handle);
  785. if (CurrentRecvPacketCount >= MaxPacketCount)
  786. goto failure;
  787. // First, allocate a tracking structure.
  788. NewEntry = CTEAllocMem(sizeof(NdisResEntry));
  789. if (NewEntry == NULL)
  790. goto failure;
  791. NewEntry->nre_handle = (void *) NDIS_PACKET_POOL_TAG_FOR_NWLNKSPX;
  792. // Got a tracking structure. Now allocate a packet pool.
  793. NdisAllocatePacketPoolEx(
  794. &Status,
  795. &NewEntry->nre_handle,
  796. PACKET_GROW_COUNT,
  797. 0,
  798. sizeof(SPX_RECV_RESD)
  799. );
  800. if (Status != NDIS_STATUS_SUCCESS) {
  801. CTEFreeMem(NewEntry);
  802. goto failure;
  803. }
  804. NdisSetPacketPoolProtocolId(NewEntry->nre_handle,NDIS_PROTOCOL_ID_IPX);
  805. // We've allocated the pool. Now initialize the packets, and link them
  806. // on the free list.
  807. ReturnPacket = NULL;
  808. // Link the new NDIS resource tracker entry onto the list.
  809. NewEntry->nre_next = RecvPacketPoolList;
  810. RecvPacketPoolList = NewEntry;
  811. CurrentRecvPacketCount += PACKET_GROW_COUNT;
  812. CTEFreeLock(&RecvHeaderLock, Handle);
  813. for (i = 0; i < PACKET_GROW_COUNT; i++) {
  814. SPX_RECV_RESD *RecvReserved;
  815. NdisAllocatePacket(&Status, &Packet, NewEntry->nre_handle);
  816. if (Status != NDIS_STATUS_SUCCESS) {
  817. CTEAssert(FALSE);
  818. break;
  819. }
  820. CTEMemSet(Packet->ProtocolReserved, 0, sizeof(SPX_RECV_RESD));
  821. RecvReserved = (SPX_RECV_RESD *)Packet->ProtocolReserved;
  822. // store whatever's required in the reserved section.
  823. if (i != 0) {
  824. (void)SpxFreeRecvPacket(SpxDevice, Packet);
  825. } else
  826. ReturnPacket = Packet;
  827. }
  828. // We've put all but the first one on the list. Return the first one.
  829. return ReturnPacket;
  830. failure:
  831. CTEFreeLock(&RecvHeaderLock, Handle);
  832. return NULL;
  833. }
  834. PNDIS_PACKET
  835. SpxAllocSendPacket(
  836. IN PDEVICE _Device,
  837. OUT NDIS_PACKET **_SendPacket,
  838. OUT NDIS_STATUS *_Status)
  839. {
  840. PSLIST_ENTRY Link;
  841. SPX_SEND_RESD *Common, *pSendResd;
  842. PNDIS_BUFFER pNdisIpxMacBuffer, pNdisIpxSpxBuffer;
  843. NDIS_STATUS ndisStatus;
  844. PUCHAR pHdrMem = NULL;
  845. Link = ExInterlockedPopEntrySList(&SendPacketList, &SendHeaderLock);
  846. if (Link != NULL) {
  847. Common = STRUCT_OF(SPX_SEND_RESD, Link, Linkage);
  848. (*_SendPacket) = STRUCT_OF(NDIS_PACKET, Common, ProtocolReserved);
  849. (*_Status) = NDIS_STATUS_SUCCESS;
  850. } else {
  851. (*_SendPacket) = GrowSPXSendPacketList();
  852. (*_Status) = NDIS_STATUS_SUCCESS;
  853. if (NULL == *_SendPacket) {
  854. DBGPRINT(NDIS, DBG, ("Couldn't grow packets allocated...\r\n"));
  855. (*_Status) = NDIS_STATUS_RESOURCES;
  856. return NULL;
  857. }
  858. }
  859. //
  860. // Now add the NdisBuffers to the packet.
  861. // 1. IPX MAC HDR
  862. // 2. IPX/SPX Hdr
  863. // 3. Chain these
  864. //
  865. if (NDIS_STATUS_SUCCESS == (*_Status)) {
  866. //
  867. // First allocate the memory
  868. //
  869. pHdrMem = SpxAllocateMemory(IpxMacHdrNeeded + MIN_IPXSPX2_HDRSIZE);
  870. if (NULL == pHdrMem) {
  871. DBGPRINT(NDIS, DBG, ("Cannot allocate non paged pool for sendpacket\n"));
  872. (*_Status) = NDIS_STATUS_RESOURCES;
  873. goto failure;
  874. }
  875. NdisAllocateBuffer(
  876. &ndisStatus,
  877. &pNdisIpxMacBuffer,
  878. SpxDevice->dev_NdisBufferPoolHandle,
  879. pHdrMem,
  880. IpxMacHdrNeeded);
  881. if (ndisStatus != NDIS_STATUS_SUCCESS)
  882. {
  883. if (NULL != pHdrMem) {
  884. SpxFreeMemory(pHdrMem);
  885. pHdrMem = NULL;
  886. }
  887. DBGPRINT(NDIS, DBG, ("NdisallocateBuffer failed\r\n", ndisStatus));
  888. goto failure;
  889. }
  890. // Link the buffer descriptor into the packet descriptor
  891. NdisChainBufferAtBack(
  892. (*_SendPacket),
  893. pNdisIpxMacBuffer);
  894. NdisAllocateBuffer(
  895. &ndisStatus,
  896. &pNdisIpxSpxBuffer,
  897. SpxDevice->dev_NdisBufferPoolHandle,
  898. pHdrMem + IpxMacHdrNeeded,
  899. MIN_IPXSPX2_HDRSIZE);
  900. if (ndisStatus != NDIS_STATUS_SUCCESS)
  901. {
  902. DBGPRINT(NDIS, DBG, ("NdisallocateBuffer failed\r\n", ndisStatus));
  903. goto failure;
  904. }
  905. // Link the buffer descriptor into the packet descriptor
  906. NdisChainBufferAtBack(
  907. (*_SendPacket),
  908. pNdisIpxSpxBuffer);
  909. pSendResd = (PSPX_SEND_RESD)(*_SendPacket)->ProtocolReserved;
  910. // Initialize elements of the protocol reserved structure.
  911. pSendResd->sr_Id = IDENTIFIER_SPX;
  912. pSendResd->sr_Reserved1 = NULL;
  913. pSendResd->sr_Reserved2 = NULL;
  914. pSendResd->sr_State = SPX_SENDPKT_IDLE;
  915. return (*_SendPacket);
  916. }
  917. failure:
  918. SpxFreeSendPacket(SpxDevice, (*_SendPacket));
  919. (*_Status) = NDIS_STATUS_RESOURCES;
  920. return NULL;
  921. }
  922. PNDIS_PACKET
  923. SpxAllocRecvPacket(
  924. IN PDEVICE _Device,
  925. OUT NDIS_PACKET **_RecvPacket,
  926. OUT NDIS_STATUS *_Status)
  927. {
  928. PSLIST_ENTRY Link;
  929. SPX_RECV_RESD *Common, *pRecvResd;
  930. Link = ExInterlockedPopEntrySList(
  931. &RecvPacketList,
  932. &RecvHeaderLock
  933. );
  934. if (Link != NULL) {
  935. Common = STRUCT_OF(SPX_RECV_RESD, Link, Linkage);
  936. //PC = STRUCT_OF(PacketContext, Common, pc_common);
  937. (*_RecvPacket) = STRUCT_OF(NDIS_PACKET, Common, ProtocolReserved);
  938. (*_Status) = NDIS_STATUS_SUCCESS;
  939. } else {
  940. (*_RecvPacket) = GrowSPXRecvPacketList();
  941. (*_Status) = NDIS_STATUS_SUCCESS;
  942. if (NULL == *_RecvPacket) {
  943. DBGPRINT(NDIS, DBG, ("Couldn't grow packets allocated...\r\n"));
  944. (*_Status) = NDIS_STATUS_RESOURCES;
  945. }
  946. }
  947. if ((*_Status) == NDIS_STATUS_SUCCESS) {
  948. pRecvResd = (PSPX_RECV_RESD)(*_RecvPacket)->ProtocolReserved;
  949. // Initialize elements of the protocol reserved structure.
  950. pRecvResd->rr_Id = IDENTIFIER_SPX;
  951. pRecvResd->rr_State = SPX_RECVPKT_IDLE;
  952. }
  953. return (*_RecvPacket);
  954. }
  955. //* SpxFreeSendPacket - Free an SPX packet when we're done with it.
  956. //
  957. // Called when a send completes and a packet needs to be freed. We look at the
  958. // packet, decide what to do with it, and free the appropriate components.
  959. //
  960. // Entry: Packet - Packet to be freed.
  961. //
  962. //
  963. void
  964. SpxFreeSendPacket(PDEVICE _Device,
  965. PNDIS_PACKET _Packet)
  966. {
  967. PNDIS_BUFFER NextBuffer, Buffer;
  968. SPX_SEND_RESD *Context = (SPX_SEND_RESD *)_Packet->ProtocolReserved;
  969. PVOID Header = NULL;
  970. ULONG Length = 0;
  971. DBGPRINT(NDIS, DBG,
  972. ("SpxFreeSendPacket\n"));
  973. NdisQueryPacket(_Packet, NULL, NULL, &Buffer, NULL);
  974. if (NULL != Buffer) {
  975. NdisQueryBuffer(Buffer, &Header, &Length);
  976. //KdPrint(("Pointer = %x Length = %x", Header, Length));
  977. if (Header != NULL && Length > 0) {
  978. //KdPrint(("Freed buffer"));
  979. SpxFreeMemory(Header);
  980. }
  981. }
  982. while (Buffer != (PNDIS_BUFFER)NULL) {
  983. NdisGetNextBuffer(Buffer, &NextBuffer);
  984. NdisFreeBuffer(Buffer);
  985. Buffer = NextBuffer;
  986. }
  987. NdisReinitializePacket(_Packet);
  988. ExInterlockedPushEntrySList(
  989. &SendPacketList,
  990. STRUCT_OF(SLIST_ENTRY, &(Context->Linkage), Next),
  991. &SendHeaderLock
  992. );
  993. return;
  994. }
  995. //* SpxFreeRecvPacket - Free an SPX packet when we're done with it.
  996. //
  997. // Called when a recv completes and a packet needs to be freed. We look at the
  998. // packet, decide what to do with it, and free the appropriate components.
  999. //
  1000. // Entry: Packet - Packet to be freed.
  1001. //
  1002. //
  1003. void
  1004. SpxFreeRecvPacket(PDEVICE _Device,
  1005. PNDIS_PACKET _Packet)
  1006. {
  1007. PNDIS_BUFFER NextBuffer, Buffer;
  1008. SPX_RECV_RESD *Context = (SPX_RECV_RESD *)_Packet->ProtocolReserved;
  1009. DBGPRINT(NDIS, DBG,
  1010. ("SpxFreeRecvPacket\n"));
  1011. NdisQueryPacket(_Packet, NULL, NULL, &Buffer, NULL);
  1012. while (Buffer != (PNDIS_BUFFER)NULL) {
  1013. NdisGetNextBuffer(Buffer, &NextBuffer);
  1014. NdisFreeBuffer(Buffer);
  1015. Buffer = NextBuffer;
  1016. }
  1017. NdisReinitializePacket(_Packet);
  1018. ExInterlockedPushEntrySList(
  1019. &RecvPacketList,
  1020. STRUCT_OF(SLIST_ENTRY, &(Context->Linkage), Next),
  1021. &RecvHeaderLock
  1022. );
  1023. return;
  1024. }
  1025. void
  1026. SpxReInitSendPacket(PNDIS_PACKET _Packet)
  1027. {
  1028. DBGPRINT(NDIS, DBG,
  1029. ("SpxReInitSendPacket\n"));
  1030. }
  1031. void
  1032. SpxReInitRecvPacket(PNDIS_PACKET _Packet)
  1033. {
  1034. DBGPRINT(NDIS, DBG,
  1035. ("SpxReInitRecvPacket\n"));
  1036. }
  1037. #endif //SPX_OWN_PACKETS