ndis6.0 NetBufferSend相关函数与数据结构

FilterSendNetBufferListsComplete:

NDIS calls the FilterSendNetBufferListsComplete function to complete a send request that a filter driver started by calling the NdisFSendNetBufferLists function.

FilterSendNetBufferLists:

NDIS calls the FilterSendNetBufferLists function to allow a filter driver to filter a linked list of NET_BUFFER_LISTstructures.
 
调用关系如下:


ndis6.0中NET_BUFFER_LIST和NET_BUFFER是两个很重要的数据结构。
如何在FilterSendNetBufferLists函数中读取数据包的内容呢,步骤如下:
1.pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(CurrNbl)
2.pMdl = NET_BUFFER_CURRENT_MDL(pCurrentNetBuffer)
3.NdisQueryMdl(
        pMdl,
        &pEthHeader,
        &ulBufferLength,
        NormalPagePriority);可以获得Mdl的地址指针保存在pEthHeader中,同时返回MDL内存块的大小ulBufferLength。
4.pEthHeader = (struct ether_header *)((PUCHAR)pEthHeader + NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNetBuffer)),这样pEthHeader 即指向我们熟悉的数据帧了(包含以太头+TCP/IP层头部)。
 
在获取数据包的过程中需要注意的是:
1).一个NET_BUFFER_LIST结构指向的是一连串的NET_BUFFER,这些NET_BUFFER中保存的数据包内容属于同一个stream(the same src-ip,dst-ip,src-port,dst-port and protocol)。通过NET_BUFFER_NEXT_NB(pCurrentNetBuffer)可以获取下一个NET_BUFFER。
2).在NET_BUFFER中包含NET_BUFFER_DATA结构
typedef struct _NET_BUFFER_DATA {
  PNET_BUFFER   Next;
  PMDL   MdlChain;
  ULONG   DataLength;
  ULONG   DataOffset;
  PMDL   CurrentMdl;
  ULONG   CurrentMdlOffset;
} NET_BUFFER_DATA, *PNET_BUFFER_DATA;
数据包的内容保存在MDL中,在上面的步骤2和3中,可通过NET_BUFFER信息获取到保存数据包内容的地址。因为MDL指示的那一块内存会有一个MDL头部信息(我并不确定),所以需要用pEthHeader + NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNetBuffer),这时才指向真正意义上的数据包内容。
3).一个NET_BUFFER因为MDL指向的内存大小有限制(我的观察是100个字节左右),所以一个NET_BUFFER会含有多个MDL(如一个1000字节的数据包,可能就会分为10个MDL进行保存),用MdlChain表示(即一个Mdl链表)。
4).通常情况下,NET_BUFFER中MdlChain与NET_BUFFER_CURRENT_MDL(pCurrentNetBuffer)获取到的CurrentMdl相同,同样的NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNetBuffer)与NET_BUFFER中DataOffset相同。
5).NET_BUFFER中DataLength代表数据包的总长度。在上面的步骤3中,获取到的ulBufferLength - NET_BUFFER_CURRENT_MDL(pCurrentNetBuffer),若所得值小于DataLength,则说明NET_BUFFER中含有多个MDL,若想获取完整包的信息则通过pMdl.next获取下一个MDL指针,在进行相关操作。
 
下面是我改写filter中FilterSendNetBufferLists函数的代码:
 
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;
	PMDL				pMdl;
	ULONG				ulOffset;
	struct ether_header *pEthHeader = NULL;
	ULONG				ulBufferLength = 0;
	ULONG				NBDO;
	ULONG 				NBDL;

	//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)
		{
			FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
			CurrNbl = NetBufferLists;
			while (CurrNbl)
			{
				pFilter->OutstandingSends++;
				FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends);

				NextNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
				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)) 
				{
					pMdl = NET_BUFFER_CURRENT_MDL(pCurrentNetBuffer);
					ulOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNetBuffer);
					NBDL = NET_BUFFER_DATA_LENGTH(pCurrentNetBuffer);
					NBDO = NET_BUFFER_DATA_OFFSET(pCurrentNetBuffer);
					
					do 
					{
						ASSERT(pMdl != NULL);
						if (pMdl)
						{
							NdisQueryMdl(
								pMdl,
								&pEthHeader,
								&ulBufferLength,
								NormalPagePriority);
						}
						if (NULL == pEthHeader)
						{
							//
							//  The system is low on resources. Set up to handle failure
							//  below.
							//
							ulBufferLength = 0;
							break;
						}

						if (0 == ulBufferLength)
						{
							break;
						}

						ASSERT(ulBufferLength > ulOffset);
						//if the ulBufferLength < NBDL, then there are some more MDLs.
						DbgPrint("NBDL IS %d, NBD0 IS %d, MDL_OFFSET IS %d, MDL NET BUFFER LENGTH IS %d\n", NBDL, NBDO, ulOffset, ulBufferLength);

						ulBufferLength -= ulOffset;
						pEthHeader = (struct ether_header *)((PUCHAR)pEthHeader + ulOffset);

						if (ulBufferLength < sizeof(struct ether_header))
						{
							DEBUGP(DL_WARN,
								("ReceiveNetBufferList: runt nbl %p, first buffer length %d\n",
								CurrNbl, ulBufferLength));
							break;
						}
						DbgPrint("DstMAC: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",pEthHeader->ether_dhost[0],pEthHeader->ether_dhost[1],pEthHeader->ether_dhost[2],pEthHeader->ether_dhost[3],pEthHeader->ether_dhost[4],pEthHeader->ether_dhost[5]);
						DbgPrint("srcMAC: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",pEthHeader->ether_shost[0],pEthHeader->ether_shost[1],pEthHeader->ether_shost[2],pEthHeader->ether_shost[3],pEthHeader->ether_shost[4],pEthHeader->ether_shost[5]);				
					}while (bFalse);
					DbgPrint("End one NB process!\n");
				}
				//DbgPrint("IF NOT SHOW THIE, MAYBE SOME PROBLEM.\n");
				CurrNbl= NextNbl;
			}
			FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
		}
		//
		// If necessary, queue the NetBufferList in a local structure for later processing
		//		
		NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags);

	}
	while (bFalse);

	DEBUGP(4, ("<===SendNetBufferList. \n"));
}
其中用到了一个新的数据类型,可以添加到filter.h头文件中:
#define	ETHER_ADDR_LEN		6	/* length of an Ethernet address */
struct	ether_header {
	UCHAR	ether_dhost[ETHER_ADDR_LEN];
	UCHAR	ether_shost[ETHER_ADDR_LEN];
	USHORT	ether_type;
};


你可能感兴趣的:(NDIS学习)