和NIC小端口驱动不同的是,无需考虑网络数据具体是如何传输的,只需要针对NBL进行处理即可。Filter驱动程序可以启动发送请求和接收指示,或“过滤”其他驱动程序的请求和指示。Filter模块堆叠在微型端口适配器上。
驱动程序堆栈中的Filter模块可以筛选与基础适配器关联的所有发送请求和接收指示。 这适用于适配器的所有协议绑定。
Filter驱动程序不直接支持基于 NDIS_PACKET 结构的旧发送和接收操作。 相反,NDIS 将接收来自旧微型端口驱动程序的指示转换为 NET_BUFFER 结构。 此外,NDIS 还处理从基于NET_BUFFER结构的发送请求到基于NDIS_PACKET结构的旧发送请求的所需转换。
Filter驱动程序缓冲区管理
Filter驱动程序创建缓冲区以复制从其他驱动程序获取的网络数据,或启动发送或接收操作。
如果Filter驱动程序不创建缓冲区,则驱动程序不会管理缓冲池。 此类驱动程序只是传递它从其他驱动程序接收的缓冲区。
创建缓冲区以支持发送或接收操作的Filter驱动程序必须管理 NET_BUFFER_LIST 结构池和 NET_BUFFER 结构池。
若要创建这些池,驱动程序会调用以下函数:
- NdisAllocateNetBufferListPool
- NdisAllocateNetBufferPool
Filter驱动程序可以使用以下函数从池中分配结构:
- NdisAllocateNetBufferAndNetBufferList
- NdisAllocateNetBufferList
- NdisAllocateNetBuffer
调用 NdisAllocateNetBufferAndNetBufferList 比调用 NdisAllocateNetBufferList 和 NdisAllocateNetBuffer 更高效。 但是, NdisAllocateNetBufferAndNetBufferList 仅在NET_BUFFER_LIST结构上创建一个NET_BUFFER结构。 若要使用 NdisAllocateNetBufferAndNetBufferList,驱动程序必须在调用 NdisAllocateNetBufferListPool 时将 AllocateNetBuffer 参数设置为 TRUE。
源自发送请求的Filter驱动程序应确定基础驱动程序的上下文和回填空间要求。 Filter驱动程序使用重启属性来确定基础驱动程序的回填要求。 Filter驱动程序应确定处于 “正在重启” 状态的回填和上下文要求。 驱动程序应为整个堆栈分配足够的回填和上下文空间。 如有必要,Filter驱动程序可以释放池并将其重新分配为 “正在重启” 状态。
Filter驱动程序使用以下函数来释放池:
- NdisFreeNetBufferListPool
- NdisFreeNetBufferPool
Filter驱动程序使用以下函数释放从池中分配的结构:
- NdisFreeNetBufferList
- NdisFreeNetBuffer
在释放关联的NET_BUFFER_LIST结构之前,驱动程序应释放使用 NdisAllocateNetBuffer 分配NET_BUFFER结构。 当驱动程序为关联的NET_BUFFER_LIST结构调用 NdisFreeNetBufferList 时,将释放使用 NdisAllocateNetBufferAndNetBufferList 分配的NET_BUFFER结构。
从Filter驱动程序发送数据
发送Filter驱动程序启动的请求
Filter驱动程序可以启动发送请求或过滤驱动程序启动的发送请求。 当协议驱动程序调用 NdisSendNetBufferLists 函数时,NDIS 会将指定的 NET_BUFFER_LIST 结构提交到驱动程序堆栈中最顶层的Filter模块,下图演示了Filter驱动程序启动的发送操作。
Filter驱动程序调用 NdisFSendNetBufferLists 函数以发送 在NET_BUFFER_LIST 结构列表中定义的网络数据。
Filter驱动程序必须将它创建的每个NET_BUFFER_LIST结构的 SourceHandle 成员设置为它传递给 NdisFSendNetBufferLists 的 NdisFilterHandle 参数的相同值。 NDIS 驱动程序不应修改该驱动程序未源自NET_BUFFER_LIST结构的 SourceHandle 成员。
在调用 NdisFSendNetBufferLists 之前,Filter驱动程序可以设置随 NET_BUFFER_LIST_INFO 宏一起发送请求的信息。 基础驱动程序可以使用 NET_BUFFER_LIST_INFO 宏检索此信息。
Filter驱动程序一旦调用 NdisFSendNetBufferLists,就会放弃NET_BUFFER_LIST结构和所有关联资源的所有权。 NDIS 可以处理发送请求或将请求传递给基础驱动程序。
NDIS 调用 FilterSendNetBufferListsComplete 函数,将结构和数据返回到Filter驱动程序。 在将列表传递给 FilterSendNetBufferListsComplete 之前,NDIS 可以将多个发送请求中的结构和数据收集到NET_BUFFER_LIST结构的单个链接列表中
在 NDIS 调用 FilterSendNetBufferListsComplete 之前,发送请求的当前状态是未知的。 在 NDIS 将结构返回到 FilterSendNetBufferListsComplete 之前,Filter驱动程序绝不应尝试检查NET_BUFFER_LIST结构或任何关联数据。
FilterSendNetBufferListsComplete 执行完成发送操作所需的任何后处理。
当 NDIS 调用 FilterSendNetBufferListsComplete 时,Filter驱动程序将重新获得与 NetBufferLists 参数指定的NET_BUFFER_LIST结构关联的所有资源的所有权。 FilterSendNetBufferListsComplete 可以释放这些资源 ,例如,通过调用 NdisFreeNetBuffer 和 NdisFreeNetBufferList 函数 ,或者准备在后续调用 NdisFSendNetBufferLists 时重复使用。
NDIS 始终按照传递给 NdisFSendNetBufferLists 的Filter驱动程序确定的顺序向基础驱动程序提交Filter提供的网络数据。 但是,按指定顺序发送数据后,基础驱动程序可以按任意顺序返回缓冲区。
Filter驱动程序可以请求其发起的发送请求的环回。 若要请求环回,驱动程序在 NdisFSendNetBufferLists 的 SendFlags 参数中设置NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK标志。 NDIS 指示包含发送数据的已接收数据包。
注意 Filter驱动程序应跟踪其发起的发送请求,并确保在此类请求完成时不会调用 NdisFSendNetBufferListsComplete 函数。
过滤发送请求
下图说明了如何过滤由过度分配的驱动程序发起的发送请求:
NDIS 调用Filter驱动程序的 FilterSendNetBufferLists 函数来筛选过大驱动程序的发送请求。
Filter驱动程序不得修改从其他驱动程序接收的 NET_BUFFER_LIST 结构中的 SourceHandle 成员。
Filter驱动程序可以筛选数据并将筛选的数据发送到基础驱动程序。 对于提交到 FilterSendNetBufferLists 的每个NET_BUFFER结构,Filter驱动程序可以执行以下操作:
- 通过调用 NdisFSendNetBufferLists 函数,将缓冲区传递到下一个基础驱动程序。 NDIS 保证上下文空间的可用性, 查看Filter驱动程序 NET_BUFFER_LIST_CONTEXT结构。 Filter驱动程序可以在调用 NdisFSendNetBufferLists 之前修改缓冲区内容。 筛选数据的处理与Filter驱动程序启动的发送操作一样进行;
- 通过调用 NdisFSendNetBufferListsComplete 函数删除缓冲区;
- 在本地数据结构中将缓冲区排队,供以后处理。 Filter驱动程序的设计决定了导致驱动程序处理排队缓冲区的原因。 一些示例包括超时后的处理或在收到特定缓冲区后进行处理。注意 如果驱动程序将发送请求排队以供以后处理,则必须支持发送取消请求。 有关发送取消请求的详细信息,请参阅 在Filter驱动程序中取消发送请求;
- 复制缓冲区,并使用副本发起发送请求。 发送操作类似于Filter驱动程序发起的发送请求。 在这种情况下,驱动程序必须通过调用 NdisFSendNetBufferListsComplete 函数,将原始缓冲区返回到上置驱动程序;
完成发送请求会继续上行驱动程序堆栈。 当微型端口驱动程序调用 NdisMSendNetBufferListsComplete 函数时,NDIS 将调用 FilterSendNetBufferListsComplete 函数以获取最低覆盖Filter模块。
发送操作完成后,Filter驱动程序将反转对Filter驱动程序在 FilterSendNetBufferLists 中对过度覆盖驱动程序的缓冲区描述符的修改。 驱动程序调用 NdisFSendNetBufferListsComplete 函数,以将NET_BUFFER_LIST结构的链接列表返回到上部驱动程序,并返回发送请求的最终状态。
当最顶层的Filter模块调用 NdisFSendNetBufferListsComplete 时,NDIS 将调用原始协议驱动程序的 ProtocolSendNetBufferListsComplete 函数。
不提供 FilterSendNetBufferLists 函数的Filter 驱动程序仍然可以启动发送请求。 如果此类驱动程序确实启动发送请求,则必须提供 FilterSendNetBufferListsComplete 函数,并且不得在驱动程序堆栈上传递完整事件。
Filter驱动程序可以传递或筛选过大驱动程序的环回请求。 若要传递环回请求,如果 NDIS 在 FilterSendNetBufferLists 的 SendFlags 参数中设置NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK,Filter驱动程序在调用 NdisFSendNetBufferLists 时在 SendFlags 参数中设置NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK。 NDIS 指示包含发送数据的已接收数据包。
通常,如果Filter驱动程序以 NDIS 无法提供标准服务(如环回 )的方式修改任何行为,则Filter驱动程序必须为 NDIS 提供该服务。 例如,修改硬件地址请求 ( OID_802_3_CURRENT_ADDRESS) 的Filter驱动程序应处理定向到新硬件地址的缓冲区的环回。 在这种情况下,NDIS 无法提供它通常提供的环回服务,因为Filter更改了地址。 此外,如果Filter驱动程序设置杂乱模式 ,例如OID_GEN_CURRENT_PACKET_FILTER),则它不应将其收到的额外数据传递给过度覆盖的驱动程序。
取消Filter驱动程序中的发送请求
Filter驱动程序可以取消发送由Filter驱动程序发起或由过度分配驱动程序发起的请求。
取消Filter驱动程序发送请求
下图说明了如何取消由Filter驱动程序发起的发送请求:
Filter驱动程序为它为发送操作创建的每个NET_BUFFER_LIST结构调用 NDIS_SET_NET_BUFFER_LIST_CANCEL_ID宏。 NDIS_SET_NET_BUFFER_LIST_CANCEL_ID 函数使用取消标识符标记指定的数据。
在将取消 ID 分配给网络数据之前,Filter驱动程序必须调用 NdisGeneratePartialCancelId 以获取它分配的每个取消 ID 的高序字节。 这可确保驱动程序不会重复系统中其他驱动程序分配的取消 ID。 驱动程序通常从 DriverEntry 例程调用 NdisGeneratePartialCancelId 一次。 但是,驱动程序可以通过多次调用 NdisGeneratePartialCancelId 来获取多个部分取消标识符。
若要取消标记NET_BUFFER_LIST结构中数据的挂起传输,Filter驱动程序会将取消 ID 传递给 NdisFCancelSendNetBufferLists 函数。 驱动程序可以通过调用 NDIS_GET_NET_BUFFER_LIST_CANCEL_ID 宏来获取 NET_BUFFER_LIST 结构的取消 ID。
如果Filter驱动程序使用相同的取消标识符标记所有NET_BUFFER_LIST结构,则只需调用 NdisFCancelSendNetBufferLists 即可取消所有挂起的传输。 如果Filter驱动程序使用唯一标识符标记NET_BUFFER_LIST结构的子组中的所有NET_BUFFER_LIST结构,则只需调用 NdisFCancelSendNetBufferLists 即可取消该子组中所有挂起的传输。
NDIS 调用基础驱动程序的取消发送函数。 中止挂起的传输后,基础驱动程序调用 send complete 函数 (例如 NdisMSendNetBufferListsComplete) ,以返回完成状态为NDIS_STATUS_SEND_ABORTED的NET_BUFFER_LIST结构。 NDIS 又调用Filter驱动程序的 FilterSendNetBufferListsComplete 函数。
在 FilterSendNetBufferListsComplete 中,Filter驱动程序可以在 CancelId 设置为 NULL 的情况下调用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID。 这可以防止NET_BUFFER_LIST意外地再次使用过时的取消 ID。
取消发送由过度覆盖驱动程序发出的请求
下图说明了如何取消由过度分配的驱动程序发起的发送请求:
过度调用驱动程序 ( NdisFCancelSendNetBufferLists 或 NdisCancelSendNetBufferLists) 取消未完成的发送请求。 在发出发送请求之前,这些过度的驱动程序必须使用取消 ID 标记发送数据。
NDIS 调用Filter驱动程序的 FilterCancelSendNetBufferLists 函数来取消所有标有指定取消标识符的 NET_BUFFER_LIST 结构的传输。
FilterCancelSendNetBufferLists 执行以下操作:
- 遍历指定Filter模块的已排队NET_BUFFER_LIST结构的Filter驱动程序列表,并调用 NDIS_GET_NET_BUFFER_LIST_CANCEL_ID 宏以获取每个结构的取消标识符。 Filter驱动程序将NDIS_GET_NET_BUFFER_LIST_CANCEL_ID返回的取消 ID 与 NDIS 传递给 FilterCancelSendNetBufferLists 的取消 ID 进行比较;
- 从发送队列中删除 (取消链接) 其取消标识符与指定取消标识符匹配的所有NET_BUFFER_LIST结构;
- 为所有未链接的NET_BUFFER_LIST结构调用 NdisFSendNetBufferListsComplete 函数以返回结构。 Filter驱动程序将NET_BUFFER_LIST结构的状态字段设置为NDIS_STATUS_SEND_ABORTED;
- 调用 NdisFCancelSendNetBufferLists 函数,将取消发送请求传递给基础驱动程序。 Filter驱动程序传递它从过度的驱动程序收到的取消标识符。 取消操作与Filter驱动程序发起的取消发送操作一样继续;
在Filter驱动程序中接收数据
Filter驱动程序可以启动接收指示,也可以从基础驱动程序启动Filter接收指示。 当微型端口驱动程序调用 NdisMIndicateReceiveNetBufferLists 函数时,NDIS 会将指定的 NET_BUFFER_LIST 结构提交到驱动程序堆栈中最低的过度筛选模块。
接收Filter驱动程序启动的指示
下图演示了Filter驱动程序启动的接收指示。
Filter驱动程序调用 NdisFIndicateReceiveNetBufferLists 函数来指示收到的数据。 NdisFIndicateReceiveNetBufferLists 函数将堆栈上NET_BUFFER_LIST结构的指示列表传递给超载驱动程序。 Filter驱动程序从它在初始化期间创建的池中分配结构。
如果Filter驱动程序在 NdisFIndicateReceiveNetBufferLists 的 ReceiveFlags 参数中设置NDIS_RECEIVE_FLAGS_RESOURCES标志,则表示Filter驱动程序必须立即重新获得NET_BUFFER_LIST结构的所有权。 在这种情况下,NDIS 不会调用Filter驱动程序的 FilterReturnNetBufferLists 函数来返回 NET_BUFFER_LIST 结构。 Filter驱动程序在 NdisFIndicateReceiveNetBufferLists 返回后立即重新获得所有权。
如果Filter驱动程序未在 NdisFIndicateReceiveNetBufferLists 的 ReceiveFlags 参数中设置NDIS_RECEIVE_FLAGS_RESOURCES标志,则 NDIS 会将指示的NET_BUFFER_LIST结构返回到Filter驱动程序的 FilterReturnNetBufferLists 函数。 在这种情况下,Filter驱动程序将放弃所指示结构的所有权,直到 NDIS 将它们返回到 FilterReturnNetBufferLists。
注意 Filter驱动程序应跟踪它启动的接收指示,并确保它在接收操作完成时不调用 NdisFReturnNetBufferLists 函数。
过滤接收指示
下图演示了基础驱动程序启动的过滤接收指示:
NDIS 调用Filter驱动程序的 FilterReceiveNetBufferLists 函数来处理来自基础驱动程序的接收指示。 NDIS 在基础驱动程序调用接收指示函数后调用 FilterReceiveNetBufferLists , (例如 ,NdisMIndicateReceiveNetBufferLists) 来指示接收的网络数据或环回数据。
如果未设置 FilterReceiveNetBufferLists 的 ReceiveFlags 参数中的NDIS_RECEIVE_FLAGS_RESOURCES标志,Filter驱动程序将保留NET_BUFFER_LIST结构的所有权,直到调用 NdisFReturnNetBufferLists 函数。
如果设置了 ReceiveFlags 参数中的NDIS_RECEIVE_FLAGS_RESOURCES标志,则Filter驱动程序无法保留NET_BUFFER_LIST结构和关联的基础驱动程序分配的资源。 此标志可以指示基础驱动程序的接收资源不足。 FilterReceiveNetBufferLists 函数应尽快返回。
注意 如果设置了 NDIS_RECEIVE_FLAGS_RESOURCES 标志,Filter驱动程序必须在链接列表中保留原始 NET_BUFFER_LIST 结构集。 例如,当设置此标志时,驱动程序可能会处理结构,并一次一个地在堆栈上指示它们,但在函数返回之前,它必须还原原始链接列表。
Filter驱动程序可以先对收到的数据执行筛选操作,然后再将数据指示给过度覆盖的驱动程序。 对于提交到 FilterReceiveNetBufferLists 函数的每个缓冲区,Filter驱动程序可以执行以下操作:
- 通过调用 NdisFIndicateReceiveNetBufferLists,将其传递给下一个过度覆盖的驱动程序。 驱动程序可以修改缓冲区的内容。 NDIS 保证上下文空间的可用性, 通过查看 NET_BUFFER_LIST_CONTEXT结构;Filter驱动程序可以更改 NDIS 传递到 FilterReceiveNetBufferLists 的状态,也可以直接将其传递给 NdisFIndicateReceiveNetBufferLists。注意即使 NDIS 在 FilterReceiveNetBufferLists 的ReceiveFlags 参数中设置了 NDIS_RECEIVE_FLAGS_RESOURCES 标志,Filter驱动程序也可以使用 NdisFIndicateReceiveNetBufferLists 传递缓冲区。 在这种情况下,Filter驱动程序不得从 FilterReceiveNetBufferLists 返回,直到它重新获得缓冲区的所有权;
- 放弃缓冲区。 如果 NDIS 清除 FilterReceiveNetBufferLists 的 ReceiveFlags 参数中的NDIS_RECEIVE_FLAGS_RESOURCES标志,请调用 NdisFReturnNetBufferLists 函数以放弃缓冲区。 如果 NDIS 在 FilterReceiveNetBufferLists 的 ReceiveFlags 参数中设置NDIS_RECEIVE_FLAGS_RESOURCES标志,则不执行任何操作,并从 FilterReceiveNetBufferLists 返回以放弃缓冲区;
- 在本地数据结构中将缓冲区排队,供以后处理。 如果 NDIS 在 FilterReceiveNetBufferLists 的 ReceiveFlags 参数中设置NDIS_RECEIVE_FLAGS_RESOURCES标志,则Filter驱动程序必须在从 FilterReceiveNetBufferLists 返回之前创建副本;
- 复制缓冲区,并使用副本生成接收指示。 接收指示类似于Filter驱动程序启动的接收指示。 在这种情况下,驱动程序必须将原始缓冲区返回到基础驱动程序;
NdisFIndicateReceiveNetBufferLists 函数将指示的NET_BUFFER_LIST结构列表传递到驱动程序堆栈上到过度覆盖的驱动程序。 接收操作的继续方式类似于Filter驱动程序发起的接收操作。
如果过分驱动程序保留了缓冲区的所有权,NDIS 会为Filter模块调用 FilterReturnNetBufferLists 函数。 在其 FilterReturnNetBufferLists 函数中,Filter驱动程序将撤消它在接收指示路径上的缓冲区上执行的操作。
当最低层Filter模块指示它已使用缓冲区完成时,NDIS 会将缓冲区返回到微型端口驱动程序。 如果 NDIS 清除 FilterReceiveNetBufferLists 的 ReceiveFlags 参数中的 NDIS_RECEIVE_FLAGS_RESOURCES 标志,则Filter驱动程序会调用 NdisFReturnNetBufferLists 以返回缓冲区。 如果 NDIS 在 FilterReceiveNetBufferLists 的 ReceiveFlags 参数中设置NDIS_RECEIVE_FLAGS_RESOURCES标志,则从 FilterReceiveNetBufferLists 返回将返回缓冲区。