mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 15:47:46 +00:00
[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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
Executable
+109
@@ -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()
|
||||
Reference in New Issue
Block a user