[mac] move auxiliary frame counter from Mac to SubMac (#4976)

In Thread 1.2, it is possible to receive an IEEE 802.15.4-2015
packet. Per specification, receiver should acknowledge this packet
with an IEEE 802.15.4-2015 ACK(Enh-ACK). This Enh-ACK can include
header IE with it and requires security enabled bit in FCF be set to
true. It is impractical for the host to generate the Enh-ACK and send
to RCP for transmission within AIFS time(192us). So RCP should prepare
the Enh-ACK by itself, which requires it to fill in the frame counter
and do the encryption/authentication.

This commit tries to address the need of filling auxiliary frame
counter in RCP by including the following changes:

- Move frame counter related functions from MAC layer to SubMac layer,
  which is mirrored in RCP.

- Set mMacFrameCounter to RCP using newly added spinel properties.

- RCP reports last used frame counter to host in TxDone and RxDone.

- Add a simulation test for reset verification.
This commit is contained in:
Jintao Lin
2020-06-03 22:09:16 -07:00
committed by GitHub
parent 72c369ced3
commit 201b7b1a3d
24 changed files with 466 additions and 122 deletions
+1
View File
@@ -778,6 +778,7 @@ void radioProcessFrame(otInstance *aInstance)
sReceiveFrame.mInfo.mRxInfo.mLqi = OT_RADIO_LQI_NONE;
sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = false;
sReceiveFrame.mInfo.mRxInfo.mAckedWithSecEnhAck = false;
otEXPECT(sPromiscuous == false);
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (1)
#define OPENTHREAD_API_VERSION (2)
/**
* @addtogroup api-instance
+12
View File
@@ -351,6 +351,18 @@ otError otLinkRawSetMacKey(otInstance * aInstance,
const otMacKey *aCurrKey,
const otMacKey *aNextKey);
/**
* Sets the current MAC frame counter value.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMacFrameCounter The MAC frame counter value.
*
* @retval OT_ERROR_NONE If successful.
* @retval OT_ERROR_INVALID_STATE If the raw link-layer isn't enabled.
*
*/
otError otLinkRawSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter);
/**
* @}
*
+20 -3
View File
@@ -234,11 +234,14 @@ typedef struct otRadioFrame
*/
uint64_t mTimestamp;
int8_t mRssi; ///< Received signal strength indicator in dBm for received frames.
uint8_t mLqi; ///< Link Quality Indicator for received frames.
uint32_t mAckFrameCounter; ///< ACK security frame counter (applicable when `mAckedWithSecEnhAck` is set).
uint8_t mAckKeyId; ///< ACK security key index (applicable when `mAckedWithSecEnhAck` is set).
int8_t mRssi; ///< Received signal strength indicator in dBm for received frames.
uint8_t mLqi; ///< Link Quality Indicator for received frames.
// Flags
bool mAckedWithFramePending : 1; /// This indicates if this frame was acknowledged with frame pending set.
bool mAckedWithFramePending : 1; ///< This indicates if this frame was acknowledged with frame pending set.
bool mAckedWithSecEnhAck : 1; ///< This indicates if this frame was acknowledged with secured enhance ACK.
} mRxInfo;
} mInfo;
} otRadioFrame;
@@ -475,6 +478,17 @@ void otPlatRadioSetMacKey(otInstance * aInstance,
const otMacKey *aCurrKey,
const otMacKey *aNextKey);
/**
* This method sets the current MAC frame counter value.
*
* This function is used when radio provides `OT_RADIO_CAPS_TRANSMIT_SEC` capability.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMacFrameCounter The MAC frame counter value.
*
*/
void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter);
/**
* @}
*
@@ -635,6 +649,9 @@ extern void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame);
* The radio driver calls this function to notify OpenThread that the transmit operation has completed,
* providing both the transmitted frame and, if applicable, the received ack frame.
*
* When radio provides `OT_RADIO_CAPS_TRANSMIT_SEC` capability, radio platform layer updates @p aFrame
* with the security frame counter and key index values maintained by the radio.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aFrame A pointer to the frame that was transmitted.
* @param[in] aAckFrame A pointer to the ACK frame, NULL if no ACK was received.
+5
View File
@@ -233,6 +233,11 @@ otError otLinkRawSetMacKey(otInstance * aInstance,
*static_cast<const Mac::Key *>(aNextKey));
}
otError otLinkRawSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
{
return static_cast<Instance *>(aInstance)->Get<Mac::LinkRaw>().SetMacFrameCounter(aMacFrameCounter);
}
#if OPENTHREAD_RADIO
otDeviceRole otThreadGetDeviceRole(otInstance *aInstance)
+11
View File
@@ -220,6 +220,17 @@ exit:
return error;
}
otError LinkRaw::SetMacFrameCounter(uint32_t aMacFrameCounter)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
mSubMac.SetFrameCounter(aMacFrameCounter);
exit:
return error;
}
// LCOV_EXCL_START
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
+11
View File
@@ -263,6 +263,17 @@ public:
const Key &aCurrKey,
const Key &aNextKey);
/**
* This method sets the current MAC frame counter value.
*
* @param[in] aMacFrameCounter The MAC frame counter value.
*
* @retval OT_ERROR_NONE If successful.
* @retval OT_ERROR_INVALID_STATE If the raw link-layer isn't enabled.
*
*/
otError SetMacFrameCounter(uint32_t aMacFrameCounter);
/**
* This method records the status of a frame transmission attempt and is mainly used for logging failures.
*
+2 -13
View File
@@ -970,19 +970,8 @@ void Mac::ProcessTransmitSecurity(TxFrame &aFrame)
break;
case Frame::kKeyIdMode1:
// If the frame is marked as a retransmission, `MeshForwarder` which
// prepared the frame should set the frame counter and key id to the
// same values used in the earlier transmit attempt. For a new frame (not
// a retransmission), we get a new frame counter and key id from the key
// manager.
if (!aFrame.IsARetransmission())
{
aFrame.SetFrameCounter(keyManager.GetMacFrameCounter());
keyManager.IncrementMacFrameCounter();
}
// For MAC key ID mode 1, the AES CCM* is done at SubMac or Radio if supported
// For MAC Key ID Mode 1, the security frame counter update and CCM* is done at SubMac or Radio depending on
// `OT_RADIO_CAPS_TRANSMIT_SEC`.
ExitNow();
break;
+42
View File
@@ -59,6 +59,7 @@ SubMac::SubMac(Instance &aInstance)
, mCallbacks(aInstance)
, mPcapCallback(NULL)
, mPcapCallbackContext(NULL)
, mFrameCounter(0)
, mKeyId(0)
, mTimer(aInstance, &SubMac::HandleTimer, this)
{
@@ -201,6 +202,11 @@ void SubMac::HandleReceiveDone(RxFrame *aFrame, otError aError)
mPcapCallback(aFrame, false, mPcapCallbackContext);
}
if (!ShouldHandleTransmitSecurity() && aFrame != NULL && aFrame->mInfo.mRxInfo.mAckedWithSecEnhAck)
{
UpdateFrameCounter(aFrame->mInfo.mRxInfo.mAckFrameCounter);
}
mCallbacks.ReceiveDone(aFrame, aError);
}
@@ -247,7 +253,11 @@ void SubMac::ProcessTransmitSecurity(void)
if (!mTransmitFrame.IsARetransmission())
{
uint32_t frameCounter = GetFrameCounter();
mTransmitFrame.SetKeyId(mKeyId);
mTransmitFrame.SetFrameCounter(frameCounter);
UpdateFrameCounter(frameCounter + 1);
}
extAddress = &GetExtAddress();
@@ -378,6 +388,19 @@ void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, otError aEr
OT_UNREACHABLE_CODE(ExitNow());
}
if (!ShouldHandleTransmitSecurity() && aFrame.GetSecurityEnabled())
{
uint8_t keyIdMode;
uint32_t frameCounter = 0;
IgnoreError(aFrame.GetKeyIdMode(keyIdMode));
if (keyIdMode == Frame::kKeyIdMode1)
{
OT_ASSERT(aFrame.GetFrameCounter(frameCounter) == OT_ERROR_NONE);
UpdateFrameCounter(frameCounter);
}
}
// Determine whether a CSMA retry is required.
if (!ccaSuccess && ShouldHandleCsmaBackOff() && mCsmaBackoffs < aFrame.GetMaxCsmaBackoffs())
@@ -655,6 +678,25 @@ exit:
return;
}
void SubMac::UpdateFrameCounter(uint32_t aFrameCounter)
{
mFrameCounter = aFrameCounter;
mCallbacks.FrameCounterUpdated(aFrameCounter);
}
void SubMac::SetFrameCounter(uint32_t aFrameCounter)
{
mFrameCounter = aFrameCounter;
VerifyOrExit(!ShouldHandleTransmitSecurity(), OT_NOOP);
Get<Radio>().SetMacFrameCounter(aFrameCounter);
exit:
return;
}
// LCOV_EXCL_START
const char *SubMac::StateToString(State aState)
+26
View File
@@ -167,6 +167,14 @@ public:
*
*/
void EnergyScanDone(int8_t aMaxRssi);
/**
* This method notifies user of `SubMac` that MAC frame counter is updated.
*
* @param[in] aFrameCounter The MAC frame counter value.
*
*/
void FrameCounterUpdated(uint32_t aFrameCounter);
};
/**
@@ -383,6 +391,22 @@ public:
*/
const Key &GetNextMacKey(void) const { return mNextKey; }
/**
* This method returns the current MAC frame counter value.
*
* @returns The current MAC frame counter value.
*
*/
uint32_t GetFrameCounter(void) const { return mFrameCounter; };
/**
* This method sets the current MAC Frame Counter value.
*
* @param[in] aFrameCounter The MAC Frame Counter value.
*
*/
void SetFrameCounter(uint32_t aFrameCounter);
private:
enum
{
@@ -426,6 +450,7 @@ private:
bool ShouldHandleEnergyScan(void) const;
void ProcessTransmitSecurity(void);
void UpdateFrameCounter(uint32_t aFrameCounter);
void StartCsmaBackoff(void);
void BeginTransmit(void);
void SampleRssi(void);
@@ -457,6 +482,7 @@ private:
Key mPrevKey;
Key mCurrKey;
Key mNextKey;
uint32_t mFrameCounter;
uint8_t mKeyId;
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
TimerMicro mTimer;
+10
View File
@@ -107,6 +107,11 @@ void SubMac::Callbacks::EnergyScanDone(int8_t aMaxRssi)
}
}
void SubMac::Callbacks::FrameCounterUpdated(uint32_t aFrameCounter)
{
Get<KeyManager>().MacFrameCounterUpdated(aFrameCounter);
}
#elif OPENTHREAD_RADIO
void SubMac::Callbacks::ReceiveDone(RxFrame *aFrame, otError aError)
@@ -137,6 +142,11 @@ void SubMac::Callbacks::EnergyScanDone(int8_t aMaxRssi)
Get<LinkRaw>().InvokeEnergyScanDone(aMaxRssi);
}
void SubMac::Callbacks::FrameCounterUpdated(uint32_t aFrameCounter)
{
OT_UNUSED_VARIABLE(aFrameCounter);
}
#endif // OPENTHREAD_RADIO
} // namespace Mac
+11
View File
@@ -267,6 +267,17 @@ public:
otPlatRadioSetMacKey(GetInstance(), aKeyIdMode, aKeyId, &aPrevKey, &aCurrKey, &aNextKey);
}
/**
* This method sets the current MAC Frame Counter value.
*
* @param[in] aMacFrameCounter The MAC Frame Counter value.
*
*/
void SetMacFrameCounter(uint32_t aMacFrameCounter)
{
otPlatRadioSetMacFrameCounter(GetInstance(), aMacFrameCounter);
}
/**
* This method gets the radio's transmit power in dBm.
*
+6
View File
@@ -139,3 +139,9 @@ OT_TOOL_WEAK void otPlatRadioSetMacKey(otInstance * aInstance,
OT_UNUSED_VARIABLE(aCurrKey);
OT_UNUSED_VARIABLE(aNextKey);
}
OT_TOOL_WEAK void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aMacFrameCounter);
}
+12 -5
View File
@@ -69,7 +69,6 @@ const otMasterKey KeyManager::kDefaultMasterKey = {{
KeyManager::KeyManager(Instance &aInstance)
: InstanceLocator(aInstance)
, mKeySequence(0)
, mMacFrameCounter(0)
, mMleFrameCounter(0)
, mStoredMacFrameCounter(0)
, mStoredMleFrameCounter(0)
@@ -193,7 +192,7 @@ void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence)
mKeySequence = aKeySequence;
UpdateKeyMaterial();
mMacFrameCounter = 0;
SetMacFrameCounter(0);
mMleFrameCounter = 0;
Get<Notifier>().Signal(OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER);
@@ -212,11 +211,19 @@ const Mle::Key &KeyManager::GetTemporaryMleKey(uint32_t aKeySequence)
return mTemporaryMleKey;
}
void KeyManager::IncrementMacFrameCounter(void)
uint32_t KeyManager::GetMacFrameCounter(void) const
{
mMacFrameCounter++;
return Get<Mac::SubMac>().GetFrameCounter();
}
if (mMacFrameCounter >= mStoredMacFrameCounter)
void KeyManager::SetMacFrameCounter(uint32_t aMacFrameCounter)
{
Get<Mac::SubMac>().SetFrameCounter(aMacFrameCounter);
}
void KeyManager::MacFrameCounterUpdated(uint32_t aMacFrameCounter)
{
if (aMacFrameCounter >= mStoredMacFrameCounter)
{
IgnoreError(Get<Mle::MleRouter>().Store());
}
+10 -9
View File
@@ -211,7 +211,7 @@ public:
* @returns The current MAC Frame Counter value.
*
*/
uint32_t GetMacFrameCounter(void) const { return mMacFrameCounter; }
uint32_t GetMacFrameCounter(void) const;
/**
* This method sets the current MAC Frame Counter value.
@@ -219,7 +219,7 @@ public:
* @param[in] aMacFrameCounter The MAC Frame Counter value.
*
*/
void SetMacFrameCounter(uint32_t aMacFrameCounter) { mMacFrameCounter = aMacFrameCounter; }
void SetMacFrameCounter(uint32_t aMacFrameCounter);
/**
* This method sets the MAC Frame Counter value which is stored in non-volatile memory.
@@ -229,12 +229,6 @@ public:
*/
void SetStoredMacFrameCounter(uint32_t aStoredMacFrameCounter) { mStoredMacFrameCounter = aStoredMacFrameCounter; }
/**
* This method increments the current MAC Frame Counter value.
*
*/
void IncrementMacFrameCounter(void);
/**
* This method returns the current MLE Frame Counter value.
*
@@ -430,6 +424,14 @@ public:
*/
void UpdateKeyMaterial(void);
/**
* This method handles MAC frame counter change.
*
* @param[in] aMacFrameCounter The MAC frame counter value.
*
*/
void MacFrameCounterUpdated(uint32_t aMacFrameCounter);
private:
enum
{
@@ -467,7 +469,6 @@ private:
Mle::Key mMleKey;
Mle::Key mTemporaryMleKey;
uint32_t mMacFrameCounter;
uint32_t mMleFrameCounter;
uint32_t mStoredMacFrameCounter;
uint32_t mStoredMleFrameCounter;
+9 -1
View File
@@ -617,6 +617,14 @@ public:
const otMacKey &aCurrKey,
const otMacKey &aNextKey);
/**
* This method sets the current MAC Frame Counter value.
*
* @param[in] aMacFrameCounter The MAC Frame Counter value.
*
*/
otError SetMacFrameCounter(uint32_t aMacFrameCounter);
/**
* This method checks whether the spinel interface is radio-only
*
@@ -751,7 +759,7 @@ private:
spinel_tid_t tid,
const char * pack_format,
va_list args);
otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength);
otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength, spinel_ssize_t &aUnpacked);
otError ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength);
/**
+69 -47
View File
@@ -739,17 +739,17 @@ void RadioSpinel<InterfaceType, ProcessContextType>::HandleValueIs(spinel_prop_k
const uint8_t * aBuffer,
uint16_t aLength)
{
otError error = OT_ERROR_NONE;
otError error = OT_ERROR_NONE;
spinel_ssize_t unpacked;
if (aKey == SPINEL_PROP_STREAM_RAW)
{
SuccessOrExit(error = ParseRadioFrame(mRxRadioFrame, aBuffer, aLength));
SuccessOrExit(error = ParseRadioFrame(mRxRadioFrame, aBuffer, aLength, unpacked));
RadioReceive();
}
else if (aKey == SPINEL_PROP_LAST_STATUS)
{
spinel_status_t status = SPINEL_STATUS_OK;
spinel_ssize_t unpacked;
unpacked = spinel_datatype_unpack(aBuffer, aLength, "i", &status);
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
@@ -769,9 +769,8 @@ void RadioSpinel<InterfaceType, ProcessContextType>::HandleValueIs(spinel_prop_k
}
else if (aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT)
{
uint8_t scanChannel;
int8_t maxRssi;
spinel_ssize_t unpacked;
uint8_t scanChannel;
int8_t maxRssi;
unpacked = spinel_datatype_unpack(aBuffer, aLength, "Cc", &scanChannel, &maxRssi);
@@ -780,9 +779,8 @@ void RadioSpinel<InterfaceType, ProcessContextType>::HandleValueIs(spinel_prop_k
}
else if (aKey == SPINEL_PROP_STREAM_DEBUG)
{
char logStream[OPENTHREAD_CONFIG_NCP_SPINEL_LOG_MAX_SIZE + 1];
unsigned int len = sizeof(logStream);
spinel_ssize_t unpacked;
char logStream[OPENTHREAD_CONFIG_NCP_SPINEL_LOG_MAX_SIZE + 1];
unsigned int len = sizeof(logStream);
unpacked = spinel_datatype_unpack_in_place(aBuffer, aLength, SPINEL_DATATYPE_DATA_S, logStream, &len);
assert(len < sizeof(logStream));
@@ -792,9 +790,8 @@ void RadioSpinel<InterfaceType, ProcessContextType>::HandleValueIs(spinel_prop_k
}
else if ((aKey == SPINEL_PROP_STREAM_LOG) && mSupportsLogStream)
{
const char * logString;
spinel_ssize_t unpacked;
uint8_t logLevel;
const char *logString;
uint8_t logLevel;
unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, &logString);
VerifyOrExit(unpacked >= 0, error = OT_ERROR_PARSE);
@@ -837,9 +834,10 @@ exit:
}
template <typename InterfaceType, typename ProcessContextType>
otError RadioSpinel<InterfaceType, ProcessContextType>::ParseRadioFrame(otRadioFrame & aFrame,
const uint8_t *aBuffer,
uint16_t aLength)
otError RadioSpinel<InterfaceType, ProcessContextType>::ParseRadioFrame(otRadioFrame & aFrame,
const uint8_t * aBuffer,
uint16_t aLength,
spinel_ssize_t &aUnpacked)
{
otError error = OT_ERROR_NONE;
uint16_t flags = 0;
@@ -848,29 +846,35 @@ otError RadioSpinel<InterfaceType, ProcessContextType>::ParseRadioFrame(otRadioF
unsigned int receiveError = 0;
spinel_ssize_t unpacked;
unpacked = spinel_datatype_unpack_in_place(aBuffer, aLength,
SPINEL_DATATYPE_DATA_WLEN_S // Frame
SPINEL_DATATYPE_INT8_S // RSSI
SPINEL_DATATYPE_INT8_S // Noise Floor
SPINEL_DATATYPE_UINT16_S // Flags
SPINEL_DATATYPE_STRUCT_S( // PHY-data
SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
SPINEL_DATATYPE_UINT64_S // Timestamp (us).
) SPINEL_DATATYPE_STRUCT_S( // Vendor-data
SPINEL_DATATYPE_UINT_PACKED_S // Receive error
),
aFrame.mPsdu, &size, &aFrame.mInfo.mRxInfo.mRssi, &noiseFloor, &flags,
&aFrame.mChannel, &aFrame.mInfo.mRxInfo.mLqi,
&aFrame.mInfo.mRxInfo.mTimestamp, &receiveError);
unpacked = spinel_datatype_unpack_in_place(
aBuffer, aLength,
SPINEL_DATATYPE_DATA_WLEN_S // Frame
SPINEL_DATATYPE_INT8_S // RSSI
SPINEL_DATATYPE_INT8_S // Noise Floor
SPINEL_DATATYPE_UINT16_S // Flags
SPINEL_DATATYPE_STRUCT_S( // PHY-data
SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
SPINEL_DATATYPE_UINT64_S // Timestamp (us).
) SPINEL_DATATYPE_STRUCT_S( // Vendor-data
SPINEL_DATATYPE_UINT_PACKED_S // Receive error
) SPINEL_DATATYPE_STRUCT_S( // MAC-data
SPINEL_DATATYPE_UINT8_S // Security key index
SPINEL_DATATYPE_UINT32_S // Security frame counter
),
aFrame.mPsdu, &size, &aFrame.mInfo.mRxInfo.mRssi, &noiseFloor, &flags, &aFrame.mChannel,
&aFrame.mInfo.mRxInfo.mLqi, &aFrame.mInfo.mRxInfo.mTimestamp, &receiveError, &aFrame.mInfo.mRxInfo.mAckKeyId,
&aFrame.mInfo.mRxInfo.mAckFrameCounter);
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
aUnpacked = unpacked;
if (receiveError == OT_ERROR_NONE)
{
aFrame.mLength = static_cast<uint8_t>(size);
aFrame.mInfo.mRxInfo.mAckedWithFramePending = ((flags & SPINEL_MD_FLAG_ACKED_FP) != 0);
aFrame.mInfo.mRxInfo.mAckedWithSecEnhAck = ((flags & SPINEL_MD_FLAG_ACKED_SEC) != 0);
}
else if (receiveError < OT_NUM_ERRORS)
{
@@ -1030,6 +1034,17 @@ exit:
return error;
}
template <typename InterfaceType, typename ProcessContextType>
otError RadioSpinel<InterfaceType, ProcessContextType>::SetMacFrameCounter(uint32_t aMacFrameCounter)
{
otError error;
SuccessOrExit(error = Set(SPINEL_PROP_RCP_MAC_FRAME_COUNTER, SPINEL_DATATYPE_UINT32_S, aMacFrameCounter));
exit:
return error;
}
template <typename InterfaceType, typename ProcessContextType>
otError RadioSpinel<InterfaceType, ProcessContextType>::GetIeeeEui64(uint8_t *aIeeeEui64)
{
@@ -1433,8 +1448,9 @@ void RadioSpinel<InterfaceType, ProcessContextType>::HandleTransmitDone(uint32_t
const uint8_t * aBuffer,
uint16_t aLength)
{
otError error = OT_ERROR_NONE;
spinel_status_t status = SPINEL_STATUS_OK;
otError error = OT_ERROR_NONE;
spinel_status_t status = SPINEL_STATUS_OK;
bool framePending = false;
spinel_ssize_t unpacked;
VerifyOrExit(aCommand == SPINEL_CMD_PROP_VALUE_IS && aKey == SPINEL_PROP_LAST_STATUS, error = OT_ERROR_FAILED);
@@ -1445,30 +1461,36 @@ void RadioSpinel<InterfaceType, ProcessContextType>::HandleTransmitDone(uint32_t
aBuffer += unpacked;
aLength -= static_cast<uint16_t>(unpacked);
unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_BOOL_S, &framePending);
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
aBuffer += unpacked;
aLength -= static_cast<uint16_t>(unpacked);
if (status == SPINEL_STATUS_OK)
{
bool framePending = false;
unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_BOOL_S, &framePending);
OT_UNUSED_VARIABLE(framePending);
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
SuccessOrExit(error = ParseRadioFrame(mAckRadioFrame, aBuffer, aLength, unpacked));
aBuffer += unpacked;
aLength -= static_cast<spinel_size_t>(unpacked);
if (aLength > 0)
{
SuccessOrExit(error = ParseRadioFrame(mAckRadioFrame, aBuffer, aLength));
}
else
{
mAckRadioFrame.mLength = 0;
}
aLength -= static_cast<uint16_t>(unpacked);
}
else
{
error = SpinelStatusToOtError(status);
}
if ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_SEC) && static_cast<Mac::TxFrame *>(mTransmitFrame)->GetSecurityEnabled())
{
uint8_t keyId;
uint32_t frameCounter;
// Replace transmit frame security key index and frame counter with the one filled by RCP
unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UINT32_S, &keyId,
&frameCounter);
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
static_cast<Mac::TxFrame *>(mTransmitFrame)->SetKeyId(keyId);
static_cast<Mac::TxFrame *>(mTransmitFrame)->SetFrameCounter(frameCounter);
}
exit:
mState = kStateTransmitDone;
mTxError = error;
+16 -5
View File
@@ -692,11 +692,12 @@ typedef uint8_t spinel_tid_t;
enum
{
SPINEL_MD_FLAG_TX = 0x0001, //!< Packet was transmitted, not received.
SPINEL_MD_FLAG_BAD_FCS = 0x0004, //!< Packet was received with bad FCS
SPINEL_MD_FLAG_DUPE = 0x0008, //!< Packet seems to be a duplicate
SPINEL_MD_FLAG_ACKED_FP = 0x0010, //!< Packet was acknowledged with frame pending set
SPINEL_MD_FLAG_RESERVED = 0xFFE2, //!< Flags reserved for future use.
SPINEL_MD_FLAG_TX = 0x0001, //!< Packet was transmitted, not received.
SPINEL_MD_FLAG_BAD_FCS = 0x0004, //!< Packet was received with bad FCS
SPINEL_MD_FLAG_DUPE = 0x0008, //!< Packet seems to be a duplicate
SPINEL_MD_FLAG_ACKED_FP = 0x0010, //!< Packet was acknowledged with frame pending set
SPINEL_MD_FLAG_ACKED_SEC = 0x0020, //!< Packet was acknowledged with secure enhance ACK
SPINEL_MD_FLAG_RESERVED = 0xFFC2, //!< Flags reserved for future use.
};
enum
@@ -3952,6 +3953,16 @@ enum
*/
SPINEL_PROP_RCP_MAC_KEY = SPINEL_PROP_RCP__BEGIN + 0,
/// MAC Frame Counter
/** Format: `L`.
*
* `L`: MAC frame counter
*
* The Spinel property is used to set MAC frame counter to RCP.
*
*/
SPINEL_PROP_RCP_MAC_FRAME_COUNTER = SPINEL_PROP_RCP__BEGIN + 1,
SPINEL_PROP_RCP__END = 0x900,
SPINEL_PROP_NEST__BEGIN = 0x3BC0,
+1
View File
@@ -267,6 +267,7 @@ protected:
otError DecodeChannelMask(uint32_t &aChannelMask);
#if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
otError PackRadioFrame(otRadioFrame *aFrame, otError aError);
static void LinkRawReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError);
void LinkRawReceiveDone(otRadioFrame *aFrame, otError aError);
+1
View File
@@ -414,6 +414,7 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey)
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
#if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_RCP_MAC_KEY),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_RCP_MAC_FRAME_COUNTER),
#endif
#if OPENTHREAD_MTD || OPENTHREAD_FTD
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_UNSOL_UPDATE_FILTER),
+71 -36
View File
@@ -51,20 +51,12 @@ namespace Ncp {
// MARK: Raw Link-Layer Datapath Glue
// ----------------------------------------------------------------------------
void NcpBase::LinkRawReceiveDone(otInstance *, otRadioFrame *aFrame, otError aError)
otError NcpBase::PackRadioFrame(otRadioFrame *aFrame, otError aError)
{
sNcpInstance->LinkRawReceiveDone(aFrame, aError);
}
otError error = OT_ERROR_FAILED;
uint16_t flags = 0;
void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError)
{
uint16_t flags = 0;
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
// Append frame header
SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_STREAM_RAW));
if (aError == OT_ERROR_NONE)
if (aFrame != NULL && aError == OT_ERROR_NONE)
{
// Append the frame contents
SuccessOrExit(mEncoder.WriteDataWithLen(aFrame->mPsdu, aFrame->mLength));
@@ -76,28 +68,61 @@ void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError)
}
// Append metadata (rssi, etc)
SuccessOrExit(mEncoder.WriteInt8(aFrame->mInfo.mRxInfo.mRssi)); // RSSI
SuccessOrExit(mEncoder.WriteInt8(-128)); // Noise Floor (Currently unused)
SuccessOrExit(mEncoder.WriteInt8(aFrame ? aFrame->mInfo.mRxInfo.mRssi : 0)); // RSSI
SuccessOrExit(mEncoder.WriteInt8(-128)); // Noise Floor (Currently unused)
if (aFrame->mInfo.mRxInfo.mAckedWithFramePending)
if (aFrame != NULL)
{
flags |= SPINEL_MD_FLAG_ACKED_FP;
if (aFrame->mInfo.mRxInfo.mAckedWithFramePending)
{
flags |= SPINEL_MD_FLAG_ACKED_FP;
}
if (aFrame->mInfo.mRxInfo.mAckedWithSecEnhAck)
{
flags |= SPINEL_MD_FLAG_ACKED_SEC;
}
}
SuccessOrExit(mEncoder.WriteUint16(flags)); // Flags
SuccessOrExit(mEncoder.OpenStruct()); // PHY-data
SuccessOrExit(mEncoder.WriteUint8(aFrame->mChannel)); // 802.15.4 channel (Receive channel)
SuccessOrExit(mEncoder.WriteUint8(aFrame->mInfo.mRxInfo.mLqi)); // 802.15.4 LQI
SuccessOrExit(mEncoder.WriteUint64(aFrame->mInfo.mRxInfo.mTimestamp)); // The timestamp in microseconds
SuccessOrExit(mEncoder.OpenStruct()); // PHY-data
SuccessOrExit(mEncoder.WriteUint8(aFrame ? aFrame->mChannel : 0)); // 802.15.4 channel (Receive channel)
SuccessOrExit(mEncoder.WriteUint8(aFrame ? aFrame->mInfo.mRxInfo.mLqi
: static_cast<uint8_t>(OT_RADIO_LQI_NONE))); // 802.15.4 LQI
SuccessOrExit(mEncoder.WriteUint64(aFrame ? aFrame->mInfo.mRxInfo.mTimestamp : 0)); // The timestamp in microseconds
SuccessOrExit(mEncoder.CloseStruct());
SuccessOrExit(mEncoder.OpenStruct()); // Vendor-data
SuccessOrExit(mEncoder.WriteUintPacked(aError)); // Receive error
SuccessOrExit(mEncoder.CloseStruct());
SuccessOrExit(mEncoder.OpenStruct()); // MAC-data
SuccessOrExit(mEncoder.WriteUint8(aFrame ? aFrame->mInfo.mRxInfo.mAckKeyId : 0)); // The ACK auxiliary key ID
SuccessOrExit(
mEncoder.WriteUint32(aFrame ? aFrame->mInfo.mRxInfo.mAckFrameCounter : 0)); // The ACK auxiliary frame counter
SuccessOrExit(mEncoder.CloseStruct());
error = OT_ERROR_NONE;
exit:
return error;
}
void NcpBase::LinkRawReceiveDone(otInstance *, otRadioFrame *aFrame, otError aError)
{
sNcpInstance->LinkRawReceiveDone(aFrame, aError);
}
void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError)
{
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
// Append frame header
SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_STREAM_RAW));
SuccessOrExit(PackRadioFrame(aFrame, aError));
SuccessOrExit(mEncoder.EndFrame());
exit:
@@ -125,25 +150,22 @@ void NcpBase::LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame,
SuccessOrExit(mEncoder.WriteUintPacked(ThreadErrorToSpinelStatus(aError)));
SuccessOrExit(mEncoder.WriteBool(framePending));
if (aAckFrame && aError == OT_ERROR_NONE)
if (aError == OT_ERROR_NONE)
{
SuccessOrExit(mEncoder.WriteUint16(aAckFrame->mLength));
SuccessOrExit(mEncoder.WriteData(aAckFrame->mPsdu, aAckFrame->mLength));
SuccessOrExit(PackRadioFrame(aAckFrame, aError));
}
SuccessOrExit(mEncoder.WriteInt8(aAckFrame->mInfo.mRxInfo.mRssi)); // RSSI
SuccessOrExit(mEncoder.WriteInt8(-128)); // Noise Floor (Currently unused)
SuccessOrExit(mEncoder.WriteUint16(0)); // Flags
if (static_cast<Mac::TxFrame *>(aFrame)->GetSecurityEnabled())
{
uint8_t keyId;
uint32_t frameCounter;
SuccessOrExit(mEncoder.OpenStruct()); // PHY-data
SuccessOrExit(mEncoder.WriteUint8(aAckFrame->mChannel)); // Receive channel
SuccessOrExit(mEncoder.WriteUint8(aAckFrame->mInfo.mRxInfo.mLqi)); // Link Quality Indicator
SuccessOrExit(mEncoder.WriteUint64(aAckFrame->mInfo.mRxInfo.mTimestamp)); // The timestamp in microseconds
// Transmit frame auxiliary key index and frame counter
SuccessOrExit(static_cast<Mac::TxFrame *>(aFrame)->GetKeyId(keyId));
SuccessOrExit(static_cast<Mac::TxFrame *>(aFrame)->GetFrameCounter(frameCounter));
SuccessOrExit(mEncoder.CloseStruct());
SuccessOrExit(mEncoder.OpenStruct()); // Vendor-data
SuccessOrExit(mEncoder.WriteUintPacked(aError)); // Receive error
SuccessOrExit(mEncoder.CloseStruct());
SuccessOrExit(mEncoder.WriteUint8(keyId));
SuccessOrExit(mEncoder.WriteUint32(frameCounter));
}
SuccessOrExit(mEncoder.EndFrame());
@@ -461,6 +483,19 @@ exit:
return error;
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_RCP_MAC_FRAME_COUNTER>(void)
{
otError error = OT_ERROR_NONE;
uint32_t frameCounter;
SuccessOrExit(error = mDecoder.ReadUint32(frameCounter));
error = otLinkRawSetMacFrameCounter(mInstance, frameCounter);
exit:
return error;
}
} // namespace Ncp
} // namespace ot
+6
View File
@@ -489,3 +489,9 @@ void otPlatRadioSetMacKey(otInstance * aInstance,
SuccessOrDie(sRadioSpinel.SetMacKey(aKeyIdMode, aKeyId, *aPrevKey, *aCurrKey, *aNextKey));
OT_UNUSED_VARIABLE(aInstance);
}
void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
{
SuccessOrDie(sRadioSpinel.SetMacFrameCounter(aMacFrameCounter));
OT_UNUSED_VARIABLE(aInstance);
}
+4 -2
View File
@@ -157,10 +157,11 @@ EXTRA_DIST = \
test_lowpan.py \
test_mac802154.py \
test_mle.py \
test_service.py \
test_network_data.py \
test_network_layer.py \
test_reed_address_solicit_rejected.py \
test_reset.py \
test_service.py \
thread_cert.py \
tlvs_parsing.py \
$(NULL)
@@ -181,10 +182,11 @@ check_SCRIPTS = \
test_lowpan.py \
test_mac802154.py \
test_mle.py \
test_service.py \
test_network_data.py \
test_network_layer.py \
test_reed_address_solicit_rejected.py \
test_reset.py \
test_service.py \
Cert_5_1_01_RouterAttach.py \
Cert_5_1_02_ChildAddressTimeout.py \
Cert_5_1_03_RouterAddressReallocation.py \
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env python3
#
# Copyright (c) 2020, 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.
#
import unittest
import thread_cert
LEADER = 1
ROUTER = 2
ED = 3
SED = 4
class TestReset(thread_cert.TestCase):
topology = {
LEADER: {
'mode': 'rsdn',
'panid': 0xface,
'whitelist': [ROUTER]
},
ROUTER: {
'mode': 'rsdn',
'panid': 0xface,
'router_selection_jitter': 1,
'whitelist': [LEADER, ED]
},
ED: {
'is_mtd': True,
'mode': 'rsn',
'panid': 0xface,
'whitelist': [ROUTER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()
self.simulator.go(7)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.nodes[ED].start()
self.simulator.go(7)
self.assertEqual(self.nodes[ED].get_state(), 'child')
leader_addrs = self.nodes[LEADER].get_addrs()
router_addrs = self.nodes[ROUTER].get_addrs()
for i in range(0, 1010):
self.assertTrue(self.nodes[ED].ping(leader_addrs[0]))
self.simulator.go(1)
# 1 - Leader
self.nodes[LEADER].reset()
self.nodes[LEADER].start()
self.simulator.go(7)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for addr in router_addrs:
self.assertTrue(self.nodes[LEADER].ping(addr))
# 2 - Router
self.nodes[ROUTER].reset()
self.nodes[ROUTER].start()
self.simulator.go(7)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
for addr in leader_addrs:
self.assertTrue(self.nodes[ROUTER].ping(addr))
# 3 - Child
self.nodes[ED].reset()
self.nodes[ED].start()
self.simulator.go(7)
self.assertEqual(self.nodes[ED].get_state(), 'child')
for addr in router_addrs:
self.assertTrue(self.nodes[ED].ping(addr))
if __name__ == '__main__':
unittest.main()