Skip to content

Commit

Permalink
[mle] implement alternate RLOC16 usage during role transition (openth…
Browse files Browse the repository at this point in the history
…read#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.
  • Loading branch information
abtink authored Oct 30, 2024
1 parent a5e1c91 commit 444d1dd
Show file tree
Hide file tree
Showing 35 changed files with 519 additions and 28 deletions.
15 changes: 12 additions & 3 deletions examples/platforms/simulation/radio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 12 additions & 1 deletion examples/platforms/utils/mac_frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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:
Expand Down
20 changes: 20 additions & 0 deletions examples/platforms/utils/mac_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/openthread/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 10 additions & 1 deletion include/openthread/link.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
20 changes: 20 additions & 0 deletions include/openthread/link_raw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
46 changes: 35 additions & 11 deletions include/openthread/platform/radio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
};

/**
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
*
Expand Down
12 changes: 11 additions & 1 deletion src/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down
16 changes: 15 additions & 1 deletion src/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/core/api/link_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
5 changes: 5 additions & 0 deletions src/core/api/link_raw_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions src/core/mac/link_raw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions src/core/mac/link_raw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
33 changes: 31 additions & 2 deletions src/core/mac/mac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ Mac::Mac(Instance &aInstance)
SetPanId(mPanId);
SetExtAddress(randomExtAddress);
SetShortAddress(GetShortAddress());
#if OPENTHREAD_FTD
SetAlternateShortAddress(kShortAddrInvalid);
#endif

mMode2KeyMaterial.SetFrom(AsCoreType(&sMode2Key));
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 444d1dd

Please sign in to comment.