Hello,
I write a Filter Driver for our GigE Vision Cameras with NDIS Version 6.30. The FilterClass is set to custom:
HKR, Ndi,FilterClass,custom
because we have Bandwidth above 5 Gbit/s and want to exclude the Firewall/Antivirus-Filter-Driver from the Data.
Receiving works till now like charme, but if the background Image is changing I got packet loses.
My Problem is the sending side.
I send the low count of Pakets over iocontrol (a complete Networkframe including Ethernet Frame is send by the user Application).
It works at the beginning, but after a unspecified time it stops working.
I debugged that I call the NdisFSendNetBufferLists but the Callback Func FilterSendNetBufferListsComplete is never called. Only a restart of the computer fix this problem.
Uninstalling ends in hang up, because of waiting for the missing Packets.
Code:
BOOLEAN SendRawPacket(PMS_FILTER aFilter, PVOID aPacketPtr, LONG aPacketByteSize,PLONG Status)
{
InterlockedIncrement(&SendActive); // a global Variable for checking if there an Sendprocess active
BOOLEAN res = FALSE;
PMDL mdl = NULL;
PSENDBUF_MEM iSendBuf = NULL;
do
{
if (SendTerminate)
{
*Status = 11000;
InterlockedIncrement(&ErrorCounter.SendTerminated);
break;
}
iSendBuf = SendBufMem_get(); // a local cache -> the memory is allocated by ExAllocatePoolWithTag(NonPagedPool, sizeof(SENDBUF_MEM), MEMID_SENDBUFFER);
if (iSendBuf == NULL)
{
*Status = 13000;
break;
}
if ((aFilter == NULL) || (aPacketPtr == NULL) || (aPacketByteSize < 1) || (aPacketByteSize > ARRAYSIZE(iSendBuf->buffer)))
{
*Status = 12000;
InterlockedIncrement(&ErrorCounter.SendInvalidParams);
break;
}
NdisMoveMemory(iSendBuf->buffer, aPacketPtr, aPacketByteSize);
mdl = NdisAllocateMdl(FilterDriverHandle, iSendBuf->buffer, aPacketByteSize);
if (mdl == NULL)
{
*Status = 14000;
InterlockedIncrement(&ErrorCounter.SendAllocMdl);
break;
}
mdl->Next = NULL;
NDIS_HANDLE sndbufpool = InterlockedCompareExchangePointer(&SendBufferPool, NULL, NULL);
// SendBufferpool is initialized at Init
// NET_BUFFER_LIST_POOL_PARAMETERS params;
// NdisZeroMemory(¶ms, sizeof(params));
// params.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
// params.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
// params.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
// params.PoolTag = MEMID_SENDLISTS;
// params.fAllocateNetBuffer = TRUE;
// SendBufferPool = NdisAllocateNetBufferListPool(aHandle, ¶ms);
if (sndbufpool == NULL)
{
*Status = 15000;
InterlockedIncrement(&ErrorCounter.SendBufferPool);
break;
}
PNET_BUFFER_LIST BufList = NdisAllocateNetBufferAndNetBufferList(sndbufpool, sizeof(SEND_CONTEXT), 0, mdl, 0, aPacketByteSize);
if (BufList == NULL)
{
*Status = 16000;
InterlockedIncrement(&ErrorCounter.SendAllocBufList);
break;
}
BufList->SourceHandle = FilterDriverHandle; // Times before I used the Handle from Attach - this is a try with the globa Filterhandle from NdisFRegisterFilterDriver
SENDCONTEXT(BufList)->Signature = MEMID_SENDBUFFER;
SENDCONTEXT(BufList)->Filter = aFilter;
SENDCONTEXT(BufList)->Buffer = iSendBuf;
// this block is also a Try
BOOLEAN isDispatch = KeGetCurrentIrql() >= DISPATCH_LEVEL;
KIRQL oldIrql = PASSIVE_LEVEL;
if (!isDispatch)
{
NDIS_RAISE_IRQL_TO_DISPATCH(&oldIrql);
}
// Try Block End
NdisFSendNetBufferLists(aFilter->FilterHandle, BufList, NDIS_DEFAULT_PORT_NUMBER, NDIS_SEND_FLAGS_DISPATCH_LEVEL);
// the aFitler->Filterhandle comes from FilterAttach
// this block is also a Try
if (!isDispatch)
{
NDIS_LOWER_IRQL(oldIrql, DISPATCH_LEVEL);
}
// Try Block End
InterlockedIncrement(&InfoCounter.SendCounter);
mdl = NULL;
iSendBuf = NULL;
} while (FALSE);
if (iSendBuf != NULL)
{
*Status += 100;
SendBufMem_free(iSendBuf);
}
if (mdl != NULL)
{
*Status += 10;
NdisFreeMdl(mdl);
}
InterlockedDecrement(&SendActive);
return res;
}
// this Function is registed by the NdisFRegisterFilterDriver call
Use_decl_annotations
VOID
FilterSendNetBufferListsComplete(
NDIS_HANDLE FilterModuleContext,
PNET_BUFFER_LIST NetBufferLists,
ULONG SendCompleteFlags
)
{
PMS_FILTER aFilter = (PMS_FILTER)FilterModuleContext;
PNET_BUFFER_LIST BufList = NetBufferLists;
PNET_BUFFER_LIST BufListOld = NULL;
while (BufList)
{
PNET_BUFFER_LIST pNextNetBufList = NET_BUFFER_LIST_NEXT_NBL(BufList);
if (BufList->SourceHandle == FilterDriverHandle)
{
if (SENDCONTEXT(BufList)->Signature != MEMID_SENDBUFFER)
{
#if DBG
DbgBreakPoint();
#endif
}
if (BufListOld == NULL)
{
NetBufferLists = pNextNetBufList;
}
else
{
BufListOld->Next = pNextNetBufList;
}
BufList->Next = NULL;
PNET_BUFFER Currbuff = NET_BUFFER_LIST_FIRST_NB(BufList);
while (Currbuff)
{
while (TRUE)
{
PMDL pmdl = Currbuff->MdlChain;
if (pmdl == NULL) break;
Currbuff->MdlChain = pmdl->Next;
pmdl->Next = NULL;
PSENDBUF_MEM buf = CONTAINING_RECORD(pmdl->MappedSystemVa, SENDBUF_MEM, buffer);
SendBufMem_free(buf);
NdisFreeMdl(pmdl); //Free MDL
InterlockedIncrement(&InfoCounter.SendCompleteCounter);
}
Currbuff->CurrentMdl = NULL;
Currbuff->CurrentMdlOffset = 0;
Currbuff->DataLength = 0;
Currbuff->DataOffset = 0;
Currbuff = NET_BUFFER_NEXT_NB(Currbuff);
}
NdisFreeNetBufferList(BufList);
InterlockedIncrement(&InfoCounter.SendCompleteCounter);
}
else
{
BufListOld = BufList;
}
BufList = pNextNetBufList;
}
if (NetBufferLists)
{
NdisFSendNetBufferListsComplete(aFilter->FilterHandle, NetBufferLists, SendCompleteFlags);
}
}
A funny fact is, that the receiving Packets are indeed filtered and not visible in Wireshark. But the sending Packets are visible in Wireshark.
Why are the overling Filter drivers involved?
Another thing is that this send routine needs about 4ms instead of 1ms with the old winpcap implementation.
thanks in advance
derMischka