我正在将著名的数据包捕获软件-WinPcap从NDIS 5.0移植到NDIS6.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

微软还表示:“协议(protocol)驱动程序必须从其ProtocolBindAdapterEx函数调用NdisOpenAdapterEx。NDIS在ProtocolBindAdapterEx上下文之外调用NdisOpenAdapterEx的任何尝试均将失败。”因此,似乎无法在NPF_OpenAdapter中调用NdisOpenAdapterEx。必须在NPF_BindAdapterEx函数中调用它。我用自己的版本替换了驱动程序npf.sys,启动了Wireshark(数据包捕获前端),在NPF_BindAdapterEx中设置了断点,发现NPF_BindAdapterEx在NPF_OpenAdapter之前从未被调用过。因此,对我而言,在调用NdisOpenAdapterEx之前获取BindContext参数是不可能的。

我只想将WinPcap修改为NDIS 6.0,并进行尽可能小的修改。以及如何解决这个问题?

这是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;
}

最佳答案

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

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

但是,由于NPF API和NDIS如何考虑绑定(bind)之间存在很大的阻抗,因此您需要解决一些问题:

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

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

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

    最后,俗气的解决方案是总是分配两个(或三个)绑定(bind)句柄,并在Wireshark需要它们时保留额外的缓存。这实现起来很便宜,但仍然有些脆弱,因为您无法真正知道Wireshark是否需要比预分配的更多的句柄。
  • 缺少INetCfg绑定(bind)。即使实际上不应该绑定(bind)协议(protocol),NDIS 5.x协议(protocol)也可以绑定(bind)到适配器(根据INetCfg)。 Wireshark使用此方法将自己绑定(bind)到各种随机适配器,而不必担心INetCfg是否同意应绑定(bind)NPF。转换为NDIS 6.x后,将严格执行规则,并且需要确保协议(protocol)的INF对于要绑定(bind)的每种适配器类型都具有LowerRange关键字。 (即,NPF协议(protocol)应显示在“适配器属性”对话框中。)
  • 异​​步绑定(bind)NdisReEnumerateProtocolBindings模型是您调用它的方式,NDIS将尝试将您的协议(protocol)绑定(bind)到所有可绑定(bind)适配器。如果适配器由于某种原因(例如处于低功率状态或被意外删除)不可绑定(bind),则NDIS不会简单地回叫您的协议(protocol)。确切地知道何时应该放弃并将失败返回给用户模式NPF API将会很困难,因为您不会收到说“您不会绑定(bind)到此适配器”的回调。您也许可以使用NetEventBindsComplete,但是坦率地说,这是一个模糊的,定义不明确的事件,我不认为这是防弹的。我会设置一个超时时间,然后使用NetEvent作为提示以缩短超时时间。

  • 最后,我只是想指出一点,尽管您说过要最小化WinPcap中的流失量,但您可能要考虑将其驱动程序重新打包为NDIS LWF。 LWF正是为此目的而设计的,因此它们往往更适合NPF的需求。 (特别是,LWF可以看到 native 802.11流量,无需经过环回hack就可以获取更准确的数据,并且比协议(protocol)要简单得多。)

    关于windows - 如何调用NdisOpenAdapterEx或ProtocolBindAdapter例程之外的替代方法?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17636148/

    10-13 03:22