[radio-spinel] check RCP API Version to be in the supported range (#5863)

This commit adds a new method `CheckRcpApiVersion()` which is used
during `Init()` to get the API version from RCP and verify that it
is within supported range.
This commit is contained in:
Abtin Keshavarzian
2020-11-30 18:22:35 -08:00
committed by Jonathan Hui
parent 5111bbee65
commit 0ca10a6538
2 changed files with 47 additions and 4 deletions
+6 -2
View File
@@ -650,13 +650,16 @@ public:
otError SetMacFrameCounter(uint32_t aMacFrameCounter);
/**
* This method checks whether the spinel interface is radio-only
* This method checks whether the spinel interface is radio-only.
*
* @param[out] aSupportsRcpApiVersion A reference to a boolean variable to update whether the list of spinel
* capabilities include `SPINEL_CAP_RCP_API_VERSION`.
*
* @retval TRUE The radio chip is in radio-only mode.
* @retval FALSE Otherwise.
*
*/
bool IsRcp(void);
bool IsRcp(bool &aSupportsRcpApiVersion);
/**
* This method checks whether there is pending frame in the buffer.
@@ -726,6 +729,7 @@ private:
otError CheckSpinelVersion(void);
otError CheckRadioCapabilities(void);
otError CheckRcpApiVersion(bool aSupportsRcpApiVersion);
/**
* This method triggers a state transfer of the state machine.
+41 -2
View File
@@ -222,6 +222,7 @@ template <typename InterfaceType, typename ProcessContextType>
void RadioSpinel<InterfaceType, ProcessContextType>::Init(bool aResetRadio, bool aRestoreDatasetFromNcp)
{
otError error = OT_ERROR_NONE;
bool supportsRcpApiVersion;
#if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
mResetRadioOnStartup = aResetRadio;
@@ -239,7 +240,7 @@ void RadioSpinel<InterfaceType, ProcessContextType>::Init(bool aResetRadio, bool
SuccessOrExit(error = Get(SPINEL_PROP_NCP_VERSION, SPINEL_DATATYPE_UTF8_S, mVersion, sizeof(mVersion)));
SuccessOrExit(error = Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_EUI64_S, mIeeeEui64.m8));
if (!IsRcp())
if (!IsRcp(supportsRcpApiVersion))
{
uint8_t exitCode = OT_EXIT_RADIO_SPINEL_INCOMPATIBLE;
@@ -251,6 +252,7 @@ void RadioSpinel<InterfaceType, ProcessContextType>::Init(bool aResetRadio, bool
DieNow(exitCode);
}
SuccessOrDie(CheckRcpApiVersion(supportsRcpApiVersion));
SuccessOrDie(CheckRadioCapabilities());
mRxRadioFrame.mPsdu = mRxPsdu;
@@ -285,7 +287,7 @@ exit:
}
template <typename InterfaceType, typename ProcessContextType>
bool RadioSpinel<InterfaceType, ProcessContextType>::IsRcp(void)
bool RadioSpinel<InterfaceType, ProcessContextType>::IsRcp(bool &aSupportsRcpApiVersion)
{
uint8_t capsBuffer[kCapsBufferSize];
const uint8_t *capsData = capsBuffer;
@@ -293,6 +295,8 @@ bool RadioSpinel<InterfaceType, ProcessContextType>::IsRcp(void)
bool supportsRawRadio = false;
bool isRcp = false;
aSupportsRcpApiVersion = false;
SuccessOrDie(Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength));
while (capsLength > 0)
@@ -318,6 +322,11 @@ bool RadioSpinel<InterfaceType, ProcessContextType>::IsRcp(void)
mSupportsLogStream = true;
}
if (capability == SPINEL_CAP_RCP_API_VERSION)
{
aSupportsRcpApiVersion = true;
}
capsData += unpacked;
capsLength -= static_cast<spinel_size_t>(unpacked);
}
@@ -364,6 +373,36 @@ exit:
return error;
}
template <typename InterfaceType, typename ProcessContextType>
otError RadioSpinel<InterfaceType, ProcessContextType>::CheckRcpApiVersion(bool aSupportsRcpApiVersion)
{
otError error = OT_ERROR_NONE;
unsigned int rcpApiVersion = 1;
// Use RCP API Version value 1, when the RCP capability
// list does not contain `SPINEL_CAP_RCP_API_VERSION`.
if (aSupportsRcpApiVersion)
{
SuccessOrExit(error = Get(SPINEL_PROP_RCP_API_VERSION, SPINEL_DATATYPE_UINT_PACKED_S, &rcpApiVersion));
}
otLogNotePlat("RCP API Version: %u", rcpApiVersion);
static_assert(SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION <= SPINEL_RCP_API_VERSION,
"MIN_HOST_SUPPORTED_RCP_API_VERSION must be smaller than or equal to RCP_API_VERSION");
if ((rcpApiVersion < SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION) || (rcpApiVersion > SPINEL_RCP_API_VERSION))
{
otLogCritPlat("RCP API Version %u is not in the supported range [%u-%u]", rcpApiVersion,
SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION, SPINEL_RCP_API_VERSION);
DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
}
exit:
return error;
}
template <typename InterfaceType, typename ProcessContextType>
otError RadioSpinel<InterfaceType, ProcessContextType>::RestoreDatasetFromNcp(void)
{