NDIS 6 LWF driver sending problem

Hi,
I want to send the packets from an NDIS 6 LWF. Here the packets just include
an Ethernet Header and some data. The following is the procedures:

  1. Call NdisAllocateNetBufferListPool to allocate a pool. In the
    FilterAttachHandler:

nblPoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
nblPoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
nblPoolParameters.Header.Size = sizeof(nblPoolParameters);

nblPoolParameters.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
nblPoolParameters.fAllocateNetBuffer = TRUE;
nblPoolParameters.PoolTag = LWF_NDIS_ALLOC_TAG;

pFilterCtx->pTxNBLPool = NdisAllocateNetBufferListPool(
g_pDriverCtx->pFDriverHandle, &nblPoolParameters);

pFilterCtx->pRxNBLPool = NdisAllocateNetBufferListPool(
g_pDriverCtx->pFDriverHandle, &nblPoolParameters);

  1. In the SendNetBufferListsHandler and ReceiveNetBufferListsHandler
    call function for complete the original package.

  2. Allocate a MDL and NBL

  3. Copy the new data to the MDL using NdisMoveMemory()

NDIS_STATUS
CreatePacketNBL(NBL_TYPE_T nblType, PFLTCONTEXT_T pFilterCtx, const
PUCHAR pNetworkBuffer,
ULONG bufferLength, const PNDIS_PACKET_CONTEXT_T pPacketCtx,
PNET_BUFFER_LIST* ppNewNBL)
{
PMDL pFirstMDL = NULL;
PUCHAR pDublicateBuffer = NULL;
PNET_BUFFER_LIST pCurrentNBL = NULL;

NDIS_STATUS ntErrorCode = NDIS_STATUS_RESOURCES;
do
{
pDublicateBuffer = CORESTD_ALLOC(bufferLength);
if (pDublicateBuffer == NULL) break;

CORESTD_MEMCPY(pDublicateBuffer, pNetworkBuffer, bufferLength);
pFirstMDL = NdisAllocateMdl(pFilterCtx->pFilterHandle,
pDublicateBuffer, bufferLength);
if (pFirstMDL == NULL) break;

switch(nblType)
{
case NBL_TYPE_RECV:
pCurrentNBL = NdisAllocateNetBufferAndNetBufferList(pFilterCtx->pRxNBLPool,
0x00, 0x00, pFirstMDL, 0x00, bufferLength);
break;
default:
pCurrentNBL = NdisAllocateNetBufferAndNetBufferList(pFilterCtx->pTxNBLPool,
0x00, 0x00, pFirstMDL, 0x00, bufferLength);
}
if (pCurrentNBL == NULL) break;

pCurrentNBL->SourceHandle = pFilterCtx->pFilterHandle;

if (pPacketCtx != NULL)
{
PVOID* ppNBLInformation = NULL;
PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO pCRCOriginalNBL = NULL;

ppNBLInformation = &NET_BUFFER_LIST_INFO(pCurrentNBL,
TcpIpChecksumNetBufferListInfo);
pCRCOriginalNBL = (PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO)
((PULONG)ppNBLInformation);

CORESTD_MEMCPY(pCRCOriginalNBL, &pPacketCtx->ndisChecksum, sizeof(ULONG));
}
*ppNewNBL = pCurrentNBL;
ntErrorCode = NDIS_STATUS_SUCCESS;
} while (FALSE);

if (ntErrorCode != NDIS_STATUS_SUCCESS)
{
if (pFirstMDL != NULL) NdisFreeMdl(pFirstMDL);
if (pDublicateBuffer != NULL) CORESTD_FREE(pDublicateBuffer);
}
return ntErrorCode;
}

  1. Call functions NdisFSendNetBufferLists or
    NdisFIndicateReceiveNetBufferLists for new NBL.

  2. In the SendNetBufferListsCompleteHandler and
    ReceiveNetBufferListsHandler free all allocated memory.

PNET_BUFFER pCurrentNB = NULL;
pCurrentNB = NET_BUFFER_LIST_FIRST_NB(pCurrentNBL);

while(pCurrentNB != NULL)
{
PMDL pCurrentMDL = NULL;
PNET_BUFFER pTemporaryNB = pCurrentNB;
pCurrentNB = NET_BUFFER_NEXT_NB(pCurrentNB);

pCurrentMDL = NET_BUFFER_FIRST_MDL(pTemporaryNB);
while(pCurrentMDL != NULL)
{
ULONG bufferLength = 0x00;
PVOID pNetworkBuffer = NULL;

PMDL pTemporaryMDL = pCurrentMDL;
pCurrentMDL = NDIS_MDL_LINKAGE(pCurrentMDL);

NdisQueryMdl(pTemporaryMDL, (PVOID *)&pNetworkBuffer, &bufferLength,
NormalPagePriority);

NdisFreeMdl(pTemporaryMDL);
if (pNetworkBuffer != NULL) CORESTD_FREE(pNetworkBuffer);
}
}
NdisFreeNetBufferList(pCurrentNBL);

Everything works fine, but I’m getting a memory leak. Why ? All the
functions of the release is called, but the memory still leaked
A memory leak occurs when I call NdisFSendNetBufferLists.

Thanks in advance.

P.S. Sorry for my bad English ))

I don’t think the leak is visible in the code you’ve shown. The code in step 6 is missing its outer loop – it’s nontrivial, so it’s possible the bug is there. E.g., you need to make sure you’re not using NBL->Next after freeing the NBL.

Here’s a simple version of how that could work. Note that it’s possible to write higher-performance code, if you complete multiple NBLs in a single call to NdisFSendNetBufferListsComplete – but worry about getting the leaks out first :).

filterSendComplete(… PNET_BUFFER_LIST pNetBufferList, …)
{
PNET_BUFFER_LIST pNBLsToFree = NULL;
PNET_BUFFER_LIST pNextNBL = NULL;
PNET_BUFFER_LIST pCurrentNBL = pNetBufferList;

// Find my NBLs
while (pCurrentNBL != NULL)
{
pNextNBL = NET_BUFFER_LIST_NEXT_NBL(pCurrentNBL);
NET_BUFFER_LIST_NEXT_NBL(pCurrentNBL) = NULL;

if (pCurrentNBL->SourceHandle == pFilterCtx->pFilterHandle)
FreeMyNBL(pCurrentNBL);
else
NdisFSendNetBufferListsComplete(…, pCurrentNBL, …);
}
}

How do you know a memory leak occurs? Does your “CORESTD_ALLOC” function have a counter? Do you leak one allocation for every packet, or is it infrequent?

Thank you for your help, error was unaccounted for in NBL-> NEXT)))