协议驱动程序源自发送请求并处理基础驱动程序的接收指示。 在单个函数调用中,NDIS 协议驱动程序可以在每个 NET_BUFFER_LIST 结构上发送具有多个 NET_BUFFER 结构的多个NET_BUFFER_LIST结构。 在接收路径中,协议驱动程序可以接收NET_BUFFER_LIST结构的列表。
协议驱动程序必须管理发送缓冲池。 正确管理此类池需要预先分配足够的缓冲区空间来优化系统性能。
协议驱动程序缓冲区管理
协议驱动程序必须管理 NET_BUFFER_LIST 结构池,并 NET_BUFFER 发送操作的结构池。 若要创建这些池,驱动程序会调用以下函数:
- NdisAllocateNetBufferListPool
- NdisAllocateNetBufferPool
协议驱动程序可以使用以下函数从池中分配结构:
- NdisAllocateNetBufferAndNetBufferList
- NdisAllocateNetBufferList
- NdisAllocateNetBuffer
调用 NdisAllocateNetBufferAndNetBufferList 比调用 NdisAllocateNetBufferList 和 NdisAllocateNetBuffer 更高效。 但是, NdisAllocateNetBufferAndNetBufferList 仅在NET_BUFFER_LIST结构上创建一个NET_BUFFER结构。 若要使用 NdisAllocateNetBufferAndNetBufferList,驱动程序必须在调用 NdisAllocateNetBufferListPool 时将 AllocateNetBuffer 参数设置为 TRUE。
协议驱动程序可以使用 OID 请求来查询基础驱动程序的回填和上下文空间要求。 协议驱动程序应确定处于 “打开” 或“ 正在重启” 状态的绑定的回填和上下文要求。 驱动程序应为整个堆栈分配足够的回填和上下文空间。 如有必要,协议驱动程序可以释放池并将其重新分配为 “正在重启” 状态。
协议驱动程序使用以下函数来释放池:
- NdisFreeNetBufferListPool;
- NdisFreeNetBufferPool;
协议驱动程序使用以下函数释放从池中分配的结构:
- NdisFreeNetBufferList;
- NdisFreeNetBuffer;
在释放关联的NET_BUFFER_LIST结构之前,驱动程序应释放使用 NdisAllocateNetBuffer 分配NET_BUFFER结构。 当驱动程序为关联的NET_BUFFER_LIST结构调用 NdisFreeNetBufferList 时,将释放使用 NdisAllocateNetBufferAndNetBufferList 分配的NET_BUFFER结构。
从协议驱动程序发送数据
下图演示了协议驱动程序发送操作,该操作涉及驱动程序堆栈中的协议驱动程序、NDIS 和基础驱动程序:
协议驱动程序调用 NdisSendNetBufferLists 函数以发送 在NET_BUFFER_LIST 结构列表中定义的网络数据。
协议驱动程序必须将每个NET_BUFFER_LIST结构的 SourceHandle 成员设置为传递给 NdisBindingHandle 参数的相同值。 绑定句柄提供在基础微型端口驱动程序调用 NdisMSendNetBufferListsComplete 后,NDIS 将NET_BUFFER_LIST结构返回到协议驱动程序所需的信息。
在调用 NdisSendNetBufferLists 之前,协议驱动程序可以设置随 NET_BUFFER_LIST_INFO宏一 起发送请求的信息。 基础驱动程序可以使用 NET_BUFFER_LIST_INFO 宏检索此信息。
一旦协议驱动程序调用 NdisSendNetBufferLists,就会放弃NET_BUFFER_LIST结构和所有关联资源的所有权。 NDIS 调用 ProtocolSendNetBufferListsComplete 函数将结构和数据返回到协议驱动程序。 在将列表传递给 ProtocolSendNetBufferListsComplete 之前,NDIS 可以将多个发送请求中的结构和数据收集到NET_BUFFER_LIST结构的单个链接列表中。
在 NDIS 调用 ProtocolSendNetBufferListsComplete 之前,协议驱动程序发起的发送的当前状态是未知的。 协议驱动程序在调用 NdisSendNetBufferLists 时暂时释放为发送请求分配的所有资源的所有权。 在 NDIS 将结构返回到 ProtocolSendNetBufferListsComplete 之前,协议驱动程序绝不应尝试检查NET_BUFFER_LIST结构或任何关联数据。
ProtocolSendNetBufferListsComplete 执行完成发送操作所需的任何后处理。 例如,协议驱动程序可以通知请求协议驱动程序发送网络数据的客户端发送操作已完成。
当 NDIS 调用 ProtocolSendNetBufferListsComplete 时,协议驱动程序将重新获得与 NetBufferLists 参数指定的NET_BUFFER_LIST结构关联的所有资源的所有权。 ProtocolSendNetBufferListsComplete 可以释放这些资源 (例如,通过调用 NdisFreeNetBuffer 和 NdisFreeNetBufferList) ,或准备在后续调用 NdisSendNetBufferLists 时重复使用。
尽管 NDIS 始终按照传递给 NdisSendNetBufferLists 的协议确定顺序将协议提供的网络数据提交到基础微型端口驱动程序,但基础驱动程序可以随机顺序完成发送请求。 也就是说,每个绑定的协议驱动程序都可以依赖于 NDIS 将协议驱动程序按 FIFO 顺序传递到 NdisSendNetBufferLists 的网络数据提交到基础驱动程序。 但是,任何协议驱动程序都不能依赖基础驱动程序以相同的顺序调用 NdisMSendNetBufferListsComplete 。
在协议驱动程序中接收数据
下图演示了一个基本的接收操作,该操作涉及驱动程序堆栈中的协议驱动程序、NDIS 和基础驱动程序:
NDIS 调用协议驱动程序的 ProtocolReceiveNetBufferLists 函数来处理来自基础驱动程序的接收指示。 NDIS 在基础驱动程序调用接收指示函数后调用 ProtocolReceiveNetBufferLists , (例如 ,NdisMIndicateReceiveNetBufferLists) 来指示接收的网络数据或环回数据。
如果未设置 ProtocolReceiveNetBufferLists 的 ReceiveFlags 参数中的NDIS_RECEIVE_FLAGS_RESOURCES标志,则协议驱动程序将保留NET_BUFFER_LIST结构的所有权,直到调用 NdisReturnNetBufferLists 函数。 如果 NDIS 设置 NDIS_RECEIVE_FLAGS_RESOURCES 标志,则协议驱动程序无法保留 NET_BUFFER_LIST 结构和关联的资源。 set NDIS_RECEIVE_FLAGS_RESOURCES 标志指示基础驱动程序在接收资源上运行不足。 在这种情况下, ProtocolReceiveNetBufferLists 函数应将接收的数据复制到协议分配的存储中,并尽快返回。
注意 NDIS 可以更改基础驱动程序指示的标志。 例如,如果微型端口驱动程序在 NdisMIndicateReceiveNetBufferLists 函数的 ReceiveFlags 参数中设置NDIS_RECEIVE_FLAGS_RESOURCES标志,则 NDIS 可以复制指示的数据,并将副本传递到已清除NDIS_RECEIVE_FLAGS_RESOURCES标志的 ProtocolReceiveNetBufferLists。
注意 如果设置了 NDIS_RECEIVE_FLAGS_RESOURCES 标志,则协议驱动程序必须在链接列表中保留原始 NET_BUFFER_LIST 结构集。 例如,当设置此标志时,驱动程序可能会处理结构,并一次一个地在堆栈上指示它们,但在函数返回之前,它必须还原原始链接列表。
协议驱动程序调用 NdisReturnNetBufferLists 函数,以释放 NET_BUFFER_LIST 结构列表以及关联的 NET_BUFFER 结构和网络数据的所有权。