简体   繁体   English

如何使用 NDIS 过滤器驱动程序读取接收到的数据包?

[英]How can I read the received packets with a NDIS filter driver?

I am currently experimenting with the NDIS driver samples .我目前正在试验NDIS 驱动程序示例 I am trying to print the packets contents (including the MAC-addresses, EtherType and the data).我正在尝试打印数据包内容(包括 MAC 地址、EtherType 和数据)。

My first guess was to implement this in the function FilterReceiveNetBufferLists .我的第一个猜测是在 function FilterReceiveNetBufferLists中实现这个。 Unfortunately I am not sure how to extract the packets contents out of the NetBufferLists .不幸的是,我不确定如何从NetBufferLists中提取数据包内容。

That's the right place to start.这是正确的起点。 Consider this code:考虑这段代码:

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, ...);
}

There are a few points to consider about this code.关于这段代码有几点需要考虑。

The NDIS datapath uses the NET_BUFFER_LIST (nbl) as its primary data structure. NDIS 数据路径使用 NET_BUFFER_LIST (nbl) 作为其主要数据结构。 An nbl represents a set of packets that all have the same metadata.一个 nbl 表示一组具有相同元数据的数据包。 For the receive path, nobody really knows much about the metadata, so that set always has exactly 1 packet in it.对于接收路径,没有人真正了解元数据,因此该集合中始终只有 1 个数据包。 In other words, the nbl is a list... of length 1. For the receive path, you can count on it.换句话说,nbl 是一个长度为 1 的列表。对于接收路径,您可以指望它。

The nbl is a list of one or more NET_BUFFER (nb) structures. nbl 是一个或多个 NET_BUFFER (nb) 结构的列表。 An nb represents a single network frame (subject to LSO or RSC). nb 表示单个网络帧(受 LSO 或 RSC 约束)。 So the nb corresponds most closely to what you think of as a packet.因此,nb 最接近于您认为的数据包。 Its metadata is stored on the nbl that contains it.它的元数据存储在包含它的 nbl 上。

Within an nb, the actual packet payload is stored as one or more buffers, each represented as an MDL.在一个 nb 中,实际的数据包有效负载存储为一个或多个缓冲区,每个缓冲区表示为一个 MDL。 Mentally, you should pretend the MDLs are just concatenated together.从心理上讲,您应该假装 MDL 只是串联在一起。 For example, the network headers might be in one MDL, while the rest of the payload might be in another MDL.例如,网络标头可能在一个 MDL 中,而有效负载的 rest 可能在另一个 MDL 中。

Finally, for performance, NDIS gives as many NBLs to your LWF as possible.最后,为了性能,NDIS 为您的 LWF 提供尽可能多的 NBL。 This means there's a list of one or more NBLs.这意味着有一个或多个 NBL 的列表。

Put it all together, and you have:把它们放在一起,你有:

  • Your function receives a list of NBLs.您的 function 收到 NBL 列表。
  • Each NBL contains exactly 1 NB (on the receive path).每个 NBL 恰好包含 1 个 NB(在接收路径上)。
  • Each NB contains a list of MDLs.每个 NB 都包含一个 MDL 列表。
  • Each MDL points to a buffer of payload.每个 MDL 指向一个有效负载缓冲区。

So in our example code above, the for-loop iterates along that first bullet point: the chain of NBLs.所以在我们上面的示例代码中,for 循环沿着第一个要点进行迭代:NBL 链。 Within the loop, we only need to look at nbl->FirstNetBuffer , since we can safely assume there is no other nb besides the first.在循环中,我们只需要查看nbl->FirstNetBuffer ,因为我们可以安全地假设除了第一个 nb 之外没有其他 nb。

It's inconvenient to have to fiddle with all those MDLs directly, so we use the helper routine NdisGetDataBuffer .必须直接摆弄所有这些 MDL 很不方便,因此我们使用辅助例程NdisGetDataBuffer You tell this guy how many bytes of payload you want to see, and he'll give you a pointer to a contiguous range of payload.你告诉这个人你想查看多少字节的有效载荷,他会给你一个指向连续有效载荷范围的指针。

  • In the good case, your buffer is contained in a single MDL, so NdisGetDataBuffer just gives you a pointer back into that MDL's buffer.在好的情况下,您的缓冲区包含在单个 MDL 中,因此 NdisGetDataBuffer 只是为您提供指向该 MDL 缓冲区的指针。
  • In the slow case, your buffer straddles more than one MDL, so NdisGetDataBuffer carefully copies the relevant bit of payload into a scratch buffer that you provided.在较慢的情况下,您的缓冲区跨越多个 MDL,因此 NdisGetDataBuffer 会小心地将有效负载的相关位复制到您提供的暂存缓冲区中。

The latter case can be fiddly, if you're trying to inspect more than a few bytes.如果您尝试检查多个字节,则后一种情况可能很繁琐。 If you're reading all 1500 bytes of the packet, you can't just allocate 1500 bytes on the stack (kernel stack space is scarce, unlike usermode), so you have to allocate it from the pool.如果您正在读取数据包的所有 1500 字节,则不能只在堆栈上分配 1500 字节(内核堆栈空间稀缺,与用户模式不同),因此您必须从池中分配它。 Once you figure that out, note it will slow things down to copy all 1500 bytes of data into a scratch buffer for every packet.一旦弄清楚这一点,请注意,将所有 1500 字节的数据复制到每个数据包的暂存缓冲区中会减慢速度。 Is the slowdown too much?减速太多了吗? It depends on your needs.这取决于您的需求。 If you're only inspecting occasional packets, or if you're deploying the LWF on a low-throughput NIC, it won't matter.如果您只是偶尔检查数据包,或者如果您将 LWF 部署在低吞吐量 NIC 上,则无关紧要。 If you're trying to get beyond 1Gbps, you shouldn't be memcpying so much data around.如果你试图超过 1Gbps,你不应该存储这么多数据。

Also note that if you ultimately want to modify the packet, you'll need to be wary of NdisGetDataBuffer.另请注意,如果您最终要修改数据包,则需要警惕 NdisGetDataBuffer。 It can give you a copy of the data (stored in your local scratch buffer), so if you modify the payload, those changes won't actually stick to the packet.它可以为您提供数据的副本(存储在本地暂存缓冲区中),因此如果您修改有效负载,这些更改实际上不会粘在数据包上。

What if you do need to scale to high throughputs, or modify the payload?如果您确实需要扩展到高吞吐量或修改有效负载怎么办? Then you need to work out how to manipulate the MDL chain.然后你需要弄清楚如何操作 MDL 链。 That's a bit confusing at first, but spend a little time with the documentation and draw yourself some whiteboard diagrams.起初这有点令人困惑,但花一点时间阅读文档并为自己画一些白板图。

I suggest first starting out by understanding an MDL.我建议首先从了解 MDL 开始。 From networking's point of view, an MDL is just a fancy way of holding a { char * buffer, size_t length }, along with a link to the next MDL.从网络的角度来看,MDL 只是保存 { char * buffer, size_t length } 以及指向下一个 MDL 的链接的一种奇特方式。

Next, consider the NB's DataOffset and DataLength.接下来,考虑 NB 的 DataOffset 和 DataLength。 These conceptually move the buffer boundaries in from the beginning and the end of the buffer.这些在概念上将缓冲区边界从缓冲区的开头和结尾移入。 They don't really care about MDL boundaries -- for example, you can reduce the length of the packet payload by decrementing DataLength, and if that means that one or more MDLs are no longer contributing any buffer space to the packet payload, it's no big deal, they're just ignored.他们并不真正关心 MDL 边界——例如,您可以通过递减 DataLength 来减少数据包有效负载的长度,如果这意味着一个或多个 MDL 不再为数据包有效负载提供任何缓冲区空间,那么它不是大不了,他们只是被忽略了。

Finally, add on top CurrentMdl and CurrentMdlOffset.最后,在顶部添加 CurrentMdl 和 CurrentMdlOffset。 These are redundant with everything above, but they exist for (microbenchmark) performance.这些对于上述所有内容都是多余的,但它们的存在是为了(微基准)性能。 You aren't required to even think about them if you're reading the NB, but if you are editing the size of the NB, you do need to update them.如果您正在阅读 NB,您甚至不需要考虑它们,但如果您正在编辑 NB 的大小,则需要更新它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 NDIS 过滤器驱动程序发送任意数据包? - How can I send arbitrary packets with a NDIS filter driver? 如何在NDIS协议驱动程序中禁用回送数据包 - How to disable loopback packets in NDIS protocol driver 如何使用 NDIS 过滤器驱动程序从协议层重定向 TCP 数据包? - How to redirect TCP packets from protocol layer using NDIS filter driver? NDIS 5/6中间滤波器驱动程序 - NDIS 5/6 intermediate filter driver 自动安装 NDIS 过滤器驱动程序 - auto install NDIS filter driver 如何在 NDIS 6 过滤器驱动程序中启用 802.11 监控模式 (DOT11_OPERATION_MODE_NETWORK_MONITOR)? - How to enable 802.11 monitor mode (DOT11_OPERATION_MODE_NETWORK_MONITOR) in a NDIS 6 filter driver? 如何确定NDIS 6筛选器驱动程序中802.11原始数据包是否具有FCS(4字节)? - How to determine whether a 802.11 raw packet has FCS (4bytes) in a NDIS 6 filter driver? 如何了解NDIS Miniport驱动程序的内部工作 - How to understand the internal working of NDIS Miniport driver 为什么不调用我的NDIS筛选器驱动程序的FilterReceiveNetBufferLists处理程序? - Why my NDIS filter driver' FilterReceiveNetBufferLists handler is not called? 加载除NetService以外的Windows驱动程序类以充当NDIS筛选器 - Loading a Windows Driver Class other than NetService to act as an NDIS Filter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM