blob: 78c26591ab8e09f89ae37ddccd5e830fc7599342 [file] [log] [blame]
/*
* 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
}