下面的代码中部分是伪代码,但关键的流程整理出来了,过滤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.