[ip6] skip MPL processing on SEDs and detect self-sent multicast (#12323)

This commit updates `Mpl::ProcessOption()` to skip MPL processing on
Sleepy End Devices (SEDs) as an optimization. Along with this it
introduces a check to prevent SEDs from processing their own
multicast messages.

Since MPL is now skipped on SEDs, they no longer have a mechanism
for multicast duplicate detection. This can cause an issue when an
SED sends a multicast message to a group it is subscribed to, as its
parent can forward the message back to the SED.

To handle this, `Ip6::DetermineAction()` is updated. For SEDs, it now
checks if the source address of a subscribed multicast message
belongs to the device itself. If it does, the message is not
received, preventing the SED from processing its own looped-back
messages.

The behavior for non-sleepy devices remains unchanged. They continue
to rely on MPL for duplicate suppression.
This commit is contained in:
Abtin Keshavarzian
2026-01-23 10:40:22 -08:00
committed by GitHub
parent 3061fa19de
commit 3b676fb6f3
2 changed files with 47 additions and 8 deletions
+35 -5
View File
@@ -1117,13 +1117,43 @@ void Ip6::DetermineAction(const Message &aMessage,
// Always forward multicast packets to host network stack
aForwardHost = true;
// If subscribed to the multicast address, receive if it is from the
// Thread netif or if multicast loop is allowed.
// Determine `aReceive` for a multicast message destined for
// an address to which this device is subscribed.
//
// 1) Accept if `MulticastLoop` is enabled.
// 2) Otherwise, if it originates from the Thread Netif:
// - Always accept if the device is non-sleepy.
// - If sleepy, only if the source is NOT the SED itself.
//
// For non-sleepy devices, duplicate multicast detection is
// handled in `Mpl::ProcessOption()`, which will update
// `aReceive` if the message was seen before (based on the
// MPL Seed).
//
// To optimize SED behavior, MPL processing is fully skipped
// on SEDs. Therefore, the check above is added to handle the
// specific case where an SED sends a multicast message to a
// group it is subscribed to. The parent can send it back to
// the SED (since the child is subscribed), we check and skip
// processing it.
if ((aMessage.IsOriginThreadNetif() || aMessage.GetMulticastLoop()) &&
Get<ThreadNetif>().IsMulticastSubscribed(aHeader.GetDestination()))
if (Get<ThreadNetif>().IsMulticastSubscribed(aHeader.GetDestination()))
{
aReceive = true;
if (aMessage.GetMulticastLoop())
{
aReceive = true;
}
else if (aMessage.IsOriginThreadNetif())
{
if (Get<Mle::Mle>().IsRxOnWhenIdle())
{
aReceive = true;
}
else
{
aReceive = !Get<ThreadNetif>().HasUnicastAddress(aHeader.GetSource());
}
}
}
ExitNow();
+12 -3
View File
@@ -117,7 +117,9 @@ exit:
Error Mpl::ProcessOption(Message &aMessage, const MplOption &aOption, bool &aReceive)
{
Error error;
Error error = kErrorNone;
VerifyOrExit(Get<Mle::Mle>().IsRxOnWhenIdle());
// Check if the MPL Data Message is new.
error = UpdateSeedSet(aOption.GetSeedId(), aOption.GetSequence());
@@ -130,12 +132,19 @@ Error Mpl::ProcessOption(Message &aMessage, const MplOption &aOption, bool &aRec
}
else if (!aMessage.IsOriginThreadNetif())
{
// If the MPL message is not new (already present in the seed
// set), avoid receiving it again. It should have been
// received and processed the first time the seed set was
// updated.
aReceive = false;
// In case MPL Data Message is generated locally, ignore potential error of the MPL Seed Set
// to allow subsequent retransmissions with the same sequence number.
// In case MPL Data Message is generated locally, ignore
// potential error of the MPL Seed Set to allow subsequent
// retransmissions with the same sequence number.
error = kErrorNone;
}
exit:
return error;
}