Windows 为什么NDisfSendNetBufferList仅在从FilterSendNetBufferList调用时工作?

Windows 为什么NDisfSendNetBufferList仅在从FilterSendNetBufferList调用时工作?,windows,driver,wdk,windows-kernel,ndis,Windows,Driver,Wdk,Windows Kernel,Ndis,我有一个NDIS过滤器驱动程序(请参阅)和一个用户空间应用程序 我想用我的筛选器驱动程序发送任意数据包(在函数SendData中)。通过函数filterReceiveNetBufferList中的DbgPrint,我可以看到我已收到该数据包,但在WireShark中找不到该数据包 只要调用或直接将SendData中的代码粘贴到FilterSendNetBufferLists-函数中,它就可以正常工作。但是现在,由于用户空间应用程序触发了SendData的执行,它不再工作了 你能猜出原因吗?Wir

我有一个NDIS过滤器驱动程序(请参阅)和一个用户空间应用程序

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

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


你能猜出原因吗?

Wireshark是一件有趣的事情,因为它不一定告诉你确切的真相。如果可能的话,我建议在另一台电脑上运行Wireshark,这会让你更清楚地了解到底是什么被放到了电线上。(从最纯粹的角度来看:禁用另一台PC的硬件卸载,尤其是RSC,这样在您捕获数据包之前,另一台PC的NIC就不会咀嚼数据包。)

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

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

请查收!ndiskd.miniport查看wireshark在您的机器上的外观:是名为NPF的协议,还是名为NPCAP的筛选器驱动程序。如果是后者,它是在过滤器驱动程序之上还是之下

总之,所有这一切都意味着你不能完全相信wireshark和你测试的驱动程序在同一个盒子上。在单独的机器上捕获数据包更好更容易

至于您的代码,请确保您的FilterSendNetBufferListComplete处理程序正在查看所有NBL,并删除其净缓冲区列表::SourceHandle等于您的
原始NDisFilterHandle
的NBL。应该将它们释放回NdisFreeNetBufferList(或缓存以供以后重用,但NDIS已经完成了相当不错的缓存工作)。您可能已经有了该代码,但它没有进入pastebin

我看不到任何东西会导致发送总是失败。您确实需要跟踪筛选器的暂停状态,并在暂停时阻止(或排队)发送操作。因此,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还没有准备好发送数据包时,您会看到状态暂停。)

Wireshark是一件有趣的事情,因为它不一定告诉您确切的真相。如果可能的话,我建议在另一台电脑上运行Wireshark,这会让你更清楚地了解到底是什么被放到了电线上。(从最纯粹的角度来看:禁用另一台PC的硬件卸载,尤其是RSC,这样在您捕获数据包之前,另一台PC的NIC就不会咀嚼数据包。)

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

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

请查收!ndiskd.miniport查看wireshark在您的机器上的外观:是名为NPF的协议,还是名为NPCAP的筛选器驱动程序。如果是后者,它是在过滤器驱动程序之上还是之下

总之,所有这一切都意味着你不能完全相信wireshark和你测试的驱动程序在同一个盒子上。在单独的机器上捕获数据包更好更容易

至于您的代码,请确保您的FilterSendNetBufferListComplete处理程序正在查看所有NBL,并删除其净缓冲区列表::SourceHandle等于您的
原始NDisFilterHandle
的NBL。应该将它们释放回NdisFreeNetBufferList(或缓存以供以后重用,但NDIS已经完成了相当不错的缓存工作)。您可能已经有了该代码,但它没有进入pastebin

我看不到任何东西会导致发送总是失败。您确实需要跟踪筛选器的暂停状态,并在暂停时阻止(或排队)发送操作。因此,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尚未准备就绪时,您将在尝试发送数据包时看到状态“NDIS”暂停。)