您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 人事档案/员工关系 > 基于PassThru的NDIS中间层驱动程序扩展
基于PassThru的NDIS中间层驱动程序扩展概要:开发一个NDIS驱动是一项相对复杂的工作,这一方面是由于核心驱动本身有更多的限制和要求,有更多的“游戏规则”要求开发者理解和掌握,NDIS的复杂性把难度更是提高了,本文以PassThru为例,加上自己的理解,讲述了NDIS驱动的处理过程和在PassThru的基础上进行扩展的基本方法,本文并不是一个入门读物,所以没有提及任何核心驱动开发的相关知识,本文主要讲述的是NDIS中间层对数据包处理的流程。在阅读过程中,关于相关API的用法,或其它信息,请参看DDK文档。一NDIS驱动程序分类.NDIS(NetworkDriverInterfaceSpecification)是Windows网络驱动程序接口标准,NDIS驱动程序分为三类:1.NDISMiniportNICDriver:底层的微端口NIC驱动,这就是网络设备的物理的驱动程序了。2.NDISProtocolDriver:高层的协议驱动,用来实现某个具体的协议栈,如TCP/IP协议栈,并向上导出TDI接口。3.NDISIntermediateDriver:中间层驱动,位于MiniportDriver和ProtocolDriver之间。二NDIS驱动结构简介.其中,最上层是一个NDISProtocolDriver,它向上提供一个TransportDriverInterface(TDI),向下通过NDIS接口与下面的NDIS中间层的上边界交互,NDIS中间层的下边界通过NDIS接口与下层的NDISMiniportDriver交互。最后,由NDISMiniportDriver利用NDIS接口与物理网络设备NetCard交互。NetCard是由不同的网卡设备产商提供的,而NDIS接口库是由Microsoft开发好的,为什么NDISMiniportDriver不是直接与物理网卡交互,而是通过NDIS接口与下物理网卡交互呢?(我想很多人都会和我当初一样,有这个疑问)。事实上,这是由于Windows系统为了提高可移植性,而设计出一个硬件抽象层(HAL),硬件抽象层在内部处理不同的硬件之间的差异,并且暴露出一个统一的接口给核心驱动开发者。例如:在Intel构架的系统中,内存和外部设备的端口采用分别编址,如果要从某个外部设备的端口上读写数据的话,可能要通过专用指令IN/OUT读写,而在Alpha构架的系统上,采用的是统一编址的方式,所以对外部设备的IO端口进行读写的话还是通过访问内存的指令,HAL提供一组服务支持函数,如果要访问外部设备上的端口数据可以使用READ_PORT_UCHAR/WRITE_PORT_UCHAR等等,核心驱动开发者不用去考虑不同硬件构架的之间的差异。在NDISMiniportDriver中,NetCard驱动的程序,正是这样通过NDIS接口提供的一组类似功能的函数,与物理的网络设备进行交互。其中,最上层是一个NDISProtocolDriver,它向上提供一个TransportDriverInterface(TDI),向下通过NDIS接口与下面的NDIS中间层的上边界交互,NDIS中间层的下边界通过NDIS接口与下层的NDISMiniportDriver交互。最后,由NDISMiniportDriver利用NDIS接口与物理网络设备NetCard交互。三NDIS驱动程序的数据处理流程3.1三种NDIS驱动程序的关系。通常一个NDISProtocolDriver的上边沿导出TDI接口,并在其下边沿向NDIS注册一组Protocolxxx操作例程;一个NDISMiniportDriver则在其下边沿通过NDIS接口操作物理网络设备,并在其上边沿向NDIS注册一组Miniportxxx操作例程。当一个中间层介入的时候,必需遵守这个规则,因此,中间层驱动对上层来说,扮演一个MiniportDriver的角色,它在上边沿向NDIS注册一组Miniportxxx函数;对于下层MiniportDriver来说,中间层驱动扮演一个ProtocolDriver的角色,因此它在下边沿向NDIS注册一组Protocolxxx函数。MiniportDriver通过调用NdisMRegisterMiniport向NDIS注册一组MiniportXxx函数。其中原型如下:NDIS_STATUSNdisMRegisterMiniport(INNDIS_HANDLENdisWrapperHandle,INPNDIS_MINIPORT_CHARACTERISTICSMiniportCharacteristics,INUINTCharacteristicsLength);其中,NdisWrapperHandls是之前通过调用NdisMInitializeWrapper取得的句柄MiniportCharacteristics包含一组MiniportXxx函数指针。ProtocolDriver通过调用NdisRegisterProtocol向NDIS注册一组ProtocolXxx函数。其中原型如下:VOIDNdisRegisterProtocol(OUTPNDIS_STATUSStatus,OUTPNDIS_HANDLENdisProtocolHandle,INPNDIS_PROTOCOL_CHARACTERISTICSProtocolCharacteristics,INUINTCharacteristicsLength);其中,ProtocolCharacteristics包含一组ProtocolXxx函数。由于NDISIntermediateDriver的双重性,它需要调用NdisIMRegisterLayeredMiniport向NDIS注册,并向上层导出一组MiniportXxx函数,之后,调用NdisRegisterProtocol向NIDS注册,并向下层导出一组ProtocolXxx函数。当一个NDIS中间层介入后,如图二所示。3.2NDIS数据发送流程:当上层协议驱动要发数据时,调用NdisSend/NdisSendPackets请求NDIS发送数据包,NDIS将会调用紧接其下的中间层驱动的MiniportSend/MiniportSendPackets,中间层驱动MiniportSend/MiniportSendPackets有机会在这里对包进行必要的操作,然后,中间层驱动再次调用NdisSend/NdisSendPackets请NDIS发送数据包,NDIS将调用其下层的MiniportDriver的MiniportSend/MiniportSendPackets,底层MiniportSend/MiniportSendPackets通过NDIS接口控制物理网络设备,将数据发送出去。在上层请求发送数据包时,上层分配了相关的资源(如内存),希望在下层完成发送动作后,能够及时的收回相关的资源,所以,当上层调用NdisSend/NdisSendPackets返回NDIS_STATUS_PENDING以外的任何值时,上层就可以释放资源了,如果得到返回的结果是NDIS_STATUS_PENDING话,说明下层还没有完成发送请求,以后,等下层最终完成发送请求时,下层调用NdisMSendComplete请求NDIS通知上层可以释放资源了,于是NDIS调用上层注册的ProtocolSendComplete函数,上层在这它的ProtocolSendComplete中释放了资源后,再次调用NdisMSendComplete请求NDIS通知更上层。3.3NDIS数据接收流程:当底层网络设备有数据到来的时候,将触发中断,相应的中断处理程序接管中断后,将可能调用MiniportDriver所注册的中断处理例程(ISR),MiniportDriver通常在这里把网卡上的数据考贝到MiniportDriver缓冲区队列中去,出于效率的考虑,MiniportDriver这时可能不会立即通知上层处理新的数据,因为很可能,马上还有随后的新的数据到来,当接收到的包的数量达到一定程度的时候,MiniportDriver会调用NdisMIndicateReceivePacket指示新的NDIS新数据的到来,这时候,NdisMIndicateReceivePacket的调用将导致NDIS调用位于Miniport上层的中间层向NDIS注册的下边沿ProtocolReceivePacket函数。中间层驱动程序的ProtocolReceivePacket可以对收到的数据包进行相应的处理,之后,可以选择再次调用NdisMIndicateReceivePacket请求NDIS通知更上层数据包的到来,这时,NDIS调用更上层注册的ProtocolReceive函数,上层的ProtocolReceive对数据包进行必要的处理后,继续调用NdisMIndicateReceivePacket请求NDIS,通知更上层,最终数据包传到协议驱动中,由相关的协议栈进行处理。有时候,在这种级连的上传过程中,并不是那么的顺利,例如,由于某种原因,如:网络设备的驱动程序的可用缓冲区数量减少到某个指定的数量时,网络设备的驱动程序调用NdisMxxxIndicateReceivePacket请求NDIS通知上层数据的到来,这时NDIS将调用上层注册的ProtocolReceive,上层在ProtocolReceive中进行必要的处理后,进一步调用NdisMxxxIndicateReceivePacket使得NDIS调用上层的协议驱动注册的ProtocolReceive。在一些不太理想的情况下,一次中断,从网络设备中接收到的数据对某个协议来说并不是一个完整的协议数据包。(一般情况下,其余的数据bit已经在链路途中了,并随后立即就会到达网络设备,这有可能就发生在一个CPU在处理网络设备中断的同时,网络设备的板载存储器上就已经收到了其余的数据了,甚至DMA控制器可能已经把这些数据传到了系统的主存储器上了),这时,上层的ProtocolReceive都无法进行正常的处理(一般对某个包进行处理,都要以相关的协议为依据,进行分析)。这时,在上传到某一层时,可以调用NdisTransferData请求NDIS把随后的信息传上来,这时,NDIS又将在向上传递的途中回过头来向下调用下面的MiniportTransferData,下层重复调用NdisTransferData把这个请求传送到底程的MiniportDriver。如果在上层调用NdisTransferData时不是返回NDIS_STATUS_PENDING,则上层可以继续它的处理,而如果返回NDIS_STATUS_PENDING,底程在最终完成请求时,调用NdisMTransferDataComplete请求NDIS通知上层传送完成,这将导致上层注册的ProtocolTransferDataComplete被调用,上层调用NdisMTransferDataComplete请求NDIS通知更上层。由于硬件技术的发展,网络设备板载存储的增加,系统主存储器的增加,以及网络传输能力的改善,NDIS那么迂回的通过MdisMxxxIndicateReceivePacket,ProtocolReceive,MiniportTransferData这一条坎坷的路径进行数据处理的情况似乎越来越少见了。接收过程是由下层传递上去的,同样,底层的Miniport分配了一些资源,如用于存储这个数据包内容的内存,我们希望这些资源最终能极时的被归还,以供以后使用。一个包在从下到上的传递过程时,如果某一层的ProtocolReceive/ProtocolReceivePacket有兴趣对这个包进行处理的话,则需要检查这个包的OOB信息段是不是携带NDIS_STATUS_RESOURCES,如果是的话,说明其下层资源紧缺,希望上层在处理的时候,自己考贝一份副本,以供自己使用,因为下层希望自己能够
本文标题:基于PassThru的NDIS中间层驱动程序扩展
链接地址:https://www.777doc.com/doc-1002766 .html