[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.
This commit is contained in:
Abtin Keshavarzian
2024-10-30 16:38:10 -07:00
committed by GitHub
parent a5e1c91055
commit 444d1dd6bc
35 changed files with 519 additions and 28 deletions
+12 -3
View File
@@ -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);
+12 -1
View File
@@ -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<const Mac::Frame *>(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:
+20
View File
@@ -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;
+1 -1
View File
@@ -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
+10 -1
View File
@@ -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.
*
+20
View File
@@ -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.
+35 -11
View File
@@ -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.
*
+11 -1
View File
@@ -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.
+15 -1
View File
@@ -7306,7 +7306,21 @@ template <> otError Interpreter::Process<Cmd("mac")>(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)
+5
View File
@@ -182,6 +182,11 @@ otShortAddress otLinkGetShortAddress(otInstance *aInstance)
return AsCoreType(aInstance).Get<Mac::Mac>().GetShortAddress();
}
otShortAddress otLinkGetAlternateShortAddress(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Mac::Mac>().GetAlternateShortAddress();
}
uint8_t otLinkGetMaxFrameRetriesDirect(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Mac::Mac>().GetMaxFrameRetriesDirect();
+5
View File
@@ -53,6 +53,11 @@ otError otLinkRawSetShortAddress(otInstance *aInstance, uint16_t aShortAddress)
return AsCoreType(aInstance).Get<Mac::LinkRaw>().SetShortAddress(aShortAddress);
}
otError otLinkRawSetAlternateShortAddress(otInstance *aInstance, otShortAddress aShortAddress)
{
return AsCoreType(aInstance).Get<Mac::LinkRaw>().SetAlternateShortAddress(aShortAddress);
}
bool otLinkRawGetPromiscuous(otInstance *aInstance) { return AsCoreType(aInstance).Get<Radio>().GetPromiscuous(); }
otError otLinkRawSetPromiscuous(otInstance *aInstance, bool aEnable)
+11
View File
@@ -161,6 +161,17 @@ exit:
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;
+10
View File
@@ -183,6 +183,16 @@ public:
*/
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.
*
+31 -2
View File
@@ -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 @@ exit:
}
#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
+15
View File
@@ -251,6 +251,20 @@ public:
*/
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 @@ private:
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);
+1
View File
@@ -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
+30
View File
@@ -330,6 +330,35 @@ public:
#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 @@ private:
#if !OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
ShortAddress mShortAddress;
ShortAddress mAlternateShortAddress;
ExtAddress mExtAddress;
#endif
};
+2 -2
View File
@@ -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.
+17 -4
View File
@@ -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<Radio>().SetAlternateShortAddress(mAlternateShortAddress);
LogDebg("RadioAlternateShortAddress: 0x%04x", mAlternateShortAddress);
exit:
return;
}
void SubMac::SetExtAddress(const ExtAddress &aExtAddress)
{
ExtAddress address;
+15
View File
@@ -232,6 +232,20 @@ public:
*/
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 @@ private:
uint8_t mCsmaBackoffs;
uint8_t mTransmitRetries;
ShortAddress mShortAddress;
ShortAddress mAlternateShortAddress;
ExtAddress mExtAddress;
bool mRxOnWhenIdle : 1;
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
+14
View File
@@ -330,6 +330,13 @@ public:
*/
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 &,
+6
View File
@@ -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);
+14
View File
@@ -693,6 +693,7 @@ void Mle::SetStateDetached(void)
Get<MeshForwarder>().SetRxOnWhenIdle(true);
Get<Mac::Mac>().SetBeaconEnabled(false);
#if OPENTHREAD_FTD
Get<MleRouter>().ClearAlternateRloc16();
Get<MleRouter>().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<MleRouter>().ClearAlternateRloc16();
}
#endif
if (IsAttached())
{
bool shouldReattach = false;
@@ -953,6 +961,12 @@ void Mle::SetRloc16(uint16_t aRloc16)
Get<ThreadNetif>().AddUnicastAddress(mMeshLocalRloc);
#if OPENTHREAD_FTD
Get<AddressResolver>().RestartAddressQueries();
#endif
}
else
{
#if OPENTHREAD_FTD
Get<MleRouter>().ClearAlternateRloc16();
#endif
}
}
+37
View File
@@ -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<Mac::Mac>().SetAlternateShortAddress(aRloc16);
mAlternateRloc16Timeout = kAlternateRloc16Timeout;
exit:
return;
}
void MleRouter::ClearAlternateRloc16(void)
{
VerifyOrExit(Get<Mac::Mac>().GetAlternateShortAddress() != Mac::kShortAddrInvalid);
LogInfo("Clearing alternate RLOC16");
Get<Mac::Mac>().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));
+4
View File
@@ -515,6 +515,7 @@ private:
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 @@ private:
//------------------------------------------------------------------------------------------------------------------
// Methods
void SetAlternateRloc16(uint16_t aRloc16);
void ClearAlternateRloc16(void);
void HandleDetachStart(void);
void HandleChildStart(AttachMode aMode);
void HandleSecurityPolicyChanged(void);
@@ -680,6 +683,7 @@ private:
uint8_t mPreviousPartitionRouterIdSequence;
uint8_t mPreviousPartitionIdTimeout;
uint8_t mChildRouterLinks;
uint8_t mAlternateRloc16Timeout;
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
uint8_t mMaxChildIpAddresses;
#endif
+11
View File
@@ -846,6 +846,17 @@ exit:
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)
+11
View File
@@ -223,6 +223,17 @@ public:
*/
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.
*
+1
View File
@@ -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"},
+9 -1
View File
@@ -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,
+3
View File
@@ -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),
+13
View File
@@ -407,6 +407,19 @@ exit:
return error;
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_15_4_ALT_SADDR>(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<SPINEL_PROP_MULTIPAN_ACTIVE_INTERFACE>(void)
{
+6
View File
@@ -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);
+3
View File
@@ -312,6 +312,9 @@ class Node(object):
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)
+108
View File
@@ -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))
+1
View File
@@ -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