3.2.2 协议驱动程序的特征结构体
协议驱动程序在DriverEntry函数中调用NDIS库的NdisRegisterProtocol函数向NDIS库注册。在WinPcap中,就使用了下列代码进行注册。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
……
NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar;
……
NdisRegisterProtocol(
&Status,
&g_NdisProtocolHandle,
&ProtocolChar,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
……
}
结构体NDIS_PROTOCOL_CHARACTERISTICS(协议驱动程序特征结构体)是函数NdisRegisterProtocol的一个重要参数。该结构体用于指定一个协议驱动的版本号与各种回调函数,此结构体的具体定义如下:
typedef struct_NDIS_PROTOCOL_CHARACTERISTICS{
UCHAR MajorNdisVersion;
UCHAR MinorNdisVersion;
UINT Reserved;
OPEN_ADAPTER_COMPLETE_HANDLER OpenAdapterCompleteHandler;
CLOSE_ADAPTER_COMPLETE_HANDLER CloseAdapterCompleteHandler;
SEND_COMPLETE_HANDLER SendCompleteHandler;
TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
RESET_COMPLETE_HANDLER ResetCompleteHandler;
REQUEST_COMPLETE_HANDLER RequestCompleteHandler;
RECEIVE_HANDLER ReceiveHandler;
RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
STATUS_HANDLER StatusHandler;
STATUS_COMPLETE_HANDLER StatusCompleteHandler;
NDIS_STRING Name;
/*
*如果需要使用下列任何成员,就要把MajorNdisVersion设置为0x04或0x05
*/
RECEIVE_PACKET_HANDLER ReceivePacketHandler;
BIND_HANDLER BindAdapterHandler;
UNBIND_HANDLER UnbindAdapterHandler;
PNP_EVENT_HANDLER PnPEventHandler;
UNLOAD_PROTOCOL_HANDLER UnloadHandler;
/*
*如果需要使用下列任何成员,就要把MajorNdisVersion设置为0x05
*面向连接的协议驱动程序使用,此处不作分析
*/
CO_SEND_COMPLETE_HANDLER CoSendCompleteHandler;
CO_STATUS_HANDLER CoStatusHandler;
CO_RECEIVE_PACKET_HANDLER CoReceivePacketHandler;
CO_AF_REGISTER_NOTIFY_HANDLER CoAfRegisterNotifyHandler;
}NDIS_PROTOCOL_CHARACTERISTICS,
*PNDIS_PROTOCOL_CHARACTERISTICS;
下面分别说明结构体NDIS_PROTOCOL_CHARACTERISTICS中各成员的作用,但是对只在面向连接的协议驱动程序中使用的成员此处不作说明。
❑MajorNdisVersion:描述驱动程序所使用NDIS库的主要版本。本书所用版本为0x05(最新版本已为0x06)。NDIS库支持早期采用NDIS V4.0开发的驱动程序,但不支持V3.0版本的协议驱动程序。
❑MinorNdisVersion:描述NDIS的次版本,本章所分析的WinPcap使用的是0x00。
❑Reserved:该成员保留给系统使用。
❑OpenAdapterCompleteHandler:指定驱动程序ProtocolOpenAdapterComplete函数的入口点,必须提供该函数。如果协议驱动程序对NdisOpenAdapter的调用返回NDIS_STATUS_PENDING,则调用ProtocolOpenAdapterComplete函数来完成绑定操作。
❑CloseAdapterCompleteHandler:指定驱动程序ProtocolCloseAdapterComplete函数的入口点,必须提供该函数。如果协议驱动程序对NdisCloseAdapter的调用返回NDIS_STATUS_PENDING,则调用ProtocolCloseAdapterComplete函数来完成解除绑定操作。
❑SendCompleteHandler:指定驱动程序ProtocolSendComplete函数的入口点,必须提供该函数。如果协议驱动程序对NdisSendPackets或NdisSend的调用返回NDIS_STATUS_PENDING,则调用SendCompleteHandler函数来完成发送处理。
❑TransferDataCompleteHandler:指定驱动程序ProtocolTransferDataComplete函数的入口点。如果协议驱动程序可以把它自己绑定到一个底层非面向连接的NIC驱动程序上,这就是一个必须被提供的函数。当协议驱动程序发起传输数据请求,且对NdisTransferData的调用返回NDIS_STATUS_PENDING时,函数ProtocolTransferDataComplete被调用。专门面向连接的协议驱动程序不需要ProtocolTransferDataComplete函数。
❑ResetCompleteHandler:指定驱动程序ProtocolResetComplete函数的入口点,必须提供该函数。当协议驱动程序调用NdisReset函数执行复位操作,且返回值为NDIS_STATUS_PENDING时,则调用ProtocolResetComplete函数完成复位操作。
❑RequestCompleteHandler:指定驱动程序ProtocolRequestComplete函数的入口点,必须提供该函数。当协议驱动程序调用NdisRequest函数查询和设置操作,且返回值为NDIS_STATUS_PENDING时,则调用ProtocolRequestComplete函数完成操作。
❑ReceiveHandler:指定驱动程序ProtocolReceive函数的入口点。对绑定到一个非面向连接的NIC驱动程序上的NDIS协议驱动程序来说,ProtocolReceive函数是一个必须被提供的函数,其决定协议驱动程序的使用者对一个被接收的网络数据包是否感兴趣,如果感兴趣,则复制所需要的数据,如有必要,可进一步调用NdisTransferData函数获取剩余的数据包。
❑ReceiveCompleteHandler:指定驱动程序ProtocolReceiveComplete函数的入口点,必须提供该函数。驱动程序完成接收所需数据的操作后,ProtocolReceiveComplete函数完成诸如通知协议驱动程序使用者处理所接收数据包之类的后处理操作。
❑StatusHandler:指定驱动程序ProtocolStatus函数的入口点,必须提供该函数。ProtocolStatus函数用来处理底层NIC驱动程序所指示状态的改变。
❑StatusCompleteHandler:指定驱动程序ProtocolStatusComplete函数的入口点,必须提供该函数。ProtocolStatusComplete完成一个状态改变的操作,该操作由底层驱动程序调用NdisMIndicateStatus发起。
❑Name:一个NDIS_STRING类型,用来对驱动程序进行命名,包含调用者初始化的一个字符串,采用系统默认的字符集。
对于Windows 2000及更高版本的驱动来说,该字符串为Unicode字符。也就是说,对于Windows 2000及更高的版本,NDIS库定义NDIS_STRING类型为一个UNICODE_STRING类型。当协议被安装时,该字符串必须与注册表所指定的(在Services条目之下)服务匹配。
函数NdisRegisterProtocol把所提供的字符串转换为大写字符,因此一个协议驱动程序的编写者不能通过改变一个已经注册协议名称的大小写来为驱动创建一个唯一的名称。
❑ReceivePacketHandler:指定驱动程序ProtocolReceiveComplete函数的入口点,该函数是可选的。如果协议驱动程序绑定到支持多数据包(multipacket)的NIC驱动程序(通过调用NdisMIndicateReceivePacket函数指定),那么该函数应该被提供。
❑BindAdapterHandler:指定驱动程序ProtocolBindAdapter函数的入口点,必须提供该函数。NDIS调用该函数把协议驱动程序绑定到底层网卡或虚拟网卡上,而网卡名则作为该处理函数的参数传递。
❑UnbindAdapterHandler:指定驱动程序ProtocolUnbindAdapter函数的入口点,必须提供该函数。NDIS调用ProtocolUnbindAdapter函数释放对底层网卡或虚拟网卡的绑定,网卡名作为参数传递。当成功解除绑定时,该函数调用NdisCloseAdapter函数,并释放资源。
❑PnPEventHandler:指定驱动程序ProtocolPnPEvent函数的入口点,必须提供该函数。NDIS调用ProtocolPnPEvent来指示即插即用事件或电源管理事件。
❑UnloadHandler:指定驱动程序ProtocolUnbind函数的入口点,该函数是可选的。NDIS调用该函数来响应用户卸载中间层驱动程序的请求。对于每一个绑定的适配器,在调用NDIS库的ProtocolUnbindAdapter函数之后,会调用该函数卸载驱动程序,执行驱动程序决定的清除操作。