Exemplo n.º 1
0
// Worker thread for processing all tunnel events
_Use_decl_annotations_
VOID
otLwfTunWorkerThread(
    PVOID   Context
    )
{
    PMS_FILTER pFilter = (PMS_FILTER)Context;
    NT_ASSERT(pFilter);

    LogFuncEntry(DRIVER_DEFAULT);

    PKEVENT WaitEvents[] = 
    { 
        &pFilter->TunWorkerThreadStopEvent,
        &pFilter->TunWorkerThreadAddressChangedEvent
    };

    LogFuncExit(DRIVER_DEFAULT);
    
    while (true)
    {
        // Wait for event to stop or process event to fire
        NTSTATUS status = 
            KeWaitForMultipleObjects(
                ARRAYSIZE(WaitEvents), 
                (PVOID*)WaitEvents, 
                WaitAny, 
                Executive, 
                KernelMode, 
                FALSE, 
                NULL, 
                NULL);

        // If it is the first event, then we are shutting down. Exit loop and terminate thread
        if (status == STATUS_WAIT_0)
        {
            LogInfo(DRIVER_DEFAULT, "Received tunnel worker thread shutdown event.");
            break;
        }
        else if (status == STATUS_WAIT_0 + 1) // TunWorkerThreadAddressChangedEvent fired
        {
            PVOID DataBuffer = NULL;
            const uint8_t* value_data_ptr = NULL;
            spinel_size_t value_data_len = 0;
            
            // Query the current addresses
            status = 
                otLwfCmdGetProp(
                    pFilter,
                    &DataBuffer,
                    SPINEL_PROP_IPV6_ADDRESS_TABLE,
                    SPINEL_DATATYPE_DATA_S,
                    &value_data_ptr,
                    &value_data_len);
            if (NT_SUCCESS(status))
            {
                uint32_t aNotifFlags = 0;
                otLwfTunAddressesUpdated(pFilter, value_data_ptr, value_data_len, &aNotifFlags);

                // Send notification
                if (aNotifFlags != 0)
                {
                    PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
                    if (NotifEntry)
                    {
                        RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
                        NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
                        NotifEntry->Notif.NotifType = OTLWF_NOTIF_STATE_CHANGE;
                        NotifEntry->Notif.StateChangePayload.Flags = aNotifFlags;

                        otLwfIndicateNotification(NotifEntry);
                    }
                }
            }
            else
            {
                LogWarning(DRIVER_DEFAULT, "Failed to query addresses, %!STATUS!", status);
            }

            if (DataBuffer) FILTER_FREE_MEM(DataBuffer);
        }
        else
        {
            LogWarning(DRIVER_DEFAULT, "Unexpected wait result, %!STATUS!", status);
        }
    }

    PsTerminateSystemThread(STATUS_SUCCESS);
}
Exemplo n.º 2
0
_Use_decl_annotations_
NDIS_STATUS
FilterRestart(
    NDIS_HANDLE                     FilterModuleContext,
    PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
    )
/*++

Routine Description:

    Filter restart routine.
    Start the datapath - begin sending and receiving NBLs.

Arguments:

    FilterModuleContext - pointer to the filter context stucture.
    RestartParameters   - additional information about the restart operation.

Return Value:

    NDIS_STATUS_SUCCESS: if filter restarts successfully
    NDIS_STATUS_XXX: Otherwise.

--*/
{
    NTSTATUS            NtStatus = STATUS_SUCCESS;
    NDIS_STATUS         NdisStatus = NDIS_STATUS_SUCCESS;
    PMS_FILTER          pFilter = (PMS_FILTER)FilterModuleContext;
    PVOID               SpinelCapsDataBuffer = NULL;
    const uint8_t*      SpinelCapsPtr = NULL;
    spinel_size_t       SpinelCapsLen = 0;
    NL_INTERFACE_KEY    key = {0};
    NL_INTERFACE_RW     interfaceRw;
    ULONG               ThreadOnHost = TRUE;

    PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;
    PNDIS_RESTART_ATTRIBUTES         NdisRestartAttributes;

    LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", FilterModuleContext);

    NT_ASSERT(pFilter->State == FilterPaused);

    NdisRestartAttributes = RestartParameters->RestartAttributes;

    //
    // If NdisRestartAttributes is not NULL, then the filter can modify generic 
    // attributes and add new media specific info attributes at the end. 
    // Otherwise, if NdisRestartAttributes is NULL, the filter should not try to 
    // modify/add attributes.
    //
    if (NdisRestartAttributes != NULL)
    {
        ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES);

        NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data;

        //
        // Check to see if we need to change any attributes. For example, the
        // driver can change the current MAC address here. Or the driver can add
        // media specific info attributes.
        //
        NdisGeneralAttributes->LookaheadSize = 128;
    }

    // Initialize the Spinel command processing
    NdisStatus = otLwfCmdInitialize(pFilter);
    if (NdisStatus != NDIS_STATUS_SUCCESS)
    {
        LogError(DRIVER_DEFAULT, "otLwfCmdInitialize failed, %!NDIS_STATUS!", NdisStatus);
        goto exit;
    }

    // Query the device capabilities
    NtStatus = otLwfCmdGetProp(pFilter, SpinelCapsDataBuffer, SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, &SpinelCapsPtr, &SpinelCapsLen);
    if (!NT_SUCCESS(NtStatus))
    {
        NdisStatus = NDIS_STATUS_NOT_SUPPORTED;
        LogError(DRIVER_DEFAULT, "Failed to query SPINEL_PROP_CAPS, %!STATUS!", NtStatus);
        goto exit;
    }

    // Iterate and process returned capabilities
    while (SpinelCapsLen > 0)
    {
        ULONG SpinelCap = 0;
        spinel_ssize_t len = spinel_datatype_unpack(SpinelCapsPtr, SpinelCapsLen, SPINEL_DATATYPE_UINT_PACKED_S, &SpinelCap);
        if (len < 1) break;
        SpinelCapsLen -= (spinel_size_t)len;

        switch (SpinelCap)
        {
        case SPINEL_CAP_MAC_RAW:
            pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO;
            pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO_ACK_TIMEOUT;
            pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO_ENERGY_SCAN;
            break;
        case SPINEL_CAP_NET_THREAD_1_0:
            pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_THREAD_1_0;
            break;
        default:
            break;
        }
    }

    // Set the state indicating where we should be running the Thread logic (Host or Device).
    if (!NT_SUCCESS(GetRegDWORDValue(pFilter, L"RunOnHost", &ThreadOnHost)))
    {
        // Default to running on the host if the key isn't present
        ThreadOnHost = TRUE;
        SetRegDWORDValue(pFilter, L"RunOnHost", ThreadOnHost);
    }

    LogInfo(DRIVER_DEFAULT, "Filter: %p initializing ThreadOnHost=%d", FilterModuleContext, ThreadOnHost);

    // Initialize the processing logic
    if (ThreadOnHost)
    {
        // Ensure the device has the capabilities to support raw radio commands
        if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO) == 0)
        {
            LogError(DRIVER_DEFAULT, "Failed to start because device doesn't support raw radio commands");
            NdisStatus = NDIS_STATUS_NOT_SUPPORTED;
            goto exit;
        }

        pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_RADIO_MODE;
        NtStatus = otLwfInitializeThreadMode(pFilter);
        if (!NT_SUCCESS(NtStatus))
        {
            LogError(DRIVER_DEFAULT, "otLwfInitializeThreadMode failed, %!STATUS!", NtStatus);
            NdisStatus = NDIS_STATUS_FAILURE;
            pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED;
            goto exit;
        }
    }
    else
    {
        // Ensure the device has the capabilities to support Thread commands
        if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_THREAD_1_0) == 0)
        {
            LogError(DRIVER_DEFAULT, "Failed to start because device doesn't support thread commands");
            NdisStatus = NDIS_STATUS_NOT_SUPPORTED;
            goto exit;
        }

        pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_THREAD_MODE;
        NtStatus = otLwfTunInitialize(pFilter);
        if (!NT_SUCCESS(NtStatus))
        {
            LogError(DRIVER_DEFAULT, "otLwfInitializeTunnelMode failed, %!STATUS!", NtStatus);
            NdisStatus = NDIS_STATUS_FAILURE;
            pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED;
            goto exit;
        }
    }

    //
    // Disable DAD and Neighbor advertisements
    //
    key.Luid = pFilter->InterfaceLuid;
    NlInitializeInterfaceRw(&interfaceRw);
    interfaceRw.DadTransmits = 0;
    interfaceRw.SendUnsolicitedNeighborAdvertisementOnDad = FALSE;
  
    NtStatus =
        NsiSetAllParameters(
            NsiActive,
            NsiSetDefault,
            &NPI_MS_IPV6_MODULEID,
            NlInterfaceObject,
            &key,
            sizeof(key),
            &interfaceRw,
            sizeof(interfaceRw));
    if (!NT_SUCCESS(NtStatus))
    {
        LogError(DRIVER_DEFAULT, "NsiSetAllParameters (NlInterfaceObject) failed, %!STATUS!", NtStatus);
        NdisStatus = NDIS_STATUS_FAILURE;
        goto exit;
    }

    //
    // Enable the external references to the filter
    //
    ExReInitializeRundownProtection(&pFilter->ExternalRefs);

    //
    // If everything is OK, set the filter in running state.
    //
    pFilter->State = FilterRunning; // when successful
    otLwfNotifyDeviceAvailabilityChange(pFilter, TRUE);
    LogInfo(DRIVER_DEFAULT, "Interface %!GUID! arrival, Filter=%p", &pFilter->InterfaceGuid, pFilter);

exit:

    //
    // Ensure the state is Paused if restart failed.
    //
    if (NdisStatus != NDIS_STATUS_SUCCESS)
    {
        pFilter->State = FilterPaused;

        if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE)
        {
            otLwfUninitializeThreadMode(pFilter);
        }
        else if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_THREAD_MODE)
        {
            otLwfTunUninitialize(pFilter);
        }

        pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED;

        // Clean up Spinel command processing
        otLwfCmdUninitialize(pFilter);
    }

    // Free the buffer for the capabilities we queried
    if (SpinelCapsDataBuffer != NULL)
    {
        FILTER_FREE_MEM(SpinelCapsDataBuffer);
    }

    LogFuncExitNDIS(DRIVER_DEFAULT, NdisStatus);
    return NdisStatus;
}