From 444d1dd6bc62ccf2a471890a2c55ee2a1a7c56a8 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 30 Oct 2024 16:38:10 -0700 Subject: [PATCH] [mle] implement alternate RLOC16 usage during role transition (#10006) This commit introduces a mechanism for a device transitioning from child to router role to keep receiving frames addressed to its previous short address for a brief period. A new radio platform API, `otPlatRadioSetAlternateShortAddress()`, is introduced. This allows the OT stack to configure an alternate short address. Radio platform support for this function is indicated by the `OT_RADIO_CAPS_ALT_SHORT_ADDR` capability in `otPlatRadioGetCaps()` The same function can be used with `OT_RADIO_INVALID_SHORT_ADDR` (`0xfffe`) to clear a previously set alternate short address. Support for the new API is implemented in RCP and `RadioSpinel`, ensuring backward compatibility by dynamically checking supported radio capabilities. MLE code is updated to instruct the radio to use the old child RLOC16 as an alternate address upon role transition. The MLE layer will automatically clear the alternate address after eight seconds, or if other state/mode changes occur. This eight-second window ensures the new router can transmit four MLE Advertisement messages. --- examples/platforms/simulation/radio.c | 15 ++- examples/platforms/utils/mac_frame.cpp | 13 ++- examples/platforms/utils/mac_frame.h | 20 ++++ include/openthread/instance.h | 2 +- include/openthread/link.h | 11 +- include/openthread/link_raw.h | 20 ++++ include/openthread/platform/radio.h | 46 ++++++-- src/cli/README.md | 12 +- src/cli/cli.cpp | 16 ++- src/core/api/link_api.cpp | 5 + src/core/api/link_raw_api.cpp | 5 + src/core/mac/link_raw.cpp | 11 ++ src/core/mac/link_raw.hpp | 10 ++ src/core/mac/mac.cpp | 33 +++++- src/core/mac/mac.hpp | 15 +++ src/core/mac/mac_links.cpp | 1 + src/core/mac/mac_links.hpp | 30 +++++ src/core/mac/mac_types.hpp | 4 +- src/core/mac/sub_mac.cpp | 21 +++- src/core/mac/sub_mac.hpp | 15 +++ src/core/radio/radio.hpp | 14 +++ src/core/radio/radio_platform.cpp | 6 + src/core/thread/mle.cpp | 14 +++ src/core/thread/mle_router.cpp | 37 ++++++ src/core/thread/mle_router.hpp | 4 + src/lib/spinel/radio_spinel.cpp | 11 ++ src/lib/spinel/radio_spinel.hpp | 11 ++ src/lib/spinel/spinel.c | 1 + src/lib/spinel/spinel.h | 10 +- src/ncp/ncp_base_dispatcher.cpp | 3 + src/ncp/ncp_base_radio.cpp | 13 +++ src/posix/platform/radio.cpp | 6 + tests/toranj/cli/cli.py | 3 + ...test-033-alt-short-addr-role-transition.py | 108 ++++++++++++++++++ tests/toranj/start.sh | 1 + 35 files changed, 519 insertions(+), 28 deletions(-) create mode 100755 tests/toranj/cli/test-033-alt-short-addr-role-transition.py diff --git a/examples/platforms/simulation/radio.c b/examples/platforms/simulation/radio.c index 735f6177e63..acf4bc029d4 100644 --- a/examples/platforms/simulation/radio.c +++ b/examples/platforms/simulation/radio.c @@ -382,6 +382,15 @@ void otPlatRadioSetShortAddress(otInstance *aInstance, otShortAddress aShortAddr sRadioContext.mShortAddress = aShortAddress; } +void otPlatRadioSetAlternateShortAddress(otInstance *aInstance, otShortAddress aShortAddress) +{ + OT_UNUSED_VARIABLE(aInstance); + + assert(aInstance != NULL); + + sRadioContext.mAlternateShortAddress = aShortAddress; +} + void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) { OT_UNUSED_VARIABLE(aInstance); @@ -849,9 +858,9 @@ void radioProcessFrame(otInstance *aInstance) otEXPECT(sPromiscuous == false); - otEXPECT_ACTION( - otMacFrameDoesAddrMatch(&sReceiveFrame, sPanid, sRadioContext.mShortAddress, &sRadioContext.mExtAddress), - error = OT_ERROR_ABORT); + otEXPECT_ACTION(otMacFrameDoesAddrMatchAny(&sReceiveFrame, sPanid, sRadioContext.mShortAddress, + sRadioContext.mAlternateShortAddress, &sRadioContext.mExtAddress), + error = OT_ERROR_ABORT); #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE otEXPECT_ACTION(otMacFrameGetSrcAddr(&sReceiveFrame, &macAddress) == OT_ERROR_NONE, error = OT_ERROR_PARSE); diff --git a/examples/platforms/utils/mac_frame.cpp b/examples/platforms/utils/mac_frame.cpp index 860b4996e94..1356c7e4b5f 100644 --- a/examples/platforms/utils/mac_frame.cpp +++ b/examples/platforms/utils/mac_frame.cpp @@ -41,6 +41,15 @@ bool otMacFrameDoesAddrMatch(const otRadioFrame *aFrame, otPanId aPanId, otShortAddress aShortAddress, const otExtAddress *aExtAddress) +{ + return otMacFrameDoesAddrMatchAny(aFrame, aPanId, aShortAddress, Mac::kShortAddrInvalid, aExtAddress); +} + +bool otMacFrameDoesAddrMatchAny(const otRadioFrame *aFrame, + otPanId aPanId, + otShortAddress aShortAddress, + otShortAddress aAltShortAddress, + const otExtAddress *aExtAddress) { const Mac::Frame &frame = *static_cast(aFrame); bool rval = true; @@ -52,7 +61,9 @@ bool otMacFrameDoesAddrMatch(const otRadioFrame *aFrame, switch (dst.GetType()) { case Mac::Address::kTypeShort: - VerifyOrExit(dst.GetShort() == Mac::kShortAddrBroadcast || dst.GetShort() == aShortAddress, rval = false); + VerifyOrExit(dst.GetShort() == Mac::kShortAddrBroadcast || dst.GetShort() == aShortAddress || + (aAltShortAddress != Mac::kShortAddrInvalid && dst.GetShort() == aAltShortAddress), + rval = false); break; case Mac::Address::kTypeExtended: diff --git a/examples/platforms/utils/mac_frame.h b/examples/platforms/utils/mac_frame.h index 62ac959a842..5501f0acd53 100644 --- a/examples/platforms/utils/mac_frame.h +++ b/examples/platforms/utils/mac_frame.h @@ -132,6 +132,25 @@ bool otMacFrameDoesAddrMatch(const otRadioFrame *aFrame, otShortAddress aShortAddress, const otExtAddress *aExtAddress); +/** + * Check if @p aFrame matches the @p aPandId and @p aShortAddress, or @p aAltShortAddress or @p aExtAddress. + * + * @param[in] aFrame A pointer to the frame. + * @param[in] aPanId The PAN id to match with. + * @param[in] aShortAddress The short address to match with. + * @param[in] aAltShortAddress The alternate short address to match with. Can be `OT_RADIO_INVALID_SHORT_ADDR` if + * there is no alternate address. + * @param[in] aExtAddress The extended address to match with. + * + * @retval true It is a broadcast or matches with the PAN id and one of the addresses. + * @retval false It doesn't match. + */ +bool otMacFrameDoesAddrMatchAny(const otRadioFrame *aFrame, + otPanId aPanId, + otShortAddress aShortAddress, + otShortAddress aAltShortAddress, + const otExtAddress *aExtAddress); + /** * Get source MAC address. * @@ -319,6 +338,7 @@ typedef struct otRadioContext uint32_t mCslSampleTime; ///< The sample time based on the microsecond timer. uint16_t mCslPeriod; ///< In unit of 10 symbols. otShortAddress mShortAddress; + otShortAddress mAlternateShortAddress; otRadioKeyType mKeyType; uint8_t mKeyId; otMacKeyMaterial mPrevKey; diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 4686ce00155..e8576df40f4 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -52,7 +52,7 @@ extern "C" { * * @note This number versions both OpenThread platform and user APIs. */ -#define OPENTHREAD_API_VERSION (460) +#define OPENTHREAD_API_VERSION (461) /** * @addtogroup api-instance diff --git a/include/openthread/link.h b/include/openthread/link.h index d74a710379f..ccdc2c7aa35 100644 --- a/include/openthread/link.h +++ b/include/openthread/link.h @@ -588,10 +588,19 @@ otError otLinkSetPollPeriod(otInstance *aInstance, uint32_t aPollPeriod); * * @param[in] aInstance A pointer to an OpenThread instance. * - * @returns A pointer to the IEEE 802.15.4 Short Address. + * @returns The IEEE 802.15.4 Short Address. */ otShortAddress otLinkGetShortAddress(otInstance *aInstance); +/** + * Get the IEEE 802.15.4 alternate short address. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The alternate short address, or `OT_RADIO_INVALID_SHORT_ADDR` (0xfffe) if there is no alternate address. + */ +otShortAddress otLinkGetAlternateShortAddress(otInstance *aInstance); + /** * Returns the maximum number of frame retries during direct transmission. * diff --git a/include/openthread/link_raw.h b/include/openthread/link_raw.h index 5bea2a04183..92c7f9b3b18 100644 --- a/include/openthread/link_raw.h +++ b/include/openthread/link_raw.h @@ -115,6 +115,26 @@ otError otLinkRawSetPromiscuous(otInstance *aInstance, bool aEnable); */ otError otLinkRawSetShortAddress(otInstance *aInstance, uint16_t aShortAddress); +/** + * Set the alternate short address. + * + * This is an optional API. Support for this is indicated by including the capability `OT_RADIO_CAPS_ALT_SHORT_ADDR` in + * `otLinkRawGetCaps()`. + * + * When supported, the radio will accept received frames destined to the specified alternate short address in addition + * to the short address provided in `otLinkRawSetShortAddress()`. + * + * The @p aShortAddress can be set to `OT_RADIO_INVALID_SHORT_ADDR` (0xfffe) to clear any previously set alternate + * short address. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aShortAddress The alternate short address. `OT_RADIO_INVALID_SHORT_ADDR` to clear. + * + * @retval OT_ERROR_NONE Successfully set the alternate short address. + * @retval OT_ERROR_INVALID_STATE The raw link-layer is not enabled. + */ +otError otLinkRawSetAlternateShortAddress(otInstance *aInstance, otShortAddress aShortAddress); + /** * Transition the radio from Receive to Sleep. * Turn off the radio. diff --git a/include/openthread/platform/radio.h b/include/openthread/platform/radio.h index bd7d24fe295..c793bd748a5 100644 --- a/include/openthread/platform/radio.h +++ b/include/openthread/platform/radio.h @@ -82,6 +82,9 @@ enum OT_RADIO_LQI_NONE = 0, ///< LQI measurement not supported OT_RADIO_RSSI_INVALID = 127, ///< Invalid or unknown RSSI value OT_RADIO_POWER_INVALID = 127, ///< Invalid or unknown power value + + OT_RADIO_INVALID_SHORT_ADDR = 0xfffe, ///< Invalid short address. + OT_RADIO_BROADCAST_SHORT_ADDR = 0xffff, ///< Broadcast short address. }; /** @@ -120,17 +123,18 @@ typedef uint16_t otRadioCaps; */ enum { - OT_RADIO_CAPS_NONE = 0, ///< Radio supports no capability. - OT_RADIO_CAPS_ACK_TIMEOUT = 1 << 0, ///< Radio supports AckTime event. - OT_RADIO_CAPS_ENERGY_SCAN = 1 << 1, ///< Radio supports Energy Scans. - OT_RADIO_CAPS_TRANSMIT_RETRIES = 1 << 2, ///< Radio supports tx retry logic with collision avoidance (CSMA). - OT_RADIO_CAPS_CSMA_BACKOFF = 1 << 3, ///< Radio supports CSMA backoff for frame transmission (but no retry). - OT_RADIO_CAPS_SLEEP_TO_TX = 1 << 4, ///< Radio supports direct transition from sleep to TX with CSMA. - OT_RADIO_CAPS_TRANSMIT_SEC = 1 << 5, ///< Radio supports tx security. - OT_RADIO_CAPS_TRANSMIT_TIMING = 1 << 6, ///< Radio supports tx at specific time. - OT_RADIO_CAPS_RECEIVE_TIMING = 1 << 7, ///< Radio supports rx at specific time. - OT_RADIO_CAPS_RX_ON_WHEN_IDLE = 1 << 8, ///< Radio supports RxOnWhenIdle handling. - OT_RADIO_CAPS_TRANSMIT_FRAME_POWER = 1 << 9, ///< Radio supports setting per-frame transmit power. + OT_RADIO_CAPS_NONE = 0, ///< Radio supports no capability. + OT_RADIO_CAPS_ACK_TIMEOUT = 1 << 0, ///< Radio supports AckTime event. + OT_RADIO_CAPS_ENERGY_SCAN = 1 << 1, ///< Radio supports Energy Scans. + OT_RADIO_CAPS_TRANSMIT_RETRIES = 1 << 2, ///< Radio supports tx retry logic with collision avoidance (CSMA). + OT_RADIO_CAPS_CSMA_BACKOFF = 1 << 3, ///< Radio supports CSMA backoff for frame tx (but no retry). + OT_RADIO_CAPS_SLEEP_TO_TX = 1 << 4, ///< Radio supports direct transition from sleep to TX with CSMA. + OT_RADIO_CAPS_TRANSMIT_SEC = 1 << 5, ///< Radio supports tx security. + OT_RADIO_CAPS_TRANSMIT_TIMING = 1 << 6, ///< Radio supports tx at specific time. + OT_RADIO_CAPS_RECEIVE_TIMING = 1 << 7, ///< Radio supports rx at specific time. + OT_RADIO_CAPS_RX_ON_WHEN_IDLE = 1 << 8, ///< Radio supports RxOnWhenIdle handling. + OT_RADIO_CAPS_TRANSMIT_FRAME_POWER = 1 << 9, ///< Radio supports setting per-frame transmit power. + OT_RADIO_CAPS_ALT_SHORT_ADDR = 1 << 10, ///< Radio supports setting alternate short address. }; #define OT_PANID_BROADCAST 0xffff ///< IEEE 802.15.4 Broadcast PAN ID @@ -517,6 +521,26 @@ void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aE */ void otPlatRadioSetShortAddress(otInstance *aInstance, otShortAddress aShortAddress); +/** + * Set the alternate short address. + * + * This is an optional radio platform API. The radio platform MUST indicate support for this API by including the + * capability `OT_RADIO_CAPS_ALT_SHORT_ADDR` in `otPlatRadioGetCaps()`. + * + * When supported, the radio should accept received frames destined to the specified alternate short address in + * addition to the short address provided in `otPlatRadioSetShortAddress()`. + * + * The @p aShortAddress can be set to `OT_RADIO_INVALID_SHORT_ADDR` (0xfffe) to clear any previously set alternate + * short address. + * + * This function is used by OpenThread stack during child-to-router role transitions, allowing the device to continue + * receiving frames addressed to its previous short address for a short period. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aShortAddress The alternate IEEE 802.15.4 short address. `OT_RADIO_INVALID_SHORT_ADDR` to clear. + */ +void otPlatRadioSetAlternateShortAddress(otInstance *aInstance, otShortAddress aShortAddress); + /** * Get the radio's transmit power in dBm. * diff --git a/src/cli/README.md b/src/cli/README.md index b6c610fc619..ad8dd647d60 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -70,7 +70,7 @@ Done - [linkmetricsmgr](#linkmetricsmgr-disable) - [locate](#locate) - [log](#log-filename-filename) -- [mac](#mac-retries-direct) +- [mac](#mac-altshortaddr) - [macfilter](#macfilter) - [meshdiag](#meshdiag-topology-ip6-addrs-children) - [mliid](#mliid-iid) @@ -4196,6 +4196,16 @@ Print API version number. Done ``` +### mac altshortaddr + +Get the alternate short address used by MAC layer. Can be `0xfffe` if not set. + +```bash +> mac altshortaddr +0x4801 +Done +``` + ### mac retries direct Get the number of direct TX retries on the MAC layer. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 78339215872..fbb4bd79be5 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -7306,7 +7306,21 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; - if (aArgs[0] == "retries") + /** + * @cli mac altshortaddr + * @code + * mac altshortaddr + * 0x4802 + * Done + * @endcode + * @par api_copy + * otLinkGetAlternateShortAddress + */ + if (aArgs[0] == "altshortaddr") + { + OutputLine("0x%04x", otLinkGetAlternateShortAddress(GetInstancePtr())); + } + else if (aArgs[0] == "retries") { /** * @cli mac retries direct (get,set) diff --git a/src/core/api/link_api.cpp b/src/core/api/link_api.cpp index f8ca7c12c71..1a46d51aaf0 100644 --- a/src/core/api/link_api.cpp +++ b/src/core/api/link_api.cpp @@ -182,6 +182,11 @@ otShortAddress otLinkGetShortAddress(otInstance *aInstance) return AsCoreType(aInstance).Get().GetShortAddress(); } +otShortAddress otLinkGetAlternateShortAddress(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().GetAlternateShortAddress(); +} + uint8_t otLinkGetMaxFrameRetriesDirect(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetMaxFrameRetriesDirect(); diff --git a/src/core/api/link_raw_api.cpp b/src/core/api/link_raw_api.cpp index 4eb4712148e..cf8f0caf039 100644 --- a/src/core/api/link_raw_api.cpp +++ b/src/core/api/link_raw_api.cpp @@ -53,6 +53,11 @@ otError otLinkRawSetShortAddress(otInstance *aInstance, uint16_t aShortAddress) return AsCoreType(aInstance).Get().SetShortAddress(aShortAddress); } +otError otLinkRawSetAlternateShortAddress(otInstance *aInstance, otShortAddress aShortAddress) +{ + return AsCoreType(aInstance).Get().SetAlternateShortAddress(aShortAddress); +} + bool otLinkRawGetPromiscuous(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetPromiscuous(); } otError otLinkRawSetPromiscuous(otInstance *aInstance, bool aEnable) diff --git a/src/core/mac/link_raw.cpp b/src/core/mac/link_raw.cpp index fdccd79f5ff..db5d5c86621 100644 --- a/src/core/mac/link_raw.cpp +++ b/src/core/mac/link_raw.cpp @@ -161,6 +161,17 @@ Error LinkRaw::SetShortAddress(ShortAddress aShortAddress) return error; } +Error LinkRaw::SetAlternateShortAddress(ShortAddress aShortAddress) +{ + Error error = kErrorNone; + + VerifyOrExit(IsEnabled(), error = kErrorInvalidState); + mSubMac.SetAlternateShortAddress(aShortAddress); + +exit: + return error; +} + Error LinkRaw::Receive(void) { Error error = kErrorNone; diff --git a/src/core/mac/link_raw.hpp b/src/core/mac/link_raw.hpp index 1f0f2533532..9f01e0f8eea 100644 --- a/src/core/mac/link_raw.hpp +++ b/src/core/mac/link_raw.hpp @@ -183,6 +183,16 @@ class LinkRaw : public InstanceLocator, private NonCopyable */ Error SetShortAddress(ShortAddress aShortAddress); + /** + * Sets the alternate short address. + * + * @param[in] aShortAddress The short address. Use `kShortAddrInvalid` to clear it. + * + * @retval kErrorNone If successful. + * @retval kErrorInvalidState If the raw link-layer isn't enabled. + */ + Error SetAlternateShortAddress(ShortAddress aShortAddress); + /** * Returns PANID. * diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index eb6fdfe0cf6..820e37e4741 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -118,6 +118,9 @@ Mac::Mac(Instance &aInstance) SetPanId(mPanId); SetExtAddress(randomExtAddress); SetShortAddress(GetShortAddress()); +#if OPENTHREAD_FTD + SetAlternateShortAddress(kShortAddrInvalid); +#endif mMode2KeyMaterial.SetFrom(AsCoreType(&sMode2Key)); } @@ -1766,6 +1769,33 @@ Error Mac::ProcessEnhAckSecurity(TxFrame &aTxFrame, RxFrame &aAckFrame) } #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 +Error Mac::FilterDestShortAddress(ShortAddress aDestAddress) const +{ + Error error = kErrorNone; + + if (aDestAddress == GetShortAddress()) + { + ExitNow(); + } + +#if OPENTHREAD_FTD + if ((GetAlternateShortAddress() != kShortAddrInvalid) && (aDestAddress == GetAlternateShortAddress())) + { + ExitNow(); + } +#endif + + if (mRxOnWhenIdle && (aDestAddress == kShortAddrBroadcast)) + { + ExitNow(); + } + + error = kErrorDestinationAddressFiltered; + +exit: + return error; +} + void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) { Address srcaddr; @@ -1795,8 +1825,7 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError) break; case Address::kTypeShort: - VerifyOrExit((mRxOnWhenIdle && dstaddr.IsBroadcast()) || dstaddr.GetShort() == GetShortAddress(), - error = kErrorDestinationAddressFiltered); + SuccessOrExit(error = FilterDestShortAddress(dstaddr.GetShort())); #if OPENTHREAD_FTD // Allow multicasts from neighbor routers if FTD diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 4a1c0d1953c..8a5e78ec268 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -251,6 +251,20 @@ class Mac : public InstanceLocator, private NonCopyable */ void SetShortAddress(ShortAddress aShortAddress) { mLinks.SetShortAddress(aShortAddress); } + /** + * Gets the alternate short address. + * + * @returns The alternate short address, or `kShortAddrInvalid` if there is no alternate address. + */ + ShortAddress GetAlternateShortAddress(void) const { return mLinks.GetAlternateShortAddress(); } + + /** + * Sets the alternate short address. + * + * @param[in] aShortAddress The alternate short address. Use `kShortAddrInvalid` to clear the alternate address. + */ + void SetAlternateShortAddress(ShortAddress aShortAddress) { mLinks.SetAlternateShortAddress(aShortAddress); } + /** * Returns the IEEE 802.15.4 PAN Channel. * @@ -807,6 +821,7 @@ class Mac : public InstanceLocator, private NonCopyable bool ShouldSendBeacon(void) const; bool IsJoinable(void) const; void BeginTransmit(void); + Error FilterDestShortAddress(ShortAddress aDestAddress) const; void UpdateNeighborLinkInfo(Neighbor &aNeighbor, const RxFrame &aRxFrame); bool HandleMacCommand(RxFrame &aFrame); void HandleTimer(void); diff --git a/src/core/mac/mac_links.cpp b/src/core/mac/mac_links.cpp index 4b8c1ec5b17..60b7aee5aad 100644 --- a/src/core/mac/mac_links.cpp +++ b/src/core/mac/mac_links.cpp @@ -127,6 +127,7 @@ Links::Links(Instance &aInstance) , mTxFrames(aInstance) #if !OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE , mShortAddress(kShortAddrInvalid) + , mAlternateShortAddress(kShortAddrInvalid) #endif { #if !OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE diff --git a/src/core/mac/mac_links.hpp b/src/core/mac/mac_links.hpp index 978f199aae7..13b89a22916 100644 --- a/src/core/mac/mac_links.hpp +++ b/src/core/mac/mac_links.hpp @@ -330,6 +330,35 @@ class Links : public InstanceLocator #endif } + /** + * Gets the alternate MAC short address. + * + * @returns The alternate MAC short address, or `kShortAddrInvalid` if there is no alternate address. + */ + ShortAddress GetAlternateShortAddress(void) const + { + return +#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE + mSubMac.GetAlternateShortAddress(); +#else + mAlternateShortAddress; +#endif + } + + /** + * Sets the alternate MAC short address. + * + * @param[in] aShortAddress The alternate short address. Use `kShortAddrInvalid` to clear it. + */ + void SetAlternateShortAddress(ShortAddress aShortAddress) + { +#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE + mSubMac.SetAlternateShortAddress(aShortAddress); +#else + mAlternateShortAddress = aShortAddress; +#endif + } + /** * Gets the MAC Extended Address. * @@ -677,6 +706,7 @@ class Links : public InstanceLocator #if !OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE ShortAddress mShortAddress; + ShortAddress mAlternateShortAddress; ExtAddress mExtAddress; #endif }; diff --git a/src/core/mac/mac_types.hpp b/src/core/mac/mac_types.hpp index d33c4ee394b..7b504ad5ec6 100644 --- a/src/core/mac/mac_types.hpp +++ b/src/core/mac/mac_types.hpp @@ -70,8 +70,8 @@ constexpr PanId kPanIdBroadcast = 0xffff; ///< Broadcast PAN ID. */ typedef otShortAddress ShortAddress; -constexpr ShortAddress kShortAddrBroadcast = 0xffff; ///< Broadcast Short Address. -constexpr ShortAddress kShortAddrInvalid = 0xfffe; ///< Invalid Short Address. +constexpr ShortAddress kShortAddrBroadcast = OT_RADIO_BROADCAST_SHORT_ADDR; ///< Broadcast Short Address. +constexpr ShortAddress kShortAddrInvalid = OT_RADIO_INVALID_SHORT_ADDR; ///< Invalid Short Address. /** * Generates a random IEEE 802.15.4 PAN ID. diff --git a/src/core/mac/sub_mac.cpp b/src/core/mac/sub_mac.cpp index 0d1a6557097..fbe243d75ef 100644 --- a/src/core/mac/sub_mac.cpp +++ b/src/core/mac/sub_mac.cpp @@ -68,10 +68,11 @@ SubMac::SubMac(Instance &aInstance) void SubMac::Init(void) { - mState = kStateDisabled; - mCsmaBackoffs = 0; - mTransmitRetries = 0; - mShortAddress = kShortAddrInvalid; + mState = kStateDisabled; + mCsmaBackoffs = 0; + mTransmitRetries = 0; + mShortAddress = kShortAddrInvalid; + mAlternateShortAddress = kShortAddrInvalid; mExtAddress.Clear(); mRxOnWhenIdle = true; mEnergyScanMaxRssi = Radio::kInvalidRssi; @@ -165,6 +166,18 @@ void SubMac::SetShortAddress(ShortAddress aShortAddress) LogDebg("RadioShortAddress: 0x%04x", mShortAddress); } +void SubMac::SetAlternateShortAddress(ShortAddress aShortAddress) +{ + VerifyOrExit(mAlternateShortAddress != aShortAddress); + + mAlternateShortAddress = aShortAddress; + Get().SetAlternateShortAddress(mAlternateShortAddress); + LogDebg("RadioAlternateShortAddress: 0x%04x", mAlternateShortAddress); + +exit: + return; +} + void SubMac::SetExtAddress(const ExtAddress &aExtAddress) { ExtAddress address; diff --git a/src/core/mac/sub_mac.hpp b/src/core/mac/sub_mac.hpp index 45448801630..4bef9381881 100644 --- a/src/core/mac/sub_mac.hpp +++ b/src/core/mac/sub_mac.hpp @@ -232,6 +232,20 @@ class SubMac : public InstanceLocator, private NonCopyable */ void SetShortAddress(ShortAddress aShortAddress); + /** + * Gets the alternate short address. + * + * @returns The alternate short address, or `kShortAddrInvalid` if there is no alternate address. + */ + ShortAddress GetAlternateShortAddress(void) const { return mAlternateShortAddress; } + + /** + * Sets the alternate short address. + * + * @param[in] aShortAddress The short address. Use `kShortAddrInvalid` to clear it. + */ + void SetAlternateShortAddress(ShortAddress aShortAddress); + /** * Gets the extended address. * @@ -627,6 +641,7 @@ class SubMac : public InstanceLocator, private NonCopyable uint8_t mCsmaBackoffs; uint8_t mTransmitRetries; ShortAddress mShortAddress; + ShortAddress mAlternateShortAddress; ExtAddress mExtAddress; bool mRxOnWhenIdle : 1; #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE diff --git a/src/core/radio/radio.hpp b/src/core/radio/radio.hpp index 5cd35b42750..8bf6993934e 100644 --- a/src/core/radio/radio.hpp +++ b/src/core/radio/radio.hpp @@ -330,6 +330,13 @@ class Radio : public InstanceLocator, private NonCopyable */ void SetShortAddress(Mac::ShortAddress aShortAddress); + /** + * Set the altrnate short address. + * + * @param[in] aShortAddress The alternate short address. + */ + void SetAlternateShortAddress(Mac::ShortAddress aShortAddress); + /** * Sets MAC key and key ID. * @@ -840,6 +847,11 @@ inline int8_t Radio::GetReceiveSensitivity(void) const { return otPlatRadioGetRe inline void Radio::SetPanId(Mac::PanId aPanId) { otPlatRadioSetPanId(GetInstancePtr(), aPanId); } +inline void Radio::SetAlternateShortAddress(Mac::ShortAddress aShortAddress) +{ + otPlatRadioSetAlternateShortAddress(GetInstancePtr(), aShortAddress); +} + inline void Radio::SetMacKey(uint8_t aKeyIdMode, uint8_t aKeyId, const Mac::KeyMaterial &aPrevKey, @@ -1003,6 +1015,8 @@ inline void Radio::SetExtendedAddress(const Mac::ExtAddress &) {} inline void Radio::SetShortAddress(Mac::ShortAddress) {} +inline void Radio::SetAlternateShortAddress(Mac::ShortAddress) {} + inline void Radio::SetMacKey(uint8_t, uint8_t, const Mac::KeyMaterial &, diff --git a/src/core/radio/radio_platform.cpp b/src/core/radio/radio_platform.cpp index e3fd35d9d76..1db6af755c9 100644 --- a/src/core/radio/radio_platform.cpp +++ b/src/core/radio/radio_platform.cpp @@ -183,6 +183,12 @@ extern "C" void otPlatDiagRadioTransmitDone(otInstance *, otRadioFrame *, otErro //--------------------------------------------------------------------------------------------------------------------- // Default/weak implementation of radio platform APIs +extern "C" OT_TOOL_WEAK void otPlatRadioSetAlternateShortAddress(otInstance *aInstance, otShortAddress aShortAddress) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aShortAddress); +} + extern "C" OT_TOOL_WEAK uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index dd8b035110b..76bf74cd3ce 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -693,6 +693,7 @@ void Mle::SetStateDetached(void) Get().SetRxOnWhenIdle(true); Get().SetBeaconEnabled(false); #if OPENTHREAD_FTD + Get().ClearAlternateRloc16(); Get().HandleDetachStart(); #endif #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE @@ -816,6 +817,13 @@ Error Mle::SetDeviceMode(DeviceMode aDeviceMode) IgnoreError(Store()); +#if OPENTHREAD_FTD + if (!aDeviceMode.IsFullThreadDevice()) + { + Get().ClearAlternateRloc16(); + } +#endif + if (IsAttached()) { bool shouldReattach = false; @@ -953,6 +961,12 @@ void Mle::SetRloc16(uint16_t aRloc16) Get().AddUnicastAddress(mMeshLocalRloc); #if OPENTHREAD_FTD Get().RestartAddressQueries(); +#endif + } + else + { +#if OPENTHREAD_FTD + Get().ClearAlternateRloc16(); #endif } } diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 930db620525..1fd2ae30894 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -56,6 +56,7 @@ MleRouter::MleRouter(Instance &aInstance) , mPreviousPartitionRouterIdSequence(0) , mPreviousPartitionIdTimeout(0) , mChildRouterLinks(kChildRouterLinks) + , mAlternateRloc16Timeout(0) #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE , mMaxChildIpAddresses(0) #endif @@ -88,6 +89,30 @@ MleRouter::MleRouter(Instance &aInstance) #endif } +void MleRouter::SetAlternateRloc16(uint16_t aRloc16) +{ + VerifyOrExit(aRloc16 != Mac::kShortAddrInvalid); + + LogInfo("Setting alternate RLOC16 0x%04x", aRloc16); + + Get().SetAlternateShortAddress(aRloc16); + mAlternateRloc16Timeout = kAlternateRloc16Timeout; + +exit: + return; +} + +void MleRouter::ClearAlternateRloc16(void) +{ + VerifyOrExit(Get().GetAlternateShortAddress() != Mac::kShortAddrInvalid); + + LogInfo("Clearing alternate RLOC16"); + Get().SetAlternateShortAddress(Mac::kShortAddrInvalid); + +exit: + mAlternateRloc16Timeout = 0; +} + void MleRouter::HandlePartitionChange(void) { mPreviousPartitionId = mLeaderData.GetPartitionId(); @@ -1474,6 +1499,16 @@ void MleRouter::HandleTimeTick(void) mPreviousPartitionIdTimeout--; } + if (mAlternateRloc16Timeout > 0) + { + mAlternateRloc16Timeout--; + + if (mAlternateRloc16Timeout == 0) + { + ClearAlternateRloc16(); + } + } + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Role transitions @@ -3278,6 +3313,8 @@ void MleRouter::HandleAddressSolicitResponse(Coap::Message *aMessage, SuccessOrExit(Tlv::FindTlv(*aMessage, routerMaskTlv)); VerifyOrExit(routerMaskTlv.IsValid()); + SetAlternateRloc16(GetRloc16()); + SetRouterId(routerId); SetStateRouter(Rloc16FromRouterId(mRouterId)); diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index e66e968da6c..772c9863c4e 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -515,6 +515,7 @@ class MleRouter : public Mle static constexpr uint16_t kUnsolicitedDataResponseJitter = 500; // Max delay for unsol Data Response (in msec). static constexpr uint8_t kLeaderDowngradeExtraDelay = 10; // Extra delay to downgrade leader (in sec). static constexpr uint8_t kDefaultLeaderWeight = 64; + static constexpr uint8_t kAlternateRloc16Timeout = 8; // Time to use alternate RLOC16 (in sec). // Threshold to accept a router upgrade request with reason // `kBorderRouterRequest` (number of BRs acting as router in @@ -587,6 +588,8 @@ class MleRouter : public Mle //------------------------------------------------------------------------------------------------------------------ // Methods + void SetAlternateRloc16(uint16_t aRloc16); + void ClearAlternateRloc16(void); void HandleDetachStart(void); void HandleChildStart(AttachMode aMode); void HandleSecurityPolicyChanged(void); @@ -680,6 +683,7 @@ class MleRouter : public Mle uint8_t mPreviousPartitionRouterIdSequence; uint8_t mPreviousPartitionIdTimeout; uint8_t mChildRouterLinks; + uint8_t mAlternateRloc16Timeout; #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE uint8_t mMaxChildIpAddresses; #endif diff --git a/src/lib/spinel/radio_spinel.cpp b/src/lib/spinel/radio_spinel.cpp index 3299208a306..82a82922629 100644 --- a/src/lib/spinel/radio_spinel.cpp +++ b/src/lib/spinel/radio_spinel.cpp @@ -846,6 +846,17 @@ otError RadioSpinel::SetShortAddress(uint16_t aAddress) return error; } +otError RadioSpinel::SetAlternateShortAddress(uint16_t aAddress) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(sRadioCaps & OT_RADIO_CAPS_ALT_SHORT_ADDR); + error = Set(SPINEL_PROP_MAC_15_4_ALT_SADDR, SPINEL_DATATYPE_UINT16_S, aAddress); + +exit: + return error; +} + #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE otError RadioSpinel::ReadMacKey(const otMacKeyMaterial &aKeyMaterial, otMacKey &aKey) diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index 482f01d9d8f..a83db5f037a 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -223,6 +223,17 @@ class RadioSpinel : private Logger */ otError SetShortAddress(uint16_t aAddress); + /** + * Sets the alternate short address. + * + * @param[in] aShortAddress The alternate short address. + * + * @retval OT_ERROR_NONE Succeeded. + * @retval OT_ERROR_BUSY Failed due to another operation is on going. + * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. + */ + otError SetAlternateShortAddress(uint16_t aAddress); + /** * Gets the factory-assigned IEEE EUI-64 for this transceiver. * diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index 60e4f0c5977..ae6fc63229f 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1263,6 +1263,7 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) {SPINEL_PROP_MAC_ENERGY_SCAN_RESULT, "MAC_ENERGY_SCAN_RESULT"}, {SPINEL_PROP_MAC_DATA_POLL_PERIOD, "MAC_DATA_POLL_PERIOD"}, {SPINEL_PROP_MAC_RX_ON_WHEN_IDLE_MODE, "MAC_RX_ON_WHEN_IDLE_MODE"}, + {SPINEL_PROP_MAC_15_4_ALT_SADDR, "SPINEL_PROP_MAC_15_4_ALT_SADDR"}, {SPINEL_PROP_MAC_ALLOWLIST, "MAC_ALLOWLIST"}, {SPINEL_PROP_MAC_ALLOWLIST_ENABLED, "MAC_ALLOWLIST_ENABLED"}, {SPINEL_PROP_MAC_EXTENDED_ADDR, "MAC_EXTENDED_ADDR"}, diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index 4f914c61a71..526e57037db 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -419,7 +419,7 @@ * * Please see section "Spinel definition compatibility guideline" for more details. */ -#define SPINEL_RCP_API_VERSION 10 +#define SPINEL_RCP_API_VERSION 11 /** * @def SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION @@ -2093,6 +2093,14 @@ enum */ SPINEL_PROP_MAC_RX_ON_WHEN_IDLE_MODE = SPINEL_PROP_MAC__BEGIN + 11, + /// MAC Alternate Short Address + /** Format: `S` + * + * The 802.15.4 alternate short address. + * + */ + SPINEL_PROP_MAC_15_4_ALT_SADDR = SPINEL_PROP_MAC__BEGIN + 12, + SPINEL_PROP_MAC__END = 0x40, SPINEL_PROP_MAC_EXT__BEGIN = 0x1300, diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index a1884e3c28c..5b137e4d77f 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -448,6 +448,9 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_DATA_POLL_PERIOD), #endif OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_RX_ON_WHEN_IDLE_MODE), +#if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_15_4_ALT_SADDR), +#endif #if OPENTHREAD_MTD || OPENTHREAD_FTD OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_NET_IF_UP), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_NET_STACK_UP), diff --git a/src/ncp/ncp_base_radio.cpp b/src/ncp/ncp_base_radio.cpp index 7da914be72c..0b701d06d83 100644 --- a/src/ncp/ncp_base_radio.cpp +++ b/src/ncp/ncp_base_radio.cpp @@ -407,6 +407,19 @@ template <> otError NcpBase::HandlePropertySet(void) return error; } +template <> otError NcpBase::HandlePropertySet(void) +{ + uint16_t shortAddress; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadUint16(shortAddress)); + + error = otLinkRawSetAlternateShortAddress(mInstance, shortAddress); + +exit: + return error; +} + #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE template <> otError NcpBase::HandlePropertySet(void) { diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index 210f6a66c3c..a0a6597ae31 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -256,6 +256,12 @@ void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress) SuccessOrDie(GetRadioSpinel().SetShortAddress(aAddress)); } +void otPlatRadioSetAlternateShortAddress(otInstance *aInstance, uint16_t aAddress) +{ + OT_UNUSED_VARIABLE(aInstance); + SuccessOrDie(GetRadioSpinel().SetAlternateShortAddress(aAddress)); +} + void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) { OT_UNUSED_VARIABLE(aInstance); diff --git a/tests/toranj/cli/cli.py b/tests/toranj/cli/cli.py index 8236ab3b5be..d86d4655003 100644 --- a/tests/toranj/cli/cli.py +++ b/tests/toranj/cli/cli.py @@ -312,6 +312,9 @@ def thread_stop(self): def get_rloc16(self): return self._cli_single_output('rloc16') + def get_mac_alt_short_addr(self): + return self._cli_single_output('mac altshortaddr') + def get_ip_addrs(self, verbose=None): return self.cli('ipaddr', verbose) diff --git a/tests/toranj/cli/test-033-alt-short-addr-role-transition.py b/tests/toranj/cli/test-033-alt-short-addr-role-transition.py new file mode 100755 index 00000000000..27406cbd9ff --- /dev/null +++ b/tests/toranj/cli/test-033-alt-short-addr-role-transition.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2024, 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. + +from cli import verify +from cli import verify_within +import cli +import time + +# ----------------------------------------------------------------------------------------------------------------------- +# Test description: +# +# Validate the use alternate short address after role transition from child to router. +# + +test_name = __file__[:-3] if __file__.endswith('.py') else __file__ +print('-' * 120) +print('Starting \'{}\''.format(test_name)) + +# ----------------------------------------------------------------------------------------------------------------------- +# Creating `cli.Nodes` instances + +speedup = 10 +cli.Node.set_time_speedup_factor(speedup) + +leader = cli.Node() +node = cli.Node() + +# ----------------------------------------------------------------------------------------------------------------------- +# Test implementation + +INVALID_SHORT_ADDR = '0xfffe' +ALT_SHORT_ADDR_TIMEOUT = 10 + +verify(leader.get_mac_alt_short_addr() == INVALID_SHORT_ADDR) + +# Form topology + +leader.form('alt-shrt-addr') +node.join(leader, cli.JOIN_TYPE_REED) + +verify(leader.get_state() == 'leader') +verify(node.get_state() == 'child') + +verify(len(leader.get_child_table()) == 1) + +# Check the short address and alternate short address + +node_rloc16_as_child = '0x' + node.get_rloc16() + +verify(node.get_mac_alt_short_addr() == INVALID_SHORT_ADDR) + +# Allow `node` to transition from child to router role + +node.set_router_selection_jitter(1) +node.set_router_eligible('enable') + + +def check_node_become_router(): + verify(node.get_state() == 'router') + + +verify_within(check_node_become_router, 10) + +# Make sure the old short address is now being used as +# the alternate short address. + +node_rloc16_as_router = '0x' + node.get_rloc16() +verify(node_rloc16_as_router != node_rloc16_as_child) +verify(node.get_mac_alt_short_addr() == node_rloc16_as_child) + +# Make sure the old short address is removed after the +# timeout + +time.sleep(ALT_SHORT_ADDR_TIMEOUT / speedup) + +verify(node.get_mac_alt_short_addr() == INVALID_SHORT_ADDR) + +# ----------------------------------------------------------------------------------------------------------------------- +# Test finished + +cli.Node.finalize_all_nodes() + +print('\'{}\' passed.'.format(test_name)) diff --git a/tests/toranj/start.sh b/tests/toranj/start.sh index 5451c51bffc..ee1c74b4e7e 100755 --- a/tests/toranj/start.sh +++ b/tests/toranj/start.sh @@ -197,6 +197,7 @@ if [ "$TORANJ_CLI" = 1 ]; then run cli/test-030-anycast-forwarding.py run cli/test-031-service-aloc-route-lookup.py run cli/test-032-leader-take-over.py + run cli/test-033-alt-short-addr-role-transition.py run cli/test-035-context-id-change-addr-reg.py run cli/test-400-srp-client-server.py run cli/test-401-srp-server-address-cache-snoop.py