NDIS協(xié)議驅(qū)動開發(fā)指南
我們知道,在以太網(wǎng)中所有的數(shù)據(jù)包都是通過以太網(wǎng)幀來發(fā)送的;但是在網(wǎng)絡(luò)上面的應(yīng)用程序如果需要通過網(wǎng)絡(luò)數(shù)據(jù)包交互,就需要依賴網(wǎng)絡(luò)協(xié)議來保障通信。平時我們用的最多的協(xié)議就是TCPIP協(xié)議。
其實(shí)在Windows中,我們可以注冊自己的協(xié)議,開發(fā)自己的協(xié)議解析和封裝驅(qū)動,實(shí)現(xiàn)以太網(wǎng)幀的通信,這就是本文的NDIS協(xié)議驅(qū)動。
以太網(wǎng)的以太包格式都是固定的,格式如下:
6字節(jié) | 6字節(jié) | 2字節(jié) | 其他長度 |
---|---|---|---|
源MAC | 目的MAC | 類型 | 數(shù)據(jù)部分 |
NDIS協(xié)議驅(qū)動就是針對以太包的協(xié)議封裝和解析過程,對上層提供一個穩(wěn)定的數(shù)據(jù)包通信的協(xié)議,對下層提供一個可以供以太網(wǎng)發(fā)送的以太數(shù)據(jù)包。本文我們來看一下NDIS協(xié)議驅(qū)動的開發(fā)原理。
1. 技術(shù)概覽
在Windows下面,網(wǎng)絡(luò)棧的基本架構(gòu)如下:
對于NDSI提供了三種功能(能力)的驅(qū)動:
- 上層的協(xié)議驅(qū)動。
- 中層的過濾驅(qū)動。
- 下層的小端口驅(qū)動。
由于NDIS早期并沒有直接提供過濾層的基本框架,因此對于早期(XP系統(tǒng)下面)版本如果需要對NDIS層的數(shù)據(jù)包進(jìn)行過濾,需要在中間層實(shí)現(xiàn)協(xié)議驅(qū)動和小端口驅(qū)動:
- 對上層,創(chuàng)建小端口驅(qū)動來和上層協(xié)議層通信(主要過濾數(shù)據(jù)包的發(fā)送)。
- 對下層,創(chuàng)建協(xié)議驅(qū)動來和小端口驅(qū)動通信(主要過濾數(shù)據(jù)包的接收)。
對于協(xié)議層驅(qū)動,實(shí)現(xiàn)比較簡單,只需要設(shè)置和處理好NDIS相關(guān)的協(xié)議層回調(diào)函數(shù)即可,下面我們看一下協(xié)議層驅(qū)動的具體實(shí)現(xiàn)。
2. NDIS協(xié)議驅(qū)動
上面我們知道NDIS協(xié)議驅(qū)動主要處理NDIS的相關(guān)協(xié)議回調(diào)例程,向NDIS注冊回調(diào)例程的函數(shù)為NdisRegisterProtocolDriver
,該例程聲明如下:
NDIS_STATUS NdisRegisterProtocolDriver(
NDIS_HANDLE ProtocolDriverContext,
PNDIS_PROTOCOL_DRIVER_CHARACTERISTICS ProtocolCharacteristics,
PNDIS_HANDLE NdisProtocolHandle
);
其中NDIS_PROTOCOL_DRIVER_CHARACTERISTICS
就是協(xié)議驅(qū)動的回調(diào)函數(shù)結(jié)構(gòu)體,該結(jié)構(gòu)體如下:
typedef struct _NDIS_PROTOCOL_DRIVER_CHARACTERISTICS {
NDIS_OBJECT_HEADER Header;
UCHAR MajorNdisVersion;
UCHAR MinorNdisVersion;
UCHAR MajorDriverVersion;
UCHAR MinorDriverVersion;
ULONG Flags;
NDIS_STRING Name;
SET_OPTIONS_HANDLER SetOptionsHandler;
BIND_HANDLER_EX BindAdapterHandlerEx;
UNBIND_HANDLER_EX UnbindAdapterHandlerEx;
OPEN_ADAPTER_COMPLETE_HANDLER_EX OpenAdapterCompleteHandlerEx;
CLOSE_ADAPTER_COMPLETE_HANDLER_EX CloseAdapterCompleteHandlerEx;
NET_PNP_EVENT_HANDLER NetPnPEventHandler;
UNINSTALL_PROTOCOL_HANDLER UninstallHandler;
OID_REQUEST_COMPLETE_HANDLER OidRequestCompleteHandler;
STATUS_HANDLER_EX StatusHandlerEx;
RECEIVE_NET_BUFFER_LISTS_HANDLER ReceiveNetBufferListsHandler;
SEND_NET_BUFFER_LISTS_COMPLETE_HANDLER SendNetBufferListsCompleteHandler;
DIRECT_OID_REQUEST_COMPLETE_HANDLER DirectOidRequestCompleteHandler;
} NDIS_PROTOCOL_DRIVER_CHARACTERISTICS, *PNDIS_PROTOCOL_DRIVER_CHARACTERISTICS;
在上述結(jié)構(gòu)體中間,對于一個簡要的協(xié)議驅(qū)動,只需要實(shí)現(xiàn)部分主要的回調(diào)函數(shù)即可,包括:
-
BindAdapterHandlerEx
:綁定回調(diào)函數(shù),當(dāng)小端口驅(qū)動和協(xié)議驅(qū)動進(jìn)行綁定的時候調(diào)用該函數(shù)通知協(xié)議驅(qū)動。 -
UnbindAdapterHandlerEx
:解除綁定的回調(diào)函數(shù),和BindAdapterHandlerEx
相反。 -
OpenAdapterCompleteHandlerEx
:當(dāng)使用NdisOpenAdapterEx
綁定小端口驅(qū)動完成的時候被調(diào)用(相當(dāng)IRP的完成例程)。 -
CloseAdapterCompleteHandlerEx
:當(dāng)使用NdisCloseAdapterEx
解除協(xié)議驅(qū)動和小端口驅(qū)動完成的時候被調(diào)用。 -
OidRequestCompleteHandler
:NdisOidRequest
請求完成的時候被調(diào)用的函數(shù)。 -
SendNetBufferListsCompleteHandler
:表示使用NdisSendNetBufferLists
發(fā)送完成數(shù)據(jù)包之后被調(diào)用的回調(diào)函數(shù)。 -
ReceiveNetBufferListsHandler
:當(dāng)小端口驅(qū)動接收到數(shù)據(jù)的時候就會通過該回調(diào)函數(shù)通知協(xié)議驅(qū)動數(shù)據(jù)包的到來。
2.1 BindAdapterHandlerEx
協(xié)議驅(qū)動是對網(wǎng)絡(luò)數(shù)據(jù)包的封裝,當(dāng)將網(wǎng)絡(luò)數(shù)據(jù)包按照協(xié)議封裝為以太網(wǎng)數(shù)據(jù)包之后,就需要通過網(wǎng)卡發(fā)送出去,那么協(xié)議驅(qū)動就需要和網(wǎng)卡驅(qū)動進(jìn)行關(guān)聯(lián)(協(xié)議驅(qū)動的數(shù)據(jù)包知道如何發(fā)送給網(wǎng)卡驅(qū)動)。
有兩種情況需要進(jìn)行協(xié)議的綁定:
- 當(dāng)協(xié)議驅(qū)動使用
NdisRegisterProtocolDriver
注冊驅(qū)動的時候,NDIS框架就會遍歷當(dāng)前系統(tǒng)所有的小端口驅(qū)動,對每個小端口驅(qū)動調(diào)用BindAdapterHandlerEx
回調(diào)函數(shù)。 - 當(dāng)有新的網(wǎng)卡設(shè)備插入并啟動的時候(
IRP_MN_START
),就會對該小端口驅(qū)動遍歷所有的協(xié)議驅(qū)動,然后調(diào)用其BindAdapterHandlerEx
回調(diào)函數(shù)進(jìn)行綁定。
BindAdapterHandlerEx
只是綁定的回調(diào)函數(shù),該函數(shù)聲明如下:
PROTOCOL_BIND_ADAPTER_EX ProtocolBindAdapterEx;
NDIS_STATUS ProtocolBindAdapterEx(
NDIS_HANDLE ProtocolDriverContext,
NDIS_HANDLE BindContext,
PNDIS_BIND_PARAMETERS BindParameters
)
{...}
該函數(shù)只是將小端口驅(qū)動和協(xié)議驅(qū)動的信息當(dāng)作回調(diào)函數(shù)的參數(shù)傳遞過來,小端口驅(qū)動的信息通過PNDIS_BIND_PARAMETERS
進(jìn)行描述。真實(shí)的綁定是通過NdisOpenAdapterEx
函數(shù)來完成的,該函數(shù)如下:
NDIS_STATUS NdisOpenAdapterEx(
NDIS_HANDLE NdisProtocolHandle,
NDIS_HANDLE ProtocolBindingContext,
PNDIS_OPEN_PARAMETERS OpenParameters,
NDIS_HANDLE BindContext,
PNDIS_HANDLE NdisBindingHandle
);
NdisOpenAdapterEx
其實(shí)是建立小端口和協(xié)議驅(qū)動的橋梁,大致如下:
這樣小端口的數(shù)據(jù)可以在NDIS框架中通過NDIS_OPEN_BLOCK
回調(diào)給協(xié)議驅(qū)動,協(xié)議驅(qū)動也可以通過NDIS_OPEN_BLOCK
調(diào)用小端口驅(qū)動。
2.2 SendNetBufferListsCompleteHandler
在協(xié)議驅(qū)動中,我們通過NdisSendNetBufferLists
將以太包發(fā)送數(shù)據(jù),該函數(shù)聲明如下:
void NdisSendNetBufferLists(
NDIS_HANDLE NdisBindingHandle,
__drv_aliasesMem PNET_BUFFER_LIST NetBufferLists,
NDIS_PORT_NUMBER PortNumber,
ULONG SendFlags
);
NET_BUFFER_LIST
描述著我們需要發(fā)送的數(shù)據(jù)包集合,當(dāng)小端口驅(qū)動將數(shù)據(jù)包發(fā)送成功之后,就會調(diào)用NdisMSendNetBufferListsComplete
來通知協(xié)議驅(qū)動數(shù)據(jù)包被發(fā)送完成,該函數(shù)如下:
void NdisMSendNetBufferListsComplete(
NDIS_HANDLE MiniportAdapterHandle,
PNET_BUFFER_LIST NetBufferList,
ULONG SendCompleteFlags
);
NdisMSendNetBufferListsComplete
完成回調(diào)的函數(shù)就是SendNetBufferListsCompleteHandler
,該函數(shù)如下:
PROTOCOL_SEND_NET_BUFFER_LISTS_COMPLETE ProtocolSendNetBufferListsComplete;
void ProtocolSendNetBufferListsComplete(
NDIS_HANDLE ProtocolBindingContext,
PNET_BUFFER_LIST NetBufferList,
ULONG SendCompleteFlags
)
{...}
SendNetBufferListsCompleteHandler
這個函數(shù)將會重新獲取NdisSendNetBufferLists
發(fā)送的數(shù)據(jù)包,在該函數(shù)中可以釋放發(fā)送分配的NET_BUFFER_LIST
內(nèi)存。
不過這里需要注意的是NET_BUFFER_LIST
是一個鏈表結(jié)構(gòu),在底層可能會被斷鏈發(fā)送;因此SendNetBufferListsCompleteHandler
這個函數(shù)中的NET_BUFFER_LIST
可能是NdisSendNetBufferLists
中的子鏈。
2.3 ReceiveNetBufferListsHandler
當(dāng)我們的網(wǎng)卡接收到數(shù)據(jù)的時候,就會通過硬件方式(例如中斷等)通知數(shù)據(jù)包到來,然后小端口驅(qū)動通過NdisMIndicateReceiveNetBufferLists
將數(shù)據(jù)包傳送給協(xié)議層驅(qū)動進(jìn)行協(xié)議解析和數(shù)據(jù)包的傳遞,該函數(shù)如下:
void NdisMIndicateReceiveNetBufferLists(
NDIS_HANDLE MiniportAdapterHandle,
PNET_BUFFER_LIST NetBufferList,
NDIS_PORT_NUMBER PortNumber,
ULONG NumberOfNetBufferLists,
ULONG ReceiveFlags
);
在NdisMIndicateReceiveNetBufferLists
內(nèi)部就會調(diào)用ReceiveNetBufferListsHandler
將接收到的網(wǎng)絡(luò)數(shù)據(jù)包通過NET_BUFFER_LIST
進(jìn)行傳遞,該函數(shù)聲明如下:
PROTOCOL_RECEIVE_NET_BUFFER_LISTS ProtocolReceiveNetBufferLists;
void ProtocolReceiveNetBufferLists(
NDIS_HANDLE ProtocolBindingContext,
PNET_BUFFER_LIST NetBufferLists,
NDIS_PORT_NUMBER PortNumber,
ULONG NumberOfNetBufferLists,
ULONG ReceiveFlags
)
{...}
在該函數(shù)中NetBufferLists
表示數(shù)據(jù)包,通過解析該數(shù)據(jù)包我們就可以進(jìn)行TCPIP網(wǎng)絡(luò)棧的協(xié)議解析了。
2.4 ProtocolNetPnpEvent
改例程是NDIS框架對于網(wǎng)絡(luò)PNP事件響應(yīng)的回調(diào)函數(shù),該函數(shù)聲明如下:
PROTOCOL_NET_PNP_EVENT ProtocolNetPnpEvent;
NDIS_STATUS ProtocolNetPnpEvent(
NDIS_HANDLE ProtocolBindingContext,
PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification
)
{...}
NET_PNP_EVENT_NOTIFICATION
描述了一個PNP事件的信息,該結(jié)構(gòu)如下:
typedef struct _NET_PNP_EVENT_NOTIFICATION {
NDIS_OBJECT_HEADER Header;
NDIS_PORT_NUMBER PortNumber;
NET_PNP_EVENT NetPnPEvent;
ULONG Flags;
NDIS_NIC_SWITCH_ID SwitchId;
NDIS_NIC_SWITCH_VPORT_ID VPortId;
} NET_PNP_EVENT_NOTIFICATION, *PNET_PNP_EVENT_NOTIFICATION;
typedef struct _NET_PNP_EVENT {
NET_PNP_EVENT_CODE NetEvent;
PVOID Buffer;
ULONG BufferLength;
ULONG_PTR NdisReserved[4];
ULONG_PTR TransportReserved[4];
ULONG_PTR TdiReserved[4];
ULONG_PTR TdiClientReserved[4];
} NET_PNP_EVENT, *PNET_PNP_EVENT;
NET_PNP_EVENT_CODE
描述網(wǎng)絡(luò)PNP事件的類型,有如下:
typedef enum _NET_PNP_EVENT_CODE
{
NetEventSetPower,
NetEventQueryPower,
NetEventQueryRemoveDevice,
NetEventCancelRemoveDevice,
NetEventReconfigure,
NetEventBindList,
NetEventBindsComplete,
NetEventPnPCapabilities,
NetEventPause,
NetEventRestart,
NetEventPortActivation,
NetEventPortDeactivation,
NetEventIMReEnableDevice,
NetEventNDKEnable,
NetEventNDKDisable,
NetEventFilterPreDetach,
NetEventBindFailed,
NetEventSwitchActivate,
NetEventAllowBindsAbove,
NetEventInhibitBindsAbove,
NetEventAllowStart,
NetEventRequirePause,
NetEventUploadGftFlowEntries,
NetEventMaximum
} NET_PNP_EVENT_CODE, *PNET_PNP_EVENT_CODE;
NET_PNP_EVENT_CODE
的具體值,參見MSDN(例如NetEventSetPower
類型Buffer
表示了NDIS_DEVICE_POWER_STATE
結(jié)構(gòu),描述電源狀態(tài))。
3. NET_BUFFER_LIST
在NDIS中,網(wǎng)絡(luò)數(shù)據(jù)包通過NET_BUFFER_LIST
來進(jìn)行抽象,這個結(jié)構(gòu)表示著網(wǎng)絡(luò)數(shù)據(jù)包的集合;該數(shù)據(jù)結(jié)構(gòu)如下:
NET_BUFFER_LIST
是一個NET_BUFFER_LIST
的鏈表集合;單個NET_BUFFER_LIST
是NET_BUFFER
的集合,NET_BUFFER
表示一個數(shù)據(jù)包,該結(jié)構(gòu)如下:
NET_BUFFER
其實(shí)就是使用MDL來描述數(shù)據(jù)包的真實(shí)類容,因此對于NET_BUFFER_LIST
的全部結(jié)構(gòu)可以描述為如下:
對于NET_BUFFER_LIST
和NET_BUFFER
提供了如下宏來操作該結(jié)構(gòu)的成員:
#define NET_BUFFER_LIST_NEXT_NBL(_NBL) ((_NBL)->Next)
#define NET_BUFFER_LIST_FIRST_NB(_NBL) ((_NBL)->FirstNetBuffer)
#define NET_BUFFER_NEXT_NB(_NB) ((_NB)->Next)
#define NET_BUFFER_FIRST_MDL(_NB) ((_NB)->MdlChain)
#define NET_BUFFER_DATA_LENGTH(_NB) ((_NB)->DataLength)
#define NET_BUFFER_DATA_OFFSET(_NB) ((_NB)->DataOffset)
#define NET_BUFFER_CURRENT_MDL(_NB) ((_NB)->CurrentMdl)
#define NET_BUFFER_CURRENT_MDL_OFFSET(_NB) ((_NB)->CurrentMdlOffset)
我們需要對接收或者發(fā)送的數(shù)據(jù)包進(jìn)行處理,都是解析NET_BUFFER_LIST
的過程。
4. ndisprot實(shí)例
對于NDIS協(xié)議驅(qū)動,WDK提供了一個示例ndisprot,該示例展示了協(xié)議驅(qū)動的工作原理,該實(shí)例提供如下功能:
- ndisprot驅(qū)動可以綁定到網(wǎng)卡上面。
- 通過
NdisprotReceiveNetBufferLists
接收底層的網(wǎng)絡(luò)數(shù)據(jù)包,并將其放入隊(duì)列中。 - 用戶層程序可以通過
ReadFile
讀取協(xié)議驅(qū)動的網(wǎng)絡(luò)數(shù)據(jù)包。 - 用戶層程序可以通過
WriteFile
往網(wǎng)絡(luò)協(xié)議驅(qū)動寫入數(shù)據(jù)包,協(xié)議驅(qū)動通過NdisSendNetBufferLists
將數(shù)據(jù)包發(fā)送到底層小端口驅(qū)動。
該協(xié)議否是可以支持網(wǎng)絡(luò)通信呢?本人沒有進(jìn)行實(shí)驗(yàn)驗(yàn)證,但是從原理上來說是可行的,只是它是一個面向非連接,并且沒有校驗(yàn)的原始通信手段的協(xié)議。
對于該驅(qū)動我們可以簡單的使用如下方式手動安裝和驗(yàn)證:
5. 總結(jié)
對于NDIS協(xié)議層驅(qū)動平時我們的使用場景不多,我們也沒有能力(也沒必要)設(shè)計(jì)一個完整的網(wǎng)絡(luò)協(xié)議驅(qū)動。但是協(xié)議驅(qū)動是我們后面NDIS過濾驅(qū)動的基礎(chǔ),NDIS過濾驅(qū)動可以幫助我們獲取本機(jī)接收到的網(wǎng)絡(luò)幀數(shù)據(jù)包,并且對以太幀數(shù)據(jù)包進(jìn)行過濾(例如ARP數(shù)據(jù)包等)。文章來源:http://www.zghlxwxcb.cn/news/detail-776760.html
因此NDIS協(xié)議驅(qū)動還是非常值得我們?nèi)W(xué)習(xí)的,它是NDIS過濾驅(qū)動的基礎(chǔ),也是以太幀數(shù)據(jù)包過濾的重要手段。文章來源地址http://www.zghlxwxcb.cn/news/detail-776760.html
到了這里,關(guān)于NDIS協(xié)議驅(qū)動開發(fā)指南的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!