下面的代码中部分是伪代码,但关键的流程整理出来了,过滤databuffer,将允许通过的NBL和不允许通过的NBL分别加入 NBL_QUEUE_HEADER NblSendQueue;或NBL_QUEUE_HEADER NblDropQueue;链表中。然后将两个NBLs分别进行处理即可。
// Send Passthrough NetBufferLists
if( GET_NBL_QUEUE_HEAD( &NblSendQueue ) )
{
NdisFSendNetBufferLists(
pFilter->FilterHandle,
GET_NBL_QUEUE_HEAD( &NblSendQueue ),
PortNumber,
SendFlags);
}
// Complete Blocked NetBufferLists
if( GET_NBL_QUEUE_HEAD( &NblDropQueue ) )
{
NdisFSendNetBufferListsComplete(
pFilter->FilterHandle,
(PNET_BUFFER_LIST)GET_NBL_QUEUE_HEAD( &NblDropQueue ),
DispatchLevel?NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL:0);
}
具体点的代码如下:
VOID
FilterSendNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG SendFlags
)
/*++
Routine Description:
Send Net Buffer List handler
This function is an optional function for filter drivers. If provided, NDIS
will call this function to transmit a linked list of NetBuffers, described by a
NetBuferList, over the network. If this handler is NULL, NDIS will skip calling
this fitler when sending a NetBufferList and will call the next lower fitler
in the stack with a non_NULL FilterSendNetBufferList handleror the miniport driver.
A filter that doesn't provide a FilerSendNetBufferList handler can not initiate a
send o its own.
Arguments:
FilterModuleContext: Pointer to our filter context area.
NetBufferLists: Pointer to a List of NetBufferLists.
PortNumber - Port Number to which this send is targetted
SendFlags- Specifies if the call is at DISPATCH_LEVEL
Return Value:
NDIS_STATUS_SUCCESS:
NDIS_STATUS_PENDING:
NDIS_STATUS_INVALID_PACKET:
NDIS_STATUS_RESOURCES:
NDIS_STATUS_FAILURE:
NOTE: The filter will act like a passthru filter.
--*/
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
BOOLEAN DispatchLevel;
BOOLEAN bFalse = FALSE;
PNET_BUFFER_LIST CurrNbl, NextNbl;
PNET_BUFFER pCurrentNetBuffer;
UCHAR pPakData[MAXSCANLENGTH];
ULONG scanlength;
USHORT StreamFlag = 0;
NBL_QUEUE_HEADER NblSendQueue;
NBL_QUEUE_HEADER NblDropQueue;
INIT_NBL_QUEUE_HEADER( &NblSendQueue );
INIT_NBL_QUEUE_HEADER( &NblDropQueue );
NdisZeroMemory(pPakData, sizeof(pPakData));
DEBUGP(DL_TRACE, ("===>SendNetBufferList: NBL = %p.\n", NetBufferLists));
do
{
DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);
#if DBG
//
// we should never get packets to send if we are not in running state
//
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
//
// If the filter is not in running state, fail the send
//
if (pFilter->State != FilterRunning)
{
DEBUGP(4, ("NOT SURE WHETHER IN THIS PATH.\n"));
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
CurrNbl = NetBufferLists;
while (CurrNbl)
{
NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
NdisFSendNetBufferListsComplete(pFilter->FilterHandle,
NetBufferLists,
DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
break;
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif
if (pFilter->TrackSends)
{
CurrNbl = NetBufferLists;
while (CurrNbl)
{
pFilter->OutstandingSends++;
NextNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
NET_BUFFER_LIST_NEXT_NBL(CurrNbl) = NULL;
DEBUGP(4, ("===>BufferList: NBL = %p, begin the NB process.\n", NetBufferLists));
for(pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(CurrNbl);
pCurrentNetBuffer != NULL;
pCurrentNetBuffer = NET_BUFFER_NEXT_NB(pCurrentNetBuffer))
{
if( NULL==NdisGetDataBuffer(pCurrentNetBuffer,scanlength,pPakData,1,0)){
goto MoveToNextNbl;
}
...
//TODO:filter the databuffer
IF FOUND THE PACKET NEED TO DROP
GO MoveToNextNbl;
...
DbgPrint("End one NB process!\n");
}
MoveToNextNbl:
//
if( StreamFlag & STREAM_POLICY_DENY)
{
INSERT_TAIL_NBL_QUEUE( &NblDropQueue, CurrNbl );
}else{
INSERT_TAIL_NBL_QUEUE( &NblSendQueue, CurrNbl );
}
CurrNbl= NextNbl;
}
}
// Send Passthrough NetBufferLists
if( GET_NBL_QUEUE_HEAD( &NblSendQueue ) )
{
NdisFSendNetBufferLists(
pFilter->FilterHandle,
GET_NBL_QUEUE_HEAD( &NblSendQueue ),
PortNumber,
SendFlags);
}
// Complete Blocked NetBufferLists
if( GET_NBL_QUEUE_HEAD( &NblDropQueue ) )
{
NdisFSendNetBufferListsComplete(
pFilter->FilterHandle,
(PNET_BUFFER_LIST)GET_NBL_QUEUE_HEAD( &NblDropQueue ),
DispatchLevel?NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL:0);
}
}
while (bFalse);
DEBUGP(4, ("<===SendNetBufferList. \n"));
}
注意:这个示例不是修改net buffer,也不是drop掉某一个net buffer。它针对stream进行操作,因为一个的NBL中保存的是相同的“srcIP、dstIP、srcPort、dstPort”,它们属于一个stream,如果一个NBL中有多个NETBUFFER,这些NETBUFFER都会被drop掉。
关于NBL_QUEUE_HEADER NblSendQueue;等相关的操作请参考:
http://ndis.com/ndis-ndis6/packetsort/packetsort.htm
Thanks, Thomas.