Porting Ndis IM to Vista LWF

All,

I am trying to port a Ndis5 Win2K/XP IM driver to run on Vista as a Ndis6 Filter driver. Most of my code in the IM driver will be easily ported once I get a packet list that I can modify so I thought the best place to start was in the packet data path.

Since the WDK documentations says that you can’t modify any of the NET_BUFFER pointers that belong to a NET_BUFFER_LIST that didn’t originate from your driver, my first guess was to use the NdisAllocateCloneNetBufferList so I have a copy to modify before sending the list and buffers on its way to the next driver. While the WDK says that I should use this function, it isn’t used anywhere in the Ndis6 driver examples … nice.

Anyhow, my send and sendcomplete functions are shown below. I have not yet modified the receive path so the problem is definitely here. I don’t get any crashes or resource leak warnings, but the cloned NET_BUFFER_LIST is not well received by the lower portion of the Ndis stack. For example: when I ping a host on my local network, I get “PING: transmit failed, error code 1231.” as output. It sounds to me like the system is unable to get ARP packets out on the wire.

If there is a Ndis Guru out there that can give me some suggestions, I would greatly appreciate it.

//-------------------------------------------------------------------
// Filter the netbuffer send list
//-------------------------------------------------------------------

VOID FilterSendNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG SendFlags )
{
PFLT_ADAPTER FLTAdapter = ( PFLT_ADAPTER ) FilterModuleContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PNET_BUFFER_LIST CurrNbl = NetBufferLists;
PNET_BUFFER_LIST NextNbl;
PNET_BUFFER_LIST ClonedNbl;
PNET_BUFFER CurrNb;
PFLT_NBL_RSVD NblReserved;
ULONG NumOfNetBufferLists = 0;
ULONG NumOfNetBuffers = 0;
BOOLEAN DispatchLevel;

DEBUGP( DL_TRACE, ( “===>SendNetBufferLists:\n” ) );

while( CurrNbl != NULL )
{
NextNbl = NET_BUFFER_LIST_NEXT_NBL( CurrNbl );

ClonedNbl = NdisAllocateCloneNetBufferList(
CurrNbl,
FLTAdapter->SendNetBufferListPool,
FLTAdapter->SendNetBufferPool,
NDIS_CLONE_FLAGS_USE_ORIGINAL_MDLS );

ClonedNbl->ParentNetBufferList = CurrNbl;
NET_BUFFER_LIST_NEXT_NBL( CurrNbl ) = NULL;
NET_BUFFER_LIST_NEXT_NBL( ClonedNbl ) = NULL;

NumOfNetBuffers = 0;
CurrNb = NET_BUFFER_LIST_FIRST_NB( ClonedNbl );
while( CurrNb != NULL )
{
NumOfNetBuffers++;
CurrNb = NET_BUFFER_NEXT_NB( CurrNb );
}

DEBUGP( DL_TRACE, ( “SendNetBufferLists: processing %i net buffers\n”, NumOfNetBuffers ) );

NdisFSendNetBufferLists(
FLTAdapter->FilterHandle,
ClonedNbl,
PortNumber,
SendFlags );

NumOfNetBufferLists++;

CurrNbl = NextNbl;
}

DEBUGP( DL_TRACE, ( “SendNetBufferLists: NumOfNetBufferLists %i\n”, NumOfNetBufferLists ) );

DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL( SendFlags );

FILTER_ACQUIRE_LOCK( &FLTAdapter->Lock, DispatchLevel );
FLTAdapter->OutstandingSends += NumOfNetBufferLists;
FILTER_RELEASE_LOCK( &FLTAdapter->Lock, DispatchLevel );

DEBUGP( DL_TRACE, ( “<===SendNetBufferLists: Status %8x\n”, Status ) );
}

VOID FilterSendNetBufferListsComplete(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG SendCompleteFlags )
{
PFLT_ADAPTER FLTAdapter = ( PFLT_ADAPTER ) FilterModuleContext;
PNET_BUFFER_LIST CurrNbl = NetBufferLists;
PNET_BUFFER_LIST NextNbl;
PNET_BUFFER_LIST ParentNetBufferList;
PFLT_NBL_RSVD NblReserved;
ULONG NumOfNetBufferLists = 0;
BOOLEAN DispatchLevel;

DEBUGP( DL_TRACE, ( “===>SendNetBufferListsComplete:\n” ) );

while( CurrNbl != NULL )
{
NextNbl = NET_BUFFER_LIST_NEXT_NBL( CurrNbl );

ParentNetBufferList = CurrNbl->ParentNetBufferList;

CurrNbl->ParentNetBufferList = NULL;

NdisFreeCloneNetBufferList(
CurrNbl,
NDIS_CLONE_FLAGS_USE_ORIGINAL_MDLS );

NdisFSendNetBufferListsComplete(
FLTAdapter->FilterHandle,
ParentNetBufferList,
SendCompleteFlags );

NumOfNetBufferLists++;

CurrNbl = NextNbl;
}

DEBUGP( DL_TRACE, ( “SendNetBufferListsComplete: NumOfNetBufferLists %i\n”, NumOfNetBufferLists ) );

DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL( SendCompleteFlags );

FILTER_ACQUIRE_LOCK( &FLTAdapter->Lock, DispatchLevel );
FLTAdapter->OutstandingSends -= NumOfNetBufferLists;
FILTER_RELEASE_LOCK( &FLTAdapter->Lock, DispatchLevel );

DEBUGP( DL_TRACE, ( “<===SendNetBufferListsComplete:\n” ) );
}

Thanks in advance,

-Matthew

NdisAllocCloneNetBufferList allocates a new NET_BUFFER_LIST structure - but the pointers still point to the original data.

If you are going to modify data you must allocate your own memory and make your modifications there.

Thomas F. Divine

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-311699-
xxxxx@lists.osr.com] On Behalf Of xxxxx@shrew.net
Sent: Wednesday, January 16, 2008 3:14 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Porting Ndis IM to Vista LWF

All,

I am trying to port a Ndis5 Win2K/XP IM driver to run on Vista as a
Ndis6 Filter driver. Most of my code in the IM driver will be easily
ported once I get a packet list that I can modify so I thought the best
place to start was in the packet data path.

Since the WDK documentations says that you can’t modify any of the
NET_BUFFER pointers that belong to a NET_BUFFER_LIST that didn’t
originate from your driver, my first guess was to use the
NdisAllocateCloneNetBufferList so I have a copy to modify before
sending the list and buffers on its way to the next driver. While the
WDK says that I should use this function, it isn’t used anywhere in the
Ndis6 driver examples … nice.

Anyhow, my send and sendcomplete functions are shown below. I have not
yet modified the receive path so the problem is definitely here. I
don’t get any crashes or resource leak warnings, but the cloned
NET_BUFFER_LIST is not well received by the lower portion of the Ndis
stack. For example: when I ping a host on my local network, I get
“PING: transmit failed, error code 1231.” as output. It sounds to me
like the system is unable to get ARP packets out on the wire.

If there is a Ndis Guru out there that can give me some suggestions, I
would greatly appreciate it.

//-------------------------------------------------------------------
// Filter the netbuffer send list
//-------------------------------------------------------------------

VOID FilterSendNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG SendFlags )
{
PFLT_ADAPTER FLTAdapter = ( PFLT_ADAPTER )
FilterModuleContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PNET_BUFFER_LIST CurrNbl = NetBufferLists;
PNET_BUFFER_LIST NextNbl;
PNET_BUFFER_LIST ClonedNbl;
PNET_BUFFER CurrNb;
PFLT_NBL_RSVD NblReserved;
ULONG NumOfNetBufferLists = 0;
ULONG NumOfNetBuffers = 0;
BOOLEAN DispatchLevel;

DEBUGP( DL_TRACE, ( “===>SendNetBufferLists:\n” ) );

while( CurrNbl != NULL )
{
NextNbl = NET_BUFFER_LIST_NEXT_NBL( CurrNbl );

ClonedNbl = NdisAllocateCloneNetBufferList(
CurrNbl,
FLTAdapter->SendNetBufferListPool,
FLTAdapter->SendNetBufferPool,
NDIS_CLONE_FLAGS_USE_ORIGINAL_MDLS
);

ClonedNbl->ParentNetBufferList = CurrNbl;
NET_BUFFER_LIST_NEXT_NBL( CurrNbl ) = NULL;
NET_BUFFER_LIST_NEXT_NBL( ClonedNbl ) = NULL;

NumOfNetBuffers = 0;
CurrNb = NET_BUFFER_LIST_FIRST_NB( ClonedNbl );
while( CurrNb != NULL )
{
NumOfNetBuffers++;
CurrNb = NET_BUFFER_NEXT_NB( CurrNb );
}

DEBUGP( DL_TRACE, ( “SendNetBufferLists: processing %i net
buffers\n”, NumOfNetBuffers ) );

NdisFSendNetBufferLists(
FLTAdapter->FilterHandle,
ClonedNbl,
PortNumber,
SendFlags );

NumOfNetBufferLists++;

CurrNbl = NextNbl;
}

DEBUGP( DL_TRACE, ( “SendNetBufferLists: NumOfNetBufferLists
%i\n”, NumOfNetBufferLists ) );

DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL( SendFlags );

FILTER_ACQUIRE_LOCK( &FLTAdapter->Lock, DispatchLevel );
FLTAdapter->OutstandingSends += NumOfNetBufferLists;
FILTER_RELEASE_LOCK( &FLTAdapter->Lock, DispatchLevel );

DEBUGP( DL_TRACE, ( “<===SendNetBufferLists: Status %8x\n”,
Status ) );
}

VOID FilterSendNetBufferListsComplete(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG SendCompleteFlags )
{
PFLT_ADAPTER FLTAdapter = ( PFLT_ADAPTER )
FilterModuleContext;
PNET_BUFFER_LIST CurrNbl = NetBufferLists;
PNET_BUFFER_LIST NextNbl;
PNET_BUFFER_LIST ParentNetBufferList;
PFLT_NBL_RSVD NblReserved;
ULONG NumOfNetBufferLists = 0;
BOOLEAN DispatchLevel;

DEBUGP( DL_TRACE, ( “===>SendNetBufferListsComplete:\n” ) );

while( CurrNbl != NULL )
{
NextNbl = NET_BUFFER_LIST_NEXT_NBL( CurrNbl );

ParentNetBufferList = CurrNbl->ParentNetBufferList;

CurrNbl->ParentNetBufferList = NULL;

NdisFreeCloneNetBufferList(
CurrNbl,
NDIS_CLONE_FLAGS_USE_ORIGINAL_MDLS );

NdisFSendNetBufferListsComplete(
FLTAdapter->FilterHandle,
ParentNetBufferList,
SendCompleteFlags );

NumOfNetBufferLists++;

CurrNbl = NextNbl;
}

DEBUGP( DL_TRACE, ( “SendNetBufferListsComplete:
NumOfNetBufferLists %i\n”, NumOfNetBufferLists ) );

DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(
SendCompleteFlags );

FILTER_ACQUIRE_LOCK( &FLTAdapter->Lock, DispatchLevel );
FLTAdapter->OutstandingSends -= NumOfNetBufferLists;
FILTER_RELEASE_LOCK( &FLTAdapter->Lock, DispatchLevel );

DEBUGP( DL_TRACE, ( “<===SendNetBufferListsComplete:\n” ) );
}

Thanks in advance,

-Matthew


NTDEV is sponsored by OSR

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

Thomas,

Thanks for the response. I understand that NdisAllocCloneNetBufferList only creates new NET_BUFFER_LIST and NET_BUFFER structures that point to the existing data. I don’t have any plans to modify the data referenced by the NET_BUFFER structures. The only changes I would make is potentially removing NET_BUFFERs from the linked list after evaluating them against an IP firewall rule set. It stands to reason that this would be a reasonable thing to do as the cloned NBL contains NBs allocated from my private pool. Th only data reused would be the original MDLS as I specify NDIS_CLONE_FLAGS_USE_ORIGINAL_MDLS in my call to NdisAllocCloneNetBufferList.

But as you can see from my code, I hardly modify anything at the moment. The only things I do is break up the NBLs passed to me by Ndis ( WDK says this is legal ), clone each NBL, set the parent pointer to the original NBL, pass the cloned NBL down the Ndis stack and wait for the completion routing to be called. All this seems to work as designed but the packet data isn’t being emitted as would be expected.

Matthew,

I think you might need to add

ParentNetBufferList->Status = CurrNbl->Status;

in your loop in FilterSendNetBufferListsComplete() to propagate the
completion status from the derived (clone) NBL to the original (parent) NBL.

Good Luck,
Dave Cattley
Consulting Engineer

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@shrew.net
Sent: Wednesday, January 16, 2008 3:14 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Porting Ndis IM to Vista LWF

All,

I am trying to port a Ndis5 Win2K/XP IM driver to run on Vista as a Ndis6
Filter driver. Most of my code in the IM driver will be easily ported once I
get a packet list that I can modify so I thought the best place to start was
in the packet data path.

Since the WDK documentations says that you can’t modify any of the
NET_BUFFER pointers that belong to a NET_BUFFER_LIST that didn’t originate
from your driver, my first guess was to use the
NdisAllocateCloneNetBufferList so I have a copy to modify before sending the
list and buffers on its way to the next driver. While the WDK says that I
should use this function, it isn’t used anywhere in the Ndis6 driver
examples … nice.

Anyhow, my send and sendcomplete functions are shown below. I have not yet
modified the receive path so the problem is definitely here. I don’t get any
crashes or resource leak warnings, but the cloned NET_BUFFER_LIST is not
well received by the lower portion of the Ndis stack. For example: when I
ping a host on my local network, I get “PING: transmit failed, error code
1231.” as output. It sounds to me like the system is unable to get ARP
packets out on the wire.

If there is a Ndis Guru out there that can give me some suggestions, I would
greatly appreciate it.

//-------------------------------------------------------------------
// Filter the netbuffer send list
//-------------------------------------------------------------------

VOID FilterSendNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG SendFlags )
{
PFLT_ADAPTER FLTAdapter = ( PFLT_ADAPTER )
FilterModuleContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PNET_BUFFER_LIST CurrNbl = NetBufferLists;
PNET_BUFFER_LIST NextNbl;
PNET_BUFFER_LIST ClonedNbl;
PNET_BUFFER CurrNb;
PFLT_NBL_RSVD NblReserved;
ULONG NumOfNetBufferLists = 0;
ULONG NumOfNetBuffers = 0;
BOOLEAN DispatchLevel;

DEBUGP( DL_TRACE, ( “===>SendNetBufferLists:\n” ) );

while( CurrNbl != NULL )
{
NextNbl = NET_BUFFER_LIST_NEXT_NBL( CurrNbl );

ClonedNbl = NdisAllocateCloneNetBufferList(
CurrNbl,

FLTAdapter->SendNetBufferListPool,

FLTAdapter->SendNetBufferPool,

NDIS_CLONE_FLAGS_USE_ORIGINAL_MDLS );

ClonedNbl->ParentNetBufferList = CurrNbl;
NET_BUFFER_LIST_NEXT_NBL( CurrNbl ) = NULL;
NET_BUFFER_LIST_NEXT_NBL( ClonedNbl ) = NULL;

NumOfNetBuffers = 0;
CurrNb = NET_BUFFER_LIST_FIRST_NB( ClonedNbl );
while( CurrNb != NULL )
{
NumOfNetBuffers++;
CurrNb = NET_BUFFER_NEXT_NB( CurrNb );
}

DEBUGP( DL_TRACE, ( “SendNetBufferLists: processing %i net
buffers\n”, NumOfNetBuffers ) );

NdisFSendNetBufferLists(
FLTAdapter->FilterHandle,
ClonedNbl,
PortNumber,
SendFlags );

NumOfNetBufferLists++;

CurrNbl = NextNbl;
}

DEBUGP( DL_TRACE, ( “SendNetBufferLists: NumOfNetBufferLists %i\n”,
NumOfNetBufferLists ) );

DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL( SendFlags );

FILTER_ACQUIRE_LOCK( &FLTAdapter->Lock, DispatchLevel );
FLTAdapter->OutstandingSends += NumOfNetBufferLists;
FILTER_RELEASE_LOCK( &FLTAdapter->Lock, DispatchLevel );

DEBUGP( DL_TRACE, ( “<===SendNetBufferLists: Status %8x\n”, Status )
); }

VOID FilterSendNetBufferListsComplete(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG SendCompleteFlags )
{
PFLT_ADAPTER FLTAdapter = ( PFLT_ADAPTER )
FilterModuleContext;
PNET_BUFFER_LIST CurrNbl = NetBufferLists;
PNET_BUFFER_LIST NextNbl;
PNET_BUFFER_LIST ParentNetBufferList;
PFLT_NBL_RSVD NblReserved;
ULONG NumOfNetBufferLists = 0;
BOOLEAN DispatchLevel;

DEBUGP( DL_TRACE, ( “===>SendNetBufferListsComplete:\n” ) );

while( CurrNbl != NULL )
{
NextNbl = NET_BUFFER_LIST_NEXT_NBL( CurrNbl );

ParentNetBufferList = CurrNbl->ParentNetBufferList;

CurrNbl->ParentNetBufferList = NULL;

NdisFreeCloneNetBufferList(
CurrNbl,
NDIS_CLONE_FLAGS_USE_ORIGINAL_MDLS );

NdisFSendNetBufferListsComplete(
FLTAdapter->FilterHandle,
ParentNetBufferList,
SendCompleteFlags );

NumOfNetBufferLists++;

CurrNbl = NextNbl;
}

DEBUGP( DL_TRACE, ( “SendNetBufferListsComplete: NumOfNetBufferLists
%i\n”, NumOfNetBufferLists ) );

DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL( SendCompleteFlags
);

FILTER_ACQUIRE_LOCK( &FLTAdapter->Lock, DispatchLevel );
FLTAdapter->OutstandingSends -= NumOfNetBufferLists;
FILTER_RELEASE_LOCK( &FLTAdapter->Lock, DispatchLevel );

DEBUGP( DL_TRACE, ( “<===SendNetBufferListsComplete:\n” ) ); }

Thanks in advance,

-Matthew


NTDEV is sponsored by OSR

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