【问题标题】:Why does NdisFSendNetBufferLists only work when called from FilterSendNetBufferLists?为什么 NdisFSendNetBufferLists 仅在从 FilterSendNetBufferLists 调用时才起作用?
【发布时间】:2020-12-25 02:36:06
【问题描述】:

我有一个 NDIS 过滤器驱动程序(请参阅 https://pastebin.com/c5r87NNw)和一个用户空间应用程序。

我想用我的过滤器驱动程序发送一个任意数据包(在函数SendData 中)。我可以通过函数FilterReceiveNetBufferLists 中的 DbgPrint 看到我已收到数据包,但在 WireShark 中找不到数据包。

只要调用SendData 中的代码或将其直接粘贴到FilterSendNetBufferLists 函数中,它就可以正常工作。但是现在,由于SendData 的执行是由用户空间应用程序触发的,所以它不再起作用了。

你有任何猜测为什么会这样吗?

【问题讨论】:

    标签: windows driver wdk windows-kernel ndis


    【解决方案1】:

    Wireshark 是一件有趣的事情,因为它不一定会告诉你确切的真相。如果可能的话,我建议在另一台 PC 上运行 Wireshark,这将使您更清楚地了解实际放在电线上的内容。 (从最纯粹的角度来看:禁用其他 PC 的硬件卸载,尤其是 RSC,因此其他 PC 的 NIC 不会在您捕获数据包之前对其进行修改。)

    旧版本的 Wireshark 有一个名为 NPF 的 NDIS5 协议驱动程序。此人位于所有过滤器驱动程序之上,因此他通常不会看到任何 Tx 流量。但作为对这种情况的特殊让步,NDIS 会将 Tx 路径循环回 Rx 路径(设置了NDIS_NBL_FLAGS_IS_LOOPBACK_PACKET 标志),因此像 NPF 这样的旧驱动程序可以在其 Rx 路径中看到 Tx 数据包的副本。

    最近,npcap 项目将旧的 NPF 驱动程序转换为名为 NPCAP 的 NDIS6 LWF。由于多种原因,此驱动程序要好得多,但要记住的一点是,作为过滤器驱动程序,它位于过滤器堆栈中的某个位置。如果它位于您的 LWF 之上,那么它将看不到您传输(或修改)的任何数据包。

    检查 !ndiskd.miniport 以查看您的机器上的 wireshark 是什么样的:它是一个名为 NPF 的协议,还是有一个名为 NPCAP 的过滤器驱动程序。如果是后者,它是在您的过滤驱动程序之上还是之下?

    无论如何,这就是说您不能完全信任与您正在测试的驱动程序在同一个盒子上的wireshark。在单独的机器上进行数据包捕获会更好也更容易。

    至于您的代码,请确保您的 FilterSendNetBufferListsComplete 处理程序正在查看所有 NBL 并删除 NET_BUFFER_LIST::SourceHandle 等于您的OriginalNdisFilterHandle 的那些。这些应该被释放回 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 。 )

    【讨论】:

    • 我在我的代码和函数 SendData 中添加了 RundownProtection,它没有返回 STATUS_NDIS_PAUSED。所以很明显它没有暂停。我还查看了我的过滤器驱动程序的位置,结果发现它是最顶层的过滤器驱动程序。我的 WireShark 已经使用 NPCAP。我已经在 FilterSendNetBufferListsComplete 函数中释放了我的 NBL。
    • 我成功了:错误出现在我的OriginalNdisFilterHandle 中。我将它设置在函数FilterAttach 中,并没有认为该函数被多次调用。因此,变量具有错误的值。感谢您的帮助!
    • 太好了,很高兴它正在工作。同意您的分析 - 您在 LWF 中往往没有太多全局状态(可能 NBL 池和控制设备除外)。
    【解决方案2】:

    我成功了:错误出现在我的OriginalNdisFilterHandle 中。我将它设置在函数FilterAttach 中,并没有认为该函数会被多次调用。因此,变量的值错误。

    【讨论】:

      猜你喜欢
      • 2018-05-06
      • 2018-11-12
      • 2013-08-13
      • 2023-03-05
      • 1970-01-01
      • 2021-06-09
      • 2011-07-13
      • 1970-01-01
      • 2022-12-16
      相关资源
      最近更新 更多