1.6.3       NPF_open函数

函数NPF_Open打开驱动的一个新实例。函数原型如下:

NTSTATUS NPF_Open(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp);
参数DeviceObject指向用户所使用的设备对象,参数Irp指向用户所请求的IRP.

函数返回操作的状态,参见DDKntstatus.h文件了解状态值的定义。

当用户的应用程序,在NPF所创建的一个设备上执行一个CreateFile系统调用时,该函数由操作系统调用。

函数NPF_Open分配与初始化一个新实例所需的变量、对象与缓冲区,填充与该实例关联的OPEN_INSTANCE结构体,并调用NdisOpenAdapter打开适配器。

函数的主要代码如下:

NTSTATUS NPF_Open(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;

 

    /*获得_DEVICE_EXTENSION结构体指针,在后面赋给Open->DeviceExtension */

    DeviceExtension = DeviceObject->DeviceExtension;

/*获得IRP中的调用者栈的位置*/

    IrpSp = IoGetCurrentIrpStackLocation(Irp);

 

    /*分配内存空间给Open结构体,并对所分配的内存清零*/  Open=ExAllocatePoolWithTag(NonPagedPool,

sizeof(OPEN_INSTANCE), '0OWA');

    if (Open==NULL) {

        //分配内存失败,函数返回

        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        return STATUS_INSUFFICIENT_RESOURCES;

    } 

    RtlZeroMemory( Open,sizeof(OPEN_INSTANCE) );

 

    Open->DeviceExtension=DeviceExtension;

 

    /*为数据包的接收与发送分配一个数据包内存缓冲池*/    NdisAllocatePacketPool(

        &Status,

        &Open->PacketPool,

        TRANSMIT_PACKETS,

        sizeof(PACKET_RESERVED));

 

    if (Status != NDIS_STATUS_SUCCESS) {

        //分配数据包缓冲池失败,函数返回

        ExFreePool(Open);

        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        return STATUS_INSUFFICIENT_RESOURCES;

    }

 

   /*初始化Open结构体的各种事件*/

    NdisInitializeEvent(&Open->WriteEvent);

    NdisInitializeEvent(&Open->NdisRequestEvent);

    NdisInitializeEvent(&Open->NdisWriteCompleteEvent);

    NdisInitializeEvent(&Open->DumpEvent);

 

/*初始化Open结构体的各种自旋锁*/

    NdisAllocateSpinLock(&Open->MachineLock);

    NdisAllocateSpinLock(&Open->WriteLock);

    

/*没有执行写操作*/

    Open->WriteInProgress = FALSE;

 

/*初始化Open结构体的各种自旋锁*/

for (i = 0; i < g_NCpu; i++)

    {

        NdisAllocateSpinLock(&Open->CpuData[i].BufferLock);

    }

 

    NdisInitializeEvent(&Open->NdisOpenCloseCompleteEvent);

 

    //初始化存储适配器复位IRP请求的链表

    InitializeListHead(&Open->ResetIrpList);

 

    //初始化请求链表

    KeInitializeSpinLock(&Open->RequestSpinLock);

    InitializeListHead(&Open->RequestList);

 

    /*初始化设置open实例的成员*/

    Open->bpfprogram = NULL;    //复位过滤器

    Open->mode = MODE_CAPT;     // 设置为捕获工作模式

    Open->Nbytes.QuadPart = 0;   //把过滤器所接收字节数量为0

Open->Npackets.QuadPart = 0; //把过滤器所接收数据包数量为0

   

    Open->Nwrites = 1;   //设置一个数据包需要被重复发送的次数为1  Open->Multiple_Write_Counter = 0;// 写操作已做的重复次数清零

    Open->MinToCopy = 0;// 设置缓冲区中没被锁定的最小可读的数据数量

    Open->TimeOut.QuadPart = (LONGLONG)1;//设置读超时值

    Open->DumpFileName.Buffer = NULL;//初始化文件转储的各参数

    Open->DumpFileHandle = NULL;

    Open->DumpLimitReached = FALSE;

    Open->MaxFrameSize = 0; //设置底层MAC所能接收的最大帧大小

    Open->WriterSN=0;  //下一个将被写入内核缓冲池中的数据包的序号。

    Open->ReaderSN=0;  //下一个将被从内核缓冲池中读取的数据包的序号

    Open->Size=0;     //包含在CpuData字段中的每个内核缓冲区的大小

    Open->SkipSentPackets = FALSE;//设置该实例捕获自己所传输的数据包

    Open->ReadEvent = NULL;//初始化事件,在该事件上对实例的读调用必须等待

 

    //初始化统计计数器的自旋锁

    NdisAllocateSpinLock(&Open->CountersLock);

 

   

    /*连接Open的请求链表*/

    for (i = 0 ; i < MAX_REQUESTS ; i++ )

    {

        NdisInitializeEvent(

&Open->Requests[i].InternalRequestCompletedEvent

);

//在双向链表的尾部插入一个元素,该插入为原子操作

        ExInterlockedInsertTailList(

            &Open->RequestList,

            &Open->Requests[i].ListElement,

            &Open->RequestSpinLock);

    }

   

    NdisResetEvent(&Open->NdisOpenCloseCompleteEvent);

 

    // 在打开MAC前,设置正确的邦定标志

    Open->AdapterBindingStatus = ADAPTER_BOUND;

    Open->AdapterHandleUsageCounter = 0;

    NdisAllocateSpinLock(&Open->AdapterHandleLock);

   

    /*试图打开网络设备,在调用的协议与一个特定底层NIC驱动程序或NDIS中间层驱动程序之间建立绑定。*/

    returnStatus = STATUS_SUCCESS;

    NdisOpenAdapter(

        &Status,

        &ErrorStatus,

        &Open->AdapterHandle,

        &Open->Medium,

        MediumArray,

        NUM_NDIS_MEDIA,

        g_NdisProtocolHandle,

        Open,

        &DeviceExtension->AdapterName,

        0,

        NULL);

 

    if (Status == NDIS_STATUS_PENDING)

    {   //打开网络设备返回挂起状态,等待打开完成事件

        NdisWaitEvent(&Open->NdisOpenCloseCompleteEvent, 0);

 

        if (!NT_SUCCESS(Open->OpenCloseStatus))

        {//失败

            returnStatus = Open->OpenCloseStatus;

        }

        else

        {

            returnStatus = STATUS_SUCCESS;

        }

    }

    else

    {

        // 请求没被挂起,我们已经知道结果,就不调用OpenComplete调用。

        if (Status == NDIS_STATUS_SUCCESS)

        {

            returnStatus = STATUS_SUCCESS;

        }

        else

        {

            //没有完成正确,我们把一个NDIS_STATUS转换为NTSTATUS

            returnStatus = Status;

        }

    }
----------------------待续--------------------------

本文出自 “千江月” 博客,请务必保留此出处http://eslxf.blog.51cto.com/918801/210016