⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 init.c

📁 网络驱动开发
💻 C
📖 第 1 页 / 共 4 页
字号:
{
    KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);

    
    return STATUS_MORE_PROCESSING_REQUIRED;
}

#ifdef INTERFACE_WITH_NDISPROT

NTSTATUS
NICOpenNdisProtocolInterface(
    PMP_ADAPTER Adapter
    )
/*++
Routine Description:

    This routine opens the NDISPROT device and sends buch of IOCTLs
    to get the names of NICs that it's bound to and pick the first
    available one as our target phycial device.
    
Arguments:

    Adapter     Pointer to our adapter
    
Return Value:

    NT Status code
    
--*/    
{
    UCHAR           Buf[512];//should be enough to get name and description of one adapter
    ULONG           BufLength = sizeof(Buf);
    ULONG           i;
    NTSTATUS        status;
    PWCHAR          deviceName = NULL;
    PWCHAR          deviceDesc = NULL;
    IO_STATUS_BLOCK ioStatus;
    UNICODE_STRING  fileName;
    ULONG           unUsed;
    PNDISPROT_QUERY_BINDING pQueryBinding = NULL;
    OBJECT_ATTRIBUTES objectAttributes;

    PAGED_CODE();

    DEBUGP(MP_TRACE, ("--> NICOpenNdisProtocolInterface\n"));
    
    RtlInitUnicodeString ( &fileName, (PCWSTR) PROTOCOL_INTERFACE_NAME );

    //
    // Initialize the object attributes to open the device.
    //

    InitializeObjectAttributes( &objectAttributes,
                                &fileName,
                                OBJ_KERNEL_HANDLE,
                                (HANDLE) NULL,
                                (PSECURITY_DESCRIPTOR) NULL );

    //
    // The reason for using ZwOpenFile instead of IoGetDeviceObjectPointer
    // is to keep the handle around because the NDISPROT makes an assumption
    // that there is no I/O requests between Cleanup and Close requests.
    //
    status = ZwOpenFile( &Adapter->FileHandle,
                         STANDARD_RIGHTS_ALL,
                         &objectAttributes,
                         &ioStatus,
                         0,
                         FILE_NON_DIRECTORY_FILE );

    if (!NT_SUCCESS( status )) {
        return status;
    }

    DEBUGP (MP_INFO, ( "Successfully opened the protocol interface\n")); 
    
    //
    // The open operation was successful.  Dereference the file handle
    // and obtain a pointer to the device object for the handle.
    //

    status = ObReferenceObjectByHandle(Adapter->FileHandle,
                                        THREAD_ALL_ACCESS,
                                        *IoFileObjectType,
                                        KernelMode,
                                        (PVOID *) &Adapter->FileObject,
                                        NULL );
    if (!NT_SUCCESS( status )) {
        return status;
    }
    
    //
    // Get a pointer to the device object for this file.
    //
    Adapter->TargetDeviceObject = 
                    IoGetRelatedDeviceObject(Adapter->FileObject);

    // 
    // Make sure the target device supports direct I/O operations. 
    //         
    if(!(Adapter->TargetDeviceObject->Flags & DO_DIRECT_IO)) {
        ASSERT(Adapter->TargetDeviceObject->Flags & DO_DIRECT_IO);        
        return STATUS_INVALID_DEVICE_REQUEST;
    }
    
    //
    // Wait for the NDISPROT to completly bind to all the miniport
    // instances.
    //
    status = NICMakeSynchronousIoctl(
                Adapter->TargetDeviceObject,
                Adapter->FileObject,
                IOCTL_NDISPROT_BIND_WAIT,
                NULL,
                0,
                NULL,
                0,
                &unUsed
                );
    if(!NT_SUCCESS(status)) {
        DEBUGP(MP_ERROR, ("IOCTL_NDISIO_BIND_WAIT failed, error %x\n", status));
        return status;
    }

    pQueryBinding = (PNDISPROT_QUERY_BINDING)Buf;

    //
    // Query the binding of NDISPROT one at a time and see if you can open
    // the bindings and use that as our physical adapter.
    //
    i = 0;
    
    for (pQueryBinding->BindingIndex = i;
         /* NOTHING */;
         pQueryBinding->BindingIndex = ++i)
    {

        status = NICMakeSynchronousIoctl(
                Adapter->TargetDeviceObject,
                Adapter->FileObject,
                IOCTL_NDISPROT_QUERY_BINDING,
                pQueryBinding,
                sizeof(NDISPROT_QUERY_BINDING),
                Buf,
                BufLength,
                &unUsed
                );
        if(NT_SUCCESS(status))
        {
            deviceName = (PWCHAR)((PUCHAR)pQueryBinding + 
                                    pQueryBinding->DeviceNameOffset);
            deviceDesc = (PWCHAR)((PUCHAR )pQueryBinding + 
                                    pQueryBinding->DeviceDescrOffset);
            
            DEBUGP(MP_WARNING, ("%2d. %ws\n     - %ws\n",
                pQueryBinding->BindingIndex, deviceName, deviceDesc));

            //
            // Make sure we are not opening our device or another instance 
            // of NDISWDM miniport if more than one instances is installed.
            // We can just use the AdapterDesc to decide this all the time.
            // There is no need to get devicename - just an illustration.
            //
            if(wcscmp(deviceName, Adapter->AdapterName) && 
                    !wcsstr(deviceDesc, Adapter->AdapterDesc))
            {
                       
                Adapter->FileObject->FsContext = NULL;
                                   
                status = NICMakeSynchronousIoctl(
                            Adapter->TargetDeviceObject,
                            Adapter->FileObject,
                            IOCTL_NDISPROT_OPEN_DEVICE,
                            (PVOID)deviceName,
                            pQueryBinding->DeviceNameLength-sizeof(WCHAR),
                            NULL,
                            0,
                            &unUsed
                            );
                if(!NT_SUCCESS(status)) {
                    DEBUGP(MP_ERROR, ("Failed to open NDIS Device %ws %x\n", deviceDesc, status));        
                } else {
                    DEBUGP(MP_WARNING, ("Successfully opened NDIS Device: %ws\n", deviceDesc)); 
                    break;
                }
            }
            RtlZeroMemory(Buf, BufLength);
        }
        else
        {
            if (status != STATUS_NO_MORE_ENTRIES)
            {
                DEBUGP(MP_ERROR, ("EnumerateDevices: terminated abnormally, error %x\n", status));
            } 
            break;
        }
    }

    DEBUGP(MP_TRACE, ("<-- NICOpenNdisProtocolInterface\n"));

    return status;
}

#endif

NTSTATUS
NICPostAsynchronousStatusIndicationIrp(
    IN PMP_ADAPTER Adapter
)
/*++

Routine Description:

    This routine sends an asynchronous ioctl request to NDISPROT.
    This ioctl is used to get the status information indicated
    by the real NIC. This IOCTL can be cancelled anytime after
    the call is made by calling NICCancelStatusIndicationIrp.
    This rotuine is called only once by the driver. If this were
    to be called multiple times, some synchronization code should
    be added to protect the status indication related field in 
    the context structure.
    
Arguments:

    Adapter     Pointer to our adapter
    
Return Value:

    NT status code
    
--*/ 
{
    PIRP                irp = Adapter->StatusIndicationIrp;
    PIO_STACK_LOCATION  nextStack = NULL;

    DEBUGP(MP_TRACE, ("--> NICPostAsynchronousStatusIndicationIrp\n"));
    
    ASSERT(irp);
    
    IoReuseIrp(irp, STATUS_SUCCESS);
    
    // 
    // Obtain a pointer to the stack location of the first driver that will be
    // invoked.  This is where the function codes and the parameters are set.
    // 

    
    nextStack = IoGetNextIrpStackLocation( irp );
    nextStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;

    nextStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(NDISPROT_INDICATE_STATUS);
    nextStack->Parameters.DeviceIoControl.InputBufferLength = 0;
    nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_NDISPROT_INDICATE_STATUS;
    nextStack->FileObject = Adapter->FileObject;

    //
    // Make sure the IOCTL is a buffered IOCTL.
    //

    ASSERT((IOCTL_NDISPROT_INDICATE_STATUS & 3) == METHOD_BUFFERED);
    
    irp->AssociatedIrp.SystemBuffer = &Adapter->NdisProtIndicateStatus;
    irp->MdlAddress = NULL;
        
    IoSetCompletionRoutine(irp,
                   NICStatusIndicationIrpCompletionRoutine,
                   Adapter,
                   TRUE,
                   TRUE,
                   TRUE);
    
    Adapter->StatusIndicationIrpLock = IRPLOCK_CANCELABLE;

    MP_INC_REF(Adapter);     
    
    (void) IoCallDriver(Adapter->TargetDeviceObject, irp);

    DEBUGP(MP_TRACE, ("<-- NICPostAsynchronousStatusIndicationIrp\n"));

    return STATUS_SUCCESS;

}

NTSTATUS
NICStatusIndicationIrpCompletionRoutine(
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp,
    IN PVOID            Context
    )
/*++

Routine Description:

    This is completion routine for status indication IRP.
    This routine carefully makes sure with an interlocked operation
    whether the IRP has been cancelled by another thread and if so
    return control. If not processes the indicate_status buffer and
    forwards the indication to the protocol bound to this NIC.
    
Arguments:

    Adapter     Pointer to our adapter
    
Return Value:

    NT status code
    
--*/ 
{
    PMP_ADAPTER Adapter = (PMP_ADAPTER)Context;
    PNDISPROT_INDICATE_STATUS pIndicateStatus = &Adapter->NdisProtIndicateStatus;
    PCHAR   buffer = (PCHAR)pIndicateStatus;
    BOOLEAN repost = FALSE;
    
    DEBUGP(MP_TRACE, ("--> NICStatusIndicationIrpCompletionRoutine\n"));

    if (InterlockedExchange(
            (PVOID)&Adapter->StatusIndicationIrpLock, 
            IRPLOCK_COMPLETED) == IRPLOCK_CANCEL_STARTED) {
        // 
        // Main line code has got the control of the IRP. It will
        // now take the responsibility of freeing  the IRP. 
        // Therefore...
        return STATUS_MORE_PROCESSING_REQUIRED;
    }

    //
    // We have the ownership of the IRP
    //
    if(!NT_SUCCESS(Irp->IoStatus.Status)) {  
        //
        // The IOCTL was failed for some reason. If the reason
        // is due to buffer overflow, we should increase our 
        // buffer and retry the operation. Well, in this driver
        // since I'm only interested in getting media indication,
        // I'm going to leave that as TODO item for developers
        // to work on depending on their real world scenario.
        //
        DEBUGP (MP_ERROR, ("IndicationIrp failed %x, %d \n", 
                Irp->IoStatus.Status,
                Irp->IoStatus.Information));
        if(NT_ERROR(Irp->IoStatus.Status)){
            //
            // Something terribly wrong. SO free the IRP and exit. 
            // If we repost the IRP we might end up in a never ending loop.
            // 
            IoFreeIrp(Irp);
            Adapter->StatusIndicationIrp = NULL;
        }else{
            //
            // This is either a warning or information status.
            //
            repost = TRUE;
        }
        
    } else {

        //
        // Find out the status is and update our Adapter context to
        // be in sync with the real NIC.
        //
        switch(pIndicateStatus->IndicatedStatus)
        {
            case NDIS_STATUS_RESET_START:
                DEBUGP(MP_LOUD, ("NDIS_STATUS_RESET_START\n"));
                break;

            case NDIS_STATUS_RESET_END:
                DEBUGP(MP_LOUD, ("NDIS_STATUS_RESET_END\n"));

                break;

            case NDIS_STATUS_MEDIA_CONNECT:
                DEBUGP(MP_TRACE, ("NDIS_STATUS_MEDIA_CONNECT\n"));                
                MP_CLEAR_FLAG(Adapter, fMP_DISCONNECTED); 
                break;

            case NDIS_STATUS_MEDIA_DISCONNECT:
                DEBUGP(MP_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT\n"));
                MP_SET_FLAG(Adapter, fMP_DISCONNECTED); 
                break;

            default:
                DEBUGP(MP_INFO, ("IndicateStatus %x\n", 
                        pIndicateStatus->IndicatedStatus));                
                break;
        }

        //
        // Let us indicate our media state to protocol drivers.
        //
        NdisMIndicateStatus(Adapter->AdapterHandle, 
                            pIndicateStatus->IndicatedStatus, 
                            (PVOID)(buffer + (pIndicateStatus->StatusBufferOffset)),
                            pIndicateStatus->StatusBufferLength);
        
        NdisMIndicateStatusComplete(Adapter->AdapterHandle);

        repost = TRUE;        
    }    

    if(repost){
        //
        // TODO:
        // Repost the request to the NDISPROT driver. Since I know that NDISPROT
        // always completes the IRP asynchronously, I don't have to worry about
        // recursion. But if you know that the target driver can complete the
        // IRP in the dispatch routine, reposting the IRP can cause recursion. SO
        // queue a workitem here and do a IoCallDriver from there. Please note
        // that this completion routine can be called at DISPATCH_LEVEL. So 
        // before reposting to the target driver, make sure it can handle 
        // requests at dispatch level.
        //
        NICPostAsynchronousStatusIndicationIrp(Adapter);
    }
    
    MP_DEC_REF(Adapter);                         

    DEBUGP(MP_TRACE, ("<-- NICStatusIndicationIrpCompletionRoutine\n"));
    
    return STATUS_MORE_PROCESSING_REQUIRED;    
}

VOID
NICCancelStatusIndicationIrp(
    IN PMP_ADAPTER Adapter
    )
/*++
Routine Description:

    This function tries to cancel the PendingIrp if it is not 
    already completed. Note that the IRP may not be completed 
    and freed when the function returns. To prevent our Halt handler
    from running to completion while the IRP is still pending, we
    have taken a ref count on the Adapter when we posted this asynchronous
    IRP. Until the refcount drops to zero, we will wait in the Halt 
    handler and as a result prevent the driver from unloading.
    
Arguments:

    Adapter     Pointer to our adapter
    
Return Value:

    NT Status code
    
--*/    
{ 
    DEBUGP(MP_TRACE, ("--> NICCancelStatusIndicationIrp\n"));

    if (Adapter->StatusIndicationIrp && 
            InterlockedExchange((PVOID)&Adapter->StatusIndicationIrpLock, IRPLOCK_CANCEL_STARTED) == IRPLOCK_CANCELABLE) {

        // 
        // You got it to the IRP before it was completed. You can cancel
        // the IRP without fear of losing it, as the completion routine
        // will not let go of the IRP until you say so.
        // 
        IoCancelIrp(Adapter->StatusIndicationIrp);
        // 
        // Release the completion routine. If it already got there,
        // then you need to free it yourself. Otherwise, you got
        // through IoCancelIrp before the IRP completed entirely.
        // 
        if (InterlockedExchange((PVOID)&Adapter->StatusIndicationIrpLock, IRPLOCK_CANCEL_COMPLETE) == IRPLOCK_COMPLETED) {
            
            IoFreeIrp(Adapter->StatusIndicationIrp);
            Adapter->StatusIndicationIrp = NULL;
            MP_DEC_REF(Adapter);                 
        }

    }

    DEBUGP(MP_TRACE, ("<-- NICCancelStatusIndicationIrp\n"));
     
    return ;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -