[mle] fix implementation of IsMinimalEndDevice() (#11926)

A Minimal End Device (MED) is defined by the spec as an MTD whose
receiver is enabled all the time.

This commit fixes the implementation of `IsMinimalEndDevice()` to
match this definition. The previous implementation of this method
would incorrectly accept any MTD config (including SED or MED).

Within the core modules, `IsMinimalEndDevice()` is only used in
`MeshForwarder::UpdateIp6Route()`. This commit updates the logic
in this method to differentiate between an FTD (calling
`UpdateIp6RouteFtd`()) and an MTD (forwarding to parent) by
checking `IsFullThreadDevice()` instead of the previous check
against `IsMinimalEndDevice()` (which was effectively checking
MTD).

This commit also adds a new unit test, `TestDeviceMode()`, to
validate all configurations of `DeviceMode` (SED, MED, FTD) and
verify the behavior of `IsMinimalEndDevice()`.
This commit is contained in:
Abtin Keshavarzian
2025-09-15 11:31:43 -07:00
committed by GitHub
parent eba5bdc434
commit f60b00695e
4 changed files with 162 additions and 13 deletions
+5 -7
View File
@@ -612,17 +612,15 @@ Error MeshForwarder::UpdateIp6Route(Message &aMessage)
{
mMacAddrs.mDestination.SetExtendedFromIid(ip6Header.GetDestination().GetIid());
}
else if (Get<Mle::Mle>().IsMinimalEndDevice())
#if OPENTHREAD_FTD
else if (Get<Mle::Mle>().IsFullThreadDevice())
{
mMacAddrs.mDestination.SetShort(Get<Mle::Mle>().GetParentRloc16());
error = UpdateIp6RouteFtd(ip6Header, aMessage);
}
#endif
else
{
#if OPENTHREAD_FTD
error = UpdateIp6RouteFtd(ip6Header, aMessage);
#else
OT_ASSERT(false);
#endif
mMacAddrs.mDestination.SetShort(Get<Mle::Mle>().GetParentRloc16());
}
exit:
+1 -1
View File
@@ -329,7 +329,7 @@ public:
bool IsFullThreadDevice(void) const { return mDeviceMode.IsFullThreadDevice(); }
/**
* Indicates whether or not the device is a Minimal End Device.
* Indicates whether or not the device is a Minimal End Device (MED), i.e., an MTD which is rx-on-when-idle.
*
* @returns TRUE if the device is a Minimal End Device, FALSE otherwise.
*/
+2 -5
View File
@@ -452,15 +452,12 @@ public:
}
/**
* Indicates whether or not the device is a Minimal End Device.
* Indicates whether or not the device is a Minimal End Device (MED), i.e., an MTD which is rx-on-when-idle.
*
* @retval TRUE If the device is a Minimal End Device.
* @retval FALSE If the device is not a Minimal End Device.
*/
bool IsMinimalEndDevice(void) const
{
return (mMode & (kModeFullThreadDevice | kModeRxOnWhenIdle)) != (kModeFullThreadDevice | kModeRxOnWhenIdle);
}
bool IsMinimalEndDevice(void) const { return !IsFullThreadDevice() && IsRxOnWhenIdle(); }
/**
* Indicates whether or not the device mode flags are valid.
+154
View File
@@ -36,6 +36,158 @@
namespace ot {
void TestDeviceMode(void)
{
Mle::DeviceMode mode;
Mle::DeviceMode::ModeConfig config;
Mle::DeviceMode::ModeConfig readConfig;
//- - - - - - - - - - - - - - - - - - - - - - - -
// SED (stable subset netdata)
config.mRxOnWhenIdle = false;
config.mDeviceType = false;
config.mNetworkData = false;
mode.Set(config);
mode.Get(readConfig);
VerifyOrQuit(!readConfig.mRxOnWhenIdle);
VerifyOrQuit(!readConfig.mDeviceType);
VerifyOrQuit(!readConfig.mNetworkData);
VerifyOrQuit(mode.IsValid());
VerifyOrQuit(!mode.IsRxOnWhenIdle());
VerifyOrQuit(!mode.IsFullThreadDevice());
VerifyOrQuit(mode.GetNetworkDataType() == NetworkData::kStableSubset);
VerifyOrQuit(!mode.IsMinimalEndDevice());
//- - - - - - - - - - - - - - - - - - - - - - - -
// SED (full set netdata)
config.mRxOnWhenIdle = false;
config.mDeviceType = false;
config.mNetworkData = true;
mode.Set(config);
mode.Get(readConfig);
VerifyOrQuit(!readConfig.mRxOnWhenIdle);
VerifyOrQuit(!readConfig.mDeviceType);
VerifyOrQuit(readConfig.mNetworkData);
VerifyOrQuit(mode.IsValid());
VerifyOrQuit(!mode.IsRxOnWhenIdle());
VerifyOrQuit(!mode.IsFullThreadDevice());
VerifyOrQuit(mode.GetNetworkDataType() == NetworkData::kFullSet);
VerifyOrQuit(!mode.IsMinimalEndDevice());
//- - - - - - - - - - - - - - - - - - - - - - - -
// MED (stable subset netdata)
config.mRxOnWhenIdle = true;
config.mDeviceType = false;
config.mNetworkData = false;
mode.Set(config);
mode.Get(readConfig);
VerifyOrQuit(readConfig.mRxOnWhenIdle);
VerifyOrQuit(!readConfig.mDeviceType);
VerifyOrQuit(!readConfig.mNetworkData);
VerifyOrQuit(mode.IsValid());
VerifyOrQuit(mode.IsRxOnWhenIdle());
VerifyOrQuit(!mode.IsFullThreadDevice());
VerifyOrQuit(mode.GetNetworkDataType() == NetworkData::kStableSubset);
VerifyOrQuit(mode.IsMinimalEndDevice());
//- - - - - - - - - - - - - - - - - - - - - - - -
// MED (full set netdata)
config.mRxOnWhenIdle = true;
config.mDeviceType = false;
config.mNetworkData = true;
mode.Set(config);
mode.Get(readConfig);
VerifyOrQuit(readConfig.mRxOnWhenIdle);
VerifyOrQuit(!readConfig.mDeviceType);
VerifyOrQuit(readConfig.mNetworkData);
VerifyOrQuit(mode.IsValid());
VerifyOrQuit(mode.IsRxOnWhenIdle());
VerifyOrQuit(!mode.IsFullThreadDevice());
VerifyOrQuit(mode.GetNetworkDataType() == NetworkData::kFullSet);
VerifyOrQuit(mode.IsMinimalEndDevice());
//- - - - - - - - - - - - - - - - - - - - - - - -
// FTD (stable subset netdata)
config.mRxOnWhenIdle = true;
config.mDeviceType = true;
config.mNetworkData = false;
mode.Set(config);
mode.Get(readConfig);
VerifyOrQuit(readConfig.mRxOnWhenIdle);
VerifyOrQuit(readConfig.mDeviceType);
VerifyOrQuit(!readConfig.mNetworkData);
VerifyOrQuit(mode.IsValid());
VerifyOrQuit(mode.IsRxOnWhenIdle());
VerifyOrQuit(mode.IsFullThreadDevice());
VerifyOrQuit(mode.GetNetworkDataType() == NetworkData::kStableSubset);
VerifyOrQuit(!mode.IsMinimalEndDevice());
//- - - - - - - - - - - - - - - - - - - - - - - -
// FTD (full set netdata)
config.mRxOnWhenIdle = true;
config.mDeviceType = true;
config.mNetworkData = true;
mode.Set(config);
mode.Get(readConfig);
VerifyOrQuit(readConfig.mRxOnWhenIdle);
VerifyOrQuit(readConfig.mDeviceType);
VerifyOrQuit(readConfig.mNetworkData);
VerifyOrQuit(mode.IsValid());
VerifyOrQuit(mode.IsRxOnWhenIdle());
VerifyOrQuit(mode.IsFullThreadDevice());
VerifyOrQuit(mode.GetNetworkDataType() == NetworkData::kFullSet);
VerifyOrQuit(!mode.IsMinimalEndDevice());
//- - - - - - - - - - - - - - - - - - - - - - - -
// Invalid
config.mRxOnWhenIdle = false;
config.mDeviceType = true;
config.mNetworkData = true;
mode.Set(config);
mode.Get(readConfig);
VerifyOrQuit(!readConfig.mRxOnWhenIdle);
VerifyOrQuit(readConfig.mDeviceType);
VerifyOrQuit(readConfig.mNetworkData);
VerifyOrQuit(!mode.IsValid());
//- - - - - - - - - - - - - - - - - - - - - - - -
// Invalid
config.mRxOnWhenIdle = false;
config.mDeviceType = true;
config.mNetworkData = false;
mode.Set(config);
mode.Get(readConfig);
VerifyOrQuit(!readConfig.mRxOnWhenIdle);
VerifyOrQuit(readConfig.mDeviceType);
VerifyOrQuit(!readConfig.mNetworkData);
VerifyOrQuit(!mode.IsValid());
printf("TestDeviceMode passed\n");
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
void TestDefaultDeviceProperties(void)
@@ -176,6 +328,8 @@ void TestLeaderWeightCalculation(void)
int main(void)
{
ot::TestDeviceMode();
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
ot::TestDefaultDeviceProperties();
ot::TestLeaderWeightCalculation();