`
yexin218
  • 浏览: 971104 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

基于PassThru的NDIS中间层驱动程序扩展(续)

阅读更多

基于PassThru的NDIS中间层驱动程序扩展

4.2 接收处理
    接收的时候,由于那个TransferData的曲折过程,使得接收处理要相对复杂一点点,在 ProtocolReceive和 ProtocolReceivePacket中的处理不同。但是由于2003 DDK中的PassThru中,没有对数据进行任何处理,所以,它的ProtocolReceive的处理相对来说,简单了一些。

NDIS_STATUS PtReceive(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN NDIS_HANDLE MacReceiveContext,
    IN PVOID HeaderBuffer,
    IN UINT HeaderBufferSize,
    IN PVOID LookAheadBuffer,
    IN UINT LookAheadBufferSize,
    IN UINT PacketSize
    )
{
    // .......


    do
    {
        // 分配一个新的包描述符

        NdisDprAllocatePacket(&Status, &MyPacket, pAdapt->RecvPacketPoolHandle);
        if (Status == NDIS_STATUS_SUCCESS)
        {
            // PassThru维护了一个自己的接收队列,当收到下层的包时,PassThru并不是立刻

            // 调用NdisMIndicateReceive/NdisMXxxIndicateReceive请求NDIS通知上层新数据

            // 的到来,而是在自己的队列中缓冲起来,当自己的队列满了以后,PassThru将一

            // 次性调用NdisMIndicateReceive请求NDIS通知上层数据的到来。

            // 通常最底程的Miniport Driver也有同样的处理机制。

            PtQueueReceivedPacket(pAdapt, MyPacket, TRUE);
            // MyPacket的一个副本被Copy到PassThru中的队列去了,现在可以释放这一个Packet了。

            NdisDprFreePacket(MyPacket);
            break; // 注意这里,跳出了整个do-while了。

        }
       else
       {
            //

            // The miniport below us uses the old-style (not packet)

            // receive indication. Fall through.

            //

       }

        if (Packet != NULL)
        {
            // 当执行到这里,说明前面没有跳出do-while循环,也就是说,包申请失败

            // 进一步说明,PassThru的缓冲队列满了,于是有必要,调用 NdisMIndicateReceive

            // 请求NDIS通知上层数据包的到来了,这将导致上层注册的 ProtocolReceivePacket

            // 被调用.

            PtFlushReceiveQueue(pAdapt);
        }
        
        // ......

        // 把队列中的包通知了给上层接收,但是这一个包,由于分配新的描述符失败

        // 所以并没有通知给上层,因此,在这里,进行单独的处理。

        
        pAdapt->IndicateRcvComplete = TRUE;
        // 以下是进行各种协议相关的处理。

        switch (pAdapt->Medium)
        {
        case NdisMedium802_3:
        case NdisMediumWan:
            NdisMEthIndicateReceive(pAdapt->MiniportHandle,
                                MacReceiveContext,
                                HeaderBuffer,
                                HeaderBufferSize,
                                LookAheadBuffer,
                                LookAheadBufferSize,
                                PacketSize);
        break;

        case NdisMedium802_5:
            NdisMTrIndicateReceive(pAdapt->MiniportHandle,
                                MacReceiveContext,
                                HeaderBuffer,
                                HeaderBufferSize,
                                LookAheadBuffer,
                                LookAheadBufferSize,
                                PacketSize);
        break;
    case NdisMediumFddi:
        NdisMFddiIndicateReceive(pAdapt->MiniportHandle,
                                 MacReceiveContext,
                                 HeaderBuffer,
                                 HeaderBufferSize,
                                 LookAheadBuffer,
                                 LookAheadBufferSize,
                                 PacketSize);
         break;

    default:
         ASSERT(FALSE);
         break;
        }
    } while(FALSE);

    return Status;
}

 注意,PassThru 并没有对收到的包进行任何处理,因此,在它的ProtocolReceive中,没有调用NdisTransferData,请求NDIS传送这个包其余 的数据,它直接Indicate,把这个工作交给了上层去处理,如果,你的中间层要处理的话,就得在放入队列前面,调用 NdisTransferData,如果返回成功,则在紧接其下进行处理,如果返回 NDIS_STATUS_PENDING 的话,就把处理放到ProtocolTransferDataComplete中处理。所以,你的ProtocolReceive应该看起来是这样的过 程:
1.  在把包加入PassThru的队列前,调用NdisTransferData.请求NDIS通知下层传递其余的数据。
    (这里回头走了一段曲折的路了)。
2A. 如果返回成功,则进行处理,如修改数据,重新修正CheckSum,
    在X86平台上可要注意字节顺序的问题了。
2B. 如果返回 NDIS_STATUS_PENDING 就在 ProtocolTransferDataComplete进行2A的处理。
3.  处理完成后,排入PassThru的队列。
    由于,现在网络设备硬件的发展,内存容量的提高,底程的Miniport Driver通常有一个类似PassThru的缓存处理机制,走这条曲折的线路上来,似乎很少见了。

    在搞懂了ProtocolReceive后,rotocolReceivePacket就更简单了。

INT
PtReceivePacket(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN PNDIS_PACKET Packet
    )

{
    // .......

    // 进行你自己的处理,修改包的内容,修正CheckSum等操作,参考前面接收过程

    // 取得Packet中的内容

    Status = NDIS_GET_PACKET_STATUS(Packet);
    if (Status == NDIS_STATUS_RESOURCES)
    {
        // 如果下层设置了NDIS_STATUS_RESOURCES,说明下层由于资源

        // 紧缺等原因,要求上层经快处理,于是产生一个考贝的

        // 包描述符排入队列,马上Indicate,并调用NdisReturnPacket请求

        // NDIS归还下层的资源。这是PassThru的处理方法

        // 事实上,如果,你自己要修改这个包,你已经有一个新的Packet和Buffer

        // 以及相关内容了,只要把你的这个新的包排入队列,并调用 NdisReturnPacket

        // 归还下层的资源,而不立即Indicate上层,也是可以的。

        PtQueueReceivedPacket(pAdapt, Packet, TRUE);
    }
    else
    {
        PtQueueReceivedPacket(pAdapt, MyPacket, FALSE);
    }
    
    if (Status == NDIS_STATUS_RESOURCES)
    {
        NdisDprFreePacket(MyPacket);
    }
    // ......

}
 

当上层处理完后,调用NdisReturnPacket请求NDIS归还下层的资源时,NDIS调用下层注册的MiniportReturnPacket在这里释放资源后,再调用NdisReturnPackets通知更下层。

 

VOID MPReturnPacket(
    IN NDIS_HANDLE MiniportAdapterContext,
    IN PNDIS_PACKET Packet
    )

{
    // 如果你和我一样,在接收的时候,自己处理不成功的情况下,就把原来的数据往上传

    // 你就可以像我处理发送的方法一样,利用那几个Reserve的字段,在这里判断,

    // 并进行必要的资源释放。

    // ......

    // 通知下层释放资源

    NdisReturnPackets(&Packet, 1);
    // ......

}
 

注意:对于一个像TCP这样面向连接的发送的数据包来说,你要是改变了它的长度的话,那问题就更复杂了,你在协议栈的下方,上层协议栈不知道这个修 改,而你把它发到目标计算机去,目标计算机得到的长度是修改后的,那双方的SEQ,ACK就不能同步了,这样的话,你必须记录下你的改动,并对以后的通 信,做相应的修正。不然,你一改的话,接下来的通信就RST了。

五 Ring 0 和 Ring 3的通信问题
    也许你并 不只是想修改过往的数据,你也想把这些数据直接传到Ring3上去,或有一些其它的理由需要在你的NDIS中间层驱动和应用程序通信, 2003 DDK中的PassThru也提供了这个功能,它已经创建好了设备对像和符号链接,你只需要修改驱动对象的DispatchTable就行了。假如,你希 望Ring3的程序通能Read NDIS中间层截获的数据,你需要维护两个队列,一个用于缓存NDIS收到的数据,另一个存放Ring3的IRP请求队列等等,是的,这个已经没有什么好 说的了,这一切对于你来说,也经不是难题了。但是,在兴奋之时,需要注意的是,现在是位于任何协议栈的下方,如果没有任何验证机制的话,别人只要在你的局 域网中向你发送链路层的广播,或目标MAC地址是你的网卡的MAC的数据包时,你的程序都要受到影响,也就是说,别人随便发个包,你的系统都要为他操劳 了,从安全的角度来说,你的系统应该尽可能减小受外部影响的程度,所以,你在加上这个功能的时候,有必要考虑这一点。

后记:
    也 许,和很多人一样,我曾经试图看着DDK中的文档学习NDIS驱动开发,但是总是不顺利,到头来似乎感觉NDIS很难,DDK的文档没用,但是,在动手写 起程序来时,发现了自己还是离不开DDK的文档,刚开始试图从看DDK文档中的描述,进而想掌握NDIS,这似乎是不容易的,至少对我来说是这样的,等你 真正的写起程序来,遇上一些具体的问题,受到一些挫折后,再带着这些问题来看DDK文档就会有收获了。本文描述了自己学习过程中的一些理解,写出来希望能 与大家交流,由于自己水平有限,错误之错在所难免,欢迎诸位指正。

QQ: 22517257. Email: Addylee2004@163.com, MSN: Addylee2004@163.com

参考资料:
    DDK开发文档。
    驱动开发网NDIS板块的讨论。
    http://www.xfocus.net/articles/200307/568.html

 

原文地址 http://www.xfocus.net/articles/200605/865.html

分享到:
评论

相关推荐

    基于PassThru的NDIS中间层驱动程序扩展

    "基于PassThru的NDIS中间层驱动程序扩展"是一个专门的话题,涉及如何利用NDIS中间层驱动来实现特定的网络功能增强。 首先,我们要理解什么是NDIS中间层驱动。NDIS中间层驱动位于协议驱动和微型端口驱动之间,它能够...

    基于PassThru的NDIS中间层驱动程序的扩展 自己的文档

    在"基于PassThru的NDIS中间层驱动程序的扩展"这个主题中,我们将深入探讨如何利用这种技术来扩展网络驱动的功能。 首先,我们要理解NDIS中间层驱动的基本工作原理。NDIS驱动分为过滤器驱动和微型端口驱动。过滤器...

    基于NDIS中间层驱动的网络数据过滤程序开发概括

    NDIS中间层驱动程序是基于DDK中passthru框架扩展的,用于网络数据过滤和拦截。NDIS中间层驱动程序可以拦截和过滤网络数据,使得网络数据的传输更加安全。 NDIS中间层驱动程序的开发需要注意以下几点: 1. 驱动程序...

    NDIS中间层驱动程序PassThru的扩展

    《NDIS中间层驱动程序PassThru的扩展与解析》 NDIS(Network Driver Interface Specification)中间层驱动程序是Windows网络驱动程序体系中的关键组成部分,它们位于底层的微端口NIC驱动(NDIS Miniport NIC Driver...

    NDIS的PASSTHRU层的驱动程序

    NDIS过滤器驱动是在原始网络数据包传递到协议驱动之前或之后插入的中间层。它们可以用来捕获、修改或转发网络数据。FilterItem.c可能包含了驱动的初始化、卸载、发送和接收处理函数等。 2. **dispatch.cpp**:此...

    passthru中间层驱动框架

    NDIS中间层驱动位于协议驱动和物理驱动之间,可以用来实现诸如网络流量监控、数据包过滤、性能优化等功能。 Passthru驱动框架提供了一种模板,帮助开发者构建具备特定功能的中间层驱动。它的主要特点是“PassThru”...

    基于NDIS Passthru 扩展源码

    【标题】"基于NDIS Passthru 扩展源码" 涉及的主要知识点是网络驱动程序开发,特别是NDIS(Network Driver Interface Specification)中间层驱动程序的Passthru技术。NDIS Passthru是一种允许硬件供应商创建自定义...

    NDIS中间层驱动中IP、MAC地址的获取

    NDIS中间层驱动,也称为过滤驱动,位于NDIS协议驱动和微型端口驱动之间,用于扩展或修改网络数据包处理流程。在这个场景中,我们将探讨如何在NDIS中间层驱动中获取并处理IP和MAC地址。 首先,我们需要理解NDIS驱动...

    passthru源码

    在给定的“passthru源码”中,我们可以深入探讨NDIS中独立中间驱动(IMD,Independent Middle Driver)的相关知识。 首先,`passthru.c`和`passthru.h`是主要的源代码文件和头文件,它们实现了所谓的“passthru”...

    windows源地址路由

    在NDIS中,源地址路由可以通过修改或扩展NDIS中间驱动(如PassThru驱动)来实现,这类驱动可以拦截和修改数据包的传输过程。 Passthru驱动是一种特殊的NDIS驱动类型,它的主要任务是透明地传递数据包,允许上层...

    Filter驱动开发笔记

    基于PassThru的NDIS中间层驱动程序扩展 - **PassThru**:是NDIS提供的一种API集合,用于实现数据包的透明传输。基于PassThru开发的Filter驱动可以实现数据包的监听、拦截和修改等功能。 - **数据包处理流程**:...

Global site tag (gtag.js) - Google Analytics