NDIS学习笔记二——(模拟丢包)

今天本来想发篇正式点的BLOG,没想到没有保存住, 以后word打开不敢随便关闭啥提示了。

以下是网络上的文章的摘录,但已经能反应整个的思路过程。

NDIS驱动结构简介

image

 

    其中,最上层是一个NDIS Protocol Driver,它向上提供一个Transport Driver Interface(TDI),向下通过NDIS接口与下面的NDIS中间层的上边界交互,NDIS中间层的下边界通过NDIS接口与下层的NDIS Miniport Driver交互。最后,由NDIS Miniport Driver利用NDIS接口与物理网络设备NetCard交互。NetCard是由不同的网卡设备产商提供的,而NDIS接口库是由Microsoft开发好的,为什么NDIS Miniport Driver不是直接与物理网卡交互,而是通过NDIS接口与下物理网卡交互呢?(我想很多人都会和我当初一样,有这个疑问)。
    事实上,这是由于Windows系统为了提高可移植性,而设计出一个硬件抽象层(HAL),硬件抽象层在内部处理不同的硬件之间的差异,并且暴露出一个统一的接口给核心驱动开发者。例如:在Intel构架的系统中,内存和外部设备的端口采用分别编址,如果要从某个外部设备的端口上读写数据的话,可能要通过专用指令IN/OUT读写,而在Alpha构架的系统上,采用的是统一编址的方式,所以对外部设备的IO端口进行读写的话还是通过访问内存的指令,HAL提供一组服务支持函数,如果要访问外部设备上的端口数据可以使用READ_PORT_UCHAR/WRITE_PORT_UCHAR等等,核心驱动开发者不用去考虑不同硬件构架的之间的差异。在NDIS Miniport Driver中,NetCard驱动的程序,正是这样通过NDIS接口提供的一组类似功能的函数,与物理的网络设备进行交互。其中,最上层是一个NDIS Protocol Driver,它向上提供一个Transport Driver Interface(TDI),向下通过NDIS接口与下面的NDIS中间层的上边界交互,NDIS中间层的下边界通过NDIS接口与下层的NDIS Miniport Driver交互。最后,由NDIS Miniport Driver利用NDIS接口与物理网络设备NetCard交互。

 

NDIS接口简介

原来的通信可以看成下面的样子:

image

协议栈处理过信息后发给Minport,或则Minport接受信息后发给协议栈,而我们在中间加了一层后变成下图所示:

image

 

在wddk中passthru的例子来说具体的各个接口如下图所示:

 

image

  1. 1.底层驱动使用NdisMIndicateReceive / NdisMEthIndicateReceive通知上层已经收到数据报文
  2. 2.在PtReceive中如果通过NdisGetReceivedPacket得到了一个完整的packet,就分配我们自己的MyPacket,根据底下传上来的packet设置MyPacket,然后调用NdisMIndicateReceivePacket通知NDIS,NDIS会接着调用上层协议驱动的相应PtReceive例程。如果此时MyPacket的status是NDIS_STATUS_RESOURCES,我们就在本函数中释放我们分配的MyPacket;否则我们在上层发送4的时候,在MPReturnPacket中释放MyPacket.
  3. 3.在PtReceive中如果通过NdisGetReceivedPacket不能得到一个完整的packet,那我们就直接调用NdisMEthIndicateReceive等函数通知NDIS。
  4. 4.当上层协议驱动得到了一个完整的数据报文并且处理完毕以后,它会调用NdisReturnPacket,然后NDIS会调用我们的MPReturnPacket.
  5. 5.在我们的MPReturnPacket中,释放我们自己分配的MyPacket,然后同样的向下层调用NdisReturnPacket。下层会释放他们自己分配的packet
  6. 6.如果3发生,当底层miniport驱动收到了一个完整的数据报文,它会调用NdisMEthIndicateReceiveComplete,然后NDIS会调用我们的PtReceiveComplete
  7. 7.我们的PtReceiveComplete同样的会调用NdisMEthIndicateReceiveComplete,通知NDIS“我们已经收到了完整的报文”
  8. 8.当上层协议驱动得知底层已经收到了完整的数据报文以后,可能会调用NdisTransferData,要求下层把剩余的数据传上来。
  9. 9.8的调用会导致NDIS调用我们的MPTransferData例程。在MPTransferData中,做同样的调用NdisTransferData。注意该函数的返回值:如果返回success,说明剩余的数据立刻就传上来了。此时会立即返回。10、11两步骤就不会调用;如果返回pending,表明底层在此阻塞,底层会在稍后的时候调用10
  10. 10.当底层miniport驱动做好了一个完整的packet,它会调用NdisTransferDataComplete
  11. 11.同样在我们的PtTransferDataComplete中,会作出同样的调用。

发送示例如下:

image

1.Protocol driver调用NdisSend向下层发送数据报文。

2. Passthru的MPSend/MPSendPacket例程根据上层传下来的数据报文分配MyPacket,调用NdisSend发送到下层。如果返回pending,就在PtSendComplete中释放我们的MyPacket;否则就在本函数中紧接着释放MyPacket。

3. 当下层miniport driver发送完成MyPacket以后,会调用NdisMSendComplete

4. NDIS接着调用passthru的PtSendComplete,在这个函数里边,我们应该释放MyPacket,并且通知上层protocol driver去释放它们的packet。

 

丢包模拟概要

知道这个过程之后就可以模拟丢包,整体架构如下:

image

 

下面为丢包模拟结构图:

image

(1)协议驱动调用NdisSend 向下层发送数据包Packet;
(2)NDIS 调用中间层驱动的MPSendPackets 函数将上层传递下来的数据包构建另一个数据包MyPacket,同样调用NdisSend 将此数据包传递到下一层驱动。如果返回pending,就在步骤(5)中释放MyPacket 的资源,否则在本函数中立即释放资源;
(3)网卡驱动收到从中间层传递下来的MyPacket;
(4)网卡驱动调用NdisSend 发送MyPacket;
(5)网卡驱动调用NdisMSendComplete,NDIS 接着调用中间层的PtSendComplete 函数释放步骤(2)中MyPacket 的所有资源,并通知上层协议驱动释放步骤(1)中Packet 的资源;
(6)协议驱动释放Packet 的所有资源。

本文对中间层驱动程序进行修改,在步骤(2)中间层中的MPSendPackets 函数中完成步骤(5),网卡驱动就无法得到上层传递的数据包从而实现了包丢弃。修改后发送流程如图3中虚线所示。

 

注意点

本文的例子也是网络上最多的(本来就是抄袭网络),但是其中Passthru的例子只适应于 wddk6.0以下,如果您的操作系统我一样是win7 64的则需要通过另外的方式来实现,请参考wddk下的filter例子。以后会再说。

posted @ 2013-03-19 15:38  Curry  阅读(1292)  评论(0编辑  收藏  举报