NDIS学习笔记二——(模拟丢包)
今天本來想發(fā)篇正式點的BLOG,沒想到?jīng)]有保存住, 以后word打開不敢隨便關閉啥提示了。
以下是網(wǎng)絡上的文章的摘錄,但已經(jīng)能反應整個的思路過程。
NDIS驅(qū)動結構簡介
其中,最上層是一個NDIS Protocol Driver,它向上提供一個Transport Driver Interface(TDI),向下通過NDIS接口與下面的NDIS中間層的上邊界交互,NDIS中間層的下邊界通過NDIS接口與下層的NDIS Miniport Driver交互。最后,由NDIS Miniport Driver利用NDIS接口與物理網(wǎng)絡設備NetCard交互。NetCard是由不同的網(wǎng)卡設備產(chǎn)商提供的,而NDIS接口庫是由Microsoft開發(fā)好的,為什么NDIS Miniport Driver不是直接與物理網(wǎng)卡交互,而是通過NDIS接口與下物理網(wǎng)卡交互呢?(我想很多人都會和我當初一樣,有這個疑問)。
事實上,這是由于Windows系統(tǒng)為了提高可移植性,而設計出一個硬件抽象層(HAL),硬件抽象層在內(nèi)部處理不同的硬件之間的差異,并且暴露出一個統(tǒng)一的接口給核心驅(qū)動開發(fā)者。例如:在Intel構架的系統(tǒng)中,內(nèi)存和外部設備的端口采用分別編址,如果要從某個外部設備的端口上讀寫數(shù)據(jù)的話,可能要通過專用指令IN/OUT讀寫,而在Alpha構架的系統(tǒng)上,采用的是統(tǒng)一編址的方式,所以對外部設備的IO端口進行讀寫的話還是通過訪問內(nèi)存的指令,HAL提供一組服務支持函數(shù),如果要訪問外部設備上的端口數(shù)據(jù)可以使用READ_PORT_UCHAR/WRITE_PORT_UCHAR等等,核心驅(qū)動開發(fā)者不用去考慮不同硬件構架的之間的差異。在NDIS Miniport Driver中,NetCard驅(qū)動的程序,正是這樣通過NDIS接口提供的一組類似功能的函數(shù),與物理的網(wǎng)絡設備進行交互。其中,最上層是一個NDIS Protocol Driver,它向上提供一個Transport Driver Interface(TDI),向下通過NDIS接口與下面的NDIS中間層的上邊界交互,NDIS中間層的下邊界通過NDIS接口與下層的NDIS Miniport Driver交互。最后,由NDIS Miniport Driver利用NDIS接口與物理網(wǎng)絡設備NetCard交互。
NDIS接口簡介
原來的通信可以看成下面的樣子:
協(xié)議棧處理過信息后發(fā)給Minport,或則Minport接受信息后發(fā)給協(xié)議棧,而我們在中間加了一層后變成下圖所示:
在wddk中passthru的例子來說具體的各個接口如下圖所示:
1.底層驅(qū)動使用NdisMIndicateReceive / NdisMEthIndicateReceive通知上層已經(jīng)收到數(shù)據(jù)報文
2.在PtReceive中如果通過NdisGetReceivedPacket得到了一個完整的packet,就分配我們自己的MyPacket,根據(jù)底下傳上來的packet設置MyPacket,然后調(diào)用NdisMIndicateReceivePacket通知NDIS,NDIS會接著調(diào)用上層協(xié)議驅(qū)動的相應PtReceive例程。如果此時MyPacket的status是NDIS_STATUS_RESOURCES,我們就在本函數(shù)中釋放我們分配的MyPacket;否則我們在上層發(fā)送4的時候,在MPReturnPacket中釋放MyPacket.
3.在PtReceive中如果通過NdisGetReceivedPacket不能得到一個完整的packet,那我們就直接調(diào)用NdisMEthIndicateReceive等函數(shù)通知NDIS。
4.當上層協(xié)議驅(qū)動得到了一個完整的數(shù)據(jù)報文并且處理完畢以后,它會調(diào)用NdisReturnPacket,然后NDIS會調(diào)用我們的MPReturnPacket.
5.在我們的MPReturnPacket中,釋放我們自己分配的MyPacket,然后同樣的向下層調(diào)用NdisReturnPacket。下層會釋放他們自己分配的packet
6.如果3發(fā)生,當?shù)讓觤iniport驅(qū)動收到了一個完整的數(shù)據(jù)報文,它會調(diào)用NdisMEthIndicateReceiveComplete,然后NDIS會調(diào)用我們的PtReceiveComplete
7.我們的PtReceiveComplete同樣的會調(diào)用NdisMEthIndicateReceiveComplete,通知NDIS“我們已經(jīng)收到了完整的報文”
8.當上層協(xié)議驅(qū)動得知底層已經(jīng)收到了完整的數(shù)據(jù)報文以后,可能會調(diào)用NdisTransferData,要求下層把剩余的數(shù)據(jù)傳上來。
9.8的調(diào)用會導致NDIS調(diào)用我們的MPTransferData例程。在MPTransferData中,做同樣的調(diào)用NdisTransferData。注意該函數(shù)的返回值:如果返回success,說明剩余的數(shù)據(jù)立刻就傳上來了。此時會立即返回。10、11兩步驟就不會調(diào)用;如果返回pending,表明底層在此阻塞,底層會在稍后的時候調(diào)用10
10.當?shù)讓觤iniport驅(qū)動做好了一個完整的packet,它會調(diào)用NdisTransferDataComplete
11.同樣在我們的PtTransferDataComplete中,會作出同樣的調(diào)用。
發(fā)送示例如下:
1.Protocol driver調(diào)用NdisSend向下層發(fā)送數(shù)據(jù)報文。
2. Passthru的MPSend/MPSendPacket例程根據(jù)上層傳下來的數(shù)據(jù)報文分配MyPacket,調(diào)用NdisSend發(fā)送到下層。如果返回pending,就在PtSendComplete中釋放我們的MyPacket;否則就在本函數(shù)中緊接著釋放MyPacket。
3. 當下層miniport driver發(fā)送完成MyPacket以后,會調(diào)用NdisMSendComplete
4. NDIS接著調(diào)用passthru的PtSendComplete,在這個函數(shù)里邊,我們應該釋放MyPacket,并且通知上層protocol driver去釋放它們的packet。
丟包模擬概要
知道這個過程之后就可以模擬丟包,整體架構如下:
下面為丟包模擬結構圖:
(1)協(xié)議驅(qū)動調(diào)用NdisSend 向下層發(fā)送數(shù)據(jù)包Packet;
(2)NDIS 調(diào)用中間層驅(qū)動的MPSendPackets 函數(shù)將上層傳遞下來的數(shù)據(jù)包構建另一個數(shù)據(jù)包MyPacket,同樣調(diào)用NdisSend 將此數(shù)據(jù)包傳遞到下一層驅(qū)動。如果返回pending,就在步驟(5)中釋放MyPacket 的資源,否則在本函數(shù)中立即釋放資源;
(3)網(wǎng)卡驅(qū)動收到從中間層傳遞下來的MyPacket;
(4)網(wǎng)卡驅(qū)動調(diào)用NdisSend 發(fā)送MyPacket;
(5)網(wǎng)卡驅(qū)動調(diào)用NdisMSendComplete,NDIS 接著調(diào)用中間層的PtSendComplete 函數(shù)釋放步驟(2)中MyPacket 的所有資源,并通知上層協(xié)議驅(qū)動釋放步驟(1)中Packet 的資源;
(6)協(xié)議驅(qū)動釋放Packet 的所有資源。
本文對中間層驅(qū)動程序進行修改,在步驟(2)中間層中的MPSendPackets 函數(shù)中完成步驟(5),網(wǎng)卡驅(qū)動就無法得到上層傳遞的數(shù)據(jù)包從而實現(xiàn)了包丟棄。修改后發(fā)送流程如圖3中虛線所示。
注意點
本文的例子也是網(wǎng)絡上最多的(本來就是抄襲網(wǎng)絡),但是其中Passthru的例子只適應于 wddk6.0以下,如果您的操作系統(tǒng)我一樣是win7 64的則需要通過另外的方式來實現(xiàn),請參考wddk下的filter例子。以后會再說。
總結
以上是生活随笔為你收集整理的NDIS学习笔记二——(模拟丢包)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑的dwg文件怎么打开如何打开电脑
- 下一篇: 互联网协议入门(1)