在线建站平台免费建网站,深圳注册公司网上申请入口,做网站建设个体经营小微企业,网站后台在哪里基于PassThru的NDIS中间层驱动程序扩展
4.2 接收处理 接收的时候#xff0c;由于那个TransferData的曲折过程#xff0c;使得接收处理要相对复杂一点点#xff0c;在 ProtocolReceive和 ProtocolReceivePacket中的处理不同。但是由于2003 DDK中的PassThru中#xff0…基于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这样面向连接的发送的数据包来说你要是改变了它的长度的话那问题就更复杂了你在协议栈的下方上层协议栈不知道这个修 改而你把它发到目标计算机去目标计算机得到的长度是修改后的那双方的SEQACK就不能同步了这样的话你必须记录下你的改动并对以后的通 信做相应的修正。不然你一改的话接下来的通信就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: Addylee2004163.com, MSN: Addylee2004163.com 参考资料 DDK开发文档。 驱动开发网NDIS板块的讨论。 http://www.xfocus.net/articles/200307/568.html 原文地址 http://www.xfocus.net/articles/200605/865.html