| /* |
| * Copyright (c) 2016, The OpenThread Authors. |
| * 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 copyright holder 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 HOLDER 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. |
| */ |
| |
| /** |
| * @file |
| * @brief |
| * This file implements the logging function required for the OpenThread library. |
| */ |
| |
| #include "precomp.h" |
| #include "radio.tmh" |
| |
| void |
| LogMac( |
| _In_ PCSTR szDir, |
| _In_ PMS_FILTER pFilter, |
| ULONG frameLength, |
| _In_reads_bytes_(frameLength) PUCHAR frame |
| ); |
| |
| const char MacSend[] = "MAC_SEND"; |
| const char MacRecv[] = "MAC_RECV"; |
| |
| #define LogMacSend(pFilter, frameLength, frame) LogMac(MacSend, pFilter, frameLength, frame) |
| #define LogMacRecv(pFilter, frameLength, frame) LogMac(MacRecv, pFilter, frameLength, frame) |
| |
| void |
| otPlatReset( |
| _In_ otInstance *otCtx |
| ) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| LogFuncEntry(DRIVER_DEFAULT); |
| |
| LogInfo(DRIVER_DEFAULT, "Interface %!GUID! resetting...", &pFilter->InterfaceGuid); |
| |
| // Indicate to the miniport |
| (void)otLwfCmdResetDevice(pFilter, TRUE); |
| |
| // Finalize previous OpenThread instance |
| otLwfReleaseInstance(pFilter); |
| |
| // Reset radio layer |
| pFilter->otRadioState = OT_RADIO_STATE_DISABLED; |
| pFilter->otCurrentListenChannel = 0xFF; |
| pFilter->otPromiscuous = false; |
| pFilter->otPendingMacOffloadEnabled = FALSE; |
| |
| // Reinitialize the OpenThread library |
| pFilter->otCachedRole = OT_DEVICE_ROLE_DISABLED; |
| pFilter->otCtx = otInstanceInit(pFilter->otInstanceBuffer + sizeof(PMS_FILTER), &pFilter->otInstanceSize); |
| ASSERT(pFilter->otCtx); |
| |
| // Make sure our helper function returns the right pointer for the filter, given the openthread instance |
| NT_ASSERT(otCtxToFilter(pFilter->otCtx) == pFilter); |
| |
| // Disable Icmp (ping) handling |
| otIcmp6SetEchoEnabled(pFilter->otCtx, FALSE); |
| |
| // Register callbacks with OpenThread |
| otSetStateChangedCallback(pFilter->otCtx, otLwfStateChangedCallback, pFilter); |
| otIp6SetReceiveCallback(pFilter->otCtx, otLwfReceiveIp6DatagramCallback, pFilter); |
| |
| // Query the current addresses from TCPIP and cache them |
| (void)otLwfInitializeAddresses(pFilter); |
| |
| // Initialze media connect state to disconnected |
| otLwfIndicateLinkState(pFilter, MediaConnectStateDisconnected); |
| |
| LogFuncExit(DRIVER_DEFAULT); |
| } |
| |
| otPlatResetReason |
| otPlatGetResetReason( |
| _In_ otInstance *otCtx |
| ) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| return pFilter->cmdResetReason; |
| } |
| |
| VOID |
| otLwfRadioGetFactoryAddress( |
| _In_ PMS_FILTER pFilter |
| ) |
| { |
| NTSTATUS status; |
| PVOID SpinelBuffer = NULL; |
| uint8_t *hwAddress = NULL; |
| |
| RtlZeroMemory(&pFilter->otFactoryAddress, sizeof(pFilter->otFactoryAddress)); |
| |
| // Query the MP for the address |
| status = |
| otLwfCmdGetProp( |
| pFilter, |
| &SpinelBuffer, |
| SPINEL_PROP_HWADDR, |
| SPINEL_DATATYPE_EUI64_S, |
| &hwAddress |
| ); |
| if (!NT_SUCCESS(status) || hwAddress == NULL) |
| { |
| LogError(DRIVER_DEFAULT, "Get SPINEL_PROP_HWADDR failed, %!STATUS!", status); |
| return; |
| } |
| |
| NT_ASSERT(SpinelBuffer); |
| memcpy(&pFilter->otFactoryAddress, hwAddress, sizeof(pFilter->otFactoryAddress)); |
| FILTER_FREE_MEM(SpinelBuffer); |
| |
| LogInfo(DRIVER_DEFAULT, "Interface %!GUID! cached factory Extended Mac Address: %llX", &pFilter->InterfaceGuid, pFilter->otFactoryAddress); |
| } |
| |
| VOID |
| otLwfRadioInit( |
| _In_ PMS_FILTER pFilter |
| ) |
| { |
| LogFuncEntry(DRIVER_DEFAULT); |
| |
| NT_ASSERT(pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE); |
| |
| // Initialize the OpenThread radio capability flags |
| pFilter->otRadioCapabilities = 0; |
| if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO_ACK_TIMEOUT) != 0) |
| pFilter->otRadioCapabilities |= OT_RADIO_CAPS_ACK_TIMEOUT; |
| if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO_MAC_RETRY_AND_COLLISION_AVOIDANCE) != 0) |
| pFilter->otRadioCapabilities |= OT_RADIO_CAPS_TRANSMIT_RETRIES; |
| if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO_ENERGY_SCAN) != 0) |
| pFilter->otRadioCapabilities |= OT_RADIO_CAPS_ENERGY_SCAN; |
| |
| pFilter->otRadioState = OT_RADIO_STATE_DISABLED; |
| pFilter->otCurrentListenChannel = 0xFF; |
| pFilter->otPromiscuous = false; |
| |
| pFilter->otReceiveFrame.mPsdu = pFilter->otReceiveMessage; |
| pFilter->otTransmitFrame.mPsdu = pFilter->otTransmitMessage; |
| |
| pFilter->otPendingMacOffloadEnabled = FALSE; |
| |
| // Cache the factory address |
| otLwfRadioGetFactoryAddress(pFilter); |
| |
| LogInfo(DRIVER_DEFAULT, "Filter %p RadioState = OT_RADIO_STATE_DISABLED.", pFilter); |
| |
| LogFuncExit(DRIVER_DEFAULT); |
| } |
| |
| void otPlatRadioGetIeeeEui64(otInstance *otCtx, uint8_t *aIeeeEui64) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| memcpy(aIeeeEui64, &pFilter->otFactoryAddress, sizeof(ULONGLONG)); |
| } |
| |
| void otPlatRadioSetPanId(_In_ otInstance *otCtx, uint16_t panid) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| NTSTATUS status; |
| |
| LogInfo(DRIVER_DEFAULT, "Interface %!GUID! set PanID: %X", &pFilter->InterfaceGuid, panid); |
| |
| pFilter->otPanID = panid; |
| |
| if (pFilter->otRadioState != OT_RADIO_STATE_DISABLED && |
| pFilter->otPanID != 0xFFFF) |
| { |
| // Indicate to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_15_4_PANID, |
| SPINEL_DATATYPE_UINT16_S, |
| panid |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_15_4_PANID failed, %!STATUS!", status); |
| } |
| } |
| } |
| |
| void otPlatRadioSetExtendedAddress(_In_ otInstance *otCtx, uint8_t *address) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| NTSTATUS status; |
| spinel_eui64_t extAddr; |
| |
| LogInfo(DRIVER_DEFAULT, "Interface %!GUID! set Extended Mac Address: %llX", &pFilter->InterfaceGuid, *(ULONGLONG*)address); |
| |
| pFilter->otExtendedAddress = *(ULONGLONG*)address; |
| |
| for (size_t i = 0; i < OT_EXT_ADDRESS_SIZE; i++) |
| { |
| extAddr.bytes[i] = address[7 - i]; |
| } |
| |
| // Indicate to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_15_4_LADDR, |
| SPINEL_DATATYPE_EUI64_S, |
| &extAddr |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_15_4_LADDR failed, %!STATUS!", status); |
| } |
| } |
| |
| void otPlatRadioSetShortAddress(_In_ otInstance *otCtx, uint16_t address) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| NTSTATUS status; |
| |
| LogInfo(DRIVER_DEFAULT, "Interface %!GUID! set Short Mac Address: %X", &pFilter->InterfaceGuid, address); |
| |
| pFilter->otShortAddress = address; |
| |
| if (pFilter->otRadioState != OT_RADIO_STATE_DISABLED) |
| { |
| // Indicate to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_15_4_SADDR, |
| SPINEL_DATATYPE_UINT16_S, |
| address |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_15_4_SADDR failed, %!STATUS!", status); |
| } |
| } |
| } |
| |
| void otPlatRadioSetPromiscuous(_In_ otInstance *otCtx, bool aEnable) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| NTSTATUS status; |
| |
| pFilter->otPromiscuous = (BOOLEAN)aEnable; |
| |
| // Indicate to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_PROMISCUOUS_MODE, |
| SPINEL_DATATYPE_UINT8_S, |
| aEnable != 0 ? SPINEL_MAC_PROMISCUOUS_MODE_NETWORK : SPINEL_MAC_PROMISCUOUS_MODE_OFF |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_PROMISCUOUS_MODE failed, %!STATUS!", status); |
| } |
| } |
| |
| bool otPlatRadioIsEnabled(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| return pFilter->otRadioState != OT_RADIO_STATE_DISABLED; |
| } |
| |
| otError otPlatRadioEnable(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| NTSTATUS status; |
| |
| NT_ASSERT(pFilter->otRadioState <= OT_RADIO_STATE_SLEEP); |
| if (pFilter->otRadioState > OT_RADIO_STATE_SLEEP) return OT_ERROR_BUSY; |
| |
| pFilter->otRadioState = OT_RADIO_STATE_SLEEP; |
| |
| // Indicate to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_PHY_ENABLED, |
| SPINEL_DATATYPE_BOOL_S, |
| TRUE |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_PHY_ENABLED (true) failed, %!STATUS!", status); |
| } |
| |
| LogInfo(DRIVER_DEFAULT, "Filter %p RadioState = OT_RADIO_STATE_SLEEP.", pFilter); |
| |
| if (pFilter->otPanID != 0xFFFF) |
| { |
| // Indicate PANID to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_15_4_PANID, |
| SPINEL_DATATYPE_UINT16_S, |
| pFilter->otPanID |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_15_4_PANID failed, %!STATUS!", status); |
| } |
| } |
| |
| // Indicate Short address to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_15_4_SADDR, |
| SPINEL_DATATYPE_UINT16_S, |
| pFilter->otShortAddress |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_15_4_SADDR failed, %!STATUS!", status); |
| } |
| |
| return NT_SUCCESS(status) ? OT_ERROR_NONE : OT_ERROR_FAILED; |
| } |
| |
| otError otPlatRadioDisable(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| NTSTATUS status; |
| |
| // First make sure we are in the Sleep state if we weren't already |
| if (pFilter->otRadioState > OT_RADIO_STATE_SLEEP) |
| { |
| (void)otPlatRadioSleep(otCtx); |
| } |
| |
| pFilter->otRadioState = OT_RADIO_STATE_DISABLED; |
| |
| // Indicate to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_PHY_ENABLED, |
| SPINEL_DATATYPE_BOOL_S, |
| FALSE |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_PHY_ENABLED (false) failed, %!STATUS!", status); |
| } |
| |
| LogInfo(DRIVER_DEFAULT, "Filter %p RadioState = OT_RADIO_STATE_DISABLED.", pFilter); |
| |
| return NT_SUCCESS(status) ? OT_ERROR_NONE : OT_ERROR_FAILED; |
| } |
| |
| otError otPlatRadioSleep(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| // If we were in the transmit state, cancel the transmit |
| if (pFilter->otRadioState == OT_RADIO_STATE_TRANSMIT) |
| { |
| pFilter->otLastTransmitError = OT_ERROR_ABORT; |
| otLwfRadioTransmitFrameDone(pFilter); |
| } |
| |
| if (pFilter->otRadioState != OT_RADIO_STATE_SLEEP) |
| { |
| pFilter->otRadioState = OT_RADIO_STATE_SLEEP; |
| LogInfo(DRIVER_DEFAULT, "Filter %p RadioState = OT_RADIO_STATE_SLEEP.", pFilter); |
| |
| // Indicate to the miniport |
| NTSTATUS status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_RAW_STREAM_ENABLED, |
| SPINEL_DATATYPE_BOOL_S, |
| FALSE |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_RAW_STREAM_ENABLED (false) failed, %!STATUS!", status); |
| } |
| } |
| |
| return OT_ERROR_NONE; |
| } |
| |
| otError otPlatRadioReceive(_In_ otInstance *otCtx, uint8_t aChannel) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| NT_ASSERT(pFilter->otRadioState != OT_RADIO_STATE_DISABLED); |
| if (pFilter->otRadioState == OT_RADIO_STATE_DISABLED) return OT_ERROR_BUSY; |
| |
| LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p", pFilter); |
| |
| // Update current channel if different |
| if (pFilter->otCurrentListenChannel != aChannel) |
| { |
| NTSTATUS status; |
| |
| NT_ASSERT(aChannel >= 11 && aChannel <= 26); |
| |
| LogInfo(DRIVER_DEFAULT, "Filter %p new Listen Channel = %u.", pFilter, aChannel); |
| pFilter->otCurrentListenChannel = aChannel; |
| |
| // Indicate to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_PHY_CHAN, |
| SPINEL_DATATYPE_UINT8_S, |
| aChannel |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_PHY_CHAN failed, %!STATUS!", status); |
| } |
| } |
| |
| // Only transition to the receive state if we were sleeping; otherwise we |
| // are already in receive or transmit state. |
| if (pFilter->otRadioState == OT_RADIO_STATE_SLEEP) |
| { |
| pFilter->otRadioState = OT_RADIO_STATE_RECEIVE; |
| LogInfo(DRIVER_DEFAULT, "Filter %p RadioState = OT_RADIO_STATE_RECEIVE.", pFilter); |
| |
| NTSTATUS status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_RAW_STREAM_ENABLED, |
| SPINEL_DATATYPE_BOOL_S, |
| TRUE |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_RAW_STREAM_ENABLED (true) failed, %!STATUS!", status); |
| } |
| |
| // Set the event to indicate we can process NBLs |
| KeSetEvent(&pFilter->EventWorkerThreadProcessNBLs, 0, FALSE); |
| } |
| |
| LogFuncExit(DRIVER_DATA_PATH); |
| |
| return OT_ERROR_NONE; |
| } |
| |
| otRadioFrame *otPlatRadioGetTransmitBuffer(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| return &pFilter->otTransmitFrame; |
| } |
| |
| int8_t otPlatRadioGetRssi(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| UNREFERENCED_PARAMETER(pFilter); |
| return 0; |
| } |
| |
| otRadioCaps otPlatRadioGetCaps(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| return otCtxToFilter(otCtx)->otRadioCapabilities; |
| } |
| |
| bool otPlatRadioGetPromiscuous(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| return pFilter->otPromiscuous; |
| } |
| |
| VOID |
| otLwfRadioReceiveFrame( |
| _In_ PMS_FILTER pFilter, |
| _In_ otError errorCode |
| ) |
| { |
| NT_ASSERT(pFilter->otReceiveFrame.mChannel >= 11 && pFilter->otReceiveFrame.mChannel <= 26); |
| |
| LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p", pFilter); |
| |
| LogMacRecv(pFilter, pFilter->otReceiveFrame.mLength, pFilter->otReceiveFrame.mPsdu); |
| |
| if (pFilter->otRadioState > OT_RADIO_STATE_DISABLED) |
| { |
| otPlatRadioReceiveDone(pFilter->otCtx, &pFilter->otReceiveFrame, errorCode); |
| } |
| else |
| { |
| LogVerbose(DRIVER_DATA_PATH, "Mac frame dropped."); |
| } |
| |
| LogFuncExit(DRIVER_DATA_PATH); |
| } |
| |
| otError otPlatRadioTransmit(_In_ otInstance *otCtx, _In_ otRadioFrame *aFrame) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| otError error = OT_ERROR_BUSY; |
| |
| UNREFERENCED_PARAMETER(aFrame); |
| |
| LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p", pFilter); |
| |
| NT_ASSERT(pFilter->otRadioState == OT_RADIO_STATE_RECEIVE); |
| if (pFilter->otRadioState == OT_RADIO_STATE_RECEIVE) |
| { |
| error = OT_ERROR_NONE; |
| pFilter->otRadioState = OT_RADIO_STATE_TRANSMIT; |
| |
| LogInfo(DRIVER_DEFAULT, "Filter %p RadioState = OT_RADIO_STATE_TRANSMIT.", pFilter); |
| } |
| |
| LogFuncExitMsg(DRIVER_DATA_PATH, "%u", error); |
| |
| return error; |
| } |
| |
| VOID otLwfRadioTransmitFrame(_In_ PMS_FILTER pFilter) |
| { |
| NT_ASSERT(pFilter->otRadioState == OT_RADIO_STATE_TRANSMIT); |
| |
| LogMacSend(pFilter, pFilter->otTransmitFrame.mLength, pFilter->otTransmitFrame.mPsdu); |
| |
| LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p", pFilter); |
| |
| otLwfCmdSendMacFrameAsync(pFilter, &pFilter->otTransmitFrame); |
| |
| LogFuncExit(DRIVER_DATA_PATH); |
| } |
| |
| VOID |
| otLwfRadioTransmitFrameDone( |
| _In_ PMS_FILTER pFilter |
| ) |
| { |
| LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p", pFilter); |
| |
| if (pFilter->otRadioState == OT_RADIO_STATE_TRANSMIT) |
| { |
| pFilter->SendPending = FALSE; |
| |
| // Now that we are completing a send, fall back to receive state and set the event |
| pFilter->otRadioState = OT_RADIO_STATE_RECEIVE; |
| LogInfo(DRIVER_DEFAULT, "Filter %p RadioState = OT_RADIO_STATE_RECEIVE.", pFilter); |
| KeSetEvent(&pFilter->EventWorkerThreadProcessNBLs, 0, FALSE); |
| |
| if (pFilter->otLastTransmitError != OT_ERROR_NONE && |
| pFilter->otLastTransmitError != OT_ERROR_CHANNEL_ACCESS_FAILURE && |
| pFilter->otLastTransmitError != OT_ERROR_NO_ACK) |
| { |
| pFilter->otLastTransmitError = OT_ERROR_ABORT; |
| } |
| |
| if (((pFilter->otTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0) || |
| pFilter->otLastTransmitError != OT_ERROR_NONE) |
| { |
| otPlatRadioTxDone(pFilter->otCtx, &pFilter->otTransmitFrame, NULL, pFilter->otLastTransmitError); |
| } |
| else |
| { |
| otPlatRadioTxDone(pFilter->otCtx, &pFilter->otTransmitFrame, &pFilter->otReceiveFrame, pFilter->otLastTransmitError); |
| } |
| } |
| |
| LogFuncExit(DRIVER_DATA_PATH); |
| } |
| |
| void otPlatRadioEnableSrcMatch(_In_ otInstance *otCtx, bool aEnable) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| // Ignore if we are already in the correct state |
| if (aEnable == pFilter->otPendingMacOffloadEnabled) return; |
| |
| // Cache the new value |
| pFilter->otPendingMacOffloadEnabled = aEnable ? TRUE : FALSE; |
| |
| // Indicate to the miniport |
| NTSTATUS status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_SRC_MATCH_ENABLED, |
| SPINEL_DATATYPE_BOOL_S, |
| (aEnable ? TRUE : FALSE) |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SRC_MATCH_ENABLED failed, %!STATUS!", status); |
| } |
| } |
| |
| otError otPlatRadioAddSrcMatchShortEntry(_In_ otInstance *otCtx, const uint16_t aShortAddress) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| // Indicate to the miniport |
| NTSTATUS status = |
| otLwfCmdInsertProp( |
| pFilter, |
| SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, |
| SPINEL_DATATYPE_UINT16_S, |
| aShortAddress |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Insert SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES failed, %!STATUS!", status); |
| } |
| |
| return NT_SUCCESS(status) ? OT_ERROR_NONE : OT_ERROR_FAILED; |
| } |
| |
| otError otPlatRadioAddSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8_t *aExtAddress) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| // Indicate to the miniport |
| NTSTATUS status = |
| otLwfCmdInsertProp( |
| pFilter, |
| SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, |
| SPINEL_DATATYPE_EUI64_S, |
| aExtAddress |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Insert SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES failed, %!STATUS!", status); |
| } |
| |
| return NT_SUCCESS(status) ? OT_ERROR_NONE : OT_ERROR_FAILED; |
| } |
| |
| otError otPlatRadioClearSrcMatchShortEntry(_In_ otInstance *otCtx, const uint16_t aShortAddress) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| // Indicate to the miniport |
| NTSTATUS status = |
| otLwfCmdRemoveProp( |
| pFilter, |
| SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, |
| SPINEL_DATATYPE_UINT16_S, |
| aShortAddress |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Remove SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES failed, %!STATUS!", status); |
| } |
| |
| return NT_SUCCESS(status) ? OT_ERROR_NONE : OT_ERROR_FAILED; |
| } |
| |
| otError otPlatRadioClearSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8_t *aExtAddress) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| // Indicate to the miniport |
| NTSTATUS status = |
| otLwfCmdRemoveProp( |
| pFilter, |
| SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, |
| SPINEL_DATATYPE_EUI64_S, |
| aExtAddress |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Remove SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES failed, %!STATUS!", status); |
| } |
| |
| return NT_SUCCESS(status) ? OT_ERROR_NONE : OT_ERROR_FAILED; |
| } |
| |
| void otPlatRadioClearSrcMatchShortEntries(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| // Indicate to the miniport |
| NTSTATUS status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, |
| NULL |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES failed, %!STATUS!", status); |
| } |
| } |
| |
| void otPlatRadioClearSrcMatchExtEntries(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| // Indicate to the miniport |
| NTSTATUS status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, |
| NULL |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES failed, %!STATUS!", status); |
| } |
| } |
| |
| otError otPlatRadioEnergyScan(_In_ otInstance *otCtx, uint8_t aScanChannel, uint16_t aScanDuration) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| |
| NTSTATUS status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_SCAN_MASK, |
| SPINEL_DATATYPE_UINT8_S, |
| aScanChannel |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SCAN_MASK failed, %!STATUS!", status); |
| goto error; |
| } |
| |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_SCAN_PERIOD, |
| SPINEL_DATATYPE_UINT16_S, |
| aScanDuration |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SCAN_PERIOD failed, %!STATUS!", status); |
| goto error; |
| } |
| |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_MAC_SCAN_STATE, |
| SPINEL_DATATYPE_UINT8_S, |
| SPINEL_SCAN_STATE_ENERGY |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SCAN_STATE failed, %!STATUS!", status); |
| goto error; |
| } |
| |
| error: |
| |
| return NT_SUCCESS(status) ? OT_ERROR_NONE : OT_ERROR_FAILED; |
| } |
| |
| void otPlatRadioSetDefaultTxPower(_In_ otInstance *otCtx, int8_t aPower) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| NTSTATUS status; |
| |
| // Indicate to the miniport |
| status = |
| otLwfCmdSetProp( |
| pFilter, |
| SPINEL_PROP_PHY_TX_POWER, |
| SPINEL_DATATYPE_INT8_S, |
| aPower |
| ); |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_PHY_TX_POWER failed, %!STATUS!", status); |
| } |
| } |
| |
| int8_t otPlatRadioGetReceiveSensitivity(_In_ otInstance *otCtx) |
| { |
| NT_ASSERT(otCtx); |
| PMS_FILTER pFilter = otCtxToFilter(otCtx); |
| NTSTATUS status; |
| int8_t receiveSensitivity; |
| |
| status = |
| otLwfCmdGetProp( |
| pFilter, |
| NULL, |
| SPINEL_PROP_PHY_RX_SENSITIVITY, |
| SPINEL_DATATYPE_INT8_S, |
| &receiveSensitivity |
| ); |
| |
| if (!NT_SUCCESS(status)) |
| { |
| LogError(DRIVER_DEFAULT, "Get SPINEL_PROP_PHY_RX_SENSITIVITY, failed, %!STATUS!", status); |
| return -100; // return default value -100dBm |
| } |
| |
| return receiveSensitivity; |
| } |
| |
| inline USHORT getDstShortAddress(const UCHAR *frame) |
| { |
| return (((USHORT)frame[IEEE802154_DSTADDR_OFFSET + 1]) << 8) | frame[IEEE802154_DSTADDR_OFFSET]; |
| } |
| |
| inline USHORT getSrcShortAddress(ULONG frameLength, _In_reads_bytes_(frameLength) PUCHAR frame, ULONG offset) |
| { |
| return (offset + 1 < frameLength) ? ((((USHORT)frame[offset + 1]) << 8) | frame[offset]) : 0; |
| } |
| |
| inline ULONGLONG getDstExtAddress(const UCHAR *frame) |
| { |
| return *(ULONGLONG*)(frame + IEEE802154_DSTADDR_OFFSET); |
| } |
| |
| inline ULONGLONG getSrcExtAddress(ULONG frameLength, _In_reads_bytes_(frameLength) PUCHAR frame, ULONG offset) |
| { |
| return (offset + 7 < frameLength) ? (*(ULONGLONG*)(frame + offset)) : 0; |
| } |
| |
| void |
| LogMac( |
| _In_ PCSTR szDir, |
| _In_ PMS_FILTER pFilter, |
| ULONG frameLength, |
| _In_reads_bytes_(frameLength) PUCHAR frame |
| ) |
| { |
| if (frameLength < 6) return; |
| |
| NT_ASSERT(frame); |
| |
| UCHAR AckRequested = (frame[0] & IEEE802154_ACK_REQUEST) != 0 ? 1 : 0; |
| UCHAR FramePending = (frame[0] & IEEE802154_FRAME_PENDING) != 0 ? 1 : 0; |
| |
| switch (frame[1] & (IEEE802154_DST_ADDR_MASK | IEEE802154_SRC_ADDR_MASK)) |
| { |
| case IEEE802154_DST_ADDR_NONE | IEEE802154_SRC_ADDR_NONE: |
| LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: null => null (%u bytes, AckReq=%u, FramePending=%u)", |
| pFilter, szDir, frameLength, AckRequested, FramePending); |
| break; |
| case IEEE802154_DST_ADDR_NONE | IEEE802154_SRC_ADDR_SHORT: |
| LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %X => null (%u bytes, AckReq=%u, FramePending=%u)", |
| pFilter, szDir, getSrcShortAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET), frameLength, AckRequested, FramePending); |
| break; |
| case IEEE802154_DST_ADDR_NONE | IEEE802154_SRC_ADDR_EXT: |
| LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %llX => null (%u bytes, AckReq=%u, FramePending=%u)", |
| pFilter, szDir, getSrcExtAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET), frameLength, AckRequested, FramePending); |
| break; |
| |
| case IEEE802154_DST_ADDR_SHORT | IEEE802154_SRC_ADDR_NONE: |
| LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: null => %X (%u bytes, AckReq=%u, FramePending=%u)", |
| pFilter, szDir, getDstShortAddress(frame), frameLength, AckRequested, FramePending); |
| break; |
| case IEEE802154_DST_ADDR_SHORT | IEEE802154_SRC_ADDR_SHORT: |
| LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %X => %X (%u bytes, AckReq=%u, FramePending=%u)", |
| pFilter, szDir, getSrcShortAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+2), getDstShortAddress(frame), frameLength, AckRequested, FramePending); |
| break; |
| case IEEE802154_DST_ADDR_SHORT | IEEE802154_SRC_ADDR_EXT: |
| LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %llX => %X (%u bytes, AckReq=%u, FramePending=%u)", |
| pFilter, szDir, getSrcExtAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+2), getDstShortAddress(frame), frameLength, AckRequested, FramePending); |
| break; |
| |
| case IEEE802154_DST_ADDR_EXT | IEEE802154_SRC_ADDR_NONE: |
| LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: null => %llX (%u bytes, AckReq=%u, FramePending=%u)", |
| pFilter, szDir, getDstExtAddress(frame), frameLength, AckRequested, FramePending); |
| break; |
| case IEEE802154_DST_ADDR_EXT | IEEE802154_SRC_ADDR_SHORT: |
| LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %X => %llX (%u bytes, AckReq=%u, FramePending=%u)", |
| pFilter, szDir, getSrcShortAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+8), getDstExtAddress(frame), frameLength, AckRequested, FramePending); |
| break; |
| case IEEE802154_DST_ADDR_EXT | IEEE802154_SRC_ADDR_EXT: |
| LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %llX => %llX (%u bytes, AckReq=%u, FramePending=%u)", |
| pFilter, szDir, getSrcExtAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+8), getDstExtAddress(frame), frameLength, AckRequested, FramePending); |
| break; |
| } |
| |
| #ifdef LOG_BUFFERS |
| otLogBuffer(frame, frameLength); |
| #endif |
| } |