0

I have this NDIS Filter Driver. I try to start in my driver a thread, that will send packet every 10 seconds.

To do that, I use this code:

LARGE_INTEGER TimePrev, TimeNow;
void ThreadedAction()
{
    while(1)
    {
        KeQuerySystemTime(&TimeNow);
        if(NBLtoSend && (TimeNow.QuadPart - TimePrev.QuadPart)>100000000)
        {
            NdisFSendNetBufferLists(NBLtoSend->SourceHandle, NBLtoSend, 0, 0);
            KeQuerySystemTime(&TimePrev);
        }
    }
}

The function started with PsCreateSystemThread in DriverEntry.
But this is not sends my packet.
I try to use this:

void ThreadedAction()
{
    while(1)
    {
        if(NBLtoSend)
        {
            NdisFSendNetBufferLists(NBLtoSend->SourceHandle, NBLtoSend, 0, 0);
        }
    }
}

This code sends my packet non stop.

The following code creates new file with my packet every 10 seconds(CreateFileS is my function), but don't sends my packet:

LARGE_INTEGER TimePrev, TimeNow;
void ThreadedAction()
{
    while(1)
    {
        KeQuerySystemTime(&TimeNow);
        if(NBLtoSend && (TimeNow.QuadPart - TimePrev.QuadPart)>100000000)
        {
            PMDL pmdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(NBLtoSend));
            CreateFileS(NULL,(char*)MmGetMdlVirtualAddress(pmdl),MmGetMdlByteCount(pmdl));
            NdisFSendNetBufferLists(NBLtoSend->SourceHandle, NBLtoSend, 0, 0);
            KeQuerySystemTime(&TimePrev);
        }
    }
}

Why it's happened, and what can I do to send packet every 10 seconds?

1 Answers1

0

The NDIS6 programming model is asynchronous. This means when you call NdisFSendNetBufferLists, you actually give up ownership of the NBL. You cannot reuse the NBL until it is returned to your filter via your FilterReturnNetBufferLists callback.

So first off, you need to change the code to look more like this:

PNET_BUFFER_LIST NblToSend;

void FilterReturnNetBufferLists(PNET_BUFFER_LIST NblChain)
{
    for each Nbl in NblChain
    {
        if(Nbl->SourceHandle == MyFilterHandle)
            NblToSend = Nbl;
        else
            NdisFReturnNetBufferLists(Nbl);
    }
}

void ThreadedAction()
{
    while(1)
    {
        if(NBLtoSend)
        {
            PNET_BUFFER_LIST TempNbl = NblToSend;
            NblToSend = NULL;
            NdisFSendNetBufferLists(TempNbl);
        }
    }
}

This way, you honor the NDIS rule: Do not send an NBL again until it's been returned to you.

Next up, the looping is highly inefficient. As implemented, the loop will consume 100% of the CPU, busily counting down the nanoseconds until it's time to send another packet. Instead, use a timer. The system will call into your thread when 10 seconds have elapsed.

Jeffrey Tippet
  • 3,146
  • 1
  • 14
  • 15
  • **1.** Are you sure it's `FilterReturnNetBufferLists` and not `FilterSendNetBufferListsComplete`? **2.** If the problem occurs because I pass the ownership of the NBL to NDIS, why it's doesn't sends in the first call?, and why it's sends the packet when I don't check the time? **3.** I don't use timer, because this thread do also something else, which I want to execute all the time. – user2403272 May 23 '13 at 10:24
  • 1. Yes, silly me. I meant `FilerSendNetBufferListsComplete` – Jeffrey Tippet May 25 '13 at 20:24
  • 2. I'm not sure what this question means; could you rephrase? – Jeffrey Tippet May 25 '13 at 20:25
  • you said that my code cannot send the packet, because "You cannot **reuse** the NBL until it is returned to your filter via your FilterReturnNetBufferLists callback". in the first time the code is executed, I am don't reuse the NBL, and don't gave up ownership of the NBL. then why the packet doesn't sent in the first time? – user2403272 May 26 '13 at 10:29
  • When you call `NdisFSendNetBufferLists`, that gives up ownership of the NBL. You cannot touch the NBL again until it comes back to you via `FilterSendNetBufferListsComplete`. – Jeffrey Tippet May 29 '13 at 20:52