在Windows 8下不调用NDIS筛选器驱动程序的FilterAttach例程

时间:2013-08-18 04:39:27

标签: c windows driver ndis

大家。我已将NDIS 5协议中着名的数据包捕获软件WinPcap移植到NDIS 6 LWF。在Win7下一切都很好。但是,在Win8下永远不会调用FilterAttach例程。我发现在DriverEntry中调用NdisFRegisterFilterDriver返回NDIS_STATUS_SUCCESS,这太奇怪了。谁能帮我? THX!

这是DriverEntry的代码

_Use_decl_annotations_
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
{
    NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
    NTSTATUS Status = STATUS_SUCCESS;
//  NDIS_STRING FriendlyName = NDIS_STRING_CONST("WinPcap NDIS LightWeight Filter");
//  NDIS_STRING UniqueName   = NDIS_STRING_CONST("{5cbf81bd-5055-47cd-9055-a76b2b4e2637}"); //unique name, quid name
//  NDIS_STRING ServiceName = NDIS_STRING_CONST("npf6x"); //this to match the service name in the INF
    NDIS_STRING FriendlyName = RTL_CONSTANT_STRING(L"WinPcap NDIS LightWeight Filter");
    NDIS_STRING UniqueName   = RTL_CONSTANT_STRING(L"{5cbf81bd-5055-47cd-9055-a76b2b4e2637}"); //unique name, quid name
    NDIS_STRING ServiceName = RTL_CONSTANT_STRING(L"npf6x"); //this to match the service name in the INF
    WCHAR* bindT;
    PKEY_VALUE_PARTIAL_INFORMATION tcpBindingsP;
    UNICODE_STRING macName;
    ULONG OsMajorVersion, OsMinorVersion;

    TRACE_ENTER();

    UNREFERENCED_PARAMETER(RegistryPath);

    FilterDriverObject = DriverObject;

    //
    // Get OS version and store it in a global variable. 
    //
    // Note: both RtlGetVersion() and PsGetVersion() are documented to always return success.
    //
    //  OsVersion.dwOSVersionInfoSize = sizeof(OsVersion);
    //  RtlGetVersion(&OsVersion);
    //
    PsGetVersion(&OsMajorVersion, &OsMinorVersion, NULL, NULL);
    TRACE_MESSAGE2(PACKET_DEBUG_INIT, "OS Version: %d.%d\n", OsMajorVersion, OsMinorVersion);


    NdisInitUnicodeString(&g_NPF_Prefix, g_NPF_PrefixBuffer);

    //
    // Get number of CPUs and save it
    //
#ifdef NDIS620
    g_NCpu = NdisGroupMaxProcessorCount(ALL_PROCESSOR_GROUPS);
#else
    g_NCpu = NdisSystemProcessorCount();
#endif

    //
    // TODO: Most handlers are optional, however, this sample includes them
    // all for illustrative purposes.  If you do not need a particular 
    // handler, set it to NULL and NDIS will more efficiently pass the
    // operation through on your behalf.
    //

    //
    // Register as a service with NDIS
    //
    NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS));
    FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
    FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
#if NDIS_SUPPORT_NDIS61
    FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_2;
#else
    FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;
#endif

    FChars.MajorNdisVersion = NDIS_FILTER_MAJOR_VERSION;
    FChars.MinorNdisVersion = NDIS_FILTER_MINOR_VERSION;
    FChars.MajorDriverVersion = 1;
    FChars.MinorDriverVersion = 0;
    FChars.Flags = 0;

    FChars.FriendlyName = FriendlyName;
    FChars.UniqueName = UniqueName;
    FChars.ServiceName = ServiceName;

    FChars.SetOptionsHandler = NPF_RegisterOptions;
    FChars.AttachHandler = NPF_Attach;
    FChars.DetachHandler = NPF_Detach;
    FChars.RestartHandler = NPF_Restart;
    FChars.PauseHandler = NPF_Pause;
    FChars.SetFilterModuleOptionsHandler = NPF_SetModuleOptions;
    FChars.OidRequestHandler = NPF_OidRequest;
    FChars.OidRequestCompleteHandler = NPF_OidRequestComplete;
    FChars.CancelOidRequestHandler = NPF_CancelOidRequest;

    FChars.SendNetBufferListsHandler = NPF_SendEx;
    FChars.ReturnNetBufferListsHandler = NPF_ReturnEx;
    FChars.SendNetBufferListsCompleteHandler = NPF_SendCompleteEx;
    FChars.ReceiveNetBufferListsHandler = NPF_TapEx;
    FChars.DevicePnPEventNotifyHandler = NPF_DevicePnPEventNotify;
    FChars.NetPnPEventHandler = NPF_NetPnPEvent;
    FChars.StatusHandler = NPF_Status;
    FChars.CancelSendNetBufferListsHandler = NPF_CancelSendNetBufferLists;

    DriverObject->DriverUnload = NPF_Unload;

    //
    // Initialize spin locks
    //
    //NdisAllocateSpinLock(&FilterListLock);

    //InitializeListHead(&FilterModuleList);


    // 
    // Standard device driver entry points stuff.
    //
    DriverObject->MajorFunction[IRP_MJ_CREATE] = NPF_OpenAdapter;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = NPF_CloseAdapter;
    DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NPF_Cleanup; 
    DriverObject->MajorFunction[IRP_MJ_READ] = NPF_Read;
    DriverObject->MajorFunction[IRP_MJ_WRITE] = NPF_Write;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NPF_IoControl;

    bindP = getAdaptersList();

    if (bindP == NULL)
    {
        TRACE_MESSAGE(PACKET_DEBUG_INIT, "Adapters not found in the registry, try to copy the bindings of TCP-IP.");

        tcpBindingsP = getTcpBindings();

        if (tcpBindingsP == NULL)
        {
            TRACE_MESSAGE(PACKET_DEBUG_INIT, "TCP-IP not found, quitting.");
            goto RegistryError;
        }

        bindP = (WCHAR *)tcpBindingsP;
        bindT = (WCHAR *)(tcpBindingsP->Data);
    }
    else
    {
        bindT = bindP;
    }

    for (; *bindT != UNICODE_NULL; bindT += (macName.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR))
    {
        RtlInitUnicodeString(&macName, bindT);
        NPF_CreateDevice(DriverObject, &macName);
    }


    Status = NdisFRegisterFilterDriver(DriverObject,
        (NDIS_HANDLE) FilterDriverObject,
        &FChars,
        &FilterDriverHandle);
    if (Status != NDIS_STATUS_SUCCESS)
    {
        TRACE_MESSAGE(PACKET_DEBUG_INIT, "Failed to register filter with NDIS.");
        TRACE_EXIT();
        return Status;
    }


    TRACE_EXIT();
    return STATUS_SUCCESS;

    RegistryError : NdisFDeregisterFilterDriver(FilterDriverHandle);

    Status = STATUS_UNSUCCESSFUL;
    TRACE_EXIT();
    return(Status);
}

2 个答案:

答案 0 :(得分:1)

为什么不调用FilterAttach例程 - 我不知道。我想不出Windows 7和Windows 8之间的任何显着差异。(另一方面,Windows 8.1 Preview确实有一些实质性的绑定更改。)

检查过滤器是否绑定在usermode中。使用powershell中的Get-NetAdapterBinding来确保从NIC到过滤器的绑定,以及绑定已启用。

验证微型端口是否正常启动。使用!ndiskd.miniport查看微型端口是否正常绑定。检查您的过滤器是否列在微型端口的过滤器绑定列表中。

一些不相关的笔记:

  • 我认为RegistryError标签不应该调用NdisFDeregisterFilterDriver,因为过滤器尚未在NDIS中注册。
  • getAdaptersListgetTcpBindings这样的代码听起来很可怕,但我想这可能是旧驱动程序中预先存在的代码。请注意,我们不支持在注册表中进行搜索,而是希望在usermode中使用INetCfg来发现适配器。对于LWF,我们希望您的过滤器始终绑定到所有有能力的适配器。如果需要考虑perf,则LWF可以根据需要使用NdisFRestartFilterNdisSetOptionalHandlers动态地将自身插入/移除到数据路径中。

答案 1 :(得分:0)

感谢您在评论中提供的其他诊断信息。您对问题的描述使我可以将其视为Windows中的错误。

首次安装过滤器时会出现此问题。在某些情况下,如果过滤器驱动程序尚未在kernelmode中启动,则NDIS可能会忽略微型端口上的绑定已更改的通知。

有几种解决方法 - 正如您所指出的,一种解决方法是更改​​过滤器的StartType。另一种解决方法是使用INetCfg在安装后禁用并重新启用每个微型端口的过滤器绑定。您也可以禁用和重新启用微型端口,或重新启动计算机,尽管这些是相当具有破坏性的解决方法。

✓此错误不会影响Windows 7 ✗此错误会影响Windows 8和Windows Server 2012 ✓此错误不会影响Windows 8.1和Windows Server 2012 R2。 (我在清理NDIS中的一些代码时不知不觉地修复了这个错误。)

如果您无法等待免费的Windows 8.1更新to roll out to all Windows 8 machines,则可以与Microsoft WDK支持部门联系。请参考WindowsSE:452306,以便他们可以找到有关该问题的笔记,或让他们在内部与我联系。

//
// DisableEnableBindings
//
// Purpose:  This code can be used to quickly disable/enable all bindings to a particular
// NDIS protocol or filter.
//
// Usage:  Run this and provide the name of a NetCfg component.  For example, "ms_pacer".

#include <Windows.h>
#include <netcfgx.h>

#include <atlbase.h>
#include <atlcom.h>

#include <stdio.h>
#include <vector>

#define MY_APP_NAME L"DisableEnableBindings test app"

bool RestartAllBindings(INetCfg *netcfg, PCWSTR name)
{
    HRESULT hr;
    CComPtr<INetCfgComponent> comp;
    CComPtr<INetCfgComponentBindings> bindings;

    hr = netcfg->FindComponent(name, &comp);
    if (FAILED(hr))
    {
        wprintf(L"INetCfg::FindComponent 0x%08x\n", hr);
        return false;
    }

    hr = comp.QueryInterface(&bindings);
    if (FAILED(hr))
    {
        wprintf(L"QueryInterface(INetCfgComponentBindings) 0x%08x\n", hr);
        return false;
    }

    CComPtr<IEnumNetCfgBindingPath> enumerator;
    hr = bindings->EnumBindingPaths(EBP_BELOW, &enumerator);
    if (FAILED(hr))
    {
        wprintf(L"INetCfgComponentBindings::EnumBindingPaths 0x%08x\n", hr);
        return false;
    }

    // Loop over all bindings that involve this component
    while (true)
    {
        CComPtr<INetCfgBindingPath> path;
        hr = enumerator->Next(1, &path, nullptr);
        if (hr == S_FALSE)
        {
            // Reached end of list; quit.
            break;
        }
        if (FAILED(hr))
        {
            wprintf(L"IEnumNetCfgBindingPath::Next 0x%08x\n", hr);
            return false;
        }

        PWSTR token = nullptr;
        hr = path->GetPathToken(&token);
        if (FAILED(hr))
        {
            wprintf(L"INetCfgBindingPath::GetPathToken 0x%08x\n", hr);
            continue;
        }

        wprintf(L"Found binding %s\n", token);
        CoTaskMemFree(token);

        hr = path->IsEnabled();
        if (FAILED(hr))
        {
            wprintf(L"INetCfgBindingPath::IsEnabled 0x%08x\n", hr);
            continue;
        }

        if (S_FALSE == hr)
        {
            wprintf(L"\tPath is already disabled.  Skipping over it.\n");
            continue;
        }

        // Diable

        hr = path->Enable(FALSE);
        if (FAILED(hr))
        {
            wprintf(L"INetCfgBindingPath::Enable(FALSE) 0x%8x\n", hr);
            continue;
        }

        hr = netcfg->Apply();
        if (FAILED(hr))
        {
            wprintf(L"INetCfg::Apply 0x%08x\n", hr);
            return false;
        }

        wprintf(L"\tPath disabled\n");

        // Enable

        hr = path->Enable(TRUE);
        if (FAILED(hr))
        {
            wprintf(L"INetCfgBindingPath::Enable(TRUE) 0x%8x\n", hr);
            return false;
        }

        hr = netcfg->Apply();
        if (FAILED(hr))
        {
            wprintf(L"INetCfg::Apply 0x%08x\n", hr);
            return false;
        }

        wprintf(L"\tPath enabled\n");
    }



    return true;
}

bool ConnectToNetCfg(PCWSTR name)
{
    HRESULT hr;
    CComPtr<INetCfg> netcfg;
    CComPtr<INetCfgLock> lock;

    // Before we can get started, we need to do some initialization work.

    hr = netcfg.CoCreateInstance(CLSID_CNetCfg);
    if (FAILED(hr))
    {
        wprintf(L"CoCreateInstance(CLSID_CNetCfg 0x%08x\n", hr);
        return false;
    }

    hr = netcfg.QueryInterface(&lock);
    if (FAILED(hr))
    {
        wprintf(L"QueryInterface(INetCfgLock) 0x%08x\n", hr);
        return false;
    }

    // Note that this call can block.
    hr = lock->AcquireWriteLock(INFINITE, MY_APP_NAME, nullptr);
    if (FAILED(hr))
    {
        wprintf(L"INetCfgLock::AcquireWriteLock 0x%08x\n", hr);
        return false;
    }

    hr = netcfg->Initialize(nullptr);
    if (FAILED(hr))
    {
        wprintf(L"INetCfg::Initialize 0x%08x\n", hr);
        return false;
    }

    bool ok = RestartAllBindings(netcfg.p, name);

    hr = netcfg->Uninitialize();
    if (FAILED(hr))
    {
        wprintf(L"INetCfg::Uninitialize 0x%08x\n", hr);
    }

    hr = lock->ReleaseWriteLock();
    if (FAILED(hr))
    {
        wprintf(L"INetCfgLock::ReleaseWriteLock 0x%08x\n", hr);
    }

    return ok;
}

int wmain(int argc, wchar_t **argv)
{
    if (argc != 2)
    {
        wprintf(L"Usage: DisableEnableBindings <componentId>\n");
        return 2;
    }

    PCWSTR name = argv[1];

    CComPtr<INetCfg> netcfg;
    CComPtr<INetCfgLock> lock;

    HRESULT hr;

    hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    if (FAILED(hr))
    {
        wprintf(L"CoInitializeEx 0x%08x\n", hr);
        return 1;
    }

    bool ok = ConnectToNetCfg(name);

    CoUninitialize();

    wprintf(ok ? L"Succeeded.\n" : L"Failed.\n");

    return ok ? 0 : 1;
}