Filter发送自定义数据详解

                                                    

这里介绍如何从创建数据到最后发送数据的一个过程。

首先要做准你要发送的数据,注意你的数据大小至少要不少于64Byte。我们这里设置数据包的大小为80Byte.里面的内容包含一个14ByteEthernet Header,其他空位用无用数据填充。下面是具体流程:

一、创建缓冲区----用于保存自定义的数据

Ndis中创建新的一块内存的函数是:NdisAllocateMemoryWithTagPriority(),其他函数自行参考MSDN. 下面是用例:

pWriteBuf = (PUCHAR)NdisAllocateMemoryWithTagPriority(pFilter->FilterHandle,BufferSize,FILTER_ALLOC_TAG, LowPoolPriority);

其中BufferSize等于80(比这个大也可以!根据需要。)

二、封装自定义数据

因为Ethernet Header是一个Struct结构,定义如下:

typedef struct _TESTPROV_ETH_HEADER

{

    UCHAR       DstAddr[TESTPROV_MAC_ADDR_LEN];

    UCHAR       SrcAddr[TESTPROV_MAC_ADDR_LEN];

    USHORT      EthType;

 

} TESTPROV_ETH_HEADER;

所以我们要把这些成员变量都赋值。首先申明一个TESTPROV_ETH_HEADER的一个指针变量,然后指向PwriteBuf所指的那块内存:

pEthHeader = (PTESTPROV_ETH_HEADER)pWriteBuf;

然后开始给TESTPROV_ETH_HEADER中的每个成员函数赋值,其中EthType= 0x8e88.

 

三、创建MDL

由于我们最终要把自定义的数据封装成NBL,然后发送出去。如果了解NBL结构,知道NBL由一个或者多个NB构成,每个NB又由一个或者多个MDL构成。所以这里我们先分配一个MDL,用来保存自定义的数据。

pMdl = NdisAllocateMdl(pFilter->FilterHandle,

                               pEthFrameNew,  

                               BufferSize);

注意这里pEthFrameNew是一个Virtual Address.指向的是MDL缓冲区的基地址。需要事先分配:

pEthFrameNew = (PUCHAR)NdisAllocateMemoryWithTagPriority(pFilter->FilterHandle,BufferSize,FILTER_ALLOC_TAG, LowPoolPriority);

 

四、拷贝数据到MDL,并且释放pWriteBuf

如果你的MDL创建成功之后,MDL中是没有内容的,需要把之前自定义在pWriteBuf中的数据拷贝到MDL中:

NdisMoveMemory(pEthFrameNew,pEthHeader, BufferSize);

之后释放pWriteBuf(勿忘)

 NdisFreeMemory(pWriteBuf,BufferSize,0);

五、创建NBL

在创建NBL之前,有一件很重要的工作,那就是要分配好NetBufferListsPool.因为之后所有从Filter创建的NBL都要建立在这个Pool之上。从方便和多次利用考虑,我们把Pool分配工作在FilterAttach中完成:

        NdisZeroMemory(&PoolParameters,            sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));

 

        PoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;

        PoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;

        PoolParameters.Header.Size = sizeof(PoolParameters);

        PoolParameters.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT ;

        PoolParameters.ContextSize = sizeof(FILTER_SEND_NETBUFLIST_RSVD);

        PoolParameters.fAllocateNetBuffer = TRUE;

        PoolParameters.PoolTag = FILTER_ALLOC_TAG;

        pFilter->SendNetBufferListPool = NdisAllocateNetBufferListPool(

                                                    NdisFilterHandle,

                                                    &PoolParameters);

需要注意的是,Ndis为每个Filter module instance 各自分配一个Pool. 还有sizeof(FILTER_SEND_NETBUFFER_RSVD)的值必须为8的整数倍(0亦可)

这里我们采用函数NdisAllocateNetBufferAndNetBufferList()来创建NBL,因为它不需要事先创建NB就可以直接跳过这一步创建NBL,有兴趣可以参考NdisAllocateNetBufferList().需要的参数为之前创建的Pool,以及预分配的MDL等。

                              pNetBufferList = NdisAllocateNetBufferAndNetBufferList(

                                pFilter->SendNetBufferListPool,

                                sizeof(FILTER_SEND_NETBUFLIST_RSVD),

                                0,           // back fill size

                                pMdl,

                                0,          // Data offset

                                BufferSize);

注意:如果没有成功创建NBL,需要释放MDL.免得内存泄露。

六、发送NBL

发送之前需要制定NBLSourceHandle,为了后面处理需要,以辨别是自己定义的数据。其次制定发送的Dispatch_level.

                              pNetBufferList->SourceHandle = pFilter->FilterHandle;

             

                              //NDIS_MDL_LINKAGE(pMdl) = NULL;

                              SendFlags = NDIS_SEND_FLAGS_DISPATCH_LEVEL;

                              NdisFSendNetBufferLists(       

                        pFilter->FilterHandle,

                        pNetBufferList,

                        NDIS_DEFAULT_PORT_NUMBER,

                        SendFlags);

七、处理NdisFSengNetBufferListComplete

这里需要注意:如果不是你自己发送的数据,需要通知Protocol层,该数据已经提交给底层了。如果是自己的创建和发送的,需要额外处理,销毁证据,因为上层Protocol没有让Filter发送该数据,如果也通知发送完毕就会出事,最显而易见的就是Blue Screen. 所以你要做的:

1.       判断是否是自己发送的数据:

if(NetBufferLists->SourceHandle == pFilter->FilterHandle){}

2.       如果是,销毁自定义数据

pMdl = NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(NetBufferLists));

                                             

FILTER_ASSERT(pMdl != NULL);

NdisQueryMdl(

                pMdl,

                (PVOID *)&pCopyData,

                &BufferLength,

                NormalPagePriority);

                                                             

FILTER_ASSERT(pCopyData != NULL);

FILTER_DEREF_SEND_NBL(NetBufferLists, DispatchLevel);

  NdisFreeMdl(pMdl);

pCopyData = NULL;

3.       如果不是,调用NdisFSendNetBufferListsComplete()通知上层驱动

NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NetBufferLists, SendCompleteFlags);

到这里,该数据包发送完毕!

八、卸载释放Pool

这里是题外话:你在FilterAttach分配的Pool,你需要在FilterDetach时释放:

                if(pFilter->SendNetBufferListPool !=NULL)

              {

                  NdisFreeNetBufferListPool(pFilter->SendNetBufferListPool);

                              pFilter->SendNetBufferListPool = NULL;

              }

不要担心,各自的Filter Module Instance都会各自释放自己的Pool.

九、整理暂时结束

 

一路风尘  整理

   

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值