NDIS filter driver sends packets unsucessfully (continued)

Here is what we were last time:

http://www.osronline.com/showThread.cfm?link=241177

In summary, I was writing a NDIS filter driver that originates TCP packets (then I modified it to send ethernet packet as what the protocol driver sample does). The problem is the packets I sent were not detected on Wireshark.

Then Thomas told me the general processes for sending packets by filter driver, and finally suggested me to look at the NDIS protocol driver sample.

Since last time, I read the the protocol driver sample, and modified my filter driver, which now seems almost the same with the protocol driver. But it turns out the protocol driver works well (I monitor the packets received by another host on Wireshark), while I still cannot see the packets sent by filter driver.

Here are what I did:

I made the user application, writing and cancel routine (which never been called) exactly the same with protocol driver sample. For completion routine, the only difference is I scans the NBLs and check whether each NBL was originated by my filter driver. If it was, I free it as protocal driver does. Otherwise, I link the NBL to a list, and complete the newly-generated NBLs finally.

Is there any other routine I should pay attention to?

Looks like you are on the right track. But some detail (unknown to me) is
missing.

Below is a snippet of al old write handler for a NDIS 6 LWF. Could be a
little confusing to you because it can send packets either on the network
(down the stack) or to the local host (up the stack).

Some of the logic (W32N_OPEN_CONTEXT and friends) is just mapping the file
handle to the filter context. A user-mode file handle maps to a LWF filter
instance in some mysterious way. I won’t describe how that works. Use your
own scheme.

Perhaps this snippet can provide some help.

Good luck,

Thomas

NTSTATUS
FilterDeviceWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pWriteIrp
)
{
PIO_STACK_LOCATION pIrpSp;
PMS_FILTER pFilter = NULL;
PW32N_OPEN_CONTEXT pW32NOpenContext = NULL;
ULONG DataLength;
PNET_BUFFER_LIST pNetBufferList;
PNET_BUFFER_LIST_CONTEXT Context;
PSEND_NETBUFLIST_RSVD pSendRsvd;
ULONG Flags = 0;
PMDL pWriteMdl = NULL;

Ndf_DbgPrint(DL_TRACE, DBG_WRITE, “==>FilterDeviceWrite\n”);

//
// Initialize Default Settings
//
pWriteIrp->IoStatus.Information = 0;

//
// Get a pointer to the current stack location in the pWriteIrp. This is
// where the function codes and parameters are located.
//
pIrpSp = IoGetCurrentIrpStackLocation(pWriteIrp);

//
// Find the Win32 Open Context
//
if( pIrpSp->FileObject && pIrpSp->FileObject->FsContext &&
pIrpSp->FileObject->FsContext2 )
{
pFilter = (PMS_FILTER )pIrpSp->FileObject->FsContext;

pW32NOpenContext = W32N_MapOpenRefnum(
pFilter,
(ULONG_PTR )pIrpSp->FileObject->FsContext2
);
}

//
// Sanity Check on Win32 Context
//
if( !pW32NOpenContext )
{
//
// Fail The IRP
//
pWriteIrp->IoStatus.Status = STATUS_INVALID_HANDLE;
pWriteIrp->IoStatus.Information = 0; // Nothing Returned

IoCompleteRequest( pWriteIrp, IO_NO_INCREMENT );

return( STATUS_INVALID_HANDLE );
}

if( pW32NOpenContext->m_bIsClosing )
{
//
// Fail The IRP
//
pWriteIrp->IoStatus.Status = STATUS_CANCELLED;
pWriteIrp->IoStatus.Information = 0; // Nothing Returned

IoCompleteRequest( pWriteIrp, IO_NO_INCREMENT );

return( STATUS_CANCELLED );
}

DataLength = pIrpSp->Parameters.Write.Length;

if (DataLength < ETHER_HDR_LEN)
{
Ndf_DbgPrint(DL_WARNING, DBG_WRITE, “FilterDeviceWrite: Too small to
be a valid packet (%d bytes)\n”, DataLength);

// Fail The IRP
pWriteIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
pWriteIrp->IoStatus.Information = 0; // Nothing Returned

IoCompleteRequest( pWriteIrp, IO_NO_INCREMENT );

return( STATUS_BUFFER_TOO_SMALL ); // Win32:
ERROR_INSUFFICIENT_BUFFER
}

NDF_ACQUIRE_SPIN_LOCK(&pFilter->Lock, FALSE);

//
// Sanity Check on Filter State
//
if (pFilter->State != FilterRunning)
{
NDF_RELEASE_SPIN_LOCK(&pFilter->Lock, FALSE);

Ndf_DbgPrint(DL_WARNING, DBG_WRITE, “FilterDeviceWrite: Filter Not
Running!!!\n”);

// Fail The IRP
pWriteIrp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
pWriteIrp->IoStatus.Information = 0; // Nothing Returned

IoCompleteRequest( pWriteIrp, IO_NO_INCREMENT );

return( STATUS_DEVICE_NOT_READY ); // Win32: ERROR_NOT_READY
}

ASSERT(pFilter->UserSendNetBufferListPool != NULL);

pWriteMdl = NdisAllocateMdl(
pFilter->FilterHandle,
pWriteIrp->AssociatedIrp.SystemBuffer,
DataLength
);

if( !pWriteMdl )
{
NDF_RELEASE_SPIN_LOCK(&pFilter->Lock, FALSE);

Ndf_DbgPrint(DL_WARNING, DBG_WRITE, “FilterDeviceWrite: Could Not
Allocate MDL!!!\n”);

// Fail The IRP
pWriteIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
pWriteIrp->IoStatus.Information = 0; // Nothing Returned

IoCompleteRequest( pWriteIrp, IO_NO_INCREMENT );

return( STATUS_INSUFFICIENT_RESOURCES ); // Win32:
ERROR_NOT_READY
}

pWriteMdl->Next = NULL; // No Chained MDLs Here!

pNetBufferList = NdisAllocateNetBufferAndNetBufferList(
pFilter->UserSendNetBufferListPool,
sizeof(SEND_NETBUFLIST_RSVD), //Request control offset delta
0, // back fill size
pWriteMdl,
0, // Data offset
DataLength);

if (pNetBufferList == NULL)
{
NDF_RELEASE_SPIN_LOCK(&pFilter->Lock, FALSE);

Ndf_DbgPrint(DL_WARNING, DBG_WRITE, “FilterDeviceWrite: Binding %p:
Failed to alloc send net buffer list\n”,
pFilter);

NdisFreeMdl( pWriteMdl );

// Fail The IRP
pWriteIrp->IoStatus.Status = STATUS_NO_MEMORY;
pWriteIrp->IoStatus.Information = 0; // Nothing Returned

IoCompleteRequest( pWriteIrp, IO_NO_INCREMENT );

return( STATUS_NO_MEMORY );
}

//
// Find and Initialize the Context Area in the NBL
//
Context = pNetBufferList->Context;

ASSERT( Context );

if( !Context )
{
NDF_RELEASE_SPIN_LOCK(&pFilter->Lock, FALSE);

NdisFreeMdl( pWriteMdl );

NdisFreeNetBufferList( pNetBufferList );

Ndf_DbgPrint(DL_WARNING, DBG_WRITE, “FilterDeviceWrite: Binding %p:
Context NULL\n”,
pFilter);

// Fail The IRP
pWriteIrp->IoStatus.Status = STATUS_NO_MEMORY;
pWriteIrp->IoStatus.Information = 0; // Nothing Returned

IoCompleteRequest( pWriteIrp, IO_NO_INCREMENT );

return( STATUS_NO_MEMORY );
}

pSendRsvd = (PSEND_NETBUFLIST_RSVD )&Context->ContextData[0];

pSendRsvd->pFilter = pFilter;
pSendRsvd->pW32NOpenContext = pW32NOpenContext;
pSendRsvd->OriginID = ORIGIN_USER_APPLICATION;
pSendRsvd->pIrp = pWriteIrp;
pSendRsvd->DataLength = DataLength;

//
// Add Reference Count to Binding
// ------------------------------
// This reference will be removed when the send completes.
//
filterAddReference( pFilter );

IoMarkIrpPending(pWriteIrp);

pNetBufferList->SourceHandle = pFilter->FilterHandle;

// Increment These Counts With Lock Held
if( pW32NOpenContext->m_bIsVirtualAdapter )
++pFilter->OutstandingRcvs;
else
++pFilter->OutstandingSends;

NDF_RELEASE_SPIN_LOCK(&pFilter->Lock, FALSE);

if( pW32NOpenContext->m_bIsVirtualAdapter )
{
// Write on Virtual Adapter Indicates a Receive to the Host
pSendRsvd->Internal.ReturnPacketHandler = UserIoReturnNetBufferList;

Flags = 0;

NdisFIndicateReceiveNetBufferLists(
pFilter->FilterHandle,
pNetBufferList,
NDIS_DEFAULT_PORT_NUMBER,
1,
Flags // Receive Flags
);
}
else
{
// Write on Lower Adapter Sends a Packet on the Network
pSendRsvd->Internal.SendCompleteHandler = UserIoSendComplete;

Flags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK;

//
// Disable checksum offload on this packet
// ---------------------------------------
// From the DDK:
//
// “If the TCP/IP transport does not set either the IsIPv4 or IsIPv6
flag,
// the miniport driver should not perform checksum tasks on the
packet.”
//
NET_BUFFER_LIST_INFO( pNetBufferList, TcpIpChecksumNetBufferListInfo )
= 0;

NdisFSendNetBufferLists(
pFilter->FilterHandle,
pNetBufferList,
NDIS_DEFAULT_PORT_NUMBER,
Flags // Send Flags
);
}

return STATUS_PENDING;
}

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Thursday, May 9, 2013 6:07 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] NDIS filter driver sends packets unsucessfully (continued)

Here is what we were last time:

http://www.osronline.com/showThread.cfm?link=241177

In summary, I was writing a NDIS filter driver that originates TCP packets
(then I modified it to send ethernet packet as what the protocol driver
sample does). The problem is the packets I sent were not detected on
Wireshark.

Then Thomas told me the general processes for sending packets by filter
driver, and finally suggested me to look at the NDIS protocol driver sample.

Since last time, I read the the protocol driver sample, and modified my
filter driver, which now seems almost the same with the protocol driver. But
it turns out the protocol driver works well (I monitor the packets received
by another host on Wireshark), while I still cannot see the packets sent by
filter driver.

Here are what I did:

I made the user application, writing and cancel routine (which never been
called) exactly the same with protocol driver sample. For completion
routine, the only difference is I scans the NBLs and check whether each NBL
was originated by my filter driver. If it was, I free it as protocal driver
does. Otherwise, I link the NBL to a list, and complete the newly-generated
NBLs finally.

Is there any other routine I should pay attention to?


NTDEV is sponsored by OSR

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Do your packets go out on the wire?

You are not telling us where Wireshark is running (what host).

In all probability you need to read about how loopback works in NDIS.

Are you specifying NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK on packets that you
‘inject’?

Good Luck,
Dave Cattley

I run Wireshark on the the host that receives packets.

No, I don’t set the flag to NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK, but it still works on protocol driver.

> No, I don’t set the flag to NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK, but it
still works on protocol driver.

But your LWF is not a protocol driver. The nature of its ‘binding’ is
slightly different. Multiple protocols bind to an adapter as peers
side-by-side (horizontal if you will). Multiple LWFs are ‘attached’ to an
adapter in a stack (vertical if you will).

Let’s assume for a moment that NDIS behaves roughly the following when
something calls Ndis(*)SendNetBufferList:

If (any_other_entities_bound_as_sender_peer ||
NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK) Then
Check_For_Loopback()
Clear_Flag(NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK)

So to be clear, I don’t know that this is the logic.

But consider what would happen then in a LWF where there are never any
peers. The send packet should just keep going down without being checked
for loopback at every level in the stack of LWFs. Otherwise, there would
be quite a few loopbacks of the same packet. The assumption is that NDIS
already dealt with the loopback at the top of the stack of LWFs and has no
reason to need to do it again (thus clearing the flag). NOTE: It might not
clear the flag. It might just know it has already looped the packet back.
Whatever.

But in your case you are ‘injecting’ a packet in the middle of the stack of
LWFs starts the packet downward at a different point in the processing.
There are no ‘peers’ ever at the bottom edge of your LWF and unless you tell
NDIS that you need this packet processed for loopback, how would it guess to
do so?

I did note in the snippet of code Thomas graciously posted that this flag is
‘set’ on injections. You should probably try setting it and see if that
solves your problem.

Good Luck,
Dave Cattley

The problem was solved, but not because of the flag.
I just changed a new computer. when I reconfigured the driver, it sent packets successfully. I still don’t know the reason though.