NDIS 6.0 引入了暂停和重启驱动程序堆栈的功能。 若要支持 NDIS 6.0 提供的堆栈管理功能,必须重写旧版驱动程序。
NDIS 6.0 还引入了 NDIS Filter驱动程序。 Filter驱动程序可以监视和修改协议驱动程序与微型端口驱动程序之间的交互。 与 NDIS 5 相比,Filter驱动程序更易于实现,并且处理开销更少。x 中间驱动程序。 出于这些原因,应使用Filter驱动程序而不是Filter中间驱动程序。
驱动程序堆栈包含以下逻辑元素:
- 微型端口适配器:微型端口适配器是 NDIS 微型端口驱动程序或中间驱动程序的适配器实例。 中间驱动程序的虚拟微型端口是微型端口适配器。 设备可用后,NDIS 在微型端口适配器上配置驱动程序堆栈的其他元素。
- 协议绑定:协议绑定是协议驱动程序的绑定实例。 协议绑定将 NDIS 协议驱动程序绑定到微型端口适配器。 多个协议驱动程序可以绑定到微型端口适配器。
- Filter模块:Filter模块是Filter驱动程序的实例。 NDIS 可以暂停驱动程序堆栈以插入、删除或重新配置Filter模块。 Filter模块可以监视和修改微型端口适配器的行为。
两种堆栈配置
中间层驱动和Filter驱动是两个不同的概念,这一点非常奇特,因为在最开始的时候(NDIS 5.1)只有中间层过滤驱动,那时候需要同时实现协议驱动和小端口驱动,但是6.0之后,这个部分可以使用Filter来完成,一个明显的需求就是包过滤防火墙,不过由于Filter驱动的加入,导致堆栈变复杂了,下面是没有中间层驱动的堆栈:
以及有中间层驱动的堆栈:
在最开始的时候,我们认为中间层驱动会被Filter取代,但是后来发现中间层被用于其它目的了。下面分别给出三种驱动的状态图,注意可能和其他分栏中的内容重合,不过,给出这些图是为了综合的讨论整个NDIS堆栈。
微型端口驱动程序的适配器状态图
对于它管理的每个微型端口适配器, NDIS 微型端口驱动程序 必须支持以下一组操作状态:
- 停止
- 关闭
- 正在初始化
- 已暂停
- 重新启动
- 正在运行
- 正在暂停
下图显示了这些状态之间的相互关系:
注意 重置操作不会影响微型端口适配器的操作状态。 此外,重置操作正在进行时,适配器的状态可能会更改。 例如,当重置操作正在进行时,NDIS 可能会调用驱动程序的暂停处理程序。 在这种情况下,驱动程序可以按任何顺序完成重置或暂停操作,同时遵循每个操作的正常要求。 对于重置操作,驱动程序可能会使传输请求数据包失败,也可以让数据包保持排队并稍后完成。 但是,应注意,在传输数据包挂起时,过分的驱动程序无法完成暂停操作。
下面定义了适配器状态:
- “已停止 ”是所有微型端口适配器的初始状态。 当微型端口适配器处于“已停止”状态,并且 NDIS 调用驱动程序的 MiniportInitializeEx 函数来初始化微型端口适配器时,微型端口适配器将进入“正在初始化”状态。 如果 MiniportInitializeEx 失败,微型端口适配器将返回到 Halted 状态。 当微型端口适配器处于“已暂停”状态并且 NDIS 调用 MiniportHaltEx 函数时,微型端口适配器将返回到“已暂停”状态。
- 在系统关闭并重新启动之前,不能使用处于 关闭 状态的微型端口适配器。 当微型端口适配器处于“已暂停”、“正在重启”、“正在运行”或“正在暂停”状态,并且 NDIS 调用微型端口驱动程序的 MiniportShutdownEx 函数时,微型端口适配器将进入“关闭”状态。
- 在 “正在初始化 ”状态下,微型端口驱动程序完成初始化微型端口适配器所需的任何操作。 当微型端口适配器处于“已停止”状态,并且 NDIS 调用微型端口驱动程序的 MiniportInitializeEx 函数时,微型端口适配器将进入“正在初始化”状态。 如果 MiniportInitializeEx 成功,微型端口适配器将进入 Paused 状态。 如果 MiniportInitializeEx 失败,微型端口适配器将返回到 Halted 状态。
- 当微型端口适配器处于 “已暂停” 状态时,微型端口驱动程序不会指示已收到网络数据或接受发送请求。 当微型端口适配器处于暂停状态并且暂停操作完成时,微型端口适配器将进入“已暂停”状态。 当微型端口适配器处于“正在初始化”状态并且 MiniportInitializeEx 成功时,微型端口适配器将进入“已暂停”状态。 当 NDIS 调用微型端口驱动程序的 MiniportRestart 函数时,微型端口适配器将从“已暂停”状态转换为“正在重启”状态。 当 NDIS 调用微型端口驱动程序的 MiniportHaltEx 函数时,微型端口适配器将从“已暂停”状态转换为“已停止”状态。
- 在 “正在重启” 状态下,微型端口驱动程序完成重启微型端口适配器的发送和接收操作所需的任何操作。 当微型端口适配器处于“已暂停”状态并且 NDIS 调用驱动程序的 MiniportRestart 函数时,微型端口适配器将进入“正在重启”状态。 如果重启失败,微型端口适配器将返回到“已暂停”状态。 如果重启成功,微型端口适配器将进入“正在运行”状态。
- 在 “正在运行” 状态下,微型端口驱动程序对微型端口适配器执行正常的发送和接收处理。 当微型端口适配器处于“正在重启”状态,并且驱动程序已准备好执行发送和接收操作时,微型端口适配器将进入“正在运行”状态。
- 在 暂停 状态下,微型端口驱动程序完成停止微型端口适配器的发送和接收操作所需的任何操作。 驱动程序必须等待 NDIS 返回所有未完成的接收指示。 当微型端口适配器处于“正在运行”状态并且 NDIS 调用驱动程序的 MiniportPause 函数时,微型端口适配器将进入暂停状态。 微型端口驱动程序不能使暂停操作失败。 暂停操作完成后,微型端口适配器将进入“已暂停”状态。
协议驱动程序的绑定状态
对于驱动程序管理的每个绑定, NDIS 协议驱动程序 必须支持以下操作状态:
- 未绑定
- 打开
- 正在运行
- 关闭
- 正在暂停
- 已暂停
- 重新启动
下图显示了这些状态之间的关系:
下面定义了协议驱动程序绑定状态:
- “未绑定”状态是绑定的初始状态。 在此状态下,协议驱动程序等待 NDIS 调用 ProtocolBindAdapterEx 函数。 NDIS 调用 ProtocolBindAdapterEx 后,绑定将进入“打开”状态。 取消绑定操作完成后,绑定将从“关闭”状态返回到“未绑定”状态。
- 在 “打开” 状态下,协议驱动程序为绑定分配资源,并尝试打开微型端口适配器。 NDIS 调用驱动程序的 ProtocolBindAdapterEx 函数后,绑定将进入“打开”状态。 如果协议驱动程序无法绑定到微型端口适配器,则绑定将返回到“未绑定”状态。 如果驱动程序成功绑定到微型端口适配器,绑定将进入“已暂停”状态。
- 在 “正在运行” 状态下,协议驱动程序对绑定执行正常的发送和接收处理。 当绑定处于“正在重启”状态并且驱动程序已准备好执行发送和接收操作时,绑定将进入“正在运行”状态。
- 在 “关闭” 状态下,协议驱动程序关闭与微型端口适配器的绑定,然后释放绑定的资源。 NDIS 调用协议驱动程序的 ProtocolUnbindAdapterEx 函数后,绑定将进入“正在关闭”状态。 协议驱动程序完成取消绑定操作后,绑定将进入“未绑定”状态。
- 在 暂停 状态下,协议驱动程序完成停止绑定的发送和接收操作所需的任何操作。 当绑定处于“正在运行”状态并且 NDIS 向协议驱动程序发送 PnP 暂停通知时,绑定将进入暂停状态。 协议驱动程序必须等待其所有未完成的发送请求完成。 协议驱动程序无法使暂停操作失败。 暂停操作完成后,绑定将进入“已暂停”状态。
- 在 “已暂停” 状态下,协议驱动程序不对绑定执行发送或接收操作。 当绑定处于暂停状态并且暂停操作完成时,绑定将进入“已暂停”状态。 当绑定处于“打开”状态并且打开操作成功完成时,绑定将进入“已暂停”状态。 如果 NDIS 向协议驱动程序发送绑定的 PnP 重启通知,则绑定将进入“正在重启”状态。 如果 NDIS 调用驱动程序的 ProtocolUnbindAdapterEx 函数,则绑定将进入“正在关闭”状态。
- 在 “正在重启” 状态下,协议驱动程序完成重启绑定的发送和接收操作所需的任何操作。 当绑定处于“已暂停”状态并且 NDIS 向协议驱动程序发送 PnP 重启通知时,绑定将进入“正在重启”状态。 如果重启失败,绑定将返回到“已暂停”状态。 如果重启成功,绑定将进入“正在运行”状态。
Filter驱动程序的模块状态
NDIS Filter驱动程序必须支持驱动程序管理的每个Filter模块 (Filter驱动程序) 实例的以下操作状态:
- 分离
- 附加
- 已暂停
- 重新启动
- 运行
- 正在暂停
下图显示了这些状态之间的关系。
下面定义了Filter模块状态:
- 分离:分离状态是Filter模块的初始状态。 当Filter模块处于此状态时,NDIS 可以调用Filter驱动程序的 FilterAttach 函数,以将Filter模块附加到驱动程序堆栈。 当 NDIS 调用Filter驱动程序的 FilterAttach 函数时,Filter模块将进入“正在附加”状态。 如果附加操作失败,Filter模块将返回到“分离”状态。 当模块处于“已暂停”状态且 NDIS 调用 FilterDetach 函数时,模块将返回到“已分离”状态;
- 附加:当Filter模块处于 “正在附加” 状态时,Filter驱动程序准备将模块附加到驱动程序堆栈。 Filter模块准备完成后,Filter模块将进入“已暂停”状态。 例如,如果 (发生故障,因为所需的资源在) 不可用,Filter模块将返回到“分离”状态;
- 暂停:当Filter模块处于 “已暂停” 状态时,Filter模块不会执行发送或接收操作。 当Filter模块处于 “正在附加” 状态并且 FilterAttach 成功时,Filter模块将进入“ 已暂停” 状态。 当Filter模块处于 暂停 状态并且暂停操作完成时,Filter模块将进入 “已暂停” 状态。 当Filter模块处于 “已暂停” 状态并且 NDIS 调用Filter驱动程序的 FilterRestart 函数时,Filter模块将进入 “正在重启” 状态。 当Filter模块处于 “已暂停” 状态并且 NDIS 调用驱动程序的 FilterDetach 处理程序时,Filter模块将进入 “已分离 ”状态;
- 重新 启动:在 “正在重启” 状态下,Filter驱动程序完成重启Filter模块的发送和接收操作所需的任何操作。 当Filter模块处于“已暂停”状态并且 NDIS 调用驱动程序的 FilterRestart 函数时,Filter模块将进入“正在重启”状态。 如果重启失败,Filter模块将返回到“已暂停”状态。 如果重启成功,Filter模块将进入“正在运行”状态;
- 运行:在 “正在运行” 状态下,Filter驱动程序对Filter模块执行正常的发送和接收处理。 当Filter模块处于“正在重启”状态并且驱动程序已准备好执行发送和接收操作时,Filter模块将进入“正在运行”状态;
- 暂停:在 暂停 状态下,Filter驱动程序完成停止Filter模块的发送和接收操作所需的任何操作。 Filter驱动程序必须等待其所有未完成的发送请求完成,并且 NDIS 必须返回其所有未完成的接收指示。 当Filter模块处于“正在运行”状态并且 NDIS 调用驱动程序的 FilterPause 函数时,Filter模块将进入“正在暂停”状态。 Filter驱动程序无法使暂停操作失败。 暂停操作完成后,Filter模块将进入“已暂停”状态;
启动驱动程序堆栈
系统检测到网络设备后,系统将启动设备的 NDIS 驱动程序堆栈。 设备可以是虚拟设备,也可以是物理设备。 在任一情况下,驱动程序堆栈启动操作将按如下所示进行:
1. 如果驱动程序尚未加载,系统会加载并初始化这些驱动程序。它不会按任何特定顺序加载驱动程序;
2. 系统调用每个驱动程序的 DriverEntry 函数。在 DriverEntry 返回后:
- 设备的微型端口适配器处于“已停止”状态;
- Filter模块处于“分离”状态;
- 协议绑定处于“未绑定”状态;
3. 系统请求 NDIS 启动微型端口适配器。为了初始化微型端口适配器,NDIS 调用微型端口驱动程序的 MiniportInitializeEx 函数。 如果 MiniportInitializeEx 成功,微型端口适配器将进入 Paused 状态;
4. NDIS 附加Filter模块,从最靠近微型端口驱动程序的模块开始,并前进到驱动程序堆栈的顶部。若要请求驱动程序将Filter模块附加到驱动程序堆栈,NDIS 调用Filter驱动程序的 FilterAttach 函数。 如果每个附加操作都成功,Filter模块将进入“已暂停”状态;
5. 在所有基础驱动程序都处于“已暂停”状态后,NDIS 会调用协议驱动程序的 ProtocolBindAdapterEx 函数。然后,协议驱动程序绑定进入“打开”状态。 协议驱动程序调用 NdisOpenAdapterEx 函数以使用微型端口适配器打开绑定;
6. NDIS 为绑定分配必要的资源,并调用协议驱动程序的 ProtocolOpenAdapterCompleteEx 函数。绑定进入“已暂停”状态;
7. 若要完成绑定操作,协议驱动程序调用 NdisCompleteBindAdapterEx 函数;
8. NDIS 重启驱动程序堆栈;
停止驱动程序堆栈
如果删除了设备,NDIS 将停止驱动程序堆栈。 驱动程序堆栈停止操作继续如下:
- NDIS 暂停驱动程序堆栈;
- NDIS 调用协议驱动程序的 ProtocolUnbindAdapterEx 函数。绑定进入“正在关闭”状态。 完成未完成的 OID 和发送请求并返回所有接收数据后,绑定将进入“未绑定”状态;
- NDIS 分离所有Filter模块,从堆栈的顶部开始,向下推进到微型端口驱动程序。在 NDIS 调用Filter驱动程序的 FilterDetach 函数并且Filter驱动程序释放Filter模块的所有资源后,Filter模块将处于“分离”状态;
- NDIS 停止微型端口适配器。在 NDIS 调用微型端口驱动程序的 MiniportHaltEx 函数后,微型端口驱动程序将释放微型端口适配器的所有资源,并且微型端口适配器处于“已停止”状态;
- 如果分离了Filter驱动程序的所有模块,则系统可以卸载Filter驱动程序;
- 如果微型端口驱动程序管理的所有微型端口适配器已停止,则系统可以卸载微型端口驱动程序;
暂停驱动程序堆栈
NDIS 暂停驱动程序堆栈以完成插入Filter模块或添加绑定等操作。 通常,驱动程序堆栈暂停操作将按如下所示进行:
- NDIS 将 PnP 暂停事件发送到协议驱动程序。绑定进入暂停状态。 完成所有未完成的发送请求后,协议驱动程序将完成 PnP 事件。 绑定处于“已暂停”状态;
- NDIS 暂停所有Filter模块,从堆栈顶部开始,并向下推进到微型端口驱动程序。NDIS 调用Filter驱动程序的 FilterPause 函数后,Filter模块将进入暂停状态。 NDIS 返回所有未完成的接收指示并完成所有未完成的发送操作后,Filter模块将进入“已暂停”状态;
- NDIS 暂停微型端口适配器。NDIS 调用微型端口驱动程序的 MiniportPause 函数后,微型端口适配器将进入暂停状态。 NDIS 返回所有未完成的接收指示后,微型端口适配器将进入“已暂停”状态;
注意 NDIS 驱动程序无法使暂停请求失败。 应记录发生的任何错误。
重启驱动程序堆栈
NDIS 在插入Filter模块或添加绑定等操作后重启驱动程序堆栈。 驱动程序堆栈重启操作将按如下所示进行:
- NDIS 重启微型端口适配器。NDIS 调用微型端口驱动程序的 MiniportRestart 函数后,微型端口适配器将进入“正在重启”状态。 微型端口驱动程序准备恢复发送和接收操作。 如果准备失败,微型端口适配器将返回到“已暂停”状态。 驱动程序准备好继续发送和接收操作后,微型端口适配器将进入“正在运行”状态;
- NDIS 重启Filter模块,从驱动程序堆栈的底部开始,一直升级到协议驱动程序。NDIS 调用Filter驱动程序的 FilterRestart 函数后,Filter模块将进入“正在重启”状态。 Filter驱动程序准备恢复发送和接收操作。 如果准备失败,模块将返回到“已暂停”状态。 驱动程序准备好恢复发送和接收操作后,Filter模块将进入“正在运行”状态;
- NDIS 将 PnP 重启事件发送到协议驱动程序。绑定进入“正在重启”状态。 协议驱动程序准备恢复发送和接收操作。 如果准备失败,绑定将返回到“已暂停”状态。 在协议驱动程序准备好恢复发送和接收操作后,绑定将进入“正在运行”状态;
修改正在运行的驱动程序堆栈
NDIS 修改用于插入、删除或重新配置Filter模块等操作的驱动程序堆栈。 NDIS 可以在Filter模块中激活或停用绕过模式。
注意 如果Filter驱动程序入口点更改,即由于绕过模式,NDIS 将暂停并重启驱动程序堆栈。 暂停和重启可能会导致某些网络数据包在传输路径或接收路径上被删除。 提供可靠传输机制的网络协议可能会在数据包丢失时重试网络 I/O 操作,但其他不保证可靠性的协议不会重试该操作。
NDIS 修改正在运行的驱动程序堆栈,如下所示:
- NDIS 暂停驱动程序堆栈;
- NDIS 修改堆栈。例如,若要添加Filter模块,NDIS 将确定将新Filter模块插入堆栈的位置,并创建、插入和附加Filter模块;
- 插入或删除Filter模块时,驱动程序堆栈的特征可能会更改。 在这种情况下,NDIS 会向驱动程序堆栈中的所有协议绑定和Filter模块发送即插即用事件通知,以通知驱动程序此更改;
- NDIS 重启驱动程序堆栈;
绕过模式-数据旁路模式
Filter驱动程序 数据旁路模式 可提供改进的系统性能。 NDIS 不调用绕过的 FilterXxx 函数。 例如,如果给定的Filter应用程序不需要发送和接收服务,则Filter驱动程序可以绕过发送和接收函数。
Filter驱动程序指定在驱动程序初始化期间调用 NdisFRegisterFilterDriver 函数时可以绕过的函数的默认入口点。 对于默认跳过的函数,入口点为 NULL 。
若要在运行时更改绕过状态,驱动程序必须在驱动程序初始化期间为 FilterSetModuleOptions 函数指定入口点。 驱动程序可以初始化NDIS_FILTER_PARTIAL_CHARACTERISTICS结构,并从 FilterSetModuleOptions 的上下文中将新特征传递给 NdisSetOptionalHandlers 函数。
NDIS 在重启操作开始时调用 FilterSetModuleOptions 函数(如果有)。 Filter驱动程序可以为每个Filter模块单独设置绕过模式。
Filter驱动程序可以绕过在 NDIS_FILTER_DRIVER_CHARACTERISTICS 结构中指定的以下可选 FilterXxx 函数:
- FilterSendNetBufferLists
- FilterSendNetBufferListsComplete
- FilterCancelSendNetBufferLists
- FilterReturnNetBufferLists
- FilterReceiveNetBufferLists
若要将 FilterXxx 函数设置为绕过模式,Filter驱动程序会为该函数的入口点指定 NULL 。 但是,如果驱动程序调用具有关联的 FilterXxx 函数的任何 NDIS 函数,则必须为该 FilterXxx 函数提供入口点。 例如,如果驱动程序调用 NdisFIndicateReceiveNetBufferLists 函数,则必须提供 FilterReturnNetBufferLists 函数。
如果Filter驱动程序指定 FilterSendNetBufferLists 函数并排队发送请求,则它还必须指定 FilterCancelSendNetBufferLists 函数。
如果Filter驱动程序指定 FilterReceiveNetBufferLists 或 FilterReturnNetBufferLists 函数,则驱动程序还必须指定 FilterStatus 函数。
若要在运行时更改其绕过模式设置,Filter驱动程序可以调用 NdisFRestartFilter 函数。 NdisFRestartFilter 计划一个暂停操作,然后是指定Filter模块的重启操作。 当 NDIS 调用 FilterSetModuleOptions 时,Filter驱动程序可以通过调用 NdisSetOptionalHandlers 并指定一组新的入口点来更改该Filter模块的函数。
注意 暂停和重启可能会导致某些网络数据包丢弃在传输路径或接收路径上,或同时删除两者。 如果数据包丢失,则提供可靠传输机制的网络协议可能会重试网络 I/O 操作,但其他不保证可靠性的协议不会重试该操作。
Filter驱动程序可以注册支持可选驱动程序服务的其他可选函数。 驱动程序在 FilterSetOptions 函数中注册这些可选服务。