NDIS Filter Drivers 指南

fhqbgmqj

贡献于2015-06-16

字数:0 关键词: 嵌入式开发

  NDIS Filter Drivers      SamllBug  2010/10/18          目录  1 介绍NDIS Filter Drivers ..................................................................................................... 4 1.1 Filter Drivers  特性..................................................................................................... 4 1.2 Filter Drivers  服务..................................................................................................... 5 1.3 Filter Drivers  类型..................................................................................................... 5 1.4 Mandatory Filter Drivers............................................................................................ 6 2 编写NDIS Filter Drivers ..................................................................................................... 7 2.1 初始化Filter Driver..................................................................................................... 7 2.2 卸载Filter Drivers..................................................................................................... 11 2.3 Filter Module  状态和操作...................................................................................... 12 2.4 附加Filter Module.................................................................................................... 14 2.5 分离Filter Module.................................................................................................... 18 2.6 重启和暂停Filter Module........................................................................................ 20 2.6.1 重启Filter Module ............................................................................................ 20 2.6.2 暂停Filter Module ............................................................................................ 24 2.7 Data Bypass Mode.................................................................................................... 26 2.8 Filter Driver的选项配置........................................................................................... 26 2.9 Filter Module发送和接收........................................................................................ 27 2.9.1 Filter Driver的缓冲区管理............................................................................... 27 2.9.2 在Filter Driver中发送数据............................................................................... 28 2.9.3 在Filter Driver中取消一个发送请求............................................................... 30 2.9.4 在Filter Driver中接收数据............................................................................... 31 2.10 Filter Module OID请求............................................................................................. 33 2.10.1 在Filter Driver中过滤OID请求..................................................................... 33 2.10.2 在Filter Driver发起OID请求......................................................................... 34 2.10.3 Filter Module的直接OID请求(Direct OID Request) ................................... 35 2.11 Filter Module PnP事件通知..................................................................................... 36 2.12 Filter Module  状态指示.......................................................................................... 37 3 安装NDIS Filter Drivers ................................................................................................... 37 3.1 指定Filter Driver的绑定关系................................................................................... 38 3.2 Filter Driver的INF文件设置 ..................................................................................... 39 3.2.1 Monitoring Filter Driver的INF文件配置 .......................................................... 39 3.2.2 Modifying Filter Driver的INF文件配置 ............................................................ 42 3.3 Filter Driver访问配置信息....................................................................................... 45 4 附录................................................................................................................................. 46 4.1 NET_BUFFER体系结构............................................................................................. 46 4.1.1 网络数据结构 .................................................................................................. 46 4.1.2 Retreat和Advance操作 .................................................................................... 52 4.1.3 获得池句柄 ...................................................................................................... 54 4.1.4 分发IRQL跟踪................................................................................................... 54 4.1.5 发送和接收操作 .............................................................................................. 55 4.1.6 以太网发送和接收操作 .................................................................................. 61 4.1.7 派生NET_BUFFER_LIST结构............................................................................. 62 4.2 指定NDIS版本信息.................................................................................................. 66 4.2.1 概览NDIS支持的版本 ...................................................................................... 66 4.2.2 NDIS驱动需要支持的版本信息 ...................................................................... 66 4.2.3 NDIS需要的版本信息 ...................................................................................... 67 4.2.4 获得NDIS版本 .................................................................................................. 67 4.2.5 NDIS  对象版本发布到WMI ............................................................................ 67                               译者序  本文是根据DDK中相关章节翻译,本人英语水有限文中难免有翻译及写的不当之处,如 果有任何问题可以通LZIOG@163.com邮件联系和交流。  1 介绍NDIS Filter Drivers  Filter Drivers提供了针对微端口驱动(Miniport Drivers)的过滤服务(filtering service), NDIS驱动栈上必须包含微端口驱动(Miniport Drivers)和协议驱动(Protocol Drivers),可选 的包含Filter  Drivers。更多关于NDIS驱动栈的信息可查看DDK的MSDN中的Driver  Stack  Management。下面列举基本的栈配置图示:  下面的应用可能就需要一个 Filter Drivers 来完成:  1) 基于安全或其它目录的数据过滤应用  2) 对网络数据进行监视,收集及统计的应用  下面的几个小节将介绍 Filter Drivers 的一些特性和服务。  1.1 Filter Drivers  特性  Filter Drivers 主要包括以下特性:  1) 一个Filter Drivers实例叫Filter Module。Filter Module附加在一个适配器的微端口驱动上, 来自相同或不同 Filter Drivers 的多个 Filter Module 都可以被堆叠在一个网络适配器上  2) 在 Filter Module 被安装到驱动栈时,之上的协议驱动和之下的微端口驱动都不需要提供 额外的支持功能  3) 因为 Filter Module 不像中间层驱动(intermediate driver)那样提供一个虚拟的微口,也 不与某个设备对象联结,所以在微端口适配器(miniport adapter)之上的 Filter Module  功 能相当于一个修过过版本的微端口适配器(miniport adapter)。(原文:Because filter drivers  do  not  implement  virtual  miniports  like  an  intermediate  driver,  filter  drivers  are  not  associated with a device object. A miniport adapter with overlying filter modules functions as  a modified version of the miniport adapter.)  4) NDIS 使用配置信息来到决定一个 Filter Module 附加到一个网络适配器栈上的顺序  5) 在不用拆除整驱动栈的情况下,NDIS 可以动态的插入、删除 Filter Module 或进行重新配 置  6) 当 NDIS 重起驱动栈的时候协议驱动可以获得在栈上的 Filter Module 列表  7) Filter Drivers 可以过滤下层网络适配器上绝大部分的通信。Filter Module 不联结某特定的 绑定(Filter  modules  are  not  associated  with  any  particular  binding  between  overlying  protocol drivers and the miniport adapter.)  8) Filter Drivers  可以选择为过滤服务也可以选择为分流的不过滤服务,选择为哪一种是可 以动态配置的(Filter drivers can select the services that are filtered and can be bypassed for  the services that are not filtered. The selection of the services that are bypassed and the  services that are filtered can be reconfigured dynamically.)  9) NDIS  保证有效的上下文空间,也不就是说 Filter Drivers 不要需要通代码 COPY 缓冲区来 获得上下文空间  1.2 Filter Drivers  服务  Filter Drivers  提供发下服务:  1) 发起一个发送请求和接收指示  2) 改变数据缓冲区的顺序或对发送和接收数据进行调速  3) 在一个驱动栈的接收或发送路径上更改、删除、添加数据  4) 发起查询或设置 OID 的请求给下层驱动  5) 过滤对下层驱动的 OID 查询或设置请求  6) 过滤从下层驱动传来的 OID 查询和设置请求的应答  7) 发起一个状态指示给上层的设备  8) 过滤从下层传来的状态指示  9) 管理注册表中每一个微端口适配器和其接口的参数  1.3 Filter Drivers  类型  下面是两种主要类型的 Filter Drivers:  1) Monitoring  这种类型可以在驱动栈上做监视行为,但是它不能在驱动栈上进行数据修改行为。 Monitoring Filter Drivers 不在修改或发起数据。  2) Modifying  这种类型可以在驱动栈上做更改行为,该类修改类型是特定于驱动的(The  type  of  modification is driver‐specific)。  在驱动的安装 INF 文件中 FilterType 的值是 0x00000001 就是一个 monitoring filter,如果 是 0x00000002 就是一个 modifying filter。  你可以指定一个过滤驱动是 mandatory(强制)的(也是在配置 INF 文件中指定个特征), 它通常用在 modifying filter 驱动上,如果一个 mandatory 的 Filter  驱动不能被加载,那么它 联结的驱动栈将被拆除。  1.4 Mandatory Filter Drivers  Mandatory  Filter  Drivers 必须存在于驱动栈上,驱动栈才能正常工作。如果一个 Mandatory Filter Module 不附加,那么驱动栈也将会被拆除。Modifying 或 Monitoring 类型的 Filter Drivers 可以被指定为 Mandatory(强制)的。  所有中间层过滤驱动(filter intermediate  drivers)都是可选的(与 Mandatory 相对,就是说如果不存在驱动栈也不被拆除)  要附加一个 Mandatory Filter Drivers 在一个驱动栈上,NDIS 先解绑定所有协议驱动,附 加 Filter Module 后再重新绑定协议驱动。如果不能成功附加 Filter Drivers 那么拆除驱动栈的 下边界。  要分离一个 Mandatory Filter Drivers 在一个驱动栈上,NDIS  先解绑定所有协议驱动,分 离 Filter Module 后重新绑定协议驱动。要分离一个 optional Filter Drivers(可选 Filter Drivers, 与 Mandatory(强制)  Filter Drivers 相对)时,NDIS 只暂停驱动栈,分离后重起驱动栈这时 并不解绑定协议驱动。  如果计算机重起,如果一个 Mandatory  Filter  Drivers 还没有附加到微端口适配器 (miniport adapter)这时 NDIS 是不会绑定协议驱动的。  在安装时用的 INF 文件中指是驱动是 Mandatory 还是 Optional。在 INF 文件在指定 FilterRunType 为 0x00000001 代表驱动是 Mandatory,指定 0x00000002 代表是 Optional。  下面列出 DDK 所有例子 filter 中的 INF 文件的一个相关节,内容如下:  ;‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐  ; Ndi installation support  ;‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐  [Inst_Ndi]  HKR, Ndi,Service,,"NdisMon"  HKR, Ndi,CoServices,0x00010000,"NdisMon"  HKR, Ndi,HelpText,,%NdisMon_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000001  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1   标蓝的行是指定它是一个 Modifying 类型的 filter 驱动,标红的行就是指定它是一个 Mandatory Filter Drivers。关于 INF 的语法可以参看 DDK 帮助文档中的相关节。  2 编写NDIS Filter Drivers  在写一个 Filter 驱动之前,应该先了解一下 Miniport Drivers 和 Protocol Drivers 的相关知 识。可以参见 DDK 帮助文件的相关章节。下面各小节将提供一个如何编写一个 Filter Drivers 的参考。  2.1 初始化Filter Driver  系统加载 Filter Driver 后初始化立即发生,Filter Dreivers 被加载为系统服务。系统加载 Filter  Drivers 可在 Miniport  Drivers 被加载的之前、期间和之后。如果一个微端口适配器 (miniport adatpter)所支持的类型与 Filter Drivers 所要绑定的类匹配且 Filter Drivers 也完成 了初始化,那么 NDIS 可以加附加一个 Filter Module 到这个微端口适配器上。  如果一个 Filter Drivers 没有加载,那即使现在驱动栈启动了那么系统也会加载它。详细 的信息可查看 DDK 帮助文档中的 Starting a Driver Stack。  Filter Drivers 被加载后,系统会调用驱动的 DriverEntry 例程。在 DriverEntry 例程在应用 当立即调用 NdisFRegisterFilterDriver 注册驱动的 FilterXXX 入口例程。NdisFRegisterFilterDriver 成功将会返回 STATUS_SUCCESS。然后申请相关资源,如果一个资源申请分配置失败那么记 得释放已经申请分配到资源。系统通过两个参数调用 DriverEntry:  1) 一个指向被 I/O 系统事先创建好的驱动对像的指针  2) 一个指向存储驱动特定参数注册表路径的指针  Filter  Drivers 通过 DriverEntry 的 DriverObject 参数做 NdisFRegisterFilterDriver 向 NDIS 注 册一个 NDIS Filter Driver。Filter Drivers 使用注册表路径参数来获得相关的运行参数。  一个 Filter  Drivers 在 DriverEntry 中调用 NdisFRegisterFilterDriver,它导出一系统的 FilterXXX 的例程序集合,并通过一个 NDIS_FILTER_DRIVER_CHARACTERISTICS 结构做为 NdisFRegisterFilterDriver 的 FilterCharacteristics 参数。NDIS_FILTER_DRIVER_CHARACTERISTICS 结构指定 Mandatory 和 Optional  FilterXXX 的例程入口。有些 Optional  例程可以被 BYPASS。  NdisFRegisterFilterDriver 定义:  NDIS_STATUS NdisFRegisterFilterDriver( IN PDRIVER_OBJECT DriverObject, IN NDIS_HANDLE FilterDriverContext, IN PNDIS_FILTER_DRIVER_CHARACTERISTICS FilterCharacteristics, OUT PNDIS_HANDLE NdisFilterDriverHandle ); NDIS_FILTER_DRIVER_CHARACTERISTICS 结构内容:  typedef struct _NDIS_FILTER_DRIVER_CHARACTERISTICS { NDIS_OBJECT_HEADER Header; UCHAR MajorNdisVersion; UCHAR MinorNdisVersion; UCHAR MajorDriverVersion; UCHAR MinorDriverVersion; ULONG Flags; NDIS_STRING FriendlyName; NDIS_STRING UniqueName; NDIS_STRING ServiceName; SET_OPTIONS_HANDLER SetOptionsHandler; FILTER_SET_FILTER_MODULE_OPTIONS_HANDLER SetFilterModuleOptionsHandler; FILTER_ATTACH_HANDLER AttachHandler; FILTER_DETACH_HANDLER DetachHandler; FILTER_RESTART_HANDLER RestartHandler; FILTER_PAUSE_HANDLER PauseHandler; FILTER_SEND_NET_BUFFER_LISTS_HANDLER SendNetBufferListsHandler; FILTER_SEND_NET_BUFFER_LISTS_COMPLETE_HANDLER SendNetBufferListsCompleteHandle r; FILTER_CANCEL_SEND_HANDLER CancelSendNetBufferListsHandler; FILTER_RECEIVE_NET_BUFFER_LISTS_HANDLER ReceiveNetBufferListsHandler; FILTER_RETURN_NET_BUFFER_LISTS_HANDLER ReturnNetBufferListsHandler; FILTER_OID_REQUEST_HANDLER OidRequestHandler; FILTER_OID_REQUEST_COMPLETE_HANDLER OidRequestCompleteHandler; FILTER_CANCEL_OID_REQUEST_HANDLER CancelOidRequestHandler; FILTER_DEVICE_PNP_EVENT_NOTIFY_HANDLER DevicePnPEventNotifyHandler; FILTER_NET_PNP_EVENT_HANDLER NetPnPEventHandler; FILTER_STATUS_HANDLER StatusHandler; FILTER_DIRECT_OID_REQUEST_HANDLER DirectOidRequestHandler; FILTER_DIRECT_OID_REQUEST_COMPLETE_HANDLER DirectOidRequestCompleteHandler; FILTER_CANCEL_DIRECT_OID_REQUEST_HANDLER CancelDirectOidRequestHandler; } NDIS_FILTER_DRIVER_CHARACTERISTICS, *PNDIS_FILTER_DRIVER_CHARACTERISTICS;   NDIS_FILTER_DRIVER_CHARACTERISTICS 结构中 Mandatory 例程:  FilterAttach   FilterDetach   FilterRestart   FilterPause   NDIS_FILTER_DRIVER_CHARACTERISTICS 结构中 Optional 且不能在运行时变更的例程:  FilterSetOptions   FilterSetModuleOptions   FilterOidRequest   FilterOidRequestComplete   FilterStatus   FilterNetPnPEvent   FilterDevicePnPEventNotify   FilterCancelSendNetBufferLists   NDIS_FILTER_DRIVER_CHARACTERISTICS 结构中 Optional 且能在运行时变更的例程:  FilterSendNetBufferLists   FilterSendNetBufferListsComplete   FilterReturnNetBufferLists   FilterReceiveNetBufferLists   上述四个例程也定义在 NDIS_FILTER_PARTIAL_CHARACTERISTICS 中,这个结构中指定的例程 可以在运行时的 FilterSetModuleOptions 例在中调用 NdisSetOptionalHandles 来改变。如果 Filter Drivers 要在例中改自身的一个特性那么就必须提供 FilterSetModuleOpitons 例程。部分 特性每一个不同的 Filter Module 可以各不相同。  如果 NdisFRegisterFilterDriver 调用成功,NDIS 会填充 NdisFilterDriverHandle 变量返回一 个 Filter  Driver 句柄。Filter  Driver 应该保存这个句柄,后面调有 NDIS  例程时会使这个句柄 做为输入参数,例如 NdisFDeregisterFilterDriver 例程就用它做输入参数。在驱动被卸载时会 调用驱动的卸载例程,必须在卸载例程中调用 NdisFDeregisterFilterDriver 来释放这个句柄, 同时也要释放所以在申请分配的资源。  FilterSetOptions 返回后,Filter Moudle 处于 Detached 状态。NDIS 可以在 FilterSetPtions 返回后的任何时间调用 FilterAttach 例程。Filter  Module 在 FilterAttach 中完成和它相关的特 定初始化。  Filter  Drivers 也可以在 DriverEntry 中选择一些其它(如全局的)初始化。但一定要在 FilterDriverUnload 例程中释放所有初始化时或运行时申请分配的资源。正面是 DDK 中所带例 子的 DriverEntry 例程的源码。  NDIS_STATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NDIS_STATUS Status; NDIS_FILTER_DRIVER_CHARACTERISTICS FChars; NDIS_STRING ServiceName; NDIS_STRING UniqueName; NDIS_STRING FriendlyName; DEBUGP(DL_TRACE,("===>DriverEntry...\n")); RtlInitUnicodeString(&ServiceName, FILTER_SERVICE_NAME); RtlInitUnicodeString(&FriendlyName, FILTER_FRIENDLY_NAME); RtlInitUnicodeString(&UniqueName, FILTER_UNIQUE_NAME); FilterDriverObject = DriverObject; do { NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS)); FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS; FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS); FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1; FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION; FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION; FChars.MajorDriverVersion = 1; FChars.MinorDriverVersion = 0; FChars.Flags = 0; FChars.FriendlyName = FriendlyName; FChars.UniqueName = UniqueName; FChars.ServiceName = ServiceName; // // for the time being, there is no additional options to register // but let's have this handler anyway // FChars.SetOptionsHandler = FilterRegisterOptions; FChars.AttachHandler = FilterAttach; FChars.DetachHandler = FilterDetach; FChars.RestartHandler = FilterRestart; FChars.PauseHandler = FilterPause; FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions; FChars.OidRequestHandler = FilterOidRequest; FChars.OidRequestCompleteHandler = FilterOidRequestComplete; FChars.CancelOidRequestHandler = FilterCancelOidRequest; FChars.SendNetBufferListsHandler = FilterSendNetBufferLists; FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists; FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete; FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists; FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify; FChars.NetPnPEventHandler = FilterNetPnPEvent; FChars.StatusHandler = FilterStatus; FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists; DriverObject->DriverUnload = FilterUnload; FilterDriverHandle = NULL; FILTER_INIT_LOCK(&FilterListLock); InitializeListHead(&FilterModuleList); Status = NdisFRegisterFilterDriver(DriverObject, (NDIS_HANDLE)FilterDriverObject, &FChars, &FilterDriverHandle); if (Status != NDIS_STATUS_SUCCESS) { DEBUGP(DL_WARN, ("MSFilter: Register filter driver failed.\n")); break; } // // Initilize spin locks // Status = FilterRegisterDevice(); if (Status != NDIS_STATUS_SUCCESS) { NdisFDeregisterFilterDriver(FilterDriverHandle); FILTER_FREE_LOCK(&FilterListLock); DEBUGP(DL_WARN, ("MSFilter: Register device for the filter driver failed.\n")); break; } } while(FALSE); DEBUGP(DL_TRACE, ("<===DriverEntry, Status = %8x\n", Status)); return Status; }  2.2 卸载Filter Drivers  一个与 Filter Drivers 相关联的驱动对象联结一个 Unload 例程,系统会在这个 Filter Driver 在所有微端口适配器(Miniport Adapter)上的过滤服务被移除后调用这个 Unload 例程。Filter  Drivers 的 Unload 例程被命名为 FilterDriverUnload。  FilterDriverUnload 应该释放与自己驱动相关的资源。任何 Filter  Driver 创建的驱动对象 都要就被销毁。当 FilterDriverUnload 返回后系统就可以完成 Filter Driver 的卸载操作了。  卸载例程的功能是和驱动相关的,一般的规则是,卸载例程应该撤销初始化时执行的所 有操作。一个 Filter  Driver 例程必须在 FilterDriverUnload 例程中调用 NdisFDeregisterFilterDriver 来撤销 NdisFRegisterFilterDriver 的注册。  注意:系统只会在调用 FilterDetach 分离了所有和本 Filter Driver 相关的 Filter Module 后 才会调用 FilterDriverUnload 例程。下面贴出 DDK 中例子 filter 的 FilterDriverUnload 源码。  VOID FilterUnload( IN PDRIVER_OBJECT DriverObject ) { DEBUGP(DL_TRACE, ("===>FilterUnload\n")); // // Should free the filter context list // FilterDeregisterDevice(); NdisFDeregisterFilterDriver(FilterDriverHandle); #if DBG FILTER_ACQUIRE_LOCK(&FilterListLock, FALSE); ASSERT(IsListEmpty(&FilterModuleList)); FILTER_RELEASE_LOCK(&FilterListLock, FALSE); #endif FILTER_FREE_LOCK(&FilterListLock); DEBUGP(DL_TRACE, ("<===FilterUnload\n")); return; }  2.3 Filter Module  状态和操作  一个 Filter Driver 的 Filter Module(Filter Driver 的一个实例)必须支持下列操作状态。  1) Detached  Detached 状态是每一个 Filter  Module 的初始状态。当一个 Filter  Driver 停留在这个状态 时,它可以附加一个 Filter Module 到一个驱动栈上。  2) Attaching  这个状态是标识一个 Filter Driver 正准备附加一个 Filter Module 到一个驱动栈上。  3) Paused  在这个状态时,Filter Driver 不能执行接收和发送操作。  4) Restarting  在这个状态时,一个 Filter  Driver 必须为一个 Filter  Module 完成重启发送和接收数据时 所需要的所有准备工作。  5) Running  在这个状态时,一个 Filter Driver 执行 Filter Module 正常的发送和接收入处理。  6) Pauseing  在这个状态要,一个 Filter  Driver 要为一个 Filter  Module 完成停止发送和接收处理所需 要的所有准备工作。  在下面表格中,标题列出了 Filter Module 的所有状态,第一列是主要的事件。其余的条目是 要进入的一下个状态,它是事件发生时的内部状态。空白条目表示无效状态/事件的组合。  Event/State  Detached  Attaching Paused  Restarting Running Pausing  FilterAttach  Attaching            Attach is  complete    Paused          FilterDetach      Detached        FilterRestart      Restarting       Restart is  complete        Running      FilterPause          Pausing    Pause is  complete            Paused  Attach failed    Detached         Restart  failed        Paused      Send and  Receive          Running Pausing  OID      Paused  Restarting Running Pausing  Requests    主要的过滤驱动事件定义如下:  1) FilterAttach  当 NDIS 调用 FilterAttach 例程向一个驱动栈附加一个 Filter Module 时发这个事件。  2) Attach is complete  当 Filter Module 在 Attaching 状态时且 Filter Driver 初始化了 Filter Module 所需要的所有 资源时,Filter Module 进入 Paused 状态。  3) FilterDetach  当 NDIS 调用 Filter  Driver 的 FilterDetach 从一个驱动栈上分离一个 Filter  Module 时发生 这个事件。  4) FilterRestart  当 NDIS 调用 Filter Driver 的 FilterRestart 把一个暂停的 Filter Modue 的重启动时发生这个 事件。  5) Restart is complete  当 Filter Module 在 Restarting 状态时且完成所有发送和接收所需要的准备工作时,Filter  Moduel 就进入了 Running 状态。  6) FilterPause  当 NDIS 调用 Filter Driver 的 FilterPause 暂停一个 Filter Module 时发生此事件  7) Pause is complete  当 Filter  Driver 为 Filter  Module 完成了所有发送和接收操作的停止工作时,暂停完成同 时也进入了 Paused 状态  8) Attach fail  当 NDIS 调用 FilterAttach 操作失败时(比如,Filter  Module 所有需要的资源申请分配失 败等等),这时就进入了 Detached 状态。  9) Restart fail  当 NDIS 调用 FilterRestart 操作失败时,Filter Module 就进入了 Paused 状态。  10) Send and Receive Operations  Filter Module 可以在 Pauseing 状态和 Running 状态进行发送和接收操作的处理。  11) OID Requests  Filter Module 可以在 Runnig 状态、Restarting 状态、Paused 状态和 Pauseing 状态进行 OID 的控制和处理。  2.4 附加Filter Module  在向一个驱动动栈插入一个 Filter Module 时,NDIS 会调用 Filter Driver 的 FilterAttach 全 程。在进入执行 FilterAttach 时,Filter Module 就进入了 Attaching 状态。下面列出 FilterAttach 在 DDK 中的声明。  NDIS_STATUS FilterAttach( IN NDIS_HANDLE NdisFilterHandle, IN NDIS_HANDLE FilterDriverContext, IN PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters ); NDIS 通过 NdisFilterHandle 传过来一个句柄,这个句柄将用于所有 Filter  Driver 中对 NdisXXX 类例程的调用时引用指示这个 Filter  Module,这些例程有状态指示、发送请求、接 收指示、OID 请求等等。当一个 Filter Module 进入 Attaching 时驱动可以:  1) 创建一个环境上下文区域并且初始化一个缓冲区池以及其 Filter Module 特定的资源  2) 用 NDIS 传来给 Filter Attach 的 NdisFilterHandle 做为输入来调用 NdisFSetAttributes 例程, 其中 NdisFSetAttributes 的 FilterModuleContext  参数的作用是为 FilterModule 指定环境上 下文用的(注意:这里要与 NdisFRegisterFilterDriver 中的 FilterDriverContext 参数区别开 来)。NDIS 会把这个环境上下文传递给 Filter  Drivers 注册的 FilterXXX 例程(注意: FilterAttach 中的 FilterDriverContext 是由 NdisFRegisterFilterDriver 的 FilterDriverContext 指定的),下面列出 NdisFSetAttributes 例程在 DDK 中的声明  NDIS_STATUS NdisFSetAttributes( IN NDIS_HANDLE NdisFilterHandle, IN NDIS_HANDLE FilterModuleContext, IN PNDIS_FILTER_ATTRIBUTES FilterAttributes ); 3) 这步是可选的,Filter Module 可以从注册表中读取一些参数。  4) 如果上述的操作完成成功那么 Filter Module 就进入了 Paused 状态  5) 如果上述的操作完成失败那么要释放已经成功申请分配的资源返回后进 Detached 状态  6) 返回时可以返回 NDIS_STATUS_SUCCESS 或适当的错误码,如果驱动返回失败则 NDIS 会 结束这个驱动栈。  注意:注册中可以包含一下 Filter Module 需要的执行标记这是可选的。如果 Filter Driver 被安装时指定为可选的(Optional,与 Mandatory 相对)那么 FilterAtt 工 ch 返回失败 NDIS 是不会么结束这个驱动栈的其它部分的。  一个 Filter Driver 在 Attaching 状态时不能进行发送请求、接收指示、状态指示和 OID 请 求操作。接收和发送操作只支持在 Running 和 Pauseing 两种状态下进行。OID 请求和状态指 示支持在 Paused、Restarting、Running 和 Pauseing 这四种状态下进行。NDIS 调用 FilterDetach 例程来分离之前调用 FilterAttach 附加的 Filter  Module,更多分离 Filter  Module 的信息参看 下节。这边列举一下 DDK 例子 filter 中 FilterAttach 的代码。  NDIS_STATUS FilterAttach( IN NDIS_HANDLE NdisFilterHandle, IN NDIS_HANDLE FilterDriverContext, IN PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters ) { PMS_FILTER pFilter = NULL; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PFL_NDIS_FILTER_LIST FilterHandleEntry; NDIS_FILTER_ATTRIBUTES FilterAttributes; ULONG Size; DEBUGP(DL_TRACE, ("===>FilterAttach: NdisFilterHandle %p\n", NdisFilterHandle)); do { ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject); if (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject) { Status = NDIS_STATUS_INVALID_PARAMETER; break; } if (AttachParameters->MiniportMediaType != NdisMedium802_3) { DEBUGP(DL_ERROR, ("MSFilter: Doesn't support media type other than NdisMedium802_3.\n")); Status = NDIS_STATUS_INVALID_PARAMETER; break; } Size = sizeof(MS_FILTER) + AttachParameters->FilterModuleGuidName->Length + AttachParameters->BaseMiniportInstanceName->Length + AttachParameters->BaseMiniportName->Length; pFilter = (PMS_FILTER)FILTER_ALLOC_MEM(NdisFilterHandle, Size); if (pFilter == NULL) { DEBUGP(DL_WARN, ("MSFilter: Failed to allocate context structure.\n")); Status = NDIS_STATUS_RESOURCES; break; } NdisZeroMemory(pFilter, sizeof(MS_FILTER)); pFilter->FilterModuleName.Length = pFilter->FilterModuleName.MaximumLength = AttachParameters->FilterModuleGuidName->Length; pFilter->FilterModuleName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER)); NdisMoveMemory(pFilter->FilterModuleName.Buffer, AttachParameters->FilterModuleGuidName->Buffer, pFilter->FilterModuleName.Length); pFilter->MiniportFriendlyName.Length = pFilter->MiniportFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length; pFilter->MiniportFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter->FilterModuleName.Buffer + pFilter->FilterModuleName.Length); NdisMoveMemory(pFilter->MiniportFriendlyName.Buffer, AttachParameters->BaseMiniportInstanceName->Buffer, pFilter->MiniportFriendlyName.Length); pFilter->MiniportName.Length = pFilter->MiniportName.MaximumLength = AttachParameters->BaseMiniportName->Length; pFilter->MiniportName.Buffer = (PWSTR)((PUCHAR)pFilter->MiniportFriendlyName.Buffer + pFilter->MiniportFriendlyName.Length); NdisMoveMemory(pFilter->MiniportName.Buffer, AttachParameters->BaseMiniportName->Buffer, pFilter->MiniportName.Length); pFilter->MiniportIfIndex = AttachParameters->BaseMiniportIfIndex; // // The filter should intialize NoTrackReceives and NoTrackSends properly, for this // driver, since its default characteristic has both send and receive handler, they // are initiazed to FALSE. // pFilter->TrackReceives = TRUE; pFilter->TrackSends = TRUE; pFilter->FilterHandle = NdisFilterHandle; NdisZeroMemory(&FilterAttributes, sizeof(NDIS_FILTER_ATTRIBUTES)); FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1; FilterAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES); FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES; FilterAttributes.Flags = 0; Status = NdisFSetAttributes(NdisFilterHandle, pFilter, &FilterAttributes); if (Status != NDIS_STATUS_SUCCESS) { DEBUGP(DL_WARN, ("MSFilter: Failed to set attributes.\n")); break; } pFilter->State = FilterPaused; FILTER_ACQUIRE_LOCK(&FilterListLock, FALSE); InsertHeadList(&FilterModuleList, &pFilter->FilterModuleLink); FILTER_RELEASE_LOCK(&FilterListLock, FALSE); } while (FALSE); if (Status != NDIS_STATUS_SUCCESS) { if (pFilter != NULL) { FILTER_FREE_MEM(pFilter); } } DEBUGP(DL_TRACE, ("<===FilterAttach: Status %x\n", Status)); return Status; } 2.5 分离Filter Module  NDIS 调用 Filter  Driver 的 FilterDetach 例程来对驱动栈引发一个分享 Filter  Module 的操 作。在开始执行 FilterDetach 例程时 Filter Module 进入了 Detached 状态。在从驱动栈上分离 一个 Filter  Module 时,NDIS 会先暂停这个驱动栈(这意味之在调用 FilterDetach 之前 NDIS 已经使 Filter Module 进入了 Paused 状态)。  在这个例程中在释放和这个 Filter Module 相关的环境上下文和其它资源。这个全程不能 返回失败。因此,必须保证成功释放附加时申请分配及运行时分配的所有资源。当 FilterDettach 返回后 NDIS 会重启被暂停的驱动栈。下面列出 DDK 中 filter 实现的 FilterDetach 例程。  VOID FilterDetach( IN NDIS_HANDLE FilterModuleContext ) { PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PFL_NDIS_FILTER_LIST pEntry; PLIST_ENTRY pLink; DEBUGP(DL_TRACE, ("===>FilterDetach: FilterInstance %p\n", FilterModuleContext)); // // Filter must be in paused state // FILTER_ASSERT(pFilter->State == FilterPaused); // // Don't come up anything that would prevent the filter from detaching // // // Free filter instance name if allocated. // if (pFilter->FilterName.Buffer != NULL) { FILTER_FREE_MEM(pFilter->FilterName.Buffer); } FILTER_ACQUIRE_LOCK(&FilterListLock, FALSE); RemoveEntryList(&pFilter->FilterModuleLink); FILTER_RELEASE_LOCK(&FilterListLock, FALSE); // // Free the memory allocated FILTER_FREE_MEM(pFilter); // // Alway return success // DEBUGP(DL_TRACE, ("<===FilterDetach Successfully\n")); return; }  2.6 重启和暂停Filter Module  在进行即插即用操作时 NDIS 会暂停 Filter  Module,例如添加、删除一个 Filter  Module 或添加一个新的绑定等等。NDIS 从一个 Paused 状态启动一个 Filter Module 到 Running 状态。 当一个 Filter Module 的附加和暂停操作完成时它就进入了 Paused 状态。下面的小节将讨论 启动和暂停 Filter Module。  2.6.1 重启Filter Module  要启动一个 Paused 状态的 Filter Module,如果有 FilterSetModuleOptions 就先调用它, 接着调用 FilterRestart 例程。一个 Filter Module 执行 FilterRestart 例程时就进入了 Restarting 状态。如果一个 Filter Driver 提供了 FilterSetModuleOptions 例程那驱动就可以在这个例程中 更改当前的 Filter Module 的部分特性。更多的信息可以看 Data Bypass Model 小节。  当调用一个 Filter  Driver 的 FilterRestart 例程时,NDIS 通过 FilterRestartParameters 的 RestartAttributes 成员传递一个 NDIS_RESTART_ATTRIBUTES 结构。Filter Drivers 可以修改由底 层驱动指定的重启属性。更多修改重启属性的信息可以参考 DDK 中对 FilterRestart 例程的说 明。  注意:在调用栈中的任何 Filter  Module 的 FilterRestart 例程之前都会调用,它们的 FilterSetModuleOptions 例程.  NDIS 启动一个 Filter  Module 是即插即用操作重启一个驱动栈的一部分。当一个 Filter  Module 是 Restarting 状态时,它可以:  1) 完成任何正常发送和接收所需要的准备工作  2) 可读写 Filter Module 的配置参数  3) 可以接收网络数据指示,拷贝和排队数据稍后指示给上层驱动或丢弃数据。  4) 不能发起任何新的接收指示  5) 应该立即调用 NdisFSendNetBufferListsComplete 例程来拒绝 FilterSendNetBufferLists 传来 的发送的请求。应该设置每一个 NET_BUFFER_LIST 的完成状态为 NDIS_STATUS_PAUSED  6) 可以使用 NdisFIndicateStatus 例程进行状态指示  7) 可以控制 OID 请求操作  8) 不能发起任何新的发送请求  9) 应该调用 NdisFReturnNetBufferLists 反回所有新的接收指示。如果需要的话可以在接收指 示返回之前拷贝它们。  10) 可以制作 OID 请求发送给下层驱动设置或查询配置信息。  11) 可以在 FilterStatus 中控制状态指示  12) 返回时指示 NDIS_STATUS_SUCCESS 或失败状态,如果不 Filter Module 不能启动返回 了失败,而它又是一个 Mandatory 的 Filter Driver 那个 NDIS 将会结束这个驱动栈  在一个 Filter Driver 完成对发送和接收的重启后必须指示完成这个重启操作。Filter Driver 的重启操作的完成可以是同步也可以是异步的,同步时返回 NDIS_STATUS_SUCCESS 异步时返 回 NDIS_STATUS_PENDING 。如果返回的是 NDIS_STATUS_PENDING 就必须调用 NdisFRestartComplete 例程在重启操作完成后。在这种情况下,驱动需要传递给 NdisFRestartComplete 一个固定状态(标识重启结果的成功或失败状态)。  重启操作完成 Filter Module 就进入了 Running 状态,恢得一切正常的发送和接收外理。 在 Filter  Driver 的 FilterRestart 例程执行的时候 NDIS 不会发起任即插即用操作,如附加,分 离,暂停请求等等。Ndis 可以在 Filter Module 进入 Running 状态后发起一个暂停请求,下节 将介绍。下面列出 DDK 中 Filter 的 FilterRestart 例程的实现代码。  NDIS_STATUS FilterRestart( IN NDIS_HANDLE FilterModuleContext, IN PNDIS_FILTER_RESTART_PARAMETERS RestartParameters ) { NDIS_STATUS Status; PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; // BUGBUG, the cast may be wrong NDIS_HANDLE ConfigurationHandle = NULL; PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes; PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes; NDIS_CONFIGURATION_OBJECT ConfigObject; DEBUGP(DL_TRACE, ("===>FilterRestart: FilterModuleContext %p\n", FilterModuleContext)); FILTER_ASSERT(pFilter->State == FilterPaused); ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT; ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1; ConfigObject.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT); ConfigObject.NdisHandle = FilterDriverHandle; ConfigObject.Flags = 0; Status = NdisOpenConfigurationEx(&ConfigObject, &ConfigurationHandle); if (Status != NDIS_STATUS_SUCCESS) { // // Filter driver can choose to fail the restart if it cannot open the configuration // #if 0 // // The code is here just to demonstrate how to call NDIS to write an eventlog. If drivers need to write // an event log. // PWCHAR ErrorString = L"NdisMon"; DEBUGP(DL_WARN, ("FilterRestart: Cannot open configuration.\n")); NdisWriteEventLogEntry(FilterDriverObject, EVENT_NDIS_DRIVER_FAILURE, 0, 1, &ErrorString, sizeof(Status), &Status); #endif } if (Status == NDIS_STATUS_SUCCESS) { NdisCloseConfiguration(ConfigurationHandle); } NdisRestartAttributes = RestartParameters->RestartAttributes; // // If NdisRestartAttributes is not NULL, then miniport can modify generic attributes and add // new media specific info attributes at the end. Otherwise, NDIS restarts the miniport because // of other reason, miniport should not try to modify/add attributes // if (NdisRestartAttributes != NULL) { PNDIS_RESTART_ATTRIBUTES NextAttributes; ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES); NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data; // // Check to see if we need to change any attributes, for example, the driver can change the current // MAC address here. Or the driver can add media specific info attributes. // NdisGeneralAttributes->LookaheadSize = 128; // // Check the next attributes to see whether the filter need to modify // NextAttributes = NdisRestartAttributes->Next; while (NextAttributes != NULL) { // // If somehow the filter needs to change a attributes which requires more space then // the current attributes: // 1. Remove the attribute from the Attributes list: // TempAttributes = NextAttributes; // NextAttributes = NextAttributes->Next; // 2. Free the memory for the current attributes: NdisFreeMemory(TempAttributes, 0 , 0); // 3. Dynamically allocate the memory for the new attributes by calling // NdisAllocateMemoryWithTagPriority: // NewAttributes = NdisAllocateMemoryWithTagPriority(Handle, size, Priority); // 4. Fill in the new attribute // 5. NewAttributes->Next = NextAttributes; // 6. NextAttributes = NewAttributes; // Just to make the next statement works. // NextAttributes = NextAttributes->Next; } // // Add a new attributes at the end // 1. Dynamically allocate the memory for the new attributes by calling // NdisAllocateMemoryWithTagPriority. // 2. Fill in the new attribute // 3. NextAttributes->Next = NewAttributes; // 4. NewAttributes->Next = NULL; } // // If everything is OK, set the filter in running state // If it get preempted, it doesn't matter // pFilter->State = FilterRunning; // when successful Status = NDIS_STATUS_SUCCESS; if (Status != NDIS_STATUS_SUCCESS) { pFilter->State = FilterPaused; } DEBUGP(DL_TRACE, ("<===FilterRestart: FilterModuleContext %p, Status %x\n", FilterModuleContext, Status)); return Status; } 2.6.2 暂停Filter Module  要暂停一个Running中的Filter Module,NDIS会调用Filter Driver的FIlterPause例程。当Filter  Driver执行FilterPause全程时它就进入了Pauseing状态。NDIS暂停Filter  Module的操作是即插 即用操作暂停一个驱动栈工作的一部分。详细信息可参考DDK中的Pausing a Drive   Stackr 。 一个在Pauseing中的Filter Driver  有如下约束。  1) Filter Module 不能发起任何新的接收指示,但是可以传递下层驱动的接收指示。  2) 如果这里有 Filter Module 发起的接收指示还没有完成,那么必须等待它们全部完成。有 只当 FilterReturnNetBufferLists 完成所有外部的接收指示后暂停操作才能完成  3) 要返回任何未处理的由下层驱动引发的接收指示给 NDIS ,只有等到 NdisFReturnNetBufferLists 返回了所有未处理的接收指示后暂停操作才能完成。这里也可 以排队缓冲这些未完成接收指示。  4) 立即用 NdisFReturnNetBufferLists 返回所有下层驱动新传来的接收指示,如果需要可以在 返回之前拷贝和排队这些接收指示的。  5) 不能发起任何新的发送请求  6) 这时如果有 Filter Driver 引的但 NDIS 还未完成的发送操作,必须在这里等待他们完成。  7) 应该在 FilterSendNetBufferLists 例程中立即用 NdisFSendNetBufferListsComplete 返回那些 新到达的发送请求。并且为每一个 NET_BUFFER_LIST 设置 NDIS_STATUS_PAUSED 返回状 态。  8) 这时可以用 NdisFIndicateStatus 提供状态指示  9) 可以在 FilterStatus 中处理状态指示  10) 可以在 FIlterOidRequest 中处理 OID 请求  11) 可以发起一个 OID 请求  12) 不能释放分配的相关资源,和 Filter Module 相关的资源最好放在 FilterDetach 中释放。  13) 如果有用于发送和接收的定时器也要停止它  当成功停止发送和接收操作后就必须完成暂停操作。暂停操作的完成可以是同步的也可 以是异步的,分别从 FilterPaused 返回 NDIS_STATUS_SUCCUSS 和 NDIS_STATUS_PENDING。如 果返回 NDIS_STATUS_PENDING 就必须调用 NdisFPauseComplete 来完成这个暂停操作,可以 传递一个返回状态给这个例程。暂停操作完成后代表 Filter Module 进入了 Paused 状态,这 里它有以下约束。  1) 不能发起任何接收指示,但是可以传递底层驱动发来的接收指示  2) 需要立即调用 NdisFReturnNetBufferLists 返回底层驱动的接收指示给 NDIS,如果需要可 以在返回之前可以拷贝和排队这些指示。  3) 不能引发任何新的发送指示  4) 要立即调用 NdisFSendNetBufferListsComplete 完成那些在 FilterSendNetBufferLists 中收到 的发送请求,并为每一个 NET_BUFFER_LIST 结构设置 NDIS_STATUS_PAUSED 状态。  5) 这时可以用 NdisFIndicateStatus 发起状态指示  6) 可在 FilterStatus 中进行状态指示处理  7) 可在 FIlterOidRequest 中进行 OID 请求处理  8) 可以发起 OID 请求  在 Filter  Module 进行 Pauseing 状态时 NDIS 不会发起其它 PnP 操作如附加,分离,重起 等。只当 Filter Module 进入了 Paused 状态后 NDIS 才能对它进行分离和重启操作。下面列出 DDK 中 Filter 的 FilterPause 实现。  NDIS_STATUS FilterPause( IN NDIS_HANDLE FilterModuleContext, IN PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters ) { PMS_FILTER pFilter = (PMS_FILTER)(FilterModuleContext); NDIS_STATUS Status; UNREFERENCED_PARAMETER(PauseParameters); DEBUGP(DL_TRACE, ("===>NDISMON FilterPause: FilterInstance %p\n", FilterModuleContext)); // // Set the flag that the filter is going to pause // FILTER_ASSERT(pFilter->State == FilterRunning); FILTER_ACQUIRE_LOCK(&pFilter->Lock, FALSE); pFilter->State = FilterPausing; FILTER_RELEASE_LOCK(&pFilter->Lock, FALSE); Status = NDIS_STATUS_SUCCESS; pFilter->State = FilterPaused; DEBUGP(DL_TRACE, ("<===FilterPause: Status %x\n", Status)); return Status; }  2.7 Data Bypass Mode    Filter  Driver 的 Data  Bypass  Mode 能为系统示供更好的性能。在 Data  Bypass  Mode 下 NDIS 不调用相关的 FilterXXX 例程。例如,一个 Filter Driver 对发送和接收进行过滤操作是不 需要的,那就可以 Bypass 发送和接收。(即在注册时不指定其入口,哪些例程可以 Bypass 参看 NdisFRegisterFilterDriver 在 DDK 中的说明)  当系统初始化调用 NdisFRegisterFilterDriver 时,要为可以 Bypass 的例程指定默认入口, 如果不为它们指示入口,那么就默认它们是 Bypass 的。也可以在运行时改变 Bypass 状态, 但是必须要在初始化时为驱动注册 FilterSetModuleOptions 例程,驱动可以在这个例程中初 始化 NDIS_FILTER_PARTIAL_CHARACTERISTICS 结构来调用 NdisSetOptionalHandlers 来完成必 变。这个例程如果存在那么在调用 Filter  Driver 的 FilterRestart 例程之前调用它。下面是在 NDIS_FILTER_PARTIAL_CHARACTERISTICS 结构中可以被 Bypass 的可选全程。  FilterSendNetBufferLists FilterSendNetBufferListsComplete FilterCancelSendNetBufferLists FilterReturnNetBufferLists FilterReceiveNetBufferLists 要设置例程为 Bypass 的就把它的入口设成 NULL,但是注意一点如果驱动用任何和 FilterXXX 联结的 NDIS 例程时,就必须提供相应的入口。例如,如果要调用 NdisFIndicateNetBufferLists 就必须为驱动注册 FilterReturnNetBufferLists 例程。  如果驱动在 FilterSendNetBufferLists 中排队发送请求那么它就必须提供 FilterCancelSendNetBufferLists 例程。如果指定了 FilterReceiveNetBufferLists 和 FilterReturnNetBufferLists 例程就必须提供人 FilterStatus 例程。  要在运行时更变 Bypass 状态需要调用 NdisFRestartFilter。NdisRestartFilter 可以计划一个 暂停操作后做一个重启操作。这样 NDIS 就会调用指定 Filter Module 的 FilterSetModuleOptions 例程,在其中调用 NdisSetOptionalHandlers 可以重设 FilterXXX 的入口。  注意:暂停和重启操作将可能引发一个包在传输和接收路径上被丢弃。网络协议中有些 有重试机制如 TCP,而其它协议通常没有这种机制。  Filter Driver 可以注册附加选项例程来支持驱动选项服务(Optional Driver Service),驱 动 动注册的选项服务为 FilterSetOptions 例程。  2.8 Filter Driver的选项配置  NDIS 通过 FilterSetOptions 例程来配置可选过滤驱动服务(Optional Filter Driver Service)。 传给 FilterSetOptions 的环境上下文是 NdifFRegisterFilterDriver 注册时设置的环境上下文。  FilterSetOption 可以注册选项服务(Optional  Service)需要的 FilterXXX 例程的默认入口 和分配相关资源。这里注册可选服务项也是通 NdisSetOptionalHandlers 例程来注册(会影响到 所有 Filter Module)。在当前操作系统版中并没有可选的过滤驱动服务(Optional Filter Driver  Service)。  也可以会对某一个 Filter Module 来更改一些 FilterXXX 函数,可以用在 Data Bypass Mode 小节中讲的那样。如果 NdisSetOptionalHandlers 在 FilterRestart 例程中调用,只影响本 Filter  Module 的配置,其它 Filter Module 的配置并不会受到影响。    2.9 Filter Module发送和接收  在这一节将介绍 NDIS 6.0 Filter Driver 的发送和接收操作。Filter Driver 可以发起一个发 送主请求和接收指示或过滤其它驱动的接收和发送指示。Filter Module 在一个微端口适配器 (Miniport  Adapter)的上层。一个 Filter  Module 可以在一个驱动栈上过滤他所联结的下层 适配器的所有发送请求和接收指示。绑定在这个适配器上的协议驱动的发送请求也会经过 它。  Filter  Driver 不直接支持老的基于 NDIS_PACKET 结构的发送请求和接收指示。替代老的 结构现在采新的 NET_BUFFER 结构来进行发送请求和接收指示。也就是说,NDIS 控制由 NET_BUFFER 向 NDIS_PACKET 的转换。  注意:Filter Driver 来说它可以动态改变一个 Filter Module 的发送和接收的 FilterXXX 例 程。  下面的小节将介绍关于 Filter Driver 如果进行发送请求和接收指示处理的内容。  2.9.1 Filter Driver的缓冲区管理  Filter  Driver 创建缓冲区用于拷贝从其它驱动获得的数据或用于发起一个发送请求和接 收指示。如果一个 Filter  Driver 不能创建一个缓冲区那就不能管理缓冲区池,这样就只能传 递发送请求和接收指示。Filter  Driver 创建缓冲区用于发送和接收就必须创建 NET_BUFFER_LIST 结构池和 NET_BUFFER 结构池,下面是创建这些池的例程。  NdisAllocateNetBufferListPool   NdisAllocateNetBufferPool   下面是从池里分配置结构的例程。  NdisAllocateNetBufferAndNetBufferList   NdisAllocateNetBufferList   NdisAllocateNetBuffer   调用 NdisAllocateNetBufferAndNetBufferList 比调用 NdisAllocateNetBufferList 后再调用 NdisAllocateNetBuffer 更有高效。然而 NdisAllocateNetBufferAndNetBufferList 仅在 NET_BUFFER_LIST 中创建一个 NET_BUFFER 结构。要使用 NdisAllocateNetBufferAndNetBufferList 必须在调用 NdisAllocateNetBufferListPool 时设置 AllocateNetBuffer 为 TRUE。  Filter  Driver 要发起一个发送请应该先确害内容和下层驱动对回填空间的要求,一个 Filter Driver 根据重启属性(在 FilterRestart 被调用时可以获得)来决定下层驱动回填空间的 要求,一个 Filter Driver 应该在 Restarting 状态时决定回填和内容的需求。Filter Driver 应该为 整个栈分配足够的回填和内容空间。如果需要一个 Filter Driver 可以在 Restarting 状态释放缓 冲区池并重新分配它们。下面是释放池和释放人池中分配的结构的例程。  NdisFreeNetBufferListPool   NdisFreeNetBufferPool   NdisFreeNetBufferList   NdisFreeNetBuffer   驱动在释放 NET_BUFFER_LIST 之前应该先释放用 NdisAllocateNetBuffer 的 NET_BUFFER。如果用 NET_BUFFER 是用 NdisAllocateNetBufferAndNetBufferList  申请的那 个直接调用 NdisFreeNetBufferList 释放 NET_BUFFER_LIST。  2.9.2 在Filter Driver中发送数据  Filter  Driver 可以发起一个发送请求或过滤上层驱动引发的一个发送请求。当一个协议 驱动调用 NdisFSendNetBufferLists 时,提交一个 NET_BUFFER_LIST 结构给在驱动栈最顶层的 Filter Module。  1) 一个由 Filter Driver 引发的发送请求  下面图中示例了一个 Filter Driver 引发的一个发送操作  Filter  Driver 调用 NdisFSendNetBufferLists 发一个定义为 NET_BUFFERLIST 结构的网络数 据。Filter  Driver 必须设置 NET_BUFFER_LIST 结构中 SourceHandle 的值和 NdisFSendNetBufferLists 参数中 NdisFilterHandle 的值一样。对 NDIS 驱动来说如果不是自己引 发的 NET_BUFFER_LIST 结构数据,那么就不应该修改它其中的 SourceHandle 成员的值。在调 用 NdisFSendNetBufferLists 发送前可以,利用 NET_BUFFER_LIST_INFO 宏来设置陪伴发送请求 的信息。下层的驱动同样可以通这个宏来找到这些信息。一个 Filter  Driver 一调用 NdisSentNetBufferLists,它就放弃了对 NET_BUFFER_LIST 及所有联结资源的所有权。NDIS 会 控制发送请求并传递给下层驱动。  NDIS 调用 FilterSendNetBufferListsComplete 把发送的结构和数据返还给 Filter  Driver。 NDIS 可以收集多次 NdisFSendNetBufferLists 发送的结构和数据形成一个单链表传递给 FilterSendNetBufferListsComplete。除非到 NDIS 调用 FilterSendNetBufferListsComplete,否则 一个发送请求的当前状态总是未知的。一个 Filter  Driver 是不能在 NDIS 调用 FilterSendNetBufferListsComplete 返回结构之前对 NET_BUFFER_LIST 和其关联的数据做检查 的。FilterSendNetBufferListsComplete 要完成一个发送请求完成后的任何必要的后继处理。当 NDIS 调用 FilterSendNetBufferListsComplete 时,Filter Driver 就重新获地对结构及结构相关资 源的所有权。可以在 FilterSendNetBufferListsComplete 中释放所有相关的资源和准备下一个 NdisFSendNetBufferLists 调用。  NDIS 总是按照 Filter Driver 调用 NdisFSendNetBufferLists 提交的顺序传递给下层驱动,但 是回返 FilterSendNetBufferListsComplete 的顺序则是任意的。Filter  Driver 可以请求一个回环 发送请求,只要把 NdisFSendNetBufferLists 的 SendFlags 设置成 NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK 就行了。NDIS 会引发一个包含发送数据的接收包 指示。  注意:一个 Filter  Driver 应该对自己引发的发送请求保持跟踪并确保在完成时不调用 NdisFSendNetBufferComplete 例程。  2) 过滤发送请求  下面图示例了过滤一个上层驱动引发的发送请求的过程  NDIS 调用一个 Filter Driver 的 FilterSendNetBufferLists 例程来过滤上层驱动的发送请求。 Filter  Driver 不能改变其它驱动传来的 NET_BUFFER_LIST 结构中的 SourceHandle 成员的值。 它可以过滤数据并发送过滤的数据到下层驱动。对每一个提交到 FilterSendNetBufferLists 的 NDIS_BUFFER_LIST,我们可做下面的操作。  1) 可以把缓冲区通过 NdisFSendBufferLists 传递给下层驱动,NDIS 保证上下文空间对 Filter  Driver 的有效性。过滤驱动可以在发送前修改缓冲区的内容。可以像处理自己引发的发 送请求的缓冲区一样处理这个缓冲区。  2) 可以调用 NdisFSendNetBufferListsComplete 拒绝传递这个包  3) 排队缓冲区内容到本地的供以后处理。例如要在一定超时后处理或要接收到特定包后才 处理等。注意:如果支持这种处理方式就要支持取消请求的操作。  4) 可以拷贝缓冲区并引发一个发送请求。它类似自己引发一个发送请求,但必须先调用 NdisFSendNetBufferComplete 返回上层驱动的缓冲区。  发送请求在驱动栈继续完成,当一个微端口驱动调用 NdisMSendNetBufferListsComplete 完成一个发送请求时,NDIS 会调用微端口驱动之上最近的 Filter  Driver 的 FilterSendNetBufferLists 例程。在一个发送操作完成后,Filter  Driver 可以做在 FilterSendNetBufferLists 中所有修改的相反操作。FilterSendNetBufferComplete 返回一个 NET_BUFFER_LIST 结构的单链表和发送请求的最终状态给上层的驱动。当最顶层的 Filter  Module 的 FilterSendNetBufferListsComplete 被调用完成后 NDIS 会调用引发发送请求的协议 驱动的 ProtocolSendNetBufferListsComplete。如 果 Filter Driver 不提供 FilterSendNetBufferLists 它还是可以引发一个发送操作的,但它必须提供一个 FilterSendNetBufferListsComplete 并且 不能在这个例程里把这个事件传递给上层驱动。一个 Filter  Driver 可以传递或过滤一个上层 驱动的回环请求,要传递一个回环请求,NDIS 会设置 FilterSendNetBufferLists 的 SendFlags 参数为 NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK , Filter  Driver 在调用 NdisFSendNetBufferLists 时把这个标记传给它即可。在回环请求的情况下 NDIS 会指示一个包 含发送数据的接收包。    通常情况下,如果一个 Filter Driver 修改的任何行为不是 NDIS 提供的标准服务,那么它 应该当自己为 NDIS 提供相应的服务。例如,如果一个 Filter Driver 修改了一个硬件地址请求, 就必须处理直接到这个新地址回环包。在这种情况下,因为 Filter Driver 已经更改了地址 NDIS 是不能提供一个回环服务的。还有就是如果 Filter  Driver 设置了混杂模式那它就不能传递额 外的数据给上层接收。  2.9.3 在Filter Driver中取消一个发送请求  一个 Filter Driver 可以取消一个自己引发的或上层驱动引发的发送请求  1) 取消 Filter Driver 的发送请求  下面图示中展示了一个 Filter Driver 的发送请求被取消的过程    过滤驱动调用 NDIS_SET_NET_BUFFER_LIST_CANCEL_ID 宏为每一个 NET_BUFFER_LIST 标 记一个取消 Id。在为网络数据分配取消 ID 之前,必须先调用 NdisGenratePartialCanceId 获得 取消 ID 的高字节。这是为了确保不是驱动不会把一个取消 ID 分配给两个驱动。驱动通常在 DriverEntry 调用 NdisGenratePartialCanceld,但是驱动可以在不同的时间多次调用它来获得多 个取消 ID 。要取消被标记过取消 ID 且正在传输的数据,驱动可以调用 NdisFCancelSendNetBufferLists 例程来完成。要获得取消 ID 可以用 NDIS_GET_NET_BUFFER_LIST_CANCEL_ID 宏来完成。如果一个 Filter  Driver 对所有发送的 NET_BUFFER_LIST 标记了相同的取消 ID 那它可以用一个 NdisFCancelSendNetBufferLists 来取 消所有的发送请求。如果把一部发送请求的 NET_BUFFER_LIST 标记相同的取消 ID 那么就可 以调用一次 NdisFCancelSendNetBufferLists 来取消这部分发送请求。  在实现这个功能时 NDIS 会调用下层驱动的取消发送功能。中断正在执行的发送任务后, 下层驱动会调用发送完成全程(如:NdisMSendNetBufferListComplete )返回指定的 NET_BUFFER_LIST 结构并指定返回状态为 NDIS_STATUS_CANCELLED,NDIS 依次调用 Filter  Driver 的 FilterSendNetBufferListsComplete 例程。在 FilterSendNetBufferListsComplete 中要用 NDIS_SET_NET_BUFFER_LIST_CANCEL_ID 设置取消的 NET_BUFFER_LIST 的取消 ID 为 NULL,这 样是为了防止这个 ID,在 NET_BUFFER_LIST 被再次分配时使用。  2) 取消上层驱动引发的发送请求  下面图例中展示了这种情况    上层驱动在取消一个未完成的发送请求时也必须对这个发送请求的 NET_BUFFER_LIST 结构设定取消 ID。NDIS 会传递给 Filter  Driver 的 FilterCancelSendNetBufferLists 一个取消 ID 来取消发送请求的  NET_BUFFER_LIST 发送。FilterCanCelSendNetBufferLists 下执行下列操作。  1) 遍历 Filter Driver 的发送队列,用 NDIS_GET_NET_BUFFER_LSIT_CANCEL_ID 获得队列 中 NET_BUFFER_LIST 的取消 ID 与 FilterCancelSendBufferLists 的取消 ID 比较  2) 移除队列中取消 ID 和 FilterCancelSentBufferLists 中取消 ID 相同的元素  3) 调用 NdisFSendNetBufferListsComplete 来完成这些 NET_BUFFER_LIST 并设定返回状 态为 NDIS_STATUS_CANCELLED  4) 调用 NdisFCancelSendNetBufferLists 传递取消发送请求给下层驱动。传递取消 ID 给 下层驱动就 Filter Driver  取消自己引发的发关请求一样  2.9.4 在Filter Driver中接收数据  在 Filter  Driver 中可以引发一个接收指示或过滤下层驱动引发的接收指示。当下层驱动微端 口驱动调用 NdisMIndicateReceiveNetBufferLists 时,NDIS 会提交一个 NET_BUFFER_LIST 给在 驱动栈上离微端口驱动最近的那个 Filter Module。  1) Filter Driver 引发一个接收指示  下面图例中展示了这个过程    Filter  Driver 调用 NdisFIndicateReceiveNetBufferLists 来指示发送数据。这个函数通过 NET_BUFFER_LIST 结构给上层驱动指示数据。Filter  Driver 可以从池中分配这个结构。如果 Filter Driver 设置了 NdisFIndicateReceiveNetBufferLists 的状态为 NDIS_STATUS_SUCCESS,NDIS 通过驱动的 FilterReturnNetBufferLists 返回指示数据。在这种情况下 Filter  Driver 失去了对 NET_BUFFER_LIST 的所有权直到 FilterReturnNetBufferLists 被调用。如果 Filter  Driver 在调用 NdisFIndicateReceiveNetBufferLists 时设置 ReceiveFlags 为 NDIS_RECEIVE_FLAGS_RESOURCES, 在函数返回后 Filter Driver 会立即恢复对 NET_BUFFER_LIST 的所有权,这时 Filter Driver 必须 立即处理这个 NET_BUFFER_LIST 的返回因为 NDIS 在这种表情下是不会调用 FilterReturnNetBufferLists 返回 NET_BUFFER_LIST 结构的。  注意:一个 Filter Driver 应该跟踪自己引发的接收指示确保它在 FilterReturnNetBufferLists 中不调用 NdisFReturnNetBufferLists。  2) 过滤接收指示  下面图例中展示了这个过程    NDIS 调用 FilterReceiveNetBufferLists 来处理从下层驱动而来的接收指示。当下层驱动调 用接收指示例程指示一个网络数据或回环数据时 NDIS 就会调用 Filter  Driver 的 FilterReceiveNetBufferLists 例程。  如果 FilterReceiveNetBufferLists 的 ReciverFlags 没有设置 NDIS_RECEIVE_FLAGS_RESOURCES 这个标志,那么 Filter Driver 可以保持这个 NET_BUFFER_LIST 的所有权一直到 FilterReturnNetBufferLists 调用完成。如果设置了 Filter Driver 将不能持有它 的所有权同时说明下层的驱动运行低资源模式下,Filter  Driver 应该以最快的速度处理这个 接收指示。  注意:这个标记设置了后 Filter  Driver 必须保持 NET_BUFFER_LIST 的原有集合设置和状 态。例如:在这种情况下可以在 FilterReceiveNetBufferLists 返回前对 NET_BUFFER_LIST 进行 处理但是必须对它的原始状态进行保存,处理完后必须恢复。  Filter  Driver 可以在指示数据给上层驱动之前对这个数据进行过滤。可以对每一个提交 到 FilterReceiveNetBufferLists 的数据做下列操作。  1) 可以传递这个指示给上层驱动,并且可以在传递之前修改缓冲区中的内容,NDIS 保证上 下文空间的有效性,注意:如果 NDIS 设置了 FilterReceiveNetBufferLists 参数 ReceiveFlags 的 NDIS_RECEIVE_FLAGS_RESOURCES 标记,Filter Driver 要传递这个指示给上层驱动并且 只有恢复了对数据的所有权后才能从 FilterReturnNetBufferLists 返回。  2) 拒绝数据。如果 FilterReceiveNetBufferLists 的 ReceiveFlags 没有设置 NDIS_RECEIVE_FLAGS_RESOURCES 标记,Filter  Drivre  调用 NdisFReturnNetBufferList 返回 这个缓冲区数据,如果设置了则可以什么都不做直接返回来达到拒绝的上的。  3) 排除在本地数据结构中以后再处理。如果 FilterReceiveNetBufferLists 的 ReceiveFlags 设置 NDIS_RECEIVE_FLAGS_RESOURCES 标记,需要拷贝一份 NET_BUFFER_LIST 后再返回(在这 中情况下是能不能直接使用传来的 NET_BUFFER_LIST 的,它必须原样返回给下层驱动)。  Filter Driver 调用 NdisFIndicateNetBufferLists 传递接收指示给驱动栈上的上层驱动,类似 于 Filter Driver 直接引发的接收指示。如果上层驱动保留了对缓冲区(NET_BUFFER_LIST)的 所有权,NDIS 会调用 Filter  Driver 的 FilterReturnNetBufferLists 例程。在 FilterReturnNetBufferLists 中应该撤消在接收路径上(如在 FilterReciveNetBufferLists 中做的一 些处理)的操作。当最底层的 Filter  Module 完成对缓冲区(NET_BUFFER_LIST)的处理后, NDIS 把缓冲区返回给微端口驱动。如果 FilterReceiveNetBufferLists 的 ReceiveFlags 没有设置 NDIS_RECEIVE_FLAGS_RESOURCES 标记,Filter Drivre  调用 NdisFReturnNetBufferList 返回这个 缓冲区数据,如果设置了 FilterReceiveNetBufferLists 直接返回时就把缓冲区返还给了下层微 端口驱动。   2.10 Filter Module OID请求  NDIS 为每一个适配器定义了对象 ID 值( OID),它包括设备特征,配置设置和统计信息。 更多的信息可查看 NDIS OIDs。Filter Driver 可以查询设置下层驱动的参数据或过滤上层驱动 的 OID 请求。NDIS 为 6.1 以后的版本提供直接 OID 请求接口(Direct OID Request Interface)。 直接 OID 请求方法支持频繁经常性的 OID 查询设置请求。例如:IPSec  Offload  Version  2 (IPSecV2)接口提供的 OID_TCP_TASK_IPSEC_OFFLOAD_V2_ADD_SA OID 直接 OID 请求,直接 OID 请求在 NDIS 中提可选的。  下面小节介绍关 OID 请求的信息。  2.10.1 在Filter Driver中过滤OID请求  Filter Driver可以处理上层驱动引发的OID 请求,NDIS调用Filter Driver的FilterOidRequest 例程来处理 OID 请求,Filter Driver 需要调用 NdisFOidRequest 例程来转发请求给下层驱动。  NDIS 调用 FilterCancelOidRequest 来取消一个 OID 请求,当 NDIS 调用 FilterCancelOidRequest 时,Filter Driver 应该尽可能快的调用 NdisFCancelOidRequest(原文是 NdisFOidRequest,我理解这里是一外笔误应该为 NdisFCancelOidRequest)。  下图示例了一个 OID 请求  Filter  Driver 可以从 FilterOidRequest 同步和异步完成一个 OID 请求,分别返回 NDIS_STATS_SUCCESS 和 NDIS_STATUS_PENDING 即可。FilterOidRequest 可以用同步的直接完 成一个 OID 请求并返回一个错误状态。  如果Filter  Driver 成功控制(处理)了一个OID 请求那它必须设置OID 请求传来 NDIS_OID_REQUEST结构的SupportRevision成员。这个成员是通知OID的发起者所支持的驱动 修订版本。更多信息可以参看Specifying NDIS Version Information。  如果 FilterOidRequest 返回 NDIS_STATUS_PENDING,就必须在 OID 请求完成后调用 NdisFOidRequestComplete 来通知上层驱动求请求完成。在这种情况下,请求的结果通过 NdisFOidRequestComplete 的 OidRequest 参数返回给上层驱动,并通过 Status 参数返回请求 完成的最终状态。  如果 FilterOidRequest 返回 NDIS_STATUS_SUCCESS,通过 FIlterOidRequest 的 OidRequest 参数返回一个查询结果能上层。这时不调用 NdisFOidRequestComplete 例程。  要转发 OID 请求到下层驱动,Filter  Driver 必须调用 NdisFOidRequest。如果一个 OID 请 求不能被转发到下层驱动应该当立即返回。要完成一个请求且不转发可以直接返回 NDIS_STATUS_SUCCESS 或其它错误状态或返回 NDIS_STATUS_PENDING 后调用 NdisFOidRequestComplete。  转发 OID 请求类似于自己引发 OID 请求可见下节介绍。  当下层驱动完成这个转发的请求时,如果有必要 Filter Driver  可以修改这个请求的结果 并递给上层驱动。  一个 Filter Driver 可以从上层驱动接收 OID 请求在 Restarting,Running,Pausing 和 Paused 状态时。  注意:像微端口驱动和 Filter Driver 在同一时间只可以接收到一个 OID 请求。NDIS 串行 化 OID 请求发送给 Filter Module,在一个 OID 请求没有完成之前是不会收到下一个 OID 请求 的。  下面这个例子是在 Filter Driver 中修改一个 OID 请求:  Filter  Driver 会给数据包添加一个头的情况。在这个种情况下,Filter  Driver 在 OID_GEN_MAXIMUM_FRAME_SIZE 从下层驱动返回结果后,返回的结果中减去要插入的头的 长度。因为在发送数据时 Filter Driver 要插入一个头,而在接收数据时要移除一个头。  2.10.2 在Filter Driver发起OID请求  Filter Driver 可以调用 NdisFOidRequest 引发一个 OID 查询和设置请求给下层驱动。下列 图示了这个过程。    当 Filter  Driver 调用 NdisFOidRequest 时 NDIS 会调用下层驱动的请求功能。列多信息可 以能微端口驱动程序是怎么处理 OID 请求的。  如果 NdisFOidRequest 是同步完成的 OID 请求它会返回 NDIS_STATUS_SUCCESS,如果是 异步完成它会返回 NDIS_STATUS_PENDING。  要确定哪些信息被下层驱动成功处理了,就要检查返回结果的SupportRevision成员的 值。更多信息可以参看Specifying NDIS Version Information。  如果 NdisFOidRequest 返回 NDIS_STATUS_PENDING,NDIS 在 OID 请求完成后调用 FilterOidRequestComplete 来通知求请求完成。在这种情况下,请求的结果通过 NdisFOidRequestComplete 的 OidRequest 参数返回给上层驱动,并通过 Status 参数返回请求 完成的最终状态。  如果 NdisFOidRequest 返回 NDIS_STATUS_SUCCESS,通过 NdisFOidRequest 的 OidRequest 参数返回一个查询结果能上层。这时不调用 FilterOidRequestComplete 例程。  一个 Filter Driver 可以调用 NdisFOidRequest 引发 OID 请求在 Restarting,Running,Pausing 和 Paused 状态。  注意:Filter  Driver 必须跟踪这个请求确保不在 FilterOidRequestComplete 中调用 NdisFOidRequestComplete(因为请求是自己引发的不能传到上层)。  2.10.3 Filter Module的直接OID请求(Direct OID Request)  要支持直接 OID 请求,要在 Filter  Driver 的 NDIS_FILTER_DRIVER_CHARACTERISTICS 中提 供相应的 FilterXXX 接口的入口且 NDIS 的版本要支持 NdisFDirectXXX 例程。  直接 OID 请求的接口类似于标准的 OID 请求接口,例如:  NdisFDirectOidRequest  和 FilterDirectOidRequest  例程类似于 NdisFOidRequest  和 FilterOidRequest 例程。  注意:只有 NDIS  6.1 指定一些 OID 在才可以使用直接 OID 请求,6.1 版本之前的和 6.1 中的一些 OID 是不支持直接 OID 请求的。哪些 OID 支持直接 OID 请求可以参看 OID 接口页。 例如看看 OID_TCP_TASK_IPSEC_OFFLOAD_V2_ADD_SA。  直接 OID 请求不是串行的,它不像标准的 OID 请求那样被 NDIS 串行化,一个直接 OID 发生时可能存在另一个直接 OID 或标准 OID 请求也发生了。此外,直接 OID 请求例程工作 在小于等等 DISPATCH_LEVEL 的中断级别上。  要支持直接 OID 请求就要使用文档中规定的标准备接口,下面列出直接 OID 接口与标 准 OID 请求接口的对应。  Direct OID function  Standard OID function  FilterDirectOidRequest   FilterOidRequest   FilterCancelDirectOidRequest   FilterCancelOidRequest   FilterDirectOidRequestComplete   FilterOidRequestComplete   NdisFDirectOidRequest   NdisFOidRequest   NdisFDirectOidRequestComplete   NdisFDirectOidRequestComplete   NdisFCancelDirectOidRequest   NdisFCancelOidRequest     2.11 Filter Module PnP事件通知  Filter Driver  可以接收到所有下层微端口驱动要接收的 PnP 事件通知,此外还可以接收 到上层协议驱动要接收的网络事件通知道。它可以控制驱动指定的通知事件。  下图展示了一个 Filter Driver 接收 PnP 通知的情形  Filter Driver 提供 FilterPnpEventNotify 来接收 NDIS 传递的 PnP 和电源管理事件,它类似 于微端口的 MiniportDevicePnPEventNotify 全程。  Filter Driver 要下层驱动转发收到的事件,转发事件要用到 NdisFDevicePnPEventNotify 例 程。  下面图例是 Filter Driver 接收网络通知事件的过程  Filter  Driver 提供了 FilterNetPnpEvent 例程来处理网络 PnP 和电源管理事件通知。它类 似于协议驱动的 ProtocolNetPnPEvent。  Filter  Driver 需要转发网络 PnP 和电源管理事件给上层驱动。转发这些事件是通 NdisFNetPnpEvent 来完成的。  Filter Driver应该处理驱动栈上的更改(当NDIS改变一个正在运行的栈时会先发送相关的 PnP和电源管理事件,根据实际情况Filter Driver也要在自己的程序中处理相应的事件)。更 多 关于更改运行中的驱动栈的信息可以参看DDK中Modifying a Running Driver Stack。  如查有必要可以处理这些事件,因为在一个PnP和电源管理事件通知后NDIS才可以执行 暂停操作。关于暂停操作在DDK中的Pausing a Driver Stack里有详细的介绍。  2.12 Filter Module  状态指示  Filter Driver 可以提供 FilterStatus 例程,当下层驱动报告状态的时候 NDIS 会调用它。此 外,Filter Driver 还可以自己引发一个状态指示。  下图示例一个状态指示  当下层驱动调用一个状态指示例程时(NdisMIndicateStatusEx或NdisFIndicateStats),NDIS 会调用Filter Driver的FilterStatus例程。更多的关于如何从微端口驱动指示状态的信息可以查 看DDK中的Adapter Status Indications。  Filter Driver 在 FilterStatus 中调用 NdisFIndicateStatus 传递一个状态指示给上层驱动。此 外,还可以过滤状态指示(不用调用 NdisFIndicateStatus)或在调用 NdisFIndicateStatus 之前 修改状态信息。  Filter  Driver 要自己引发一个状态报告,可以在 NDIS 未调用 FilterStatus 的情况下调用 NdisFIndicateStatus。  在这种情况下,Filter  Driver 要设置 SourceHandle 成员为 FilteAttech 参数提供的 NdisFilterHandle 句柄。如果一个状态指示是一个 OID 请求相关的(下层请求一个 OID 下层 要做相应的状态指示),那么状态的 DestinationHandle  和 RequestId 成员要设置成上层的 OID 请求包携带的数据。  Filter  Driver 调用 NdisFIndicateStatus 后 NDIS 会调用相邻上层的状态指示函数 (ProtocolStatusEx 或 FilterStatus)。  3 安装NDIS Filter Drivers  这节主要介绍如何安装 NDIS Filter Driver 的信息。Filter Driver 安装不同于中间层过滤驱 动,配置管理器把 Filter  Driver 安装成自启动的服务类似于协议驱动。对于每一个微端口适 配器(Miniport Adapter)为 NDIS 提供一个 Filter Module 的列表。Filter Driver 不像中间层过 滤驱动那样联结一个虚拟设备(或虚拟微端口(virtual miniport))。  要安装一个 Filter  Driver 需要提供一个 INF 的配置文件。配置管理器从这个配置文件中 读取相关的配置信息并复制到注册表。与此不同的是中间层过滤驱动,它有两个配置文件一 个提供上边缘协议驱动的接口配置信息,另一个提供下边缘虚拟微端口驱动的接口配置信 息。  Filter  Driver 的 INF 配置文件类似于中间层过滤驱动的协议 INF 配置文件(Prolocol  INF  File),它没有微端口 INF 配置文件(Miniport INF File)。  下面的小节将介绍如何为一个 Filter Driver 生成一个 INF 文件。  3.1 指定Filter Driver的绑定关系  在一个网络驱动的 INF 文件中,UpperRanget 条目列出可能的上边缘绑定和 LowerRange 条目列出可能的上边缘绑定。这些条目包含都是系统预定义的值。  对 Filter  Driver 来说,你必须设置 UpperRange 和 LowerRange 条目分别为 noupper 和 nolower。下面示例了一个 Filter Driver 的 INF 文件的条目。  HKR, Ndi\Interfaces,UpperRange,,"noupper" HKR, Ndi\Interfaces,LowerRange,,"nolower" 在一个 Filter Driver 的 INF 文件中 FilterMediaTypes 条目定义了 Filter Driver 要绑定的驱 动,它指定了 Filter Driver 要服务的媒体类型。下面图示列出在一个 Filter Driver 的 INF 文件 中的 FilterMediaTypes 定义及 FilterMediaTypes 可取值的列表。  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet" FilterMediaTypes 可取值的列表,它和 LowerRange 的一样。 值  描述  ethernet  下边缘是一个  Ethernet adapter  atm  下边缘是一个  ATM adapter  tokenring  下边缘是一个  token ring adapter  serial  下边缘是一个  serial adapter  fddi  下边缘是一个  FDDI adapter  baseband  下边缘是一个  baseband adapter  broadband  下边缘是一个  broadband adapter  arcnet  下边缘是一个  Arcnet adapter  isdn  下边缘是一个  ISDN adapter  localtalk  下边缘是一个  LocalTalk adapter  wan  下边缘是一个  WAN adapter  nolower  不对任何组件执行下边缘绑定  ndis5  下边缘为 NDIS 5.x 及之前的任一网络部件,都是非 ATM 网络部件  Ndisatm  下边缘为 NDIS 5.x 及之前的任一网络部件,都是 ATM 网络部件  Wlan  下边缘是一个  native 802.11 wireless LAN adapter.  当计算机加载一个 Filter Driver 时,Filter Driver 要被插入到已经存在的协议到适配器的 绑定(Protocol‐to‐Adapter Banding),这时就依赖 FilterMediaTypes 提供一个列表来决定插入 到哪些协议到适配器的绑定上。  3.2 Filter Driver的INF文件设置  一个 Filter Driver 的 INF 设置指定了它的特性,例如:可以指定这个驱动是 Modifying 还 是 Monitoring 的,是 Mandatory 还是 Optional 的。此处,在 INF 文件中还可以指定 Filter Driver 的 FilterModule 的通用配置参数和其它有具体微端口适配口相关联的细节信息。Filter  Drivr 还要指定一个唯一的过滤器识别 GUID(FID GUID)    下面两个小节分别示例如何配置 Monitoring 和 Modifying 两种类型的 Filter Driver。  3.2.1 Monitoring Filter Driver的INF文件配置  下面 Filter Driver 的安装节指定它为一个 Monitoring 类型的 Filter Driver:  1) 设置 INF 文件的 Class 条目为 NetService(同时要指定 ClassGUID)下面是一个示例。  Class       = NetService  ClassGUID    = {4D36E974‐E325‐11CE‐BFC1‐08002BE10318}  2)   必须设置安装节(DDInstall,这个名字不 INF 文件中可能有不同)的 Characteristics 条目, 下边示例一个设置  [Install]  AddReg=Inst_Ndi  Characteristics=0x40000  NetCfgInstanceId="{5cbf81bd‐5055‐47cd‐9055‐a76b2b4e3697}"  Copyfiles = NdisMon.copyfiles.sys  0x40000 这个是指 NCF_LW_FILTER 集合,一个 Filter  Driver 不设置为 NCF_FILTER(0x400) 这个标记  3)   设置 NetCfgInstanceId 条目,这个 Id 和 Filter Driver 中调用 NdisFRegisterFilterDriver 是指 定 Filter Driver 的唯一名保持一样。它可以用 Uuidgent.exe 来生成。下面示例这个条目的 配置。  [Install]  AddReg=Inst_Ndi  Characteristics=0x40000  NetCfgInstanceId="{5cbf81bd‐5055‐47cd‐9055‐a76b2b4e3697}"  Copyfiles = NdisMon.copyfiles.sys  4) 一个安装节(DDInstall,这个名字不 INF 文件中可能有不同)必须指定一个 AddReg 条目 用于配置 Ndi 键的信息,在 Ndi 节下面必须指定 Service 条目。下面是一个示例。  [Install]  AddReg=Inst_Ndi  Characteristics=0x40000  NetCfgInstanceId="{5cbf81bd‐5055‐47cd‐9055‐a76b2b4e3697}"  Copyfiles = NdisMon.copyfiles.sys  [Inst_Ndi]  HKR, Ndi,Service,,"NdisMon"  HKR, Ndi,CoServices,0x00010000,"NdisMon"  HKR, Ndi,HelpText,,%NdisMon_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000002  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1    5)   Filter  Driver 的安装节必须指定 FilterType 和 FilterRunType 条目,下面示例了将 Filter  Driver 配置为 Monitoring 且 Mandatory 的配置方法  [Inst_Ndi]  HKR, Ndi,Service,,"NdisMon"  HKR, Ndi,CoServices,0x00010000,"NdisMon"  HKR, Ndi,HelpText,,%NdisMon_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000001  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1   FilterType 为 0x00000001 说是一个 Monitoring 类型的 Filter Driver,FilterRunType 为 1 是 以 Mandatory 加载,为 2 是以 Optional 方式加载。  6) 下面示例如何为一个 Filter Driver 在系统中添加一个服务。  [Install.Services]  AddService=NdisMon,,NdisMon_Service_Inst    [NdisMon_Service_Inst]  DisplayName     = %NdisMon_Desc%  ServiceType     = 1 ;SERVICE_KERNEL_DRIVER  StartType       = 1 ;SERVICE_SYSTEM_START  ErrorControl    = 1 ;SERVICE_ERROR_NORMAL  ServiceBinary   = %12%\NdisMon.sys  LoadOrderGroup  = NDIS  Description     = %NdisMon_Desc%  AddReg          = Common.Params.reg   7)   INF 文件中要在 CoService 条目中为 Filter Driver 指定主服务名(即上一步创建的服务), 下面示例。  [Inst_Ndi]  HKR, Ndi,Service,,"NdisMon"  HKR, Ndi,CoServices,0x00010000,"NdisMon"  HKR, Ndi,HelpText,,%NdisMon_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000002  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1   8) 在 INF 文件中定 FilterClass 的值,指定 Filter  Driver 在驱动栈上的顺序(位置),但是 Monitoring 的 Filter Driver 不必指定,它固定加载到离微端口适配口最近的位置。   9) 必须为 Filter 指定绑定的信息  [Inst_Ndi]  HKR, Ndi,Service,,"NdisMon"  HKR, Ndi,CoServices,0x00010000,"NdisMon"  HKR, Ndi,HelpText,,%NdisMon_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000002  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1   10) 为 Filter  Driver 指定通用参数,这些参数可以是与具体网络适配器相关的也可以是具体 实例(Filter Module)相关的,下面为示例。  [Common.Params.reg]    HKR, FilterDriverParams\DriverParam,    ParamDesc,   , "Driverparam for Mon"  HKR, FilterDriverParams\DriverParam,    default,  , "5"  HKR, FilterDriverParams\DriverParam,    type,     , "int"    HKR, FilterAdapterParams\AdapterParam,    ParamDesc,   , "Adapterparam for Mon"  HKR, FilterAdapterParams\AdapterParam,    default,  , "10"  HKR, FilterAdapterParams\AdapterParam,    type,     , "int"    HKR, FilterInstanceParams\InstanceParam,        ParamDesc, , "Instance param for lwf"  HKR, FilterInstanceParams\InstanceParam, default, , "15"  HKR, FilterInstanceParams\InstanceParam, type, , "int"    3.2.2 Modifying Filter Driver的INF文件配置  下面 Filter Driver 的安装节指定它为一个 Modifying 类型的 Filter Driver:  1) 设置 INF 文件的 Class 条目为 NetService(同时要指定 ClassGUID)下面是一个示例。  Class       = NetService  ClassGUID    = {4D36E974‐E325‐11CE‐BFC1‐08002BE10318}  2)   必须设置安装节(DDInstall,这个名字不 INF 文件中可能有不同)的 Characteristics 条目, 下边示例一个设置  [Install]  AddReg=Inst_Ndi  Characteristics=0x40000  NetCfgInstanceId="{5cbf81bd‐5055‐47cd‐9055‐a76b2b4e3697}"  Copyfiles = NdisMon.copyfiles.sys  0x40000 这个是指 NCF_LW_FILTER 集合,一个 Filter  Driver 不设置为 NCF_FILTER(0x400) 这个标记  3)   设置 NetCfgInstanceId 条目,这个 Id 和 Filter Driver 中调用 NdisFRegisterFilterDriver 是指 定 Filter Driver 的唯一名保持一样。它可以用 Uuidgent.exe 来生成。下面示例这个条目的 配置。  [Install]  AddReg=Inst_Ndi  Characteristics=0x40000  NetCfgInstanceId="{5cbf81bd‐5055‐47cd‐9055‐a76b2b4e3697}"  Copyfiles = NdisMon.copyfiles.sys  4) 一个安装节(DDInstall,这个名字不 INF 文件中可能有不同)必须指定一个 AddReg 条目 用于配置 Ndi 键的信息,在 Ndi 节下面必须指定 Service 条目。下面是一个示例。  [Install]  AddReg=Inst_Ndi  Characteristics=0x40000  NetCfgInstanceId="{5cbf81bd‐5055‐47cd‐9055‐a76b2b4e3697}"  Copyfiles = NdisMon.copyfiles.sys  [Inst_Ndi]  HKR, Ndi,Service,,"NdisLwf"  HKR, Ndi,CoServices,0x00010000,"NdisLwf"  HKR, Ndi,HelpText,,%NdisLwf_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000002  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1    5)   Filter  Driver 的安装节必须指定 FilterType 和 FilterRunType 条目,下面示例了将 Filter  Driver 配置为 Monitoring 且 Mandatory 的配置方法  [Inst_Ndi]  HKR, Ndi,Service,,"NdisLwf"  HKR, Ndi,CoServices,0x00010000,"NdisLwf"  HKR, Ndi,HelpText,,%NdisLwf_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000002  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1   FilterType 为 0x00000002 说是一个 Modifying 类型的 Filter  Driver,FilterRunType 为 1 是 以 Mandatory 加载,为 2 是以 Optional 方式加载。  6) 下面示例如何为一个 Filter Driver 在系统中添加一个服务。  [Install.Services]  AddService=NdisLwf,,NdisLwf_Service_Inst    [NdisLwf_Service_Inst]  DisplayName     = %NdisLwf_Desc%  ServiceType     = 1 ;SERVICE_KERNEL_DRIVER  StartType       = 1 ;SERVICE_SYSTEM_START  ErrorControl    = 1 ;SERVICE_ERROR_NORMAL  ServiceBinary   = %12%\NdisLwf.sys  LoadOrderGroup  = NDIS  Description     = %NdisLwf_Desc%  AddReg          = Common.Params.reg   7)   INF 文件中要在 CoService 条目中为 Filter Driver 指定主服务名(即上一步创建的服务), 下面示例。  [Inst_Ndi]  HKR, Ndi,Service,,"NdisLwf"  HKR, Ndi,CoServices,0x00010000,"NdisLwf"  HKR, Ndi,HelpText,,%NdisLwf_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000002  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1   8) 在 INF 文件中定 FilterClass 的值,指定 Filter Driver 在驱动栈上的顺序(位置),Modifying 类型的 Filter Driver 必须为它指定一个值。  这个值可以是下面值中的一个。  值  描述  scheduler  分组调度服,这类的 Filter Driver 在驱动栈的最高层且在 Encryption 之上。它检测 802.1p 是的优先级信息同时给出质 量服务的信令组件和发送数据包的调度级别,按照其优先级 传到下层驱动。   Encryption  这类驱动存于 Scheduler 和 Compression 之间  Compression  这类驱动存于 Encryption 和 Vpn 之间  Vpn  这类驱动存于 Compression 和 load balance 之间  Loadbalance  负载均衡过滤服务。这类驱动存于 Packet‐Scheduling 和 Failover 之间.  一个负载均衡的Filter Driver均衡包传输的工作 量到下层第一个微端口适配器上。  failover  故障切换过滤服务。这类驱动存在于  Loadbalance 和 Diagnostic 之间。  Diagnostic  这类 Filter Driver 存在于 Fail‐Over 之下。  Custom  这类 Filter Driver 存在于 Diagnostic 之下。  注意:  多个 Modifying 类型的 Filter  Driver 可以存在于同一个栈层上。例如,两个 Modifying 类型的 Filter Driver 可以都指定 FilterClassic 为“ scheduler”并时存在于这个驱动栈 的这个层上。Filter  Driver 后安装的在先安装的下层,也就是说后安装的离微端口适配器最 近。此外,多个 Filter Driver 在不同微端口适配器上的顺序是一相同的。  看下面的示例:  [Inst_Ndi]  HKR, Ndi,Service,,"NdisLwf"  HKR, Ndi,CoServices,0x00010000,"NdisLwf"  HKR, Ndi,HelpText,,%NdisLwf_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000002  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1   9) 必须为 Filter 指定绑定的信息  [Inst_Ndi]  HKR, Ndi,Service,,"NdisLwf"  HKR, Ndi,CoServices,0x00010000,"NdisLwf"  HKR, Ndi,HelpText,,%NdisLwf_HelpText%  HKR, Ndi,FilterClass,, compression  HKR, Ndi,FilterType,0x00010001,0x00000002  HKR, Ndi\Interfaces,UpperRange,,"noupper"  HKR, Ndi\Interfaces,LowerRange,,"nolower"  HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet"  HKR, Ndi,FilterRunType, 0x00010001, 1   10) 为 Filter  Driver 指定通用参数,这些参数可以是与具体网络适配器相关的也可以是具体 实例(Filter Module)相关的,下面为示例。  [Common.Params.reg]    HKR, FilterDriverParams\DriverParam,    ParamDesc,   , "Driverparam for Lwf"  HKR, FilterDriverParams\DriverParam,    default,  , "5"  HKR, FilterDriverParams\DriverParam,    type,     , "int"    HKR, FilterAdapterParams\AdapterParam,    ParamDesc,   , "Adapterparam for Lwf "  HKR, FilterAdapterParams\AdapterParam,    default,  , "10"  HKR, FilterAdapterParams\AdapterParam,    type,     , "int"    HKR, FilterInstanceParams\InstanceParam,        ParamDesc, , "Instance param for lwf"  HKR, FilterInstanceParams\InstanceParam, default, , "15"  HKR, FilterInstanceParams\InstanceParam, type, , "int"  3.3 Filter Driver访问配置信息  NDIS 支持一个函数集合用来访问 Filter Driver 的注册表参数。Filter Driver 可以在附加和 重启操作时或接收到 PnP 和电源管理通知事件时访问这些参数。  NDIS_STATUS    NdisOpenConfigurationEx(      IN PNDIS_CONFIGURATION_OBJECT  ConfigObject,      OUT PNDIS_HANDLE  ConfigurationHandle      );  过滤驱动通过调用 NdisOpenConfigurationEx 来访问注册表设置。调用用 NdisFRegisterFilterDriver 时会获得一个句柄,如果用这个句柄初始化 NDIS_CONFIGURATION_OBJECT 结构的 NdisHandle 成员并调用 NdisOpenConfigurationEx 可以 得到一个标识参数存储点的注册表句柄。Filter  Driver 可以使用这个句柄一直到 NdisDeregisterFilterDriver 调用。  如果用 FilterAttech 中系统传来的句柄同初始化 NdisHandle 成员那么调用 NdisOpenConfigurationEx 得到的就是 Filter  Module 的配置存储点。获得的这个句柄到 FilterDetach 调用完成就失效了。当有多个 Filter  Module 配置在相同的微端口适配器上时, 如果 Monitoring 类型的 Filter  Driver 设置 NDIS_CONFIGURATION_OBJECT 的 Flags 值为 NDIS_CONFIG_FLAG_FILTER_INSTANCE_CONFIGURATION  ,这样驱动就可以访问特定的 Filter  Module 配置信息。Modifying 类型的 Filter Driver 不能应用这个标记。  一个 Filter Driver 在访问过配置信息后一定要用 NdisClosConfiguration 关闭配置句柄和相 关的资源。  4 附录  4.1 NET_BUFFER体系结构  4.1.1 网络数据结构  网络数据由在网络上发送和接收的数据包组成。NDIS 提供了数据结构来描述它们,NDIS  6.0 提供了如下数据结构:  1) NET_BUFFER   2) NET_BUFFER LIST   3) NET_BUFFER_LIST_CONTEXT   下图说明了这些结构之间的关系:    在 NDIS  6.0 中,NET_BUFFER 是封闭网络数据的基本构建块。每一个 NET_BUFFER 都有 一个 MDL 链。这些 MDL 映射的缓冲区地址是 NET_BUFFER 指定的数据空间。这种数据映射 同 NDIS  5.X 及之前的版本使用的 NDIS_PACKET 中的映射是一样的。NDIS 提供函数来管理这 些 MDL 链。  多个NET_BUFFER可以被附加到(可以被串到)一个NET_BUFFER_LIS上。这些NET_BUFFER 被组织成一个以 NULL 结束的单链表。驱动或 NDIS 仅创建一个 NET_BUFFER_LIST,应该修改 它的链表给它插入或删除一些 NET_BUFFER 结构。  NET_BUFFER_LIST 结构中包含的信息中描述了所有被串到一个链表上的 NET_BUFFER 结 构。如果 NET_BUFFER_LIST 需要上下文信息,可以分配额外的空间来存储一个 NET_BUFFER_LIST_CONTEXT 结构。NDIS 提供函数来分配、访问 NET_BUFFER_LIST_CONTEXT 中的数据。  多个 NET_BUFFER_LIST 结构可以串成一个 NET_BUFFER_LIST 链表。它们可以被组织成一 个以 NULL 结尾的单向链表。驱动可以对这个链表直接进行插入、删除操作。  4.1.1.1 NET_BUFFER结构  NDIS 6.0 中使用的 NET_BUFFER 结构相似于 NDIS 5.X 以前使用的 NDIS_PACKET 结构,每 一个 NET_BUFFER 结构中都包装了一个网络数据包。  下图显示了 NET_BUFFER 的各个域:  NET_BUFFER 结构包含一个 NetBufferHeader 成员它是一个 NET_BUFFER_HEADER 结构。 这个成员又包含一个 NET_BUFFER_DATA 结构的 NetBufferData 成员。应该用 NDIS 提供宏和 相关函数来访问 NET_BUFFER 结构。下面是相关宏的列表。  NET_BUFFER_NEXT_NB  NET_BUFFER_FIRST_MDL  NET_BUFFER_DATA_OFFSET  NET_BUFFER_DATA_LENGTH  NET_BUFFER_PROTOCOL_RESERVED  NET_BUFFER_MINIPORT_RESERVED  NET_BUFFER_CHECKSUM_BIAS  NET_BUFFER_CURRENT_MDL  NET_BUFFER_CURRENT_MDL_OFFSET  NdisGetPoolFromNetBuffer  NET_BUFFER 中的一些成员仅仅被 NDIS 使用,下面列出一些编写驱动中常会用到的成 员。  ProtocolReserved  它是为协议驱动保留的。(也可以理解为是为一个发送包的引发者保留的)  MiniportReserved  它是为微端口驱动保留的。(也可以理解为是为一个接收指示的引发者保留的)  NdisPoolHandle  它指示了 NET_BUFFER 结构是从哪一个 NET_BUFFER 池里分配的  Next  以一个 NET_BUFFER 链表中它是指向下一个 NET_BUFFER 结构的指针。如果它是最后个 元素那它的这个成员为 NULL  DataLength  它指明了网络数据在 MDL 链中的长度,长度以字节为单位。  DataOffset  它表示的是从 MDL 链所描述的缓冲区的开始位置到网络数据(当前驱动要使用的数据) 开始位置之间的偏移。它能字节为单位。  CurrentMdl  它是一个指向当前驱动在 MDL 链中要使用的第一个 MDL 的指针。它是 NDIS 提供的一 个优化(跳任何驱动不使用的 MDL 直接到驱动要使用的第一个 MDL。)  CurrentMdlOffset  它是一个从 CurrentMdl 指向 MDL 所描述的地址空间的开始位置到网络数据(当前驱动 要使用的数据)开始位置之间的偏移。它能字节为单位。  下面是各数据成员之间的一个关系图。  NDIS 提供了一个系列的函数来访问这些在 MDL 链中的数据。有些时候一些数据空间对 当前驱动来说是未使用的,虽然是未使用的但也可能包含了有效的数据。例如,在一些应用 中的接收路径中这个未使用的空间可能包含有下层驱动使用的头信息。  驱动使用 Retreat 和 Advance 操作来减少和增加使用的数据完间。更多关于这方面的信 息可在“Retreat 和 Advance 操作”小节看到。  下列术语和定义描述了 NET_BUFFER 的数据空间中的元素。  Used Data Space  这里包含了当前驱动当前时间可以使用的数据空间,要增加使用的空间可以执行 Retreat 操作,要减少使用的空间可以执行 Advance 操作。  Unused Data Space  当前驱动当前时间不使用的数据空间。  Total Data Size  这是当前 Used Data Space 和 Unused Data Space 空间大小的和。如果要计算这个总的空 间大小就把 DataOffset 和 DataLength 两个成员相加就可得到。  Retreat  这是一个增加使用空间的操作  Advance  这是一个减少使用空间的操作  4.1.1.2 NET_BUFFER_LIST结构  一个 NET_BUFFER_LIST 结构中包装了一个 NET_BUFFER 的单向链表。下面展示 NET_BUFFER_LIST 中的各个域。    在 NET_BUFFER_LIST 结构中包含一个 NET_BUFFER_LIST_HEADER 的 NetBufferListHeader 成员,这个成员里包含一个 NET_BUFFER_LIST_DATA 的 NetBufferListData 的子成员。应该使 用 NDIS 提供的宏和函数来访问这些成员,下面列出这些宏和函数。  NET_BUFFER_LIST_NEXT_NBL  NET_BUFFER_LIST_FIRST_NB  NET_BUFFER_LIST_FLAGS  NET_BUFFER_LIST_MINIPORT_RESERVED  NET_BUFFER_LIST_CONTEXT_DATA_START  NET_BUFFER_LIST_CONTEXT_DATA_SIZE  NET_BUFFER_LIST_INFO  NET_BUFFER_LIST_STATUS  NET_BUFFER_LIST_PROTOCOL_RESERVED  NdisGetPoolFromNetBufferList  在 NET_BUFFER_LIST 结构中大部成员仅仅是 NDIS 来使用的。下面列出的成员是我们在 编写驱动的时候最有可能用的一些成员。  ParentNetBufferList  如果一个 NET_BUFFER_LIST 是一个从父结构派生(主要是指一个对结构做的克隆、分片、 重组作操作)过来的一个子结构那么它就指向父结构。其它情况下它为 NULL。  NdisPoolHandle  分配结构时所用池的句柄。  ProtocolReserved  它是为协议驱动保留的。(也可以理解为是为一个发送包的引发者保留的)  MiniportReserved  它是为微端口驱动保留的。(也可以理解为是为一个接收指示的引发者保留的)  SourceHandle  它标识了分配这个 NET_BUFFER_LIST 的驱动。NDIS 利用它来返加这个结构,我们不应 该当在驱动中读这个句柄。  ChildRefCount  如果结构是一个父结构,它代表着它有几个子结构。其它情况下为 0。  Flags  保留给 NET_BUFFER_LIST 未来标识属性用的,目前版本没有相关的属性规范。  Status  标识一个网络操作的最终状态,如果微端口操作在完成发送后写这个状态返回给上层发 送操作的引发者。  NetBufferListInfo  是关于 NET_BUFFER_LIST 结构的信息,这个些信息通常是链表中的所有 NET_BUFFER 的 信息  Next  在一个 NET_BUFFER_LIST 链表中它是指向一个结构的指针,如果它是最后一个元素那 Next 为 NULL。  FirstNetBuffer  它指向一个联结在 NET_BUFFER_LIST 上的 NET_BUFFER 链表的第一个元素。  注意:Context 成员是指一个 NET_BUFFER_LIST_CONTEXT 结构的,NDIS 提供宏和函数来维护 这个结构,下面列出这些宏和函数。  NdisAllocateNetBufferListContext   NdisFreeNetBufferListContext   NET_BUFFER_LIST_CONTEXT_DATA_START   NET_BUFFER_LIST_CONTEXT_DATA_SIZE   4.1.1.3 NET_BUFFER_LIST_CONTEXT结构  NDIS 使用 NET_BUFFER_LIST_CONTEXT 结构来为所联结的 NET_BUFFER_LIST 存储一些附 加数据。NET_BUFFER_LIST 的 Context 成员指一个 NET_BUFFER_LIST_CONTEXT 结构,这个结 构存储的信息对 NDIS 和栈上的其它驱动是不透明的。下面列出了结构的各个域。  这个结构的 ContextData 成员包含了环境信息,这个环境信息可以是 NET_BUFFER_LIST 所需要的任何信息。我们应该使用下面的宏和函数来维护 NET_BUFFER_LIST_CONTEXT 中的 成员。  NdisAllocateNetBufferListContext   NdisFreeNetBufferListContext   NET_BUFFER_LIST_CONTEXT_DATA_START   NET_BUFFER_LIST_CONTEXT_DATA_SIZE     4.1.2 Retreat和Advance操作  NDIS 提供 Retreat 和 Advance 功能来维护 NET_BUFFER 结构。Retreat 操作标记更多当前 驱动可用的数据空间。而 Advance 则释放一些当前驱动可用的数据空间。  一个 Retreat 操作必需发生成发送数据或返回发送数据给下层数据时。例如,在发送操 作期间一个驱动调用 NdisRetreatNetBufferDataStart 给头部数据预留出空间。  一个 Advance 操作必需发生成发送完成和从底层驱动接收数据时。例如,在接收数据期 间驱动调用 NdisAdvanceNetBufferStart 直接跳上层驱动不关心的下层驱动的头部数据。在这 种情况下,这些头部数据保留在未使用数据空间内。  下图展示了网络数据和这些操作的关系。    4.1.2.1 Retreat操作  Retreat 操作是增加一个 NET_BUFFER 或所有在 NET_BUFFER_LIST 中的 NET_BUFFER 的可 用数据空间。下面是 Retreat 操作相关的函数。  NdisRetreatNetBufferDataStart   NdisRetreatNetBufferListDataStart   Retreat 操作可以同时为 NET_BUFFER 分配一些 MDL,要提供一个分配机制,驱动可以 指定一个可选的 NetAlloceMdl 函数入口,如果把这个参数设为 NULL 则用默认的分配机制。 被分配的 MDL 必须被 NetFreeMdl 释放,提供了相应的分配机制也要有相应的释放机制。  要得到新的 DataLength,调用函数 NDIS 会添加驱动指定的 DataOffsetDelta 到当前的 DataLength。如果扩展的空间小于未使用的空间,那么就用当前的 DataOffset 减去 DataOffsetDelta 得到一个新的 DataOffset 并用当前的 DataLengh 加上 DataOffsetDelta 得到一 个新的 DataLength。  如果扩展的空间大于未使用的空间,Retreat 操作会分配新的数据空间。这时 NDIS 会调 整 DataOffset。  对一个发送操作来说,如果没有足够的未使用空间给 Retreat 操作 NDIS 会分配置。如果 不需要分配,NDIS 只是简单的调整 DataOffset 和 DataLength。要得到最好性能,驱动应该分 配足够的空间供下层驱动执行 Retreat 操作。  对一个接收返回的操作来说,Retreat 操作可以只简单的调整 DataOffset 和 DataLength。 它反转了接收处理中的 Advance 操作。在 Retreat 操作完成后又恢复了下层驱动信息到可使 用数据空间。  4.1.2.2 Advance操作  Aduvance 操作减少了 NET_BUFFER 和一个 NET_BUFFER_LIST 中的所有 NET_BUFFER 的可 使用数据空间。下面列出了相关的操作函数。  NdisAdvanceNetBufferDataStart   NdisAdvanceNetBufferListDataStart   Advanced 操作可以在些时候释放掉一些关联在 NET_BUFFER 上的数据空间。驱动可以在 调用函数时提供一个 NetFreeMdl 函数入口来提供一种释放机制。如果不提供 NDIS 会使用默 认的方法进行释放。对 MDL 的释放必须使用与分配相对应用的释放方法。  要获得一个新的 DataLength,NDIS 会用当前的 DataLength 减去 DataOffsetDelta 得到一 个新的。如果在 Retreat 操作时分配了新的空间那么,Advance 操作时可以释放这些新分配 的空间。如果不释放内存那么 NDIS 只是简单的调整一下 DataLength 和 DataOffset。  对于发送操作完成的情况,Advance 操作来可释放在 Retreat 操作时分配的内存。为了 更好的性能,驱动应该分配足够的空间给下层执行 Retreat 操作。  对于接收的情况,Advance 操作可以只简单的调整一下 DataLength 和 DataOffset。在 Advance 操作完成之后,低层驱动的头信息被保留到了未使用数据空间。  4.1.3 获得池句柄  下列 NDIS 池分配函数需要一个句柄来分配资源。  NdisAllocateNetBufferPool   NdisAllocateNetBufferListPool   NDIS 6.0 可以通过下面的方式来获得这个句柄。  协议驱动    协议驱动在调用 NdisRegisterProtocolDriver 时可以获得一个句柄,它用这个句柄来分配 池资源。  微端口驱动    NDIS 会调用微端口驱动的 MiniportInitializeEx 例程并传递一个句柄,它可以用这个句柄 来分配池资源。  中间层驱动    中间层驱动调用 NdisRegisterProtocolDriver 时可以获得一个句柄用它可以分配用于发送 操作的池。NDIS 会调用它的 MiniportInitializeEx 例程并传递一个句柄给它,它可以用这个句 柄分配用于接收操作的池。  过滤驱动(Filter Driver)    NDIS 在调用 FilterAttach 进会传递一个句柄,它可以用这个句柄来分配池。  其它驱动    如果一个驱动不能用上述方法获得句柄,那它可以调用 NdisAllocateGenericObject 来获 得一个句柄来分配池。  4.1.4 分发IRQL跟踪  为了提升系统性能,一些 NDIS 函数都包含一个分发级别用于指示函数执行时的 IRQL。 清楚及正确使用这些 IRQL 可以帮助我们避免必要的 IRQL 设定。  这些其它标记(other flag)是用来控制一些其它属性(other abbritues)的,它们的名字中 都包含了对应的 IRQL。  NDIS_SEND_FLAGS_DISPATCH_LEVEL  NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL  NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL  NDIS_RETURN_FLAGS_DISPATCH_LEVEL  NDIS_RWL_AT_DISPATCH_LEVEL  不对 IRQL 进行测试,调用者必须清楚当前执行的 IRQL 才能设置这些标记。例如,我知 道它是因为它在驱动设计中是固定的,或者在驱动中可以保存这个 IRQL。  如果知道当前的 IRQL 是 DISPATCH_LEVEL,调用者就必须设置这个标记。如果当前 IRQL 未知或调用者不运行在 DISPATCH_LEVEL 上,则不用设置这些标记(清除这个些标记)。如果 调用者是 NDIS,那被调用函数应该测试这些标记避免更改这些标记。  驱动不应该测试 IRQL 来决定标记的设置,测试将会出错。如果必要可以直接调用函数 做自我测试。决定应该不应该设置这些标记是驱动设计的工作。  4.1.5 发送和接收操作  在一次函数是调用中,NDIS6.0 驱动可以发送多个 NET_BUFFER_LIST,而每一个 NET_BUFFER_LIST 都可以是多个 NET_BUFFER。此外,同样可以指示完成多个这样的 NET_BUFFER_LIST。  在接收路径中,微端口驱动可以用 NET_BUFFER_LIST 指示一个接收。每一个被微端口驱 动指示的 NET_BUFFER_LIST 中包含一个 NET_BUFFER。但是本地 802.11 驱动可以包含多个 NET_BUFFER 结构。因为不同的协议绑定可以处理每一个 NET_BUFFER_LIST,而 NDIS 也可以 独立的返回每一个 NET_BUFFER_LIST 给微端口驱动。  对于 NDIS5.X 和更早的版本,NDIS 在基于 NDIS_PACKET 和基于 NET_BUFFER 之间提供了 一个转换层(用于做两者的兼容转换)。NDIS 在其中进行两者的转换。要避免性能下降就应 该在所有路径上支持 NET_BUFFER 结构和 NET_BUFFER_LIST 结构(即应用新的 NDIS 接口模 式)。  4.1.5.1 发送数据  下面是一个发送操作的图示,它包含协议驱动,NDIS 和微端口驱动。  协议驱动在一个绑定中调用 NdisSendNetBufferLists 发送一个 NET_BUFFER_LIST 结构。 NDIS 调用 MiniportSendNetBufferLists 将这个 NET_BUFFER_LIST 结构传递给下层驱动程序。  所有基于 NET_BUFFER 的发送操作都是异步的,微端口驱动调用 NdisMSendNetBufferListsComplete 返回一个 NET_BUFFER_LIST 并返回一个适当的状态。每一 个被发送的 NET_BUFFER_LIST 结构都可以被独立的完成。微端口驱动每一次调用 NdisMSendNetBufferListsComplete 时,NDIS 都会去调用协议驱动的 ProtocolSendNetBufferListsComplete 例程。  当 NDIS 调用用协议驱动的 ProtocolSendNetBufferListsComplete 时,协议驱动可以收回对 NET_BUFFER_LIST 及它所联结 NET_BUFFER 及其它资源的所有权。  微端口驱动和 NDIS 返回 NET_BUFFER_LIST 的顺序是不确定的(并不一定按发送的顺序 来)。在这个期间协议驱动应该保证与 NET_BUFFER_LIST 相联结的 NET_BUFFER 不被修改。  任何 NDIS 驱动都可以解除 NET_BUFFER 与 NET_BUFFER_LIST 的关系也可以解除 NET_BUFFER 与 MDL 的关系统(就是说可以在发送路径上对数据包做修改),但是必须返回 原来的 NET_BUFFER_LIST (做了修改当完成后返回给上层时要返回原来那个 NET_BUFFER_LIST)。例如,一个中间层驱动可以把一个 NET_BUFFER_LIST 分解成两个 NET_BUFFER_LIST 发送给下层驱动。但是当这两个 NET_BUFFER_LIST 发送完成后必须向上层 返回 NET_BUFFER_LIST 时必须返回原来(要求 NET_BUFFER 及相关 MDL 都要和原来的一样) 的那个 NET_BUFFER_LIST(中间层驱动直接产生的 NET_BUFFER_LIST 不能返回给上层驱动)。  协议驱动要用调用 NdisOpenAdapterEx 时 NDIS 提供的 NdisBindingHandle 来设置 NET_BUFFER_LIST 的 SourceHandle 成员。NDIS 使用这个成员返回协议驱动发送的 NET_BUFFER_LIST 结构。  中间层驱动也需要设置这个 NET_BUFFER_LIST 结构中的 SourceHandle 成员为自己调用 NdisOpenAdapterEx 时返回的 NdisBindingHandle。如果中间层驱动转发一个 NET_BUFFER_LIST 要在设置它的 SourceHandle 之前保存上层驱动设置的 SourceHandle。并前在转发完成后恢 复原先的 SourceHandle 后返回给上层驱动。  4.1.5.2 取消发送  下面图例中是一个取消发送操作的过程。    驱动可以调用 NDIS_SET_NET_BUFFER_LIST_CANCEL_ID 给每一个要传输到下层驱动的 NET_BUFFER_LIST 设置一个取消 ID。  在分配取消 ID 时我们应该先调用 NdisGeneratePartialCancelId 获得取消 ID 的最高位字 节。这是为了保证系统在任意两个驱动的取消 ID 不相同。典型的用法是在 DriverEntry 中调 用它一次来获得取消 ID 的最高字节,但是也可以在不同的地方调用多次获得多个取消 ID 的 最高字节。  要取消一个未完成的发送操作,驱动可以通过取消 ID 来调用过 NdisCancelSendNetBufferLists 函数(它其中一个参数是要取消的发送 NET_BUFFER_LIST 被设 置的取消 ID)。驱动可以用 NDIS_GET_NET_BUFFER_LIST_CANCEL_ID 获得 NET_BUFFER_LIST 的取消 ID。  如果驱动对所有发送的 NET_BUFFER_LIST 设置相同的取消 ID 那么只要一次取消调用就 会取消所有的发送。对一组 NET_BUFFER_LIST 设置相同的取消 ID 对这个取消 ID 的一次取消 调用则会取消这一组的发送。  NDIS 会调用在绑定上的适当低层驱动的 MiniportCancelSend,取消正在进行的传输后, 微端口驱动调用 NdisMSendNetBufferListsComplete 返回 NET_BUFFER_LIST 和一个 NDIS_STATUS_CANCELLED 状态。NDIS  会调用适当驱动的 PotocolSendNetBufferListsComplete 函数。在这个函数中回收资源时应该设置相关 NET_BUFFER_LIST 的取消 ID 为 NULL,防止它 再次被使用时出现问题。  4.1.5.3 接收数据  下面图例是基于一个接收操作的,包括微端口驱动、NDIS 和协议驱动。  微端口驱动可以调用 NdisMIndicateReceiveNetBufferLists 来给上层驱动指示数据。这些 数据组 NET_BUFFER_LIST 来组织。协议驱动接收到 NET_BUFFER_LIST 后可以对它进行修改转 发给客户端。同样的驱动也可以,附加更多附加信息在 NET_BUFFER_LIST 中。  可以把所有要指示给上层驱动的 NET_BUFFER_LIST 链接到一起通过 NdisMIndicateReceiveNetBufferLists 来指示给上层驱动。NDIS 会校验这些 NET_BUFFER_LIST 结构并调用每一个绑定协议驱动的 ProtocolReceiveNetBufferLists 。 NDIS 仅仅把 NET_BUFFER_LIST 传递给那下正确有绑定了的协议驱动。同时会匹配 NET_BUFFER_LIST 中 NetBufferListFrameType(协议驱动在注册是会注册相应该的帧类型与之匹配后 NDIS 才转发 给它)来确定转发给某个协议驱动。  如果设置了给 ReceiveFlag 设置了 NDIS_RECEIVE_FLAGS_RESOURCES 标记,它会传递给上 层的协议驱动。NDIS 会在协议驱动的 ProtocolReceiveNetBufferLists 调用返回后收回资源(传 给协议驱动的 NET_BUFFER_LIST 及与之关联的所有资源)的所有权。  注意:如果设置了这个标记上层驱动应该尽快处理返回资源给下层驱动。同时在返回时 要恢复对资源的修改。例如,一个收如此标记的上层驱动,可以对 NET_BUFFER_LIST 及相关 资源进行修改,但返回 NDIS 进要确保 NET_BUFFER_LIST 是原始的内容(这里主要指资源本 身,如果其中的 NET_BUFFER 链,及 NET_BUFFER 中的 MDL 链,而其中的数据内容则不必要 恢复原始中)。  如果没有设置这个标记那么协议驱动则持有对这个 NET_BUFFER_LIST 的所有权。协议驱 动可以对它进行排队延后处理(注意,如果传递了标记则必须在函数内完成处理因为函数返 回后这个 NET_BUFFER_LIST 不用属于协议驱动了)。在这种情况下协议驱动必须调用 NdisReturnNetBufferLists 来返还资源给下层驱动。  如果下层的微端口驱动运行在低资源情况下,可以在指示数据给上层时传递这个标记。 这个微端口驱动就可以在指示结束后恢复所有指示所用资源的所有权。  当协议驱动调用 NdisReturnNetBufferLists 后 NDIS 会调用微端口驱动的 MiniportRetrunNetBufferLists 例程。  注意:如果一个微端口驱动指示数据给上层时传递了 NDIS_RECEIVE_FLAGS_RESOURCES 标记那么 NDIS 将不会调用它的 MiniportRetrunNetBufferLists。微端口对资源的所有权会在 NdisMIndicateReceiveNetBufferLists 返回时自动恢复。  NDIS 返回 NET_BUFFER_LIST 的顺序并不和微端口驱动调用 NdisMIndicateReceiveNetBufferLists 的顺序一致,NDIS 可以以任何顺序返回 NET_BUFFER_LIST。    微端口驱动在指示数据给上层时应该设置 NET_BUFFER_LIST 的 SourceHandle 成员。这个 成员应该设置为 NDIS 在微端口驱动的 MiniprotInitEx 中传递的那个 MiniprotAdapterHandle 句柄。NDIS 要利用这个成员返回 NET_BUFFER_LIST 结构微端口驱动。    中间层驱动也要在指示数据给上层时应该设置 NET_BUFFER_LIST 的 SourceHandle 成员。 这个成员应该设置为 NDIS 在中间层驱动的 MiniprotInitEx 中传递的那个 MiniprotAdapterHandle 句柄。如果要转发这个接收指示,驱动要保存下层驱动设置的 SourceHandle 值后再设置这个句柄为中间层驱动的。当 NDIS 返回 NET_BUFFER_LIST 给中间 层驱动时,要重新恢复原来的 SourceHandle 值再调用 NdisMReturnNetBufferLists 返回给下层 驱动。  4.1.5.4 NDIS回环包  如果 NET_BUFFER_LIST 的成员 NblFlags 设置了 NDIS_NBL_FLAGS_IS_LOOPBACK_PACKET 标记,那说明这个包是一个回环包。协议驱动和 Filter  Driver 可以检查这个标记判断这个包 是不是回环包。  回环包要被回传回来要满足下面三个条件:  1) 下层微端口的类型必须是 NdisMedium802_3  或 NdisMedium802_5  2) 下面三个条件之一必须满足:  a) 协议绑定设置了 OID 的 OID_GEN_CURRENT_PACKET_FILTER  请求设定了 NDIS_PACKET_TYPE_PROMISCUOUS 标记或下面条件为真。  z 多个绑定到微端口驱动  z 一个 Filter Module 附加到微端口并且注册了接收控制器  b) 协议绑定设置了 OID 的 OID_GEN_CURRENT_PACKET_FILTER  请求设定了 NDIS_PACKET_TYPE_ALL_LOCAL 标记或下面条件为真。  z 多个绑定到微端口驱动  z 一个 Filter Module 附加到微端口并且注册了接收控制器  c) 调用者设置 NdisSendNetBufferLists 的 SendFlags 参数的 NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK 标记  3) 包符合微端口的包过滤设置。例如下面:  a) 如果是一个直接包,它的目的 MAC 地址和微端口的 MAC 地址一样。  b) 如果是一个多播包,微端口的过滤设置了 NDIS_PACKET_TYPE_ALL_MULTICAST 标记或目标地址匹配微端口的多播地址列表且端口的过滤设置了 NDIS_PACKET_TYPE_ALL_MULTICAST 标记  c) 如果是一个广播包,微端口的过滤设置了 NDIS_PACKET_TYPE_BROADCAST 标 记。  d) 微端口的过滤设置了 NDIS_PACKET_TYPE_PROMISCUOUS 或  NDIS_PACKET_TYPE_ALL_LOCAL 标记。  一个协议绑定要接收回环包要满足下面条件:  1) 协议绑定是回环包原始发送者。  2) 协议绑定不能设置 NDIS_PACKET_TYPE_NO_LOCAL 过滤。  一个协议绑定不接收回环包要满足下面条件:  1) 协议绑定设置了 NDIS_PACKET_TYPE_NO_LOCAL 过滤且协议绑定是回环包原始 发送者。  2) 协议绑定是原始发送者但没有不能设置 SendFlags 的 NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK 标记。  下面图显示了回环包的运算逻辑:    4.1.6 以太网发送和接收操作  4.1.6.1 发送以太网帧  Windows Vista 的 TCP/IP 协议支持对一组以太网帧的发送。任何引发发送或修改发送的 上层驱动都必须遵循 TCP/IP 协议规范。  注意:如果任何上层驱动不遵循下面的规则那么下层的驱动的行为将不可预测。  1) 如果要发送一个以太网帧必须分配一个 NET_BUFFER_LIST 结构用于存放以太网帧。每一 个 NET_BUFFER_LIST 必须包含一个带外数据块(OOB),它被定义在 NET_BUFFER_LIST 是 NetBufferListInfo 成员中,被一些特殊处理使用。  2) 如果要发送一个以太网帧必须为以太网帧分配一个或多个 NET_BUFFER 结构且链接到帧 的 NET_BUFFER_LIST 结构中。  3) 必须保证 NET_BUFFER_LIST 中的 NET_BUFFER 描述的是同一种类形的以太网帧。  4) 必须保证NET_BUFFER_LIST中的NET_BUFFER描述的以太网帧是有相同源和目的MAC的。  5) 如果发送的是 TCP 或 UDP 包,那么 NET_BUFFER_LIST 中的所有 NET_BUFFER 必须是同一 TCP 或 UDP 链接的包。  6) 不能把一个 MAC 头分别放在多个 MDL 中。如果这样做部分 MAC 头会被当成 VLAN 标记。  7) 如果驱动改变了在NET_BUFFER中的MDL链或在NET_BUFFER_LIST中的NET_BUFFER_LIST 则需要在返加 NET_BUFFER_LIST 给上层驱动之前时恢复原始的状态。但 NET_BUFFER_LIST 之间的链接关系不需要和原来的一样(如果返回多个 NET_BUFFER_LIST 时)。  4.1.6.2 接收以太网帧  Windows Vista 的 TCP/IP 协议支持对一组以太网帧的接收。任何引发接指示或修改接收 指示的下层驱动都必须遵循 TCP/IP 协议规范。  注意:如果存在驱动不做下面这些需求英,那上层驱动可能行为不可预测。  驱动接收以太网帧必须遵循下面的规范。  1) 驱动必须分配一个 NET_BUFFER_LIST 结构用于存放以太网帧。每一个 NET_BUFFER_LIST 必须包含一个带外数据块(OOB),它被定义在 NET_BUFFER_LIST 是 NetBufferListInfo 成 员中,被一些特殊处理使用。  2) 必须为以太网帧分配 NET_BUFFER 结构且链接到帧的 NET_BUFFER_LIST 结构中。注意: 一个以太网帧可以被分离成多块存储在 MDL 中链接到 NET_BUFFER 结构中。  3) 对于 VISTA 版本不允许把一个接收的以太网帧分成多份存储在 MDL 中。但是以后的版本 会允许这样做。  4) 任何 Windows 版本中都不能分离(在一个 NET_BUFFER_LIST 中把数据分别存储到多个 MDL 中)IP 头,IPV4 选项,IPSEC 头,IPV6 扩展头或上层协议头,除非第一个 MDL 中包 含了个 NDIS 支持的前视数据(LOOKHEAD)长度的数据  5) 如果下层驱动遵循上述规则那到任何 NDIS6.0 以后的协议驱动和 Filter Driver 都应该支持 以太网帧的分片存储(在一个 NET_BUFFER_LIST 中把数据分别存储到多个 MDL 中)。这 样做是为了这些驱动在以后的 Windows 版本中兼容运行。    4.1.7 派生NET_BUFFER_LIST结构  NDIS6.0 提供函数来管理 NET_BUFFER_LIST 结构还可以从其它的 NET_BUFFER_LIST 派生 结构。这些函数经常被中间层驱动使用。  下面这些函数就支持从一个已经存在的 NET_BUFFER_LIST 中创建一个派生结构。  NdisAllocateCloneNetBufferList   NdisAllocateFragmentNetBufferList   NdisAllocateReassembledNetBufferList   这些函数改善了系统性能,因为这些函数在派生的过程中并不复制网络数据。可以对已 经存在的 NET_BUFFER_LIST 做以下三种派生操作。  克隆(Clone)    克隆一个 NET_BUFFER_LIST 的副本(它还是引用原来的数据),可以用克隆的副本发送 到多个传输路径。  分片(Fragrance)    一个分片 NET_BUFFER_LIST 结构包含一个 NET_BUFFER 集(它还是引用原来的数据)。 但是,数据被划分成不超过最大大小的单元。驱动可以有效将大缓冲区分解在小的。  重组(Reassembled)    一个重组的 NET_BUFFER_LIST 结构包含一个 NET_BUFFER_LIST 结构(它是引用原来多个 NET_BUFFER 结构的原始数据)。驱动可以利用这个操作来合并多个小的 NET_BUFFER_LIST 成 一个大的 NET_BUFFER_LIST。  4.1.7.1 NET_BUFFER_LIST结构的派生关系  驱动的编写者应该知道和维护经过克隆,分片,重组后派的子结构与父结构之间的关系。 这些关系主要是为了保证在父结构被释放后才能释放子结构。它应用下列规则。  1) 当一个驱动从 NET_BUFFER_LIST 创建了一个子结构后,驱动应该保留父结构的所有权, 传递时传递子结构给其它驱动。驱动决不能把父结构传递给其它驱动。  2) 驱动应该仅更新父结构中的子结构数。因为父结构不传递给它其它驱动,所以子结构数 被覆盖的机会很小。驱动应该设置子结构中的父指针指向父结构。  3) 当驱动从其它驱动收到一个 NET_BUFFER_LIST 时是不能更改它的父指示的。如果接收到 的是一个子结构那它的父指针是被设置过的。  4) NDIS 不强制上述规则。当前 NET_BUFFER_LIST 的所有者必须管理维护子结构数和父指针。 例如,一个驱动对当前的 NET_BUFFER_LIST 进行了克隆和分片,就必须管理维护好相关 的父指针和子结构总数。  5) NDIS 在分配一个 NET_BUFFER_LIST 时总是置它的父指针和子结构数据为 0。NDIS 在任何 时间向其它驱动传递这个结构时也不会修改它们。  4.1.7.2 克隆  一个驱动从一个已经存在的 NET_BUFFER_LIST 克隆一个新的结构,这样新克隆的结构引 用的还是原始的数据。驱动可以利用这种方法在多个路径上有效的传输相同的数据。  下面展示了父结构和克隆结构之间的关系。  驱动调用 NdisAllocateCloneNetBufferList 函数来克隆一个已经存在的 NET_BUFFER_LIST, 它分新分配一个 NET_BUFFER_LIST 和 NET_BUFFER 及 MDL 同时引用原来的数据,这里并不复 制数据(注意:这里并没有复制网络数据,即 MDL 描述的数据只是被引用了)。但是它不会 克隆 NET_BUFFER_LIST 的 NET_BUFFER_LIST_CONTEXT 结构成员。要释放这个克隆的新结构调 用 NdisFreeCloneNetBufferList。  4.1.7.3 分片  下面图展示了父结构与分片子结构之间的关系。  驱动可以调用 NdisAllocateFragmentNetBufferList 来分片一个已经存在的 NET_BUFFER_LIST 结构。它新分配一个 NET_BUFFER_LIST 结构和多个 NET_BUFFER 及 MDL 结 构,不会分配 NET_BUFFER_LIST_CONTEXT 结构成员。其网络数据也不复制,只是引用原来 的。  如果父结构有多个 NET_BUFFER 和单个的分片方法是一样的。例如,如果有一个父结构 有两个 NET_BUFFER,第一个 NET_BUFFER 分片后剩下的空间小于分片的长度,这时也不会 把它同下一个 NET_BUFFER 分并再分片,会像一个 NET_BUFFER 那做处理。  驱动使用 NdisFreeFragmentNetBufferList 来释放分片生成的 NET_BUFFER_LIST 结构。  4.1.7.4 重组  下图展示了重结构包与父结构之间的关系。  驱动可以调用 NdisReassemledNetBufferList 重组一个已经存在的 NET_BUFFER_LIST 结构, 它会新分配一个 NET_BUFFER_LIST 和 NET_BUFFER 及 MDL ,但是不分配 NET_BUFFER_LIST_CONTEXT 成员结构。重组的结构只是引用原来的数据并不复制数据。    驱动可以调用 NdisFreeReassemledNetBufferList 释放重组时生成的 NET_BUFFER_LIST,同 时释放与之前链的 NET_BUFFER 和 MDL 链。  4.2 指定NDIS版本信息  大多数 NDIS 结构都有一个版本信息的头(Header)成员,NDIS 和 Ndis 驱动都要设置这 个成员结构。NDIS 驱动应该在访问结构的其它成员之前先检查这个结构。此外,NDIS 驱动 在初始化其间也应该要 NDIS 指示版本信息。  4.2.1 概览NDIS支持的版本  Header 成员是一个 NDIS_OBJECT_HEADER 结构,这个结构包含保留成员,类型和长度三 个成员。  它的这些成员要符合下面的需求:  1) 在一个结构中如果在新的 NDIS 版本中为其添加了新的成员那它的保留(revision)成员 会有一个新的值。例如,在 NDIS6.1 中在结构的末尾添加了一个联合体或一个字节域, 那个 Header 成员中的保留成员会有一个新的值。  2) 一个结构被改变后,后面版本结构的长度可能会大于早期版本结构的长度,但是不能小 于早期版本的长度。后面版本新添加的成员要放到结构的末尾。  3) 如果结构早期版本的信息仍然有效且完整结构仅新加一个新的版本号。在这种情况下应 该对老的版成员支持。注意:如果上述条件不满足 NDIS 会提供一个新命名的结构来替 代原来的结构。  4) NDIS 驱动应该使用预定义的保留版本值。  5) Header.Size 的值应该和 Header.Revision 的值保持一致。这就是说如果它们应该保持是同 下版本相对应的对值。  4.2.2 NDIS驱动需要支持的版本信息  NDIS 结构提供一了个 Header 成员来保存版本信息且 NDIS 驱动也需要对它进行支持。 NDIS 支持驱动运行在不同版本操作系统所支持的 NDIS 接口上。此处,高版本的 NDIS 驱动 可以在低版本的 NDIS 上注册。例如:一个 NDIS5.X 或 6.1 的驱动可以注册在只支持 NDIS6.0 版本的操作系统上。对于 NDIS6.1 的驱动则必须检查当前 NDIS 的版本同时注册为驱动后对 上级别的驱动做适当的支持。注意:驱动不需要对之前版本的所有结构特性进行支持。例如 一个驱动创建了 revision 2 版本的一个结构只需要适当的支持 revision1 版本的成员即可。  要访问结构的成员信息必须完成下列处理:  1) 在访问任何成员之前先检查 Header.revision 和 Header.size。  2) 对于早期版的结构其 Header.revision 和 Header.size 必须匹配,同时必须根据这两个对应 的 NDIS 版对结构进行正确的访问。  3) 对于一个之后版本的结构,可以使用这个结构里的信息。对于高版本的结构总是兼容低 版本的结构。  4) 一个驱动使用结构的版本信息必须和其注册的版本信息相匹配。如一个驱动注册为 6.1 的 NDIS 驱动那么它也应该使用 NDIS6.1 的结构。  5) NDIS 驱动成功的完成一个 OID 请求后必须设置 NDIS_OID_REQUEST 的 SupportedRevision 成员。这个值是要设置为请求发起者的 revision 版本。  6) 要决定请求是不是被下层驱动完成了,要检查 OID 请求返回来的 SupportedRevision 值。    4.2.3 NDIS需要的版本信息  NDIS 通过头部标识的不同版信息来保证在不同的 NDIS 版上使驱动兼容。在支持头版本 信息上 NDIS 主要负责下面两点  1) 被操纵结构的版本信息低于 NDIS 的版本;NDIS 检查头部信息并对基于相应的修订版对 结构进行解释。  2) 如果一个驱动使用了错误的版本信息则使调用失败并返回适当的错误码;比如在在 NDIS6.1 上使用了 XXX_REVISION_2 这种版本信息 NDIS 就会使调用失败。  4.2.4 获得NDIS版本  NDIS 的版本在相同的计算机上也可能是不同的,例如我们可以通 RtlGetVersion 和 RtlVerifyVersionInfo 来获系统的版本信息,但我们不能依此来判断 NDIS 的版本信息。NDIS 驱动要获得 NDIS 的版本信息可以用 NdisGetVersion。  4.2.5 NDIS  对象版本发布到WMI  这个主题是关于 NDIS 对像版本对 WMI 的支持。WMI 的管理对像格式化文件是没有版 本的,因此如果对 NDIS 结果有了新的修订,添加了多个域就要添加到管理对像格式化文件 中去。同时应用程序在查询和设置一个版本时也必须检查了提供相关的修订版本信息。     

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享文档获得金币 ] 2 人已下载

下载文档

相关文档