[message] define Message::Checker and common predicate helpers (#13641)

This commit harmonizes message filtering and predicate checking across
core modules by defining a common `Message::Checker` type and providing
reusable simpler `Accept*` helper functions in the `Message` class.

Previously, `IndirectSender` and `MeshForwarder` defined their own local
predicate typedefs (`MessageChecker`), and callers like `IndirectSender`
and `Mle` implemented ad-hoc static checker functions.
This commit is contained in:
Abtin Keshavarzian
2026-09-23 23:01:54 -07:00
committed by GitHub
parent 89627809ff
commit 1e451158f0
7 changed files with 84 additions and 54 deletions
+63
View File
@@ -351,6 +351,16 @@ public:
kOriginHostUntrusted = OT_MESSAGE_ORIGIN_HOST_UNTRUSTED, // Message from an untrusted source on host.
};
/**
* Defines a predicate function reference which is used to check or filter a message.
*
* @param[in] aMessage The message to check.
*
* @retval TRUE If the message matches the criteria.
* @retval FALSE If the message does not match the criteria.
*/
typedef bool (&Checker)(const Message &aMessage);
/**
* Represents settings used for creating a new message.
*/
@@ -1595,6 +1605,59 @@ public:
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Helper common predicate `Checker` functions
/**
* Predicate checker function that matches and accepts any message.
*
* @param[in] aMessage The message to check.
*
* @retval TRUE Always matches and accepts the message.
*/
static bool AcceptAny(const Message &aMessage)
{
OT_UNUSED_VARIABLE(aMessage);
return true;
}
/**
* Predicate checker function that checks whether a message matches a specific type.
*
* @tparam kType The message type to match.
*
* @param[in] aMessage The message to check.
*
* @retval TRUE The message type matches @p kType.
* @retval FALSE The message type does not match @p kType.
*/
template <Type kType> static bool AcceptType(const Message &aMessage) { return aMessage.GetType() == kType; }
/**
* Predicate checker function that checks whether a message is of MLE subtype.
*
* @param[in] aMessage The message to check.
*
* @retval TRUE The message is of MLE subtype.
* @retval FALSE The message is not of MLE subtype.
*/
static bool AcceptAnyMle(const Message &aMessage) { return aMessage.IsSubTypeMle(); }
/**
* Predicate checker function that checks whether a message is a specific MLE command.
*
* @tparam kMleCommand The MLE command to match.
*
* @param[in] aMessage The message to check.
*
* @retval TRUE The message is an MLE command of @p kMleCommand type.
* @retval FALSE The message is not an MLE command of @p kMleCommand type.
*/
template <Mle::Command kMleCommand> static bool AcceptMle(const Message &aMessage)
{
return aMessage.IsMleCommand(kMleCommand);
}
protected:
class OT_GSL_POINTER ConstIterator : public ItemPtrIterator<const Message, ConstIterator>
{
+6 -16
View File
@@ -104,7 +104,9 @@ void IndirectSender::AddMessageForSleepyChild(Message &aMessage, Child &aChild)
if ((aMessage.GetType() != Message::kTypeSupervision) && (aChild.GetIndirectMessageCount() > 1))
{
Message *supervisionMessage = FindQueuedMessageForSleepyChild(aChild, AcceptSupervisionMessage);
Message *supervisionMessage;
supervisionMessage = FindQueuedMessageForSleepyChild(aChild, Message::AcceptType<Message::kTypeSupervision>);
if (supervisionMessage != nullptr)
{
@@ -158,7 +160,7 @@ exit:
return;
}
const Message *IndirectSender::FindQueuedMessageForSleepyChild(const Child &aChild, MessageChecker aChecker) const
const Message *IndirectSender::FindQueuedMessageForSleepyChild(const Child &aChild, Message::Checker aChecker) const
{
const Message *match = nullptr;
uint16_t childIndex = Get<ChildTable>().GetChildIndex(aChild);
@@ -260,7 +262,7 @@ void IndirectSender::RequestMessageUpdate(Child &aChild)
VerifyOrExit(!aChild.IsWaitingForMessageUpdate());
newMessage = FindQueuedMessageForSleepyChild(aChild, AcceptAnyMessage);
newMessage = FindQueuedMessageForSleepyChild(aChild, Message::AcceptAny);
VerifyOrExit(curMessage != newMessage);
@@ -303,7 +305,7 @@ exit:
void IndirectSender::UpdateIndirectMessage(Child &aChild)
{
Message *message = FindQueuedMessageForSleepyChild(aChild, AcceptAnyMessage);
Message *message = FindQueuedMessageForSleepyChild(aChild, Message::AcceptAny);
aChild.SetWaitingForMessageUpdate(false);
aChild.SetIndirectMessage(message);
@@ -533,18 +535,6 @@ void IndirectSender::ClearMessagesForRemovedChildren(void)
}
}
bool IndirectSender::AcceptAnyMessage(const Message &aMessage)
{
OT_UNUSED_VARIABLE(aMessage);
return true;
}
bool IndirectSender::AcceptSupervisionMessage(const Message &aMessage)
{
return aMessage.GetType() == Message::kTypeSupervision;
}
#endif // OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
+6 -19
View File
@@ -137,16 +137,6 @@ public:
"mQueuedMessageCount cannot fit max required!");
};
/**
* Represents a predicate function for checking if a given `Message` meets specific criteria.
*
* @param[in] aMessage The message to evaluate.
*
* @retval TRUE If the @p aMessage satisfies the predicate condition.
* @retval FALSE If the @p aMessage does not satisfy the predicate condition.
*/
typedef bool (&MessageChecker)(const Message &aMessage);
/**
* Initializes the object.
*
@@ -195,7 +185,7 @@ public:
/**
* Finds the first queued message for a given sleepy child that also satisfies the conditions of a given
* `MessageChecker`.
* `Message::Checker`.
*
* The caller MUST ensure that @p aChild is sleepy.
*
@@ -204,14 +194,14 @@ public:
*
* @returns A pointer to the matching queued message, or `nullptr` if none is found.
*/
Message *FindQueuedMessageForSleepyChild(const Child &aChild, MessageChecker aChecker)
Message *FindQueuedMessageForSleepyChild(const Child &aChild, Message::Checker aChecker)
{
return AsNonConst(AsConst(this)->FindQueuedMessageForSleepyChild(aChild, aChecker));
}
/**
* Finds the first queued message for a given sleepy child that also satisfies the conditions of a given
* `MessageChecker`.
* `Message::Checker`.
*
* The caller MUST ensure that @p aChild is sleepy.
*
@@ -220,11 +210,11 @@ public:
*
* @returns A pointer to the matching queued message, or `nullptr` if none is found.
*/
const Message *FindQueuedMessageForSleepyChild(const Child &aChild, MessageChecker aChecker) const;
const Message *FindQueuedMessageForSleepyChild(const Child &aChild, Message::Checker aChecker) const;
/**
* Indicates whether there is any queued message for a given sleepy child that also satisfies the conditions of a
* given `MessageChecker`.
* given `Message::Checker`.
*
* The caller MUST ensure that @p aChild is sleepy.
*
@@ -234,7 +224,7 @@ public:
* @retval TRUE There is a queued message satisfying @p aChecker for sleepy child @p aChild.
* @retval FALSE There is no queued message satisfying @p aChecker for sleepy child @p aChild.
*/
bool HasQueuedMessageForSleepyChild(const Child &aChild, MessageChecker aChecker) const
bool HasQueuedMessageForSleepyChild(const Child &aChild, Message::Checker aChecker) const
{
return (FindQueuedMessageForSleepyChild(aChild, aChecker) != nullptr);
}
@@ -279,9 +269,6 @@ private:
void UpdateIndirectMessage(Child &aChild);
void RequestMessageUpdate(Child &aChild);
void ClearMessagesForRemovedChildren(void);
static bool AcceptAnyMessage(const Message &aMessage);
static bool AcceptSupervisionMessage(const Message &aMessage);
#endif // OPENTHREAD_FTD
bool mEnabled;
+3 -5
View File
@@ -162,17 +162,15 @@ public:
void SetRxOnWhenIdle(bool aRxOnWhenIdle);
#if OPENTHREAD_FTD
typedef IndirectSender::MessageChecker MessageChecker; ///< General predicate function checking a message.
/**
* Removes and frees messages queued for a child, based on a given predicate.
*
* The `aChild` can be either sleepy or non-sleepy.
*
* @param[in] aChild The child whose messages are to be evaluated.
* @param[in] aMessageChecker The predicate function to filter messages.
* @param[in] aChild The child whose messages are to be evaluated.
* @param[in] aChecker The predicate function to filter messages.
*/
void RemoveMessagesForChild(Child &aChild, MessageChecker aMessageChecker);
void RemoveMessagesForChild(Child &aChild, Message::Checker aChecker);
#endif
/**
+2 -2
View File
@@ -259,11 +259,11 @@ exit:
return error;
}
void MeshForwarder::RemoveMessagesForChild(Child &aChild, MessageChecker &aMessageChecker)
void MeshForwarder::RemoveMessagesForChild(Child &aChild, Message::Checker aChecker)
{
for (Message &message : mSendQueue)
{
if (!aMessageChecker(message))
if (!aChecker(message))
{
continue;
}
-2
View File
@@ -2429,8 +2429,6 @@ private:
DeclareTmfResponseHandlerIn(Mle, HandleAddressSolicitResponse);
static bool IsMessageMleSubType(const Message &aMessage);
static bool IsMessageChildUpdateRequest(const Message &aMessage);
static void HandleAdvertiseTrickleTimer(TrickleTimer &aTimer);
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
+4 -10
View File
@@ -2022,13 +2022,6 @@ exit:
return error;
}
bool Mle::IsMessageMleSubType(const Message &aMessage) { return aMessage.IsSubTypeMle(); }
bool Mle::IsMessageChildUpdateRequest(const Message &aMessage)
{
return aMessage.IsMleCommand(kCommandChildUpdateRequest);
}
void Mle::HandleChildIdRequest(RxInfo &aRxInfo)
{
Error error = kErrorNone;
@@ -2059,7 +2052,7 @@ void Mle::HandleChildIdRequest(RxInfo &aRxInfo)
SuccessOrExit(error = aRxInfo.mMessage.ReadAndMatchResponseTlvWith(child->GetChallenge()));
Get<MeshForwarder>().RemoveMessagesForChild(*child, IsMessageMleSubType);
Get<MeshForwarder>().RemoveMessagesForChild(*child, Message::AcceptAnyMle);
SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
@@ -2939,10 +2932,11 @@ Error Mle::SendChildUpdateRequestToChild(Child &aChild)
// to the sleepy child if there is one already
// queued.
VerifyOrExit(!Get<IndirectSender>().HasQueuedMessageForSleepyChild(aChild, IsMessageChildUpdateRequest));
VerifyOrExit(!Get<IndirectSender>().HasQueuedMessageForSleepyChild(
aChild, Message::AcceptMle<kCommandChildUpdateRequest>));
}
Get<MeshForwarder>().RemoveMessagesForChild(aChild, IsMessageChildUpdateRequest);
Get<MeshForwarder>().RemoveMessagesForChild(aChild, Message::AcceptMle<kCommandChildUpdateRequest>);
VerifyOrExit((message = NewMleMessage(kCommandChildUpdateRequest)) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = message->AppendSourceAddressAndLeaderDataTlvs());