为什么 NdisFSendNetBufferLists 仅在从 FilterSendNetBufferLists 调用时才起作用?
Why does NdisFSendNetBufferLists only work when called from FilterSendNetBufferLists?
我有一个 NDIS 过滤器驱动程序(参见 https://pastebin.com/c5r87NNw)和一个用户空间应用程序。
我想用我的过滤器驱动程序发送一个任意数据包(在函数 SendData
中)。我可以在函数 FilterReceiveNetBufferLists
中使用 DbgPrint 看到我已收到数据包,但我无法在 WireShark.
中找到该数据包
只要 SendData
中的代码被调用或直接粘贴到 FilterSendNetBufferLists
函数中,它就可以正常工作。但是现在,由于 SendData
的执行是由用户空间应用程序触发的,它不再起作用了。
你猜猜这是为什么?
Wireshark 是一个有趣的东西,因为它不一定会告诉您确切的事实。如果可能,我建议在另一台 PC 上使用 运行 Wireshark,这将使您更清晰地了解实际传输到网络上的内容。 (从最纯粹的角度来看:禁用另一台 PC 的硬件卸载,尤其是 RSC,这样另一台 PC 的 NIC 就不会在您捕获数据包之前对其进行处理。)
旧版本的 Wireshark 有一个名为 NPF 的 NDIS5 协议 driver。此人位于 上方 所有过滤器 driver,因此他通常不会看到任何 Tx 流量。但作为对这种情况的特殊让步,NDIS 会将 Tx 路径回环到 Rx 路径(设置 NDIS_NBL_FLAGS_IS_LOOPBACK_PACKET
标志),因此像 NPF 这样的老 drivers 可以看到 Tx 的副本数据包在他们的 Rx 路径中。
最近,npcap 项目将旧的 NPF driver 转换为名为 NPCAP 的 NDIS6 LWF。这个 driver 要好得多,原因有很多,但要记住的一件事是,作为过滤器 driver,它位于过滤器堆栈中的某个位置。如果它位于您的 LWF 之上,那么它不会看到您传输(或修改)的任何数据包。
检查 !ndiskd.miniport 以查看 wireshark 在您的计算机上的样子:它是一个名为 NPF 的协议,还是有一个名为 NPCAP 的过滤器 driver。如果是后者,它是高于还是低于您的过滤器 driver?
无论如何,这就是说您不能完全信任与您正在测试的 drivers 在同一个盒子上的 wireshark。在单独的机器上抓包更好更容易。
至于您的代码,请确保您的 FilterSendNetBufferListsComplete 处理程序正在查看所有 NBL 并删除 NET_BUFFER_LIST::SourceHandle 等于您的 OriginalNdisFilterHandle
的 NBL。这些应该释放回 NdisFreeNetBufferList(或缓存以供以后重用,但 NDIS 已经在缓存方面做得不错)。您可能已经拥有该代码,只是没有进入 pastebin。
我没有看到任何会导致 Tx 总是失败的东西。您确实需要跟踪过滤器的暂停状态,并在暂停时阻止(或排队)Tx 操作。所以你的 SendData 函数可以这样写:
NTSTATUS SendData(MY_FILTER *filter) {
if (!ExAcquireRundownProtection(&filter->PauseRundown)) {
return STATUS_NDIS_PAUSED;
}
. . . allocate and send NBL . . .;
return STATUS_SUCCESS;
}
void FilterSendNetBufferListsComplete(MY_FILTER *filter, NET_BUFFER_LIST *nblChain) {
for (auto nbl = nblChain; nbl; nbl = nbl->Next) {
if (nbl->SourceHandle == filter->NdisHandle) {
. . . detach NBL from chain . . .;
. . . free NBL back to NDIS . . .;
ExReleaseRundownProtection(&filter->PauseRundown);
}
}
}
void FilterPause(MY_FILTER *filter) {
ExWaitForRundownProtectionRelease(&filter->PauseRundown);
}
void FilterRestart(MY_FILTER *filter) {
ExReInitializeRundownProtection(&filter->PauseRundown);
}
如果你弄错了,那么有时 NDIS 会在你发送数据包时崩溃。如果您不幸在数据路径暂停时发送它们,一些数据包也会悄悄地无法传输。 (解决这个问题不会神奇地导致数据包总是成功传输——它只是意味着它不再安静:当 NIC 不可用时尝试发送数据包时你会看到 STATUS_NDIS_PAUSED还没准备好。)
我成功了:错误在我的 OriginalNdisFilterHandle
中。我在函数FilterAttach
中设置了它,没想到函数被调用了多次。因此,变量的值错误。
我有一个 NDIS 过滤器驱动程序(参见 https://pastebin.com/c5r87NNw)和一个用户空间应用程序。
我想用我的过滤器驱动程序发送一个任意数据包(在函数 SendData
中)。我可以在函数 FilterReceiveNetBufferLists
中使用 DbgPrint 看到我已收到数据包,但我无法在 WireShark.
只要 SendData
中的代码被调用或直接粘贴到 FilterSendNetBufferLists
函数中,它就可以正常工作。但是现在,由于 SendData
的执行是由用户空间应用程序触发的,它不再起作用了。
你猜猜这是为什么?
Wireshark 是一个有趣的东西,因为它不一定会告诉您确切的事实。如果可能,我建议在另一台 PC 上使用 运行 Wireshark,这将使您更清晰地了解实际传输到网络上的内容。 (从最纯粹的角度来看:禁用另一台 PC 的硬件卸载,尤其是 RSC,这样另一台 PC 的 NIC 就不会在您捕获数据包之前对其进行处理。)
旧版本的 Wireshark 有一个名为 NPF 的 NDIS5 协议 driver。此人位于 上方 所有过滤器 driver,因此他通常不会看到任何 Tx 流量。但作为对这种情况的特殊让步,NDIS 会将 Tx 路径回环到 Rx 路径(设置 NDIS_NBL_FLAGS_IS_LOOPBACK_PACKET
标志),因此像 NPF 这样的老 drivers 可以看到 Tx 的副本数据包在他们的 Rx 路径中。
最近,npcap 项目将旧的 NPF driver 转换为名为 NPCAP 的 NDIS6 LWF。这个 driver 要好得多,原因有很多,但要记住的一件事是,作为过滤器 driver,它位于过滤器堆栈中的某个位置。如果它位于您的 LWF 之上,那么它不会看到您传输(或修改)的任何数据包。
检查 !ndiskd.miniport 以查看 wireshark 在您的计算机上的样子:它是一个名为 NPF 的协议,还是有一个名为 NPCAP 的过滤器 driver。如果是后者,它是高于还是低于您的过滤器 driver?
无论如何,这就是说您不能完全信任与您正在测试的 drivers 在同一个盒子上的 wireshark。在单独的机器上抓包更好更容易。
至于您的代码,请确保您的 FilterSendNetBufferListsComplete 处理程序正在查看所有 NBL 并删除 NET_BUFFER_LIST::SourceHandle 等于您的 OriginalNdisFilterHandle
的 NBL。这些应该释放回 NdisFreeNetBufferList(或缓存以供以后重用,但 NDIS 已经在缓存方面做得不错)。您可能已经拥有该代码,只是没有进入 pastebin。
我没有看到任何会导致 Tx 总是失败的东西。您确实需要跟踪过滤器的暂停状态,并在暂停时阻止(或排队)Tx 操作。所以你的 SendData 函数可以这样写:
NTSTATUS SendData(MY_FILTER *filter) {
if (!ExAcquireRundownProtection(&filter->PauseRundown)) {
return STATUS_NDIS_PAUSED;
}
. . . allocate and send NBL . . .;
return STATUS_SUCCESS;
}
void FilterSendNetBufferListsComplete(MY_FILTER *filter, NET_BUFFER_LIST *nblChain) {
for (auto nbl = nblChain; nbl; nbl = nbl->Next) {
if (nbl->SourceHandle == filter->NdisHandle) {
. . . detach NBL from chain . . .;
. . . free NBL back to NDIS . . .;
ExReleaseRundownProtection(&filter->PauseRundown);
}
}
}
void FilterPause(MY_FILTER *filter) {
ExWaitForRundownProtectionRelease(&filter->PauseRundown);
}
void FilterRestart(MY_FILTER *filter) {
ExReInitializeRundownProtection(&filter->PauseRundown);
}
如果你弄错了,那么有时 NDIS 会在你发送数据包时崩溃。如果您不幸在数据路径暂停时发送它们,一些数据包也会悄悄地无法传输。 (解决这个问题不会神奇地导致数据包总是成功传输——它只是意味着它不再安静:当 NIC 不可用时尝试发送数据包时你会看到 STATUS_NDIS_PAUSED还没准备好。)
我成功了:错误在我的 OriginalNdisFilterHandle
中。我在函数FilterAttach
中设置了它,没想到函数被调用了多次。因此,变量的值错误。