您的位置:首页 > Web前端

ndis6.0 NetBufferSend

2015-06-11 16:47 239 查看


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).
4000
通常情况下,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;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: