Exemplo n.º 1
0
NTSTATUS
NICLinkDetection(
    PFDO_DATA         FdoData
    )
/*++

Routine Description:

    Timer function for postponed link negotiation. Called from
    the NICWatchDogEvtTimerFunc. After the link detection is over
    we will complete any pending ioctl or send IRPs.

Arguments:

    FdoData     Pointer to our FdoData

Return Value:

    NT status

--*/
{
    NTSTATUS                status = STATUS_SUCCESS;
    MEDIA_STATE             CurrMediaState;
    PNDISPROT_QUERY_OID     pQuery = NULL;
    PNDISPROT_SET_OID       pSet = NULL;
    PVOID                   DataBuffer;
    ULONG                   BytesWritten;
    NDIS_OID                Oid;
    PVOID                   InformationBuffer;
    size_t               bufSize;
    WDFREQUEST              request;

    //
    // Handle the link negotiation.
    //
    if (FdoData->bLinkDetectionWait)
    {
        status = ScanAndSetupPhy(FdoData);
    }
    else
    {
        status = PhyDetect(FdoData);
    }

    if (status == STATUS_PENDING)
    {
        return status;
    }

    //
    // Reset some variables for link detection
    //
    FdoData->bLinkDetectionWait = FALSE;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "NICLinkDetection - negotiation done\n");


    WdfSpinLockAcquire(FdoData->Lock);
    MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION);

    WdfSpinLockRelease(FdoData->Lock);

    //
    // Any OID query request pending?
    //

    status = NICGetIoctlRequest(FdoData->PendingIoctlQueue,
                                IOCTL_NDISPROT_QUERY_OID_VALUE,
                                &request);

    if(NT_SUCCESS(status)) {
        status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_QUERY_OID), &DataBuffer, &bufSize);
        if(NT_SUCCESS(status)) {

            pQuery = (PNDISPROT_QUERY_OID)DataBuffer;
            Oid = pQuery->Oid;
            InformationBuffer = &pQuery->Data[0];
            switch(Oid)
            {
                case OID_GEN_LINK_SPEED:
                    *((PULONG)InformationBuffer) = FdoData->usLinkSpeed * 10000;
                    BytesWritten = sizeof(ULONG);

                    break;

                case OID_GEN_MEDIA_CONNECT_STATUS:
                default:
                    ASSERT(Oid == OID_GEN_MEDIA_CONNECT_STATUS);

                    CurrMediaState = NICIndicateMediaState(FdoData);

                    RtlMoveMemory(InformationBuffer,
                                  &CurrMediaState,
                                  sizeof(NDIS_MEDIA_STATE));

                    BytesWritten = sizeof(NDIS_MEDIA_STATE);
            }

            WdfRequestCompleteWithInformation(request, status, BytesWritten);
        }
    }

    //
    // Any OID set request pending?
    //
    status = NICGetIoctlRequest(FdoData->PendingIoctlQueue,
                            IOCTL_NDISPROT_SET_OID_VALUE,
                             &request);

    if(NT_SUCCESS(status)) {
        ULONG    PacketFilter;

        status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_SET_OID), &DataBuffer, &bufSize);
        if(NT_SUCCESS(status)) {

            pSet = (PNDISPROT_SET_OID)DataBuffer;
            Oid = pSet->Oid;
            InformationBuffer = &pSet->Data[0];
            if (Oid == OID_GEN_CURRENT_PACKET_FILTER)
            {

                RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG));


                WdfSpinLockAcquire(FdoData->Lock);

                status = NICSetPacketFilter(
                             FdoData,
                             PacketFilter);


                WdfSpinLockRelease(FdoData->Lock);

                if (status == STATUS_SUCCESS)
                {
                    FdoData->PacketFilter = PacketFilter;
                }

                WdfRequestCompleteWithInformation(request, status, 0);
            }
        }
    }

    //
    // Any read pending?
    //

    WdfSpinLockAcquire(FdoData->RcvLock);

    //
    // Start the NIC receive unit
    //
    status = NICStartRecv(FdoData);
    if (status != STATUS_SUCCESS)
    {
        MP_SET_HARDWARE_ERROR(FdoData);
    }


    WdfSpinLockRelease(FdoData->RcvLock);

    //
    // Send packets which have been queued while link detection was going on.
    //
    NICCheckForQueuedSends(FdoData);

    return status;
}
Exemplo n.º 2
0
NTSTATUS
NICHandleSetOidRequest(
    __in  PFDO_DATA                   FdoData,
    __in  PIRP                       Irp
    )
/*++

Routine Description:

    This routine handles ioctl request for Set OIDs. Most of
    the IOCTL requests are only if the upper edge is NDIS.

Arguments:


Return Value:


--*/
{
    NTSTATUS                status = STATUS_SUCCESS;
    PNDISPROT_SET_OID       pSet;
    NDIS_OID                Oid;
    ULONG                   PacketFilter;
    PVOID                   InformationBuffer = NULL;
    ULONG                   InformationBufferLength = 0;
    KIRQL                   oldIrql;
    PVOID                   DataBuffer;
    ULONG                   BufferLength, unUsed;
    PIO_STACK_LOCATION      pIrpSp;
    DEVICE_POWER_STATE      newDeviceState, oldDeviceState;

    pIrpSp = IoGetCurrentIrpStackLocation(Irp);
    DataBuffer = Irp->AssociatedIrp.SystemBuffer;
    BufferLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;

    DebugPrint(LOUD, DBG_IOCTLS, "--> HandleSetOIDRequest\n");

    Oid = 0;

    do
    {
        if (BufferLength < sizeof(NDISPROT_SET_OID))
        {
            status = STATUS_BUFFER_OVERFLOW;
            break;
        }

        pSet = (PNDISPROT_SET_OID)DataBuffer;
        Oid = pSet->Oid;
        InformationBuffer = &pSet->Data[0];
        InformationBufferLength = BufferLength - FIELD_OFFSET(NDISPROT_SET_OID, Data);
        switch(Oid)
        {

        case OID_802_3_MULTICAST_LIST:
            //
            // Verify the length
            //
            if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0)
            {
                return(STATUS_INVALID_BUFFER_SIZE);
            }

            //
            // Save the number of MC list size
            //
            FdoData->MCAddressCount = InformationBufferLength / ETH_LENGTH_OF_ADDRESS;
            ASSERT(FdoData->MCAddressCount <= NIC_MAX_MCAST_LIST);
            InformationBufferLength = InformationBufferLength > sizeof(FdoData->MCList)
					? sizeof(FdoData->MCList):InformationBufferLength;

            //
            // Save the MC list
            //
            RtlMoveMemory(
                FdoData->MCList,
                InformationBuffer,
                InformationBufferLength);

            KeAcquireSpinLock(&FdoData->Lock, &oldIrql);
            KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock);

            status = NICSetMulticastList(FdoData);

            KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
            KeReleaseSpinLock(&FdoData->Lock, oldIrql);
            break;

        case OID_GEN_CURRENT_PACKET_FILTER:
            //
            // Verify the Length
            //
            if (InformationBufferLength != sizeof(ULONG))
            {
                return(STATUS_INVALID_BUFFER_SIZE);
            }

            RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG));

            //
            // any bits not supported?
            //
            if (PacketFilter & ~NIC_SUPPORTED_FILTERS)
            {
                return(STATUS_NOT_SUPPORTED);
            }

            //
            // any filtering changes?
            //
            if (PacketFilter == FdoData->PacketFilter)
            {
                break;
            }

            KeAcquireSpinLock(&FdoData->Lock, &oldIrql);
            KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock);

            if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION))
            {

                //
                // The device is busy doing link detection. Let us queue
                // the IRP. When the link detection is over, the watchdog
                // timer DPC will complete this IRP.
                //
                ASSERT(!FdoData->SetRequest);
                status = PciDrvQueueIoctlIrp(FdoData, Irp);

                KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
                KeReleaseSpinLock(&FdoData->Lock, oldIrql);
                break;
            }

            status = NICSetPacketFilter(
                         FdoData,
                         PacketFilter);

            KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
            KeReleaseSpinLock(&FdoData->Lock, oldIrql);

            if (status == STATUS_SUCCESS)
            {
                FdoData->PacketFilter = PacketFilter;
            }

            break;

        case OID_PNP_SET_POWER:

            if (InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE ))
            {
                return(STATUS_BUFFER_TOO_SMALL);
            }

            newDeviceState = *(PDEVICE_POWER_STATE UNALIGNED)InformationBuffer;
            oldDeviceState = FdoData->DevicePowerState;
            FdoData->DevicePowerState = newDeviceState;

            if (oldDeviceState == PowerDeviceD0) {

                status = PciDrvPowerBeginQueuingIrps(
                    FdoData->Self,
                    1,              // One for current OID request.
                    FALSE           // Do not query for state change.
                    );

                ASSERT(NT_SUCCESS(status));
            }

            //
            // Set the power state - Cannot fail this request
            //
            status = NICSetPower(FdoData, newDeviceState );

            if (status != STATUS_SUCCESS)
            {
                DebugPrint(ERROR, DBG_IOCTLS, "SET Power: Hardware error !!!\n");
                break;
            }

            if (newDeviceState == PowerDeviceD0) {

                //
                // Our hardware is now on again. Here we empty our existing queue of
                // requests and let in new ones.
                //
                FdoData->QueueState = AllowRequests;
                PciDrvProcessQueuedRequests(FdoData);
            }

            status = STATUS_SUCCESS;
            break;

        case OID_PNP_ADD_WAKE_UP_PATTERN:
            //
            // call a function that would program the adapter's wake
            // up pattern, return success
            //
            DebugPrint(TRACE, DBG_IOCTLS, "--> OID_PNP_ADD_WAKE_UP_PATTERN\n");

            if (IsPoMgmtSupported(FdoData) )
            {
                status = NICAddWakeUpPattern(FdoData,
                                            InformationBuffer,
                                            InformationBufferLength,
                                            &unUsed,
                                            &unUsed);
            }
            else
            {
                status = STATUS_NOT_SUPPORTED;
            }
            break;


        case OID_PNP_REMOVE_WAKE_UP_PATTERN:

            //
            // call a function that would remove the adapter's wake
            // up pattern, return success
            //
            DebugPrint(TRACE, DBG_IOCTLS, "--> OID_PNP_ADD_WAKE_UP_PATTERN\n");

            if (IsPoMgmtSupported(FdoData) )
            {
                status = NICRemoveWakeUpPattern(FdoData,
                                               InformationBuffer,
                                               InformationBufferLength,
                                               &unUsed,
                                               &unUsed);

            }
            else
            {
                status = STATUS_NOT_SUPPORTED;
            }
            break;

        case OID_PNP_ENABLE_WAKE_UP:
            //
            // call a function that would enable wake up on the adapter
            // return success
            //
            DebugPrint(TRACE, DBG_IOCTLS, "--> OID_PNP_ENABLE_WAKE_UP\n");
            if (IsPoMgmtSupported(FdoData))
            {
                ULONG       WakeUpEnable;
                RtlMoveMemory(&WakeUpEnable, InformationBuffer,sizeof(ULONG));
                //
                // The WakeUpEable can only be 0, or NDIS_PNP_WAKE_UP_PATTERN_MATCH since the driver only
                // supports wake up pattern match
                //
                if ((WakeUpEnable != 0)
                       && ((WakeUpEnable & NDIS_PNP_WAKE_UP_PATTERN_MATCH) != NDIS_PNP_WAKE_UP_PATTERN_MATCH ))
                {
                    status = STATUS_NOT_SUPPORTED;
                    FdoData->AllowWakeArming = FALSE;
                    break;
                }
                //
                // When the driver goes to low power state, it would check WakeUpEnable to decide
                // which wake up methed it should use to wake up the machine. If WakeUpEnable is 0,
                // no wake up method is enabled.
                //
                FdoData->AllowWakeArming = TRUE;

                status = STATUS_SUCCESS;
            }
            else
            {
                status = STATUS_NOT_SUPPORTED;
            }

            break;
        default:
            status = STATUS_NOT_SUPPORTED;
            break;
        }
    }while (FALSE);

    DebugPrint(LOUD, DBG_IOCTLS, "<-- HandleSetOIDRequest\n");

    return (status);
}
Exemplo n.º 3
0
NTSTATUS
MPSetPowerD0(
    PFDO_DATA  FdoData
    )
/*++
Routine Description:

    This routine is called when the adapter receives a SetPower
    to D0.

Arguments:

    Adapter                 Pointer to the adapter structure
    PowerState              NewPowerState

Return Value:


--*/
{
    NTSTATUS            status;
    //KIRQL               oldIrql;

    //
    // MPSetPowerD0Private Initializes the adapte, issues a selective reset.
    //
    MPSetPowerD0Private (FdoData);
    ASSERT(FdoData->DevicePowerState == PowerDeviceD0);
    //
    // Set up the packet filter
    //

    WdfSpinLockAcquire(FdoData->Lock);
    status = NICSetPacketFilter(
                 FdoData,
                 FdoData->OldPacketFilter);
    //
    // If Set Packet Filter succeeds, restore the old packet filter
    //
    if (status == STATUS_SUCCESS)
    {
        FdoData->PacketFilter = FdoData->OldPacketFilter;
    }


    WdfSpinLockRelease(FdoData->Lock);

    //
    // Set up the multicast list address
    //

    WdfSpinLockAcquire(FdoData->RcvLock);

    status = NICSetMulticastList(FdoData);

    NICStartRecv(FdoData);


    WdfSpinLockRelease(FdoData->RcvLock);

    return status;
}