发送在我的 NDIS 修改过滤器驱动程序中无法正常工作

2023-12-24

我正在尝试使用 NDIS 来实现数据包修改过滤器。 我使用了丢弃数据包并从克隆 NBL 发起发送/接收的方法。

msdn 上的文档说这是允许的:https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ndis/nc-ndis-filter_send_net_buffer_lists https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ndis/nc-ndis-filter_send_net_buffer_lists

对于提交到 FilterSendNetBufferLists 的每个 NET_BUFFER 结构, 过滤器驱动程序可以执行以下操作: ...

复制缓冲区并创建一个 发送请求并附上副本。发送操作类似于 过滤器驱动程序发起发送请求。在这种情况下,驾驶员必须 通过调用将原始缓冲区返回给上层驱动程序 NdisFSendNetBufferLists完整函数。

我使用以下算法成功实现了 RX 路径:

  1. Filter获取FilterReceiveNetBufferLists中的NBL
  2. FilterReceiveNetBufferLists 创建 NBL 克隆并排队以进行进一步处理
  3. FilterReceiveNetBufferLists 调用 NdisFReturnNetBufferLists
  4. 用户连接到暴露的设备,将数据包出队并再次注入。
  5. 设备调用 NdisFIndicateReceiveNetBufferLists RX 路径良好并且网络工作正常。

我在 TX 路径中做了同样的事情:

  1. Filter获取FilterSendNetBufferLists中的NBL
  2. FilterSendNetBufferLists 创建 NBL 克隆并入队以进行进一步处理
  3. FilterSendNetBufferLists 调用 NdisFSendNetBufferListsComplete。
  4. 用户连接到暴露的设备,将数据包出队并再次注入。
  5. 设备调用 NdisFSendNetBufferLists

TX 路径不起作用。 我通过发送 ICMP 数据包(只是 ping DNS 服务器 IP)来测试它。 我在路由器和测试机之间安装了wireshark。 Wireshark 捕获由 TX 路径发起的传出 ICMP 数据包(步骤 5),但没有响应数据包。

当我在 FilterSendNetBufferLists 中调用 NdisFSendNetBufferListsComplete 时到底会发生什么? TCP/IP 驱动程序是否获得数据包已传输且没有任何错误的信息?


即兴的,我猜你不会打电话来NdisCopySendNetBufferListInfo在 TX 路径中,这意味着校验和卸载元数据正在丢失。

如果 NIC 声称支持校验和卸载(即 NIC 硬件可以插入 IPv4、TCPv4 和/或 TCPv6 校验和),则 TCPIP 驱动程序不会尝试将有效校验和放入 IPv4/TCP 标头中。 (实际上,它明确地将部分校验和放在那里,这在软件中很容易计算,但在硬件中计算起来有点困难。)然后 TCPIP 驱动程序将在 NBL 的信息字段中设置一些标志,指示硬件准确地如何计算将校验和插入数据包有效负载中。

当您克隆 NBL 时,默认情况下,克隆不会继承任何元数据。因此,克隆的 NBL 在数据包有效负载中具有不完整的校验和,但缺少 NIC 硬件插入校验和的指令。

修复方法很简单:NdisCopySendNetBufferListInfo复制与 TX 路径相关的所有数据包元数据。 (RX 路径有一个类似的 NdisCopyRecieveNetBufferListInfo`,您还应该考虑从驱动程序调用它。)每当您克隆 NBL 时,都应该调用这些例程之一,克隆最终将属于同一个数据包“流”和原来的NBL一样。

当您调用 NdisAllocateCloneNetBufferList 时,为什么 NDIS 不自动复制元数据?表面上的问题是 NDIS 不知道我们正在执行 TX 路径还是 RX 路径。但更深层次的问题是 NDIS 不知道您打算多么严重地破坏数据包。例如,如果您的驱动程序重写了 RX 数据包上的 TCP 标头,则仅简单地复制 NIC 的 TCP 校验和计算和 RSS 哈希值可能是不合适的。

所以打电话NdisCopySendNetBufferListInfo实际上意味着您声称您没有对数据包进行太多破坏,以至于它们看起来与任何硬件卸载不同。例如,您没有插入协议标头、更改 TCP 端口号等(如果您are做这些事情,那么您要么必须额外编写一些代码来平滑卸载,要么完全禁用它们。)

顺便说一句,这是一个有趣而微妙的问题,每个人的直觉都会出错:

TCP/IP 驱动程序是否获得数据包已传输且没有任何错误的信息?

Ndis[F|M]SendNetBufferListsComplete 确实not表示数据包已传输且没有任何错误。这意味着一件事:数据包有效负载、MDL、NB 和 NBL 不再使用,协议驱动程序可以重新调整它们的用途。

当传输到典型的 PCIe 硬件时,这意味着到 NIC 板载 RAM 的 DMA 已完成,并且 NIC 承诺不再接触数据包有效负载缓冲区。

这是一个简单的答案,但它提出了一个直接的后续问题:如果 SendComplete 并不意味着数据包已成功传输,那么如何does协议判断数据包是否传输成功?

答案是协议不在乎数据包是否传输到下一跳。他们真正关心的是远程端点是否收到数据包。找出答案的唯一方法是某种 ACK 系统。因此,没有人真正费心去构建一个信号,表明 NIC 硬件实际上已将 NBL 传输到下一跳,因为协议无论如何都无法对这些信息做太多事情。

(数据包时间戳 (IEEE15888/PTP/NTP) 是上述讨论的一个例外。但即使在这种情况下,我们也不actually想知道数据包何时离开本地主机。我们actually想知道数据包何时到达远程端点。但物理定律就是这样,后者是不可知的,所以我们必须满足于知道 TX 数据包何时离开本地主机。)

请注意,如果您确定数据包没有传输,那么您可以在NET_BUFFER_LIST::Status,并且某些协议(例如 UDP + Winsock)会将错误向上冒泡到应用程序。但在这种情况下,您只是针对更快的错误路径进行优化——应用程序本质上仍然有义务构建网络级反馈机制(例如 ACK),以了解数据包是否一路到达目的地。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

发送在我的 NDIS 修改过滤器驱动程序中无法正常工作 的相关文章

随机推荐