2

我正在将著名的数据包捕获软件——WinPcap 从 NDIS 5.0 移植到 NDIS 6.x。我尝试将每个 NDIS 5.0 功能转换为 6.0 版本。在 WinPcap 源代码中,函数 NdisOpenAdapter 由 Openclos.c 中的 NPF_OpenAdapter 调用。我将它翻译为 NDIS 6.0 的 NdisOpenAdapterEx。但我找不到设置第 4 个参数 BindContext 的方法。NdisOpenAdapterEx 的声明可以在这里找到:http: //msdn.microsoft.com/en-us/library/windows/hardware/ff563715 (v=vs.85).aspx

MS 还说“协议驱动程序必须从其 ProtocolBindAdapterEx 函数调用 NdisOpenAdapterEx。NDIS 无法在 ProtocolBindAdapterEx 的上下文之外调用 NdisOpenAdapterEx。”。所以在 NPF_OpenAdapter 中似乎无法调用 NdisOpenAdapterEx。它必须在 NPF_BindAdapterEx 函数中调用。我用我自己的版本替换了驱动程序 npf.sys,启动了 Wireshark(一个数据包捕获前端),在 NPF_BindAdapterEx 中设置断点,发现在 NPF_OpenAdapter 之前从未调用过 NPF_BindAdapterEx。所以我不可能在调用 NdisOpenAdapterEx 之前获取 BindContext 参数。

我只想通过尽可能小的修改将 WinPcap 移植到 NDIS 6.0。以及如何解决这个问题?</p>

这是 Openclos.c 的代码

    /*
* Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
* Copyright (c) 2005 - 2010 CACE Technologies, Davis (California)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Politecnico di Torino, CACE Technologies 
* nor the names of its contributors may be used to endorse or promote 
* products derived from this software without specific prior written 
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#include "stdafx.h"

#include <ntddk.h>
#include <ndis.h>

#include "debug.h"
#include "packet.h"
#include "..\..\Common\WpcapNames.h"


static
VOID NPF_ReleaseOpenInstanceResources(POPEN_INSTANCE pOpen);

static NDIS_MEDIUM MediumArray[] =
{
    NdisMedium802_3,
    //  NdisMediumWan,
    NdisMediumFddi, NdisMediumArcnet878_2, NdisMediumAtm, NdisMedium802_5
};

#define NUM_NDIS_MEDIA  (sizeof MediumArray / sizeof MediumArray[0])

//Itoa. Replaces the buggy RtlIntegerToUnicodeString
// void PacketItoa(UINT n, PUCHAR buf)
// {
//  int i;
//  for(i=0;i<20;i+=2){
//      buf[18-i]=(n%10)+48;
//      buf[19-i]=0;
//      n/=10;
//  }
// }

/// Global start time. Used as an absolute reference for timestamp conversion.
struct time_conv G_Start_Time =
{
    0, {0, 0},
};

ULONG g_NumOpenedInstances = 0;

BOOLEAN NPF_StartUsingBinding(IN POPEN_INSTANCE pOpen)
{
    ASSERT(pOpen != NULL);
    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    NdisAcquireSpinLock(&pOpen->AdapterHandleLock);

    if (pOpen->AdapterBindingStatus != ADAPTER_BOUND)
    {
        NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
        return FALSE;
    }

    pOpen->AdapterHandleUsageCounter++;

    NdisReleaseSpinLock(&pOpen->AdapterHandleLock);

    return TRUE;
}

VOID NPF_StopUsingBinding(IN POPEN_INSTANCE pOpen)
{
    ASSERT(pOpen != NULL);
    //
    //  There is no risk in calling this function from abobe passive level 
    //  (i.e. DISPATCH, in this driver) as we acquire a spinlock and decrement a 
    //  counter.
    //
    //  ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    NdisAcquireSpinLock(&pOpen->AdapterHandleLock);

    ASSERT(pOpen->AdapterHandleUsageCounter > 0);
    ASSERT(pOpen->AdapterBindingStatus == ADAPTER_BOUND);

    pOpen->AdapterHandleUsageCounter--;

    NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
}

VOID NPF_CloseBinding(IN POPEN_INSTANCE pOpen)
{
    NDIS_EVENT Event;
    NDIS_STATUS Status;

    ASSERT(pOpen != NULL);
    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    NdisInitializeEvent(&Event);
    NdisResetEvent(&Event);

    NdisAcquireSpinLock(&pOpen->AdapterHandleLock);

    while (pOpen->AdapterHandleUsageCounter > 0)
    {
        NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
        NdisWaitEvent(&Event, 1);
        NdisAcquireSpinLock(&pOpen->AdapterHandleLock);
    }

    //
    // now the UsageCounter is 0
    //

    while (pOpen->AdapterBindingStatus == ADAPTER_UNBINDING)
    {
        NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
        NdisWaitEvent(&Event, 1);
        NdisAcquireSpinLock(&pOpen->AdapterHandleLock);
    }

    //
    // now the binding status is either bound or unbound
    //

    if (pOpen->AdapterBindingStatus == ADAPTER_UNBOUND)
    {
        NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
        return;
    }

    ASSERT(pOpen->AdapterBindingStatus == ADAPTER_BOUND);

    pOpen->AdapterBindingStatus = ADAPTER_UNBINDING;

    NdisReleaseSpinLock(&pOpen->AdapterHandleLock);

    //
    // do the release procedure
    //
    NdisResetEvent(&pOpen->NdisOpenCloseCompleteEvent);

    // Close the adapter
    Status = NdisCloseAdapterEx(pOpen->AdapterHandle);

    if (Status == NDIS_STATUS_PENDING)
    {
        TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Pending NdisCloseAdapter");
        NdisWaitEvent(&pOpen->NdisOpenCloseCompleteEvent, 0);
    }
    else
    {
        TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Not Pending NdisCloseAdapter");
    }

    NdisAcquireSpinLock(&pOpen->AdapterHandleLock);
    pOpen->AdapterBindingStatus = ADAPTER_UNBOUND;
    NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
}

//-------------------------------------------------------------------

NTSTATUS NPF_OpenAdapter(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    PDEVICE_EXTENSION DeviceExtension;
    POPEN_INSTANCE Open;
    PIO_STACK_LOCATION IrpSp;
    NDIS_STATUS Status;
    NDIS_STATUS ErrorStatus;
    UINT i;
    PUCHAR tpointer;
    PLIST_ENTRY PacketListEntry;
    NTSTATUS returnStatus;

    NET_BUFFER_LIST_POOL_PARAMETERS PoolParameters;
    NDIS_OPEN_PARAMETERS OpenParameters;
    NET_FRAME_TYPE FrameTypeArray[2] =
    {
        NDIS_ETH_TYPE_802_1X, NDIS_ETH_TYPE_802_1Q
    };

    //  
    //  Old registry based WinPcap names
    //
    //  WCHAR               EventPrefix[MAX_WINPCAP_KEY_CHARS];
    //  UINT                RegStrLen;

    TRACE_ENTER();

    DeviceExtension = DeviceObject->DeviceExtension;

    IrpSp = IoGetCurrentIrpStackLocation(Irp);

    //  allocate some memory for the open structure
    Open = ExAllocatePoolWithTag(NonPagedPool, sizeof(OPEN_INSTANCE), '0OWA');

    if (Open == NULL)
    {
        // no memory
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    RtlZeroMemory(Open, sizeof(OPEN_INSTANCE));

    //  
    //  Old registry based WinPcap names
    //
    //  //
    //  // Get the Event names base from the registry
    //  //
    //  RegStrLen = sizeof(EventPrefix)/sizeof(EventPrefix[0]);
    //
    //  NPF_QueryWinpcapRegistryString(NPF_EVENTS_NAMES_REG_KEY_WC,
    //      EventPrefix,
    //      RegStrLen,
    //      NPF_EVENTS_NAMES_WIDECHAR);
    //

    Open->DeviceExtension = DeviceExtension;

    NdisZeroMemory(&PoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));
    PoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
    PoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
    PoolParameters.Header.Size = sizeof(PoolParameters);
    PoolParameters.ProtocolId = NDIS_PROTOCOL_ID_TCP_IP;
    PoolParameters.ContextSize = 0;
    PoolParameters.fAllocateNetBuffer = TRUE;
    PoolParameters.PoolTag = NPCAP_ALLOC_TAG;

    Open->PacketPool = NdisAllocateNetBufferListPool(NULL, &PoolParameters);
    if (Open->PacketPool == NULL)
    {
        TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Failed to allocate packet pool");

        ExFreePool(Open);
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //  //  Allocate a packet pool for our xmit and receive packets
    //  NdisAllocatePacketPool(
    //      &Status,
    //      &Open->PacketPool,
    //      TRANSMIT_PACKETS,
    //      sizeof(PACKET_RESERVED));
    // 
    //  if (Status != NDIS_STATUS_SUCCESS) {
    // 
    //      TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Failed to allocate packet pool");
    // 
    //      ExFreePool(Open);
    //      Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
    //      IoCompleteRequest(Irp, IO_NO_INCREMENT);
    //      return STATUS_INSUFFICIENT_RESOURCES;
    //  }

    NdisInitializeEvent(&Open->WriteEvent);
    NdisInitializeEvent(&Open->NdisRequestEvent);
    NdisInitializeEvent(&Open->NdisWriteCompleteEvent);
    NdisInitializeEvent(&Open->DumpEvent);
    NdisAllocateSpinLock(&Open->MachineLock);
    NdisAllocateSpinLock(&Open->WriteLock);
    Open->WriteInProgress = FALSE;

    for (i = 0; i < g_NCpu; i++)
    {
        NdisAllocateSpinLock(&Open->CpuData[i].BufferLock);
    }

    NdisInitializeEvent(&Open->NdisOpenCloseCompleteEvent);

    //  list to hold irp's want to reset the adapter
    InitializeListHead(&Open->ResetIrpList);

    //  Initialize the request list
    KeInitializeSpinLock(&Open->RequestSpinLock);
    InitializeListHead(&Open->RequestList);

    //
    // Initialize the open instance
    //
    //Open->BindContext = NULL;
    Open->bpfprogram = NULL;    //reset the filter
    Open->mode = MODE_CAPT;
    Open->Nbytes.QuadPart = 0;
    Open->Npackets.QuadPart = 0;
    Open->Nwrites = 1;
    Open->Multiple_Write_Counter = 0;
    Open->MinToCopy = 0;
    Open->TimeOut.QuadPart = (LONGLONG)1;
    Open->DumpFileName.Buffer = NULL;
    Open->DumpFileHandle = NULL;
#ifdef HAVE_BUGGY_TME_SUPPORT
    Open->tme.active = TME_NONE_ACTIVE;
#endif // HAVE_BUGGY_TME_SUPPORT
    Open->DumpLimitReached = FALSE;
    Open->MaxFrameSize = 0;
    Open->WriterSN = 0;
    Open->ReaderSN = 0;
    Open->Size = 0;
    Open->SkipSentPackets = FALSE;
    Open->ReadEvent = NULL;

    //
    // we need to keep a counter of the pending IRPs
    // so that when the IRP_MJ_CLEANUP dispatcher gets called,
    // we can wait for those IRPs to be completed
    //
    Open->NumPendingIrps = 0;
    Open->ClosePending = FALSE;
    NdisAllocateSpinLock(&Open->OpenInUseLock);

    //
    //allocate the spinlock for the statistic counters
    //
    NdisAllocateSpinLock(&Open->CountersLock);

    //
    //  link up the request stored in our open block
    //
    for (i = 0 ; i < MAX_REQUESTS ; i++)
    {
        NdisInitializeEvent(&Open->Requests[i].InternalRequestCompletedEvent);

        ExInterlockedInsertTailList(&Open->RequestList, &Open->Requests[i].ListElement, &Open->RequestSpinLock);
    }

    NdisResetEvent(&Open->NdisOpenCloseCompleteEvent);

    // 
    // set the proper binding flags before trying to open the MAC
    //
    Open->AdapterBindingStatus = ADAPTER_BOUND;
    Open->AdapterHandleUsageCounter = 0;
    NdisAllocateSpinLock(&Open->AdapterHandleLock);

    //
    //  Try to open the MAC
    //
    TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "Opening the device %ws, BindingContext=%p", DeviceExtension->AdapterName.Buffer, Open);

    returnStatus = STATUS_SUCCESS;

    NdisZeroMemory(&OpenParameters, sizeof(NDIS_OPEN_PARAMETERS));
    OpenParameters.Header.Type = NDIS_OBJECT_TYPE_OPEN_PARAMETERS;
    OpenParameters.Header.Revision = NDIS_OPEN_PARAMETERS_REVISION_1;
    OpenParameters.Header.Size = sizeof(NDIS_OPEN_PARAMETERS);
    OpenParameters.AdapterName = &DeviceExtension->AdapterName;
    OpenParameters.MediumArray = MediumArray;
    OpenParameters.MediumArraySize = sizeof(MediumArray) / sizeof(NDIS_MEDIUM);
    OpenParameters.SelectedMediumIndex = &Open->Medium;
    OpenParameters.FrameTypeArray = NULL;
    OpenParameters.FrameTypeArraySize = 0;
    //OpenParameters.FrameTypeArray = &FrameTypeArray[0];
    //OpenParameters.FrameTypeArraySize = sizeof(FrameTypeArray) / sizeof(NET_FRAME_TYPE);


    NDIS_DECLARE_PROTOCOL_OPEN_CONTEXT(OPEN_INSTANCE);
    Status = NdisOpenAdapterEx(g_NdisProtocolHandle, (NDIS_HANDLE)Open, &OpenParameters, NULL, &Open->AdapterHandle);

    //  NdisOpenAdapter(
    //      &Status,
    //      &ErrorStatus,
    //      &Open->AdapterHandle,
    //      &Open->Medium,
    //      MediumArray,
    //      NUM_NDIS_MEDIA,
    //      g_NdisProtocolHandle,
    //      Open,
    //      &DeviceExtension->AdapterName,
    //      0,
    //      NULL);

    TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened the device, Status=%x", Status);

    if (Status == NDIS_STATUS_PENDING)
    {
        NdisWaitEvent(&Open->NdisOpenCloseCompleteEvent, 0);

        if (!NT_SUCCESS(Open->OpenCloseStatus))
        {
            returnStatus = Open->OpenCloseStatus;
        }
        else
        {
            returnStatus = STATUS_SUCCESS;
        }
    }
    else
    {
        //
        // request not pending, we know the result, and OpenComplete has not been called.
        //
        if (Status == NDIS_STATUS_SUCCESS)
        {
            returnStatus = STATUS_SUCCESS;
        }
        else
        {
            //
            // this is not completely correct, as we are converting an NDIS_STATUS to a NTSTATUS
            //
            returnStatus = Status;
        }
    }

    if (returnStatus == STATUS_SUCCESS)
    {
        ULONG localNumOpenedInstances;  
        //
        // complete the open
        //
        localNumOpenedInstances = InterlockedIncrement(&g_NumOpenedInstances);

        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenedInstances);

        // Get the absolute value of the system boot time.
        // This is used for timestamp conversion.
        TIME_SYNCHRONIZE(&G_Start_Time);

        returnStatus = NPF_GetDeviceMTU(Open, Irp, &Open->MaxFrameSize);

        if (!NT_SUCCESS(returnStatus))
        {
            //
            // Close the binding
            //
            NPF_CloseBinding(Open);
        }
    }

    if (!NT_SUCCESS(returnStatus))
    {
        NPF_ReleaseOpenInstanceResources(Open);
        //
        // Free the open instance itself
        //
        ExFreePool(Open);
    }
    else
    {
        //  Save or open here
        IrpSp->FileObject->FsContext = Open;
    }

    Irp->IoStatus.Status = returnStatus;
    Irp->IoStatus.Information = 0;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    TRACE_EXIT();
    return returnStatus;
}

BOOLEAN NPF_StartUsingOpenInstance(IN POPEN_INSTANCE pOpen)
{
    BOOLEAN returnStatus;

    NdisAcquireSpinLock(&pOpen->OpenInUseLock);
    if (pOpen->ClosePending)
    {
        returnStatus = FALSE;
    }
    else
    {
        returnStatus = TRUE;
        pOpen->NumPendingIrps ++;
    }
    NdisReleaseSpinLock(&pOpen->OpenInUseLock);

    return returnStatus;
}

VOID NPF_StopUsingOpenInstance(IN POPEN_INSTANCE pOpen)
{
    NdisAcquireSpinLock(&pOpen->OpenInUseLock);
    ASSERT(pOpen->NumPendingIrps > 0);
    pOpen->NumPendingIrps --;
    NdisReleaseSpinLock(&pOpen->OpenInUseLock);
}

VOID NPF_CloseOpenInstance(IN POPEN_INSTANCE pOpen)
{
    ULONG i = 0;
    NDIS_EVENT Event;

    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    NdisInitializeEvent(&Event);
    NdisResetEvent(&Event);

    NdisAcquireSpinLock(&pOpen->OpenInUseLock);

    pOpen->ClosePending = TRUE;

    while (pOpen->NumPendingIrps > 0)
    {
        NdisReleaseSpinLock(&pOpen->OpenInUseLock);
        NdisWaitEvent(&Event, 1);
        NdisAcquireSpinLock(&pOpen->OpenInUseLock);
    }

    NdisReleaseSpinLock(&pOpen->OpenInUseLock);
}


VOID NPF_ReleaseOpenInstanceResources(POPEN_INSTANCE pOpen)
{
    PKEVENT pEvent;
    UINT i;

    TRACE_ENTER();

    ASSERT(pOpen != NULL);
    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open= %p", pOpen);

    //NdisFreePacketPool(pOpen->PacketPool);
    NdisFreeNetBufferListPool(pOpen->PacketPool);

    //
    // Free the filter if it's present
    //
    if (pOpen->bpfprogram != NULL)
        ExFreePool(pOpen->bpfprogram);

    //
    // Jitted filters are supported on x86 (32bit) only
    // 
#ifdef _X86_
    // Free the jitted filter if it's present
    if (pOpen->Filter != NULL)
        BPF_Destroy_JIT_Filter(pOpen->Filter);
#endif //_X86_

    //
    // Dereference the read event.
    //

    if (pOpen->ReadEvent != NULL)
        ObDereferenceObject(pOpen->ReadEvent);

    //
    // free the buffer
    // NOTE: the buffer is fragmented among the various CPUs, but the base pointer of the
    // allocated chunk of memory is stored in the first slot (pOpen->CpuData[0])
    //
    if (pOpen->Size > 0)
        ExFreePool(pOpen->CpuData[0].Buffer);

    //
    // free the per CPU spinlocks
    //
    for (i = 0; i < g_NCpu; i++)
    {
        NdisFreeSpinLock(&pOpen->CpuData[i].BufferLock);
    }

    //
    // Free the string with the name of the dump file
    //
    if (pOpen->DumpFileName.Buffer != NULL)
        ExFreePool(pOpen->DumpFileName.Buffer);

    TRACE_EXIT();
}


//-------------------------------------------------------------------

VOID NPF_OpenAdapterCompleteEx(IN NDIS_HANDLE  ProtocolBindingContext, IN NDIS_STATUS  Status)
{
    POPEN_INSTANCE Open;
    PLIST_ENTRY RequestListEntry;
    PINTERNAL_REQUEST MaxSizeReq;
    NDIS_STATUS ReqStatus;

    TRACE_ENTER();

    Open = (POPEN_INSTANCE)ProtocolBindingContext;

    ASSERT(Open != NULL);

    if (Status != NDIS_STATUS_SUCCESS)
    {
        //
        // this is not completely correct, as we are converting an NDIS_STATUS to a NTSTATUS
        //
        Open->OpenCloseStatus = Status;
    }
    else
    {
        Open->OpenCloseStatus = STATUS_SUCCESS;
    }

    //
    // wake up the caller of NdisOpen, that is NPF_Open
    //
    NdisSetEvent(&Open->NdisOpenCloseCompleteEvent);

    TRACE_EXIT();
}

NTSTATUS NPF_GetDeviceMTU(IN POPEN_INSTANCE pOpen, IN PIRP  pIrp, OUT PUINT  pMtu)
{
    PLIST_ENTRY RequestListEntry;
    PINTERNAL_REQUEST MaxSizeReq;
    NDIS_STATUS ReqStatus;

    TRACE_ENTER();

    ASSERT(pOpen != NULL);
    ASSERT(pIrp != NULL);
    ASSERT(pMtu != NULL);

    // Extract a request from the list of free ones
    RequestListEntry = ExInterlockedRemoveHeadList(&pOpen->RequestList, &pOpen->RequestSpinLock);

    if (RequestListEntry == NULL)
    {
        //
        // THIS IS WRONG
        //

        //
        // Assume Ethernet
        //
        *pMtu = 1514;   
        TRACE_EXIT();
        return STATUS_SUCCESS;
    }

    MaxSizeReq = CONTAINING_RECORD(RequestListEntry, INTERNAL_REQUEST, ListElement);

    MaxSizeReq->Request.RequestType = NdisRequestQueryInformation;
    MaxSizeReq->Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;

    MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBuffer = pMtu;
    MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(*pMtu);

    NdisResetEvent(&MaxSizeReq->InternalRequestCompletedEvent);

    //  submit the request
    ReqStatus = NdisOidRequest(pOpen->AdapterHandle, &MaxSizeReq->Request);

    if (ReqStatus == NDIS_STATUS_PENDING)
    {
        NdisWaitEvent(&MaxSizeReq->InternalRequestCompletedEvent, 0);
        ReqStatus = MaxSizeReq->RequestStatus;
    }

    //
    // Put the request in the list of the free ones
    //
    ExInterlockedInsertTailList(&pOpen->RequestList, &MaxSizeReq->ListElement, &pOpen->RequestSpinLock);

    if (ReqStatus == NDIS_STATUS_SUCCESS)
    {
        TRACE_EXIT();
        return STATUS_SUCCESS;
    }
    else
    {
        //
        // THIS IS WRONG
        //

        //
        // Assume Ethernet
        //
        *pMtu = 1514;   

        TRACE_EXIT();
        return STATUS_SUCCESS;

        // return ReqStatus;
    }
}


//-------------------------------------------------------------------
NTSTATUS NPF_CloseAdapter(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    POPEN_INSTANCE pOpen;
    PIO_STACK_LOCATION IrpSp;
    TRACE_ENTER();

    IrpSp = IoGetCurrentIrpStackLocation(Irp);
    pOpen = IrpSp->FileObject->FsContext;

    ASSERT(pOpen != NULL);
    //
    // Free the open instance itself
    //
    ExFreePool(pOpen);

    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    TRACE_EXIT();
    return STATUS_SUCCESS;
}

//-------------------------------------------------------------------
NTSTATUS NPF_Cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    POPEN_INSTANCE Open;
    NDIS_STATUS Status;
    PIO_STACK_LOCATION IrpSp;
    LARGE_INTEGER ThreadDelay;
    ULONG localNumOpenInstances;

    TRACE_ENTER();

    IrpSp = IoGetCurrentIrpStackLocation(Irp);
    Open = IrpSp->FileObject->FsContext;

    TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open = %p\n", Open);

    ASSERT(Open != NULL);

    NPF_CloseOpenInstance(Open);

    if (Open->ReadEvent != NULL)
        KeSetEvent(Open->ReadEvent, 0, FALSE);

    NPF_CloseBinding(Open);

    // NOTE:
    // code commented out because the kernel dump feature is disabled
    //
    //if (AdapterAlreadyClosing == FALSE)
    //{

    //  
    //   Unfreeze the consumer
    //  
    //  if(Open->mode & MODE_DUMP)
    //      NdisSetEvent(&Open->DumpEvent);
    //  else
    //      KeSetEvent(Open->ReadEvent,0,FALSE);

    //  //
    //  // If this instance is in dump mode, complete the dump and close the file
    //  //
    //  if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL)
    //  {
    //      NTSTATUS wres;

    //      ThreadDelay.QuadPart = -50000000;

    //      //
    //      // Wait the completion of the thread
    //      //
    //      wres = KeWaitForSingleObject(Open->DumpThreadObject,
    //          UserRequest,
    //          KernelMode,
    //          TRUE,
    //          &ThreadDelay);

    //      ObDereferenceObject(Open->DumpThreadObject);

    //      //
    //      // Flush and close the dump file
    //      //
    //      NPF_CloseDumpFile(Open);
    //  }
    //}


    //
    // release all the resources
    //
    NPF_ReleaseOpenInstanceResources(Open);

    //  IrpSp->FileObject->FsContext = NULL;

    //
    // Decrease the counter of open instances
    //
    localNumOpenInstances = InterlockedDecrement(&g_NumOpenedInstances);
    TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenInstances);

    if (localNumOpenInstances == 0)
    {
        //
        // Force a synchronization at the next NPF_Open().
        // This hopefully avoids the synchronization issues caused by hibernation or standby.
        //
        TIME_DESYNCHRONIZE(&G_Start_Time);
    }


    //
    // and complete the IRP with status success
    //
    Irp->IoStatus.Information = 0;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    TRACE_EXIT();

    return(STATUS_SUCCESS);
}

//-------------------------------------------------------------------

VOID NPF_CloseAdapterCompleteEx(IN NDIS_HANDLE  ProtocolBindingContext)
{
    POPEN_INSTANCE Open;
    PIRP Irp;

    TRACE_ENTER();

    Open = (POPEN_INSTANCE)ProtocolBindingContext;

    ASSERT(Open != NULL);

    TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open= %p", Open);

    NdisSetEvent(&Open->NdisOpenCloseCompleteEvent);

    TRACE_EXIT();
    return;
}
//-------------------------------------------------------------------

NDIS_STATUS NPF_NetPowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT_NOTIFICATION pNetPnPEvent)
{
    TRACE_ENTER();

    TIME_DESYNCHRONIZE(&G_Start_Time);
    TIME_SYNCHRONIZE(&G_Start_Time);

    TRACE_EXIT();
    return STATUS_SUCCESS;
}

//------------------------------------------------------------------

NDIS_STATUS NPF_BindAdapterEx(IN NDIS_HANDLE ProtocolDriverContext, IN NDIS_HANDLE BindContext, IN PNDIS_BIND_PARAMETERS BindParameters)
{
    NTSTATUS ntStatus = NDIS_STATUS_SUCCESS;
    int a = 1;
    a ++;
    TRACE_ENTER();
    TRACE_EXIT();
    return ntStatus;
}

//-------------------------------------------------------------------


NDIS_STATUS NPF_UnbindAdapterEx(IN  NDIS_HANDLE         UnbindContext, IN  NDIS_HANDLE         ProtocolBindingContext)
{
    NTSTATUS Status;
    POPEN_INSTANCE Open = (POPEN_INSTANCE)ProtocolBindingContext;

    TRACE_ENTER();

    ASSERT(Open != NULL);

    //
    // The following code has been disabled bcause the kernel dump feature has been disabled.
    //
    ////
    //// Awake a possible pending read on this instance
    //// TODO should be ok.
    ////
    //  if(Open->mode & MODE_DUMP)
    //      NdisSetEvent(&Open->DumpEvent);
    //  else
    if (Open->ReadEvent != NULL)
        KeSetEvent(Open->ReadEvent, 0, FALSE);

    //
    // The following code has been disabled bcause the kernel dump feature has been disabled.
    //
    ////
    //// If this instance is in dump mode, complete the dump and close the file
    //// TODO needs to be checked again.
    ////
    //  if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL)
    //      NPF_CloseDumpFile(Open);

    Status = NDIS_STATUS_SUCCESS;

    NPF_CloseBinding(Open);

    TRACE_EXIT();
    return Status;
}

//-------------------------------------------------------------------

VOID NPF_ResetComplete(IN NDIS_HANDLE  ProtocolBindingContext, IN NDIS_STATUS  Status)
{
    POPEN_INSTANCE Open;
    PIRP Irp;

    PLIST_ENTRY ResetListEntry;

    TRACE_ENTER();

    Open = (POPEN_INSTANCE)ProtocolBindingContext;

    //
    //  remove the reset IRP from the list
    //
    ResetListEntry = ExInterlockedRemoveHeadList(&Open->ResetIrpList, &Open->RequestSpinLock);

    Irp = CONTAINING_RECORD(ResetListEntry, IRP, Tail.Overlay.ListEntry);

    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    TRACE_EXIT();

    return;
}
4

1 回答 1

1

您肯定遇到过 WinPcap 的一个有趣问题。它的协议驱动程序 (NPF) 希望能够随时打开适配器。当与 Wireshark 配对时,它会经常执行此操作——通常会在 Wireshark GUI 加载时看到 NPF 打开和关闭同一个适配器数十次。甚至可以看到 NPF同时有多个绑定到同一个适配器。

NDIS 6.x 中与此大致等效的是NdisReEnumerateProtocolBindings函数。这样做是排队一个工作项,以便ProtocolBindAdapterEx为每个在注册表中标记为已绑定但当前未在 NDIS 中绑定的适配器调用您的协议处理程序。(即,对于 INetCfg 找到的尚未打开句柄的绑定路径的每个适配器。)

但是,由于 NPF 的 API 和 NDIS 如何看待绑定之间存在很大的阻抗,您需要解决一些问题:

  1. 多个同时绑定到同一个适配器。(这是一个很少使用的功能;NPF 是我知道使用它的两个协议之一,因此在 MSDN 文档中并没有真正讨论太多。)在 NDIS 6.x 中获得多个同时绑定的唯一方法是调用NdisOpenAdapterEx两次在同一个ProtocolBindAdapterEx通话中。这将是具有挑战性的,因为 NPF 的模型是每当 API 调用从用户模式进入时打开一个新的绑定;它事先不知道需要打开多少个句柄。

    如果另一个绑定请求进来,您可以尝试关闭该适配器的所有先前句柄(对 NPF API[!] 透明),调用NdisReEnumerateProtocolBindings,然后在即将到来的处理程序中打开 N+1 个句柄ProtocolBindAdpaterEx。但这很脆弱。

    您还可以尝试将所有 API 调用合并到同一个适配器。如果第二个绑定请求进来,只需将其路由到该适配器的预先存在的绑定。这可能很困难,具体取决于 NPF 内部的工作方式。(我不允许阅读 NPF 源代码;我不能说。)

    最后,俗气的解决方案是始终只分配两个(或三个)绑定句柄,并保留额外的缓存以防 Wireshark 需要它们。这实现起来很便宜,但仍然有点脆弱,因为您无法真正知道 Wireshark 是否需要比您预先分配的更多的句柄。

  2. 缺少INetCfg绑定。NDIS 5.x 协议允许绑定到适配器,即使该协议实际上不应该被绑定(根据INetCfg)。Wireshark 使用它来将自己绑定到各种随机适配器,而不必过多担心是否INetCfg同意 NPF 应该被绑定。转换为 NDIS 6.x 后,将严格执行规则,并且您需要确保协议的 INFLowerRange对要绑定的每种类型的适配器都有一个关键字。(即,NPF 协议应显示在适配器属性对话框中。)

  3. 异步绑定。该NdisReEnumerateProtocolBindings模型是您调用的模型,NDIS 将尝试将您的协议绑定到所有可绑定适配器。如果适配器由于某种原因不可绑定(也许它处于低功耗状态,或者它被意外删除),那么 NDIS 将根本不会回调您的协议。很难确切知道何时放弃并将失败返回给用户模式 ​​NPF API,因为您不会收到“您不会绑定到此适配器”的回调。您也许可以使用NetEventBindsComplete,但坦率地说,这是一种狡猾、定义不明确的事件,我不相信它是防弹的。我会设置一个超时,然后使用 NetEvent 作为提示来缩短超时。

最后,我只是想指出,尽管您说过要尽量减少 WinPcap 中的流失量,但您可能需要考虑将其驱动程序重新打包为 NDIS LWF。LWF 正是为此目的而设计的,因此它们往往更适合 NPF 的需求。(特别是,LWF 可以查看本地 802.11 流量,无需通过环回黑客即可获得更准确的数据,并且比协议简单得多。)

于 2013-07-15T03:31:44.060 回答