Gig*_*tti 2 windows ndis driver wdk windows-kernel
我目前正在试验NDIS 驱动程序示例。我正在尝试打印数据包内容(包括 MAC 地址、以太网类型和数据)。
我的第一个猜测是在函数中实现它FilterReceiveNetBufferLists。不幸的是,我不确定如何从NetBufferLists.
这是开始的正确地方。考虑这个代码:
void FilterReceiveNetBufferLists(..., NET_BUFFER_LIST *nblChain, ...)
{
UCHAR buffer[14];
UCHAR *header;
for (NET_BUFFER_LIST *nbl = nblChain; nbl; nbl = nbl->Next) {
header = NdisGetDataBuffer(nbl->FirstNetBuffer, sizeof(buffer), buffer, 1, 1);
if (!header)
continue;
DbgPrint("MAC address: %02x-%02x-%02x-%02x-%02x-%02x\n",
header[0], header[1], header[2],
header[3], header[4], header[5]);
}
NdisFIndicateReceiveNetBufferLists(..., nblChain, ...);
}
Run Code Online (Sandbox Code Playgroud)
关于这段代码,有几点需要考虑。
NDIS 数据路径使用 NET_BUFFER_LIST (nbl) 作为其主要数据结构。nbl 代表一组具有相同元数据的数据包。对于接收路径,没有人真正了解元数据,因此该集合中始终只有 1 个数据包。换句话说,nbl 是一个列表...长度为 1。对于接收路径,您可以依靠它。
nbl 是一个或多个 NET_BUFFER (nb) 结构的列表。nb 代表单个网络帧(受 LSO 或 RSC 约束)。因此 nb 与您认为的数据包最接近。它的元数据存储在包含它的 nbl 上。
在 nb 中,实际的数据包有效载荷存储为一个或多个缓冲区,每个缓冲区表示为一个 MDL。在心理上,您应该假装 MDL 只是连接在一起。例如,网络标头可能在一个 MDL 中,而有效负载的其余部分可能在另一个 MDL 中。
最后,为了性能,NDIS 为您的 LWF 提供尽可能多的 NBL。这意味着有一个或多个 NBL 的列表。
把它们放在一起,你有:
所以在我们上面的示例代码中,for 循环沿着第一个要点进行迭代:NBL 链。在循环中,我们只需要查看nbl->FirstNetBuffer,因为我们可以安全地假设除了第一个之外没有其他 nb。
直接处理所有这些 MDL 很不方便,所以我们使用辅助程序NdisGetDataBuffer。你告诉这个人你想看到多少字节的有效载荷,他会给你一个指向连续有效载荷范围的指针。
如果您尝试检查多个字节,后一种情况可能会很麻烦。如果您正在读取数据包的所有 1500 个字节,则不能只在堆栈上分配 1500 个字节(内核堆栈空间稀缺,与用户模式不同),因此您必须从池中分配它。一旦你弄清楚了,请注意将所有 1500 字节的数据复制到每个数据包的临时缓冲区中会减慢速度。减速是否太多?这取决于您的需求。如果您只是偶尔检查数据包,或者如果您在低吞吐量 NIC 上部署 LWF,则没有关系。如果你想超过 1Gbps,你不应该在内存中存储这么多数据。
另请注意,如果您最终想要修改数据包,则需要警惕 NdisGetDataBuffer。它可以为您提供一份数据副本(存储在您的本地暂存缓冲区中),因此如果您修改有效负载,这些更改实际上不会粘到数据包上。
如果您确实需要扩展到高吞吐量或修改有效负载怎么办?然后您需要弄清楚如何操作 MDL 链。起初这有点令人困惑,但花一点时间阅读文档并为自己画一些白板图。
我建议首先从理解 MDL 开始。从网络的角度来看,MDL 只是一种保存 { char * buffer, size_t length } 以及指向下一个 MDL 的链接的奇特方式。
接下来,考虑 NB 的 DataOffset 和 DataLength。这些从概念上将缓冲区边界从缓冲区的开头和结尾移入。他们并不真正关心 MDL 边界——例如,您可以通过递减 DataLength 来减少数据包有效载荷的长度,如果这意味着一个或多个 MDL 不再为数据包有效载荷贡献任何缓冲区空间,那就不是大不了,他们只是被忽略了。
最后,在顶部添加 CurrentMdl 和 CurrentMdlOffset。这些对于上述所有内容都是多余的,但它们存在于(微基准)性能上。如果您正在阅读 NB,您甚至不需要考虑它们,但是如果您正在编辑 NB 的大小,则确实需要更新它们。