diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/isnp/spx/spxmem.c | 897 |
1 files changed, 897 insertions, 0 deletions
diff --git a/private/ntos/tdi/isnp/spx/spxmem.c b/private/ntos/tdi/isnp/spx/spxmem.c new file mode 100644 index 000000000..9cd400e5b --- /dev/null +++ b/private/ntos/tdi/isnp/spx/spxmem.c @@ -0,0 +1,897 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + spxmem.c + +Abstract: + + This module contains code which implements the memory allocation wrappers. + +Author: + + Nikhil Kamkolkar (nikhilk) 11-November-1993 + Jameel Hyder (jameelh) Initial Version + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "precomp.h" +#pragma hdrstop + +#ifdef ALLOC_PRAGMA +#pragma alloc_text( INIT, SpxInitMemorySystem) +#pragma alloc_text( PAGE, SpxDeInitMemorySystem) +#endif + +// Define module number for event logging entries +#define FILENUM SPXMEM + +// Globals for this module +// Some block sizes (like NDISSEND/NDISRECV are filled in after binding with IPX) +USHORT spxBlkSize[NUM_BLKIDS] = // Size of each block + { + sizeof(BLK_HDR)+sizeof(TIMERLIST), // BLKID_TIMERLIST + 0, // BLKID_NDISSEND + 0 // BLKID_NDISRECV + }; + +USHORT spxChunkSize[NUM_BLKIDS] = // Size of each Chunk + { + 512-BC_OVERHEAD, // BLKID_TIMERLIST + 512-BC_OVERHEAD, // BLKID_NDISSEND + 512-BC_OVERHEAD // BLKID_NDISRECV + }; + + +// Filled in after binding with IPX +// Reference for below. +// ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/ +// (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST +USHORT spxNumBlks[NUM_BLKIDS] = // Number of blocks per chunk + { + ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/ + (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST + 0, // BLKID_NDISSEND + 0 // BLKID_NDISRECV + }; + +CTELock spxBPLock[NUM_BLKIDS] = { 0 }; +PBLK_CHUNK spxBPHead[NUM_BLKIDS] = { 0 }; + + + + +NTSTATUS +SpxInitMemorySystem( + IN PDEVICE pSpxDevice + ) +/*++ + +Routine Description: + + !!! MUST BE CALLED AFTER BINDING TO IPX!!! + +Arguments: + + +Return Value: + + +--*/ +{ + LONG i; + NDIS_STATUS ndisStatus; + + // Try to allocate the ndis buffer pool. + NdisAllocateBufferPool( + &ndisStatus, + &pSpxDevice->dev_NdisBufferPoolHandle, + 20); + + if (ndisStatus != NDIS_STATUS_SUCCESS) + return(STATUS_INSUFFICIENT_RESOURCES); + + for (i = 0; i < NUM_BLKIDS; i++) + CTEInitLock (&spxBPLock[i]); + + // Set the sizes in the block id info arrays. + for (i = 0; i < NUM_BLKIDS; i++) + { + // BUGBUG: Do it. + switch (i) + { + case BLKID_NDISSEND: + +#ifdef SPX_OWN_PACKETS + spxBlkSize[i] = sizeof(BLK_HDR) + + sizeof(SPX_SEND_RESD) + + NDIS_PACKET_SIZE + + IpxMacHdrNeeded + + MIN_IPXSPX2_HDRSIZE; +#else + spxBlkSize[i] = sizeof(PNDIS_PACKET); +#endif + + // + // Round the block size up to the next 8-byte boundary. + // + spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]); + + // Set number blocks + spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i]; + break; + + case BLKID_NDISRECV: + +#ifdef SPX_OWN_PACKETS + spxBlkSize[i] = sizeof(BLK_HDR) + + sizeof(SPX_RECV_RESD) + + NDIS_PACKET_SIZE; +#else + spxBlkSize[i] = sizeof(PNDIS_PACKET); +#endif + + // + // Round the block size up to the next 8-byte boundary. + // + spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]); + + // Set number blocks + spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i]; + break; + + default: + + break; + } + + } + + SpxTimerScheduleEvent((TIMER_ROUTINE)spxBPAgePool, + BLOCK_POOL_TIMER, + NULL); +} + + + + +VOID +SpxDeInitMemorySystem( + IN PDEVICE pSpxDevice + ) +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ +{ + LONG i, j, NumBlksPerChunk; + PBLK_CHUNK pChunk, pFree; + + for (i = 0; i < NUM_BLKIDS; i++) + { + NumBlksPerChunk = spxNumBlks[i]; + for (pChunk = spxBPHead[i]; + pChunk != NULL; ) + { + DBGPRINT(RESOURCES, ERR, + ("SpxInitMemorySystem: Freeing %lx\n", pChunk)); + + CTEAssert (pChunk->bc_NumFrees == NumBlksPerChunk); + + if ((pChunk->bc_BlkId == BLKID_NDISSEND) || + (pChunk->bc_BlkId == BLKID_NDISRECV)) + { + PBLK_HDR pBlkHdr; + + // We need to free the Ndis stuff for these guys + for (j = 0, pBlkHdr = pChunk->bc_FreeHead; + j < NumBlksPerChunk; + j++, pBlkHdr = pBlkHdr->bh_Next) + { + PNDIS_PACKET pNdisPkt; + PNDIS_BUFFER pNdisBuffer; + +#ifdef SPX_OWN_PACKETS + // Only need to free the ndis buffer. + pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)); + + if (pChunk->bc_BlkId == BLKID_NDISSEND) + { + NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer); + if (pNdisBuffer == NULL) + { + // Something is terribly awry. + KeBugCheck(0); + } + + NdisFreeBuffer(pNdisBuffer); + + // + // Free the second MDL also + // + NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer); + if (pNdisBuffer == NULL) + { + // Something is terribly awry. + KeBugCheck(0); + } + + NdisFreeBuffer(pNdisBuffer); + } +#else + // Need to free both the packet and the buffer. + ppNdisPkt = (PNDIS_PACKET *)((PBYTE)pBlkHdr + sizeof(BLK_HDR)); + + if (pChunk->bc_BlkId == BLKID_NDISSEND) + { + + NdisUnchainBufferAtFront(*ppNdisPkt, &pNdisBuffer); + if (pNdisBuffer == NULL) + { + // Something is terribly awry. + KeBugCheck(0); + } + + NdisFreeBuffer(pNdisBuffer); + } + NdisFreePacket(*ppNdisPkt); +#endif + } + } + pFree = pChunk; + pChunk = pChunk->bc_Next; + +#ifndef SPX_OWN_PACKETS + // Free the ndis packet pool in chunk + NdisFreePacketPool((NDIS_HANDLE)pFree->bc_ChunkCtx); +#endif + SpxFreeMemory(pFree); + } + } + + // Free up the ndis buffer pool + NdisFreeBufferPool( + pSpxDevice->dev_NdisBufferPoolHandle); + + return; +} + + + + +PVOID +SpxAllocMem( +#ifdef TRACK_MEMORY_USAGE + IN ULONG Size, + IN ULONG FileLine +#else + IN ULONG Size +#endif // TRACK_MEMORY_USAGE + ) +/*++ + +Routine Description: + + Allocate a block of non-paged memory. This is just a wrapper over ExAllocPool. + Allocation failures are error-logged. We always allocate a ULONG more than + the specified size to accomodate the size. This is used by SpxFreeMemory + to update the statistics. + +Arguments: + + +Return Value: + + +--*/ +{ + PBYTE pBuf; + BOOLEAN zeroed; + + // round up the size so that we can put a signature at the end + // that is on a LARGE_INTEGER boundary + zeroed = ((Size & ZEROED_MEMORY_TAG) == ZEROED_MEMORY_TAG); + + Size = QWORDSIZEBLOCK(Size & ~ZEROED_MEMORY_TAG); + + // Do the actual memory allocation. Allocate eight extra bytes so + // that we can store the size of the allocation for the free routine + // and still keep the buffer quadword aligned. + + if ((pBuf = ExAllocatePoolWithTag(NonPagedPool, Size + sizeof(LARGE_INTEGER) +#if DBG + + sizeof(ULONG) +#endif + ,SPX_TAG)) == NULL) + { + DBGPRINT(RESOURCES, FATAL, + ("SpxAllocMemory: failed - size %lx\n", Size)); + + TMPLOGERR(); + return NULL; + } + + // Save the size of this block in the four extra bytes we allocated. + *((PULONG)pBuf) = (Size + sizeof(LARGE_INTEGER)); + + // Return a pointer to the memory after the size longword. + pBuf += sizeof(LARGE_INTEGER); + +#if DBG + *((PULONG)(pBuf+Size)) = SPX_MEMORY_SIGNATURE; + DBGPRINT(RESOURCES, INFO, + ("SpxAllocMemory: %lx Allocated %lx bytes @%lx\n", + *(PULONG)((PBYTE)(&Size) - sizeof(Size)), Size, pBuf)); +#endif + + SpxTrackMemoryUsage((PVOID)(pBuf - sizeof(LARGE_INTEGER)), TRUE, FileLine); + + if (zeroed) + RtlZeroMemory(pBuf, Size); + + return (pBuf); +} + + + + +VOID +SpxFreeMemory( + IN PVOID pBuf + ) +/*++ + +Routine Description: + + Free the block of memory allocated via SpxAllocMemory. This is + a wrapper around ExFreePool. + +Arguments: + + +Return Value: + + +--*/ +{ + PULONG pRealBuffer; + + // Get a pointer to the block allocated by ExAllocatePool -- + // we allocate a LARGE_INTEGER at the front. + pRealBuffer = ((PULONG)pBuf - 2); + + SpxTrackMemoryUsage(pRealBuffer, FALSE, 0); + +#if DBG + // Check the signature at the end + if (*(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer) + != SPX_MEMORY_SIGNATURE) + { + DBGPRINT(RESOURCES, FATAL, + ("SpxFreeMemory: Memory overrun on block %lx\n", pRealBuffer)); + + DBGBRK(FATAL); + } + + *(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer) = 0; +#endif + +#if DBG + *pRealBuffer = 0; +#endif + + // Free the pool and return. + ExFreePool(pRealBuffer); +} + + + + +#ifdef TRACK_MEMORY_USAGE + +#define MAX_PTR_COUNT 4*1024 +#define MAX_MEM_USERS 512 +CTELock spxMemTrackLock = {0}; +CTELockHandle lockHandle = {0}; +struct +{ + PVOID mem_Ptr; + ULONG mem_FileLine; +} spxMemPtrs[MAX_PTR_COUNT] = {0}; + +struct +{ + ULONG mem_FL; + ULONG mem_Count; +} spxMemUsage[MAX_MEM_USERS] = {0}; + +VOID +SpxTrackMemoryUsage( + IN PVOID pMem, + IN BOOLEAN Alloc, + IN ULONG FileLine + ) +/*++ + +Routine Description: + + Keep track of memory usage by storing and clearing away pointers as and + when they are allocated or freed. This helps in keeping track of memory + leaks. + +Arguments: + + +Return Value: + + +--*/ +{ + static int i = 0; + int j, k; + + CTEGetLock (&spxMemTrackLock, &lockHandle); + + if (Alloc) + { + for (j = 0; j < MAX_PTR_COUNT; i++, j++) + { + i = i & (MAX_PTR_COUNT-1); + if (spxMemPtrs[i].mem_Ptr == NULL) + { + spxMemPtrs[i].mem_Ptr = pMem; + spxMemPtrs[i++].mem_FileLine = FileLine; + break; + } + } + + for (k = 0; k < MAX_MEM_USERS; k++) + { + if (spxMemUsage[k].mem_FL == FileLine) + { + spxMemUsage[k].mem_Count ++; + break; + } + } + if (k == MAX_MEM_USERS) + { + for (k = 0; k < MAX_MEM_USERS; k++) + { + if (spxMemUsage[k].mem_FL == 0) + { + spxMemUsage[k].mem_FL = FileLine; + spxMemUsage[k].mem_Count = 1; + break; + } + } + } + if (k == MAX_MEM_USERS) + { + DBGPRINT(RESOURCES, ERR, + ("SpxTrackMemoryUsage: Out of space on spxMemUsage !!!\n")); + + DBGBRK(FATAL); + } + } + else + { + for (j = 0, k = i; j < MAX_PTR_COUNT; j++, k--) + { + k = k & (MAX_PTR_COUNT-1); + if (spxMemPtrs[k].mem_Ptr == pMem) + { + spxMemPtrs[k].mem_Ptr = 0; + spxMemPtrs[k].mem_FileLine = 0; + break; + } + } + } + + CTEFreeLock (&spxMemTrackLock, lockHandle); + + if (j == MAX_PTR_COUNT) + { + DBGPRINT(RESOURCES, ERR, + ("SpxTrackMemoryUsage: %s\n", Alloc ? "Table Full" : "Can't find")); + + DBGBRK(FATAL); + } +} + +#endif // TRACK_MEMORY_USAGE + + + + +PVOID +SpxBPAllocBlock( + IN BLKID BlockId + ) +/*++ + +Routine Description: + + Alloc a block of memory from the block pool package. This is written to speed up + operations where a lot of small fixed size allocations/frees happen. Going to + ExAllocPool() in these cases is expensive. + +Arguments: + + +Return Value: + + +--*/ +{ + PBLK_HDR pBlk = NULL; + PBLK_CHUNK pChunk, *ppChunkHead; + USHORT BlkSize; + CTELockHandle lockHandle; + PSPX_SEND_RESD pSendResd; + PSPX_RECV_RESD pRecvResd; + PNDIS_PACKET pNdisPkt; + PNDIS_BUFFER pNdisBuffer; + PNDIS_BUFFER pNdisIpxSpxBuffer; + + + CTEAssert (BlockId < NUM_BLKIDS); + + if (BlockId < NUM_BLKIDS) + { + BlkSize = spxBlkSize[BlockId]; + ppChunkHead = &spxBPHead[BlockId]; + + CTEGetLock(&spxBPLock[BlockId], &lockHandle); + + for (pChunk = *ppChunkHead; + pChunk != NULL; + pChunk = pChunk->bc_Next) + { + CTEAssert(pChunk->bc_BlkId == BlockId); + if (pChunk->bc_NumFrees > 0) + { + DBGPRINT(SYSTEM, INFO, + ("SpxBPAllocBlock: Found space in Chunk %lx\n", pChunk)); +#ifdef PROFILING + InterlockedIncrement( &SpxStatistics.stat_NumBPHits); +#endif + break; + } + } + + if (pChunk == NULL) + { + DBGPRINT(SYSTEM, INFO, + ("SpxBPAllocBlock: Allocating a new chunk for Id %d\n", BlockId)); + +#ifdef PROFILING + InterlockedIncrement( &SpxStatistics.stat_NumBPMisses); +#endif + pChunk = SpxAllocateMemory(spxChunkSize[BlockId]); + if (pChunk != NULL) + { + LONG i, j; + PBLK_HDR pBlkHdr; + USHORT NumBlksPerChunk; + + NumBlksPerChunk = spxNumBlks[BlockId]; + pChunk->bc_NumFrees = NumBlksPerChunk; + pChunk->bc_BlkId = BlockId; + pChunk->bc_FreeHead = (PBLK_HDR)((PBYTE)pChunk + sizeof(BLK_CHUNK)); + + DBGPRINT(SYSTEM, INFO, + ("SpxBPAllocBlock: Initializing chunk %lx\n", pChunk)); + + // Initialize the blocks in the chunk + for (i = 0, pBlkHdr = pChunk->bc_FreeHead; + i < NumBlksPerChunk; + i++, pBlkHdr = pBlkHdr->bh_Next) + { + NDIS_STATUS ndisStatus; + + pBlkHdr->bh_Next = (PBLK_HDR)((PBYTE)pBlkHdr + BlkSize); + if (BlockId == BLKID_NDISSEND) + { + PBYTE pHdrMem; + +#ifdef SPX_OWN_PACKETS + // Point to the ndis packet,initialize it. + pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)); + NdisReinitializePacket(pNdisPkt); + + // Allocate a ndis buffer descriptor describing hdr memory + // and queue it in. + pHdrMem = (PBYTE)pNdisPkt + + NDIS_PACKET_SIZE + + sizeof(SPX_SEND_RESD); + + NdisAllocateBuffer( + &ndisStatus, + &pNdisBuffer, + SpxDevice->dev_NdisBufferPoolHandle, + pHdrMem, + IpxMacHdrNeeded); + + if (ndisStatus != NDIS_STATUS_SUCCESS) + { + break; + } + + // Link the buffer descriptor into the packet descriptor + NdisChainBufferAtBack( + pNdisPkt, + pNdisBuffer); + + + NdisAllocateBuffer( + &ndisStatus, + &pNdisIpxSpxBuffer, + SpxDevice->dev_NdisBufferPoolHandle, + pHdrMem + IpxMacHdrNeeded, + MIN_IPXSPX2_HDRSIZE); + + if (ndisStatus != NDIS_STATUS_SUCCESS) + { + break; + } + + // Link the buffer descriptor into the packet descriptor + NdisChainBufferAtBack( + pNdisPkt, + pNdisIpxSpxBuffer); + + + + pSendResd = (PSPX_SEND_RESD)pNdisPkt->ProtocolReserved; + +#else + // Allocate a ndis packet pool for this chunk + NdisAllocatePacketPool(); + etc. +#endif + + + // Initialize elements of the protocol reserved structure. + pSendResd->sr_Id = IDENTIFIER_SPX; + pSendResd->sr_Reserved1 = NULL; + pSendResd->sr_Reserved2 = NULL; + pSendResd->sr_State = SPX_SENDPKT_IDLE; + } + else if (BlockId == BLKID_NDISRECV) + { +#ifdef SPX_OWN_PACKETS + // Point to the ndis packet,initialize it. + pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)); + NdisReinitializePacket(pNdisPkt); + + pRecvResd = (PSPX_RECV_RESD)pNdisPkt->ProtocolReserved; + +#else + // Allocate a ndis packet pool for this chunk + NdisAllocatePacketPool(); + etc. +#endif + + // Initialize elements of the protocol reserved structure. + pRecvResd->rr_Id = IDENTIFIER_SPX; + pRecvResd->rr_State = SPX_RECVPKT_IDLE; + } + } + + if (i != NumBlksPerChunk) + { + // This has to be a failure from Ndis for send blocks!!! + // Undo a bunch of stuff + CTEAssert (BlockId == BLKID_NDISSEND); + pBlkHdr = pChunk->bc_FreeHead; + for (j = 0, pBlkHdr = pChunk->bc_FreeHead; + j < i; j++, pBlkHdr = pBlkHdr->bh_Next) + { + NdisUnchainBufferAtFront( + (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)), + &pNdisBuffer); + + CTEAssert(pNdisBuffer != NULL); + NdisFreeBuffer(pNdisBuffer); + + NdisUnchainBufferAtFront( + (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)), + &pNdisIpxSpxBuffer); + + if (pNdisIpxSpxBuffer) + { + NdisFreeBuffer(pNdisIpxSpxBuffer); + } + } + + SpxFreeMemory(pChunk); + pChunk = NULL; + } + else + { + // Successfully initialized the chunk, link it in + pChunk->bc_Next = *ppChunkHead; + *ppChunkHead = pChunk; + } + } + } + + if (pChunk != NULL) + { + CTEAssert(pChunk->bc_BlkId == BlockId); + DBGPRINT(RESOURCES, INFO, + ("SpxBPAllocBlock: Allocating a block out of chunk %lx(%d) for Id %d\n", + pChunk, pChunk->bc_NumFrees, BlockId)); + + pChunk->bc_NumFrees --; + pChunk->bc_Age = 0; // Reset age + pBlk = pChunk->bc_FreeHead; + pChunk->bc_FreeHead = pBlk->bh_Next; + pBlk->bh_pChunk = pChunk; + + // Skip the block header! + pBlk++; + } + + CTEFreeLock(&spxBPLock[BlockId], lockHandle); + } + + return pBlk; +} + + + +VOID +SpxBPFreeBlock( + IN PVOID pBlock, + IN BLKID BlockId + ) +/*++ + +Routine Description: + + Return a block to its owning chunk. + +Arguments: + + +Return Value: + + +--*/ +{ + PBLK_CHUNK pChunk; + PBLK_HDR pBlkHdr = (PBLK_HDR)((PCHAR)pBlock - sizeof(BLK_HDR)); + CTELockHandle lockHandle; + + CTEGetLock(&spxBPLock[BlockId], &lockHandle); + + for (pChunk = spxBPHead[BlockId]; + pChunk != NULL; + pChunk = pChunk->bc_Next) + { + CTEAssert(pChunk->bc_BlkId == BlockId); + if (pBlkHdr->bh_pChunk == pChunk) + { + DBGPRINT(SYSTEM, INFO, + ("SpxBPFreeBlock: Returning Block %lx to chunk %lx for Id %d\n", + pBlkHdr, pChunk, BlockId)); + + CTEAssert (pChunk->bc_NumFrees < spxNumBlks[BlockId]); + pChunk->bc_NumFrees ++; + pBlkHdr->bh_Next = pChunk->bc_FreeHead; + pChunk->bc_FreeHead = pBlkHdr; + break; + } + } + CTEAssert ((pChunk != NULL) && (pChunk->bc_FreeHead == pBlkHdr)); + + CTEFreeLock(&spxBPLock[BlockId], lockHandle); + return; +} + + + + +ULONG +spxBPAgePool( + IN PVOID Context, + IN BOOLEAN TimerShuttingDown + ) +/*++ + +Routine Description: + + Age out the block pool of unused blocks + +Arguments: + + +Return Value: + + +--*/ +{ + PBLK_CHUNK pChunk, *ppChunk, pFree = NULL; + LONG i, j, NumBlksPerChunk; + CTELockHandle lockHandle; + PNDIS_PACKET pNdisPkt; + PNDIS_BUFFER pNdisBuffer; + + if (TimerShuttingDown) + { + return TIMER_DONT_REQUEUE; + } + + for (i = 0; i < NUM_BLKIDS; i++) + { + NumBlksPerChunk = spxNumBlks[i]; + CTEGetLock(&spxBPLock[i], &lockHandle); + + for (ppChunk = &spxBPHead[i]; + (pChunk = *ppChunk) != NULL; ) + { + if ((pChunk->bc_NumFrees == NumBlksPerChunk) && + (++(pChunk->bc_Age) >= MAX_BLOCK_POOL_AGE)) + { + DBGPRINT(SYSTEM, INFO, + ("spxBPAgePool: freeing Chunk %lx, Id %d\n", + pChunk, pChunk->bc_BlkId)); + + *ppChunk = pChunk->bc_Next; +#ifdef PROFILING + InterlockedIncrement( &SpxStatistics.stat_NumBPAge); +#endif + if (pChunk->bc_BlkId == BLKID_NDISSEND) + { + PBLK_HDR pBlkHdr; + + // We need to free Ndis stuff for these guys + pBlkHdr = pChunk->bc_FreeHead; + for (j = 0, pBlkHdr = pChunk->bc_FreeHead; + j < NumBlksPerChunk; + j++, pBlkHdr = pBlkHdr->bh_Next) + { + pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)); + NdisUnchainBufferAtFront( + pNdisPkt, + &pNdisBuffer); + + NdisFreeBuffer(pNdisBuffer); + + NdisUnchainBufferAtFront( + pNdisPkt, + &pNdisBuffer); + + NdisFreeBuffer(pNdisBuffer); + } + } + + SpxFreeMemory(pChunk); + } + else + { + ppChunk = &pChunk->bc_Next; + } + } + CTEFreeLock(&spxBPLock[i], lockHandle); + } + + return TIMER_REQUEUE_CUR_VALUE; +} |