【转】NDIS协议驱动笔记

http://kruglinski.bokee.com/5746261.html

关键词NDIS    Protocol    Driver    DDK    DriverStudio                                          

今天终于把NDIS Protocol Driver开发相关的东东看完了,现在回头看其实协议驱动也不是很难,只是有些概念没有人点拨自己琢磨了很久,比如如何将收到的包写入上层应用程序ReadFile读取的buffer里,我的脑海里总有memcpy进行数据copy的概念,呵呵!

然而在NDIS协议驱动里copy数据不是通过memcpy这样的函数来完成的,这里有一个NDIS_PACKET的概念,当接收数据时先为NDIS_PACKET关联一个内存描述符NDIS_BUFFER(其实就是MDL),使用NdisChainBufferAtFront关联Buffer和Packet再调用NdisTransferData接收剩下的数据,ReceiveHandler和ReceivePacketHandler的处理方法是不一样的,ReceiveHandler先接收一个以太头然后按照我上面说的方法接收剩下的数据,因为要将头和余下数据都写入同一个块内存可能除了IRP里的MDL,还需要创建一个对同一个内存块不同位置的子描述符MDL.

而在ReceivePacketHandler里没有将以太头和数据包分开处理而是直接放在一个NDIS_PACKET里,所以只需要连接一个NDIS_BUFFER,然后使用NdisCopyFromPacketToPacket直接将数据copy进去即可.

在Windows 2000 DDK例子驱动Packet的PacketReceiveIndicate里可以看到先使用NdisMoveMappedMemory将以太头写入输出MDL指向的内存里,然后创建相同内存块的另一个子MDL跳过以太头,随后调用NdisChainBufferAtFront连接buffer到packet,最后调用NdisTransferData接收数据,并在TransferDataCompleteHandler将创建的子MDL删除,再将PacketRead时分配的NDIS_PACKET释放,并完成挂起的读请求IRP.

发送的概念很容易理解,主要就是调用NdisSend将数据从某个绑定的适配器(Adapter)发送出去,同样因为是异步的所以要处理SendCompleteHandler,主要就是将PacketWrite时分配的NDIS_PACKET包释放并完成挂起的写请求IRP.

而嗅探最常用的混杂模式是通过调用NdisRequest的发送NdisRequestSetInformation类型的OID_GEN_CURRENT_PACKET_FILTER请求,并使用NDIS_PACKET_TYPE_PROMISCUOUS参数.

主要就是要把大的流程把握清楚,其它细节的东西可以说的太多了.我觉得主要是由协议驱动设计所决定,而跟NDIS协议驱动本身的架构不是很相关,这里不再多说.

我觉得Windows 2000 DDK带的协议驱动例子是一个非常糟糕的例子,几乎没有可以分开解读的地方,必须一起读好几个函数,在某个函里会跟到一个NdisWaitEvent,然后又跳到另一个函数里看相关实现是怎么将事件设置成信号态的,某一个函数里引用一个全局变量的值,然后又要搜索在哪个函数里设置了这个全局变量值,怎么设置的,为什么那样设置,中间有太多的藕合,如控制设备和适配器逻辑设备使用同一组派遣函数(当然一个驱动对象也只能有一组,但在DriverStudio里经过包装后的驱动框架每个设备对象的派遣函数是不一样的,它们存在于不同的C++对象中),说到这里我一定要说一下DriverStudio里带的DriverNetworks有一个完全按照DDK Packet例子实现的驱动程序叫做nmPacket,在DriverNetworks的协议驱动框架里,分成四个C++对象,驱动对象,控制设备对象,适配器逻辑设备对象和协议绑定对象.

驱动对象里创建全局控制设备对象并注册协议绑定对象.协议绑定对象是对协议驱动的抽象,它的重载成员函数就是协议导出函数,在协议绑定对象的打开适配器虑函数Open里,创建一个适配器逻辑设备对象并传this指针.

协议绑定对象有一个静态链表成员,每次在适配器打开后(OpenComplete被调用时)加入一个条目,表示已经绑定的适配器,全局控制设备对象可以通过读这个成员取得绑定列表并返回给应用程序.适配器逻辑设备对象因为有协议绑定对象指针,可以随时调用协议驱动对象的相关功能(NdisSend,NdisRequest...),如在设备的Read派遣函数里在协议驱动对象的读链表里添加一个条目,随后协议绑定对象的接收函数里会从这个链表里取读取求,然后在在分割以太头和一次接收整个NDIS_PACKET的两个协议导出函数中接收数据,为读请求写入数据,并完成一个读操作.

DriverNetworks实现的这个协议驱动程序的面向对象抽象,功能划分与模块间解藕合做的非常非常好,代码可读性也非常好,编译好的驱动程序只比DDK的Packet只大一点点.我不是很清楚这么优秀的东东怎么没有流行起来,也或许已经非常流行只是我周围没有人用罢了,反正我是决定要把它用好,呵呵!

哈!在家的感觉真好......

【作者: kruglinski】【访问统计: 1534】【2006年10月11日 星期三 20:00】【 加入博采】【打印

原文地址:https://www.cnblogs.com/SummerRain/p/1714916.html