[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. 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. * Represents settings used for creating a new message.
*/ */
@@ -1595,6 +1605,59 @@ public:
#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO #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: protected:
class OT_GSL_POINTER ConstIterator : public ItemPtrIterator<const Message, ConstIterator> 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)) 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) if (supervisionMessage != nullptr)
{ {
@@ -158,7 +160,7 @@ exit:
return; 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; const Message *match = nullptr;
uint16_t childIndex = Get<ChildTable>().GetChildIndex(aChild); uint16_t childIndex = Get<ChildTable>().GetChildIndex(aChild);
@@ -260,7 +262,7 @@ void IndirectSender::RequestMessageUpdate(Child &aChild)
VerifyOrExit(!aChild.IsWaitingForMessageUpdate()); VerifyOrExit(!aChild.IsWaitingForMessageUpdate());
newMessage = FindQueuedMessageForSleepyChild(aChild, AcceptAnyMessage); newMessage = FindQueuedMessageForSleepyChild(aChild, Message::AcceptAny);
VerifyOrExit(curMessage != newMessage); VerifyOrExit(curMessage != newMessage);
@@ -303,7 +305,7 @@ exit:
void IndirectSender::UpdateIndirectMessage(Child &aChild) void IndirectSender::UpdateIndirectMessage(Child &aChild)
{ {
Message *message = FindQueuedMessageForSleepyChild(aChild, AcceptAnyMessage); Message *message = FindQueuedMessageForSleepyChild(aChild, Message::AcceptAny);
aChild.SetWaitingForMessageUpdate(false); aChild.SetWaitingForMessageUpdate(false);
aChild.SetIndirectMessage(message); 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 #endif // OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
+6 -19
View File
@@ -137,16 +137,6 @@ public:
"mQueuedMessageCount cannot fit max required!"); "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. * 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 * 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. * 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. * @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)); 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 * 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. * 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. * @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 * 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. * 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 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. * @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); return (FindQueuedMessageForSleepyChild(aChild, aChecker) != nullptr);
} }
@@ -279,9 +269,6 @@ private:
void UpdateIndirectMessage(Child &aChild); void UpdateIndirectMessage(Child &aChild);
void RequestMessageUpdate(Child &aChild); void RequestMessageUpdate(Child &aChild);
void ClearMessagesForRemovedChildren(void); void ClearMessagesForRemovedChildren(void);
static bool AcceptAnyMessage(const Message &aMessage);
static bool AcceptSupervisionMessage(const Message &aMessage);
#endif // OPENTHREAD_FTD #endif // OPENTHREAD_FTD
bool mEnabled; bool mEnabled;
+3 -5
View File
@@ -162,17 +162,15 @@ public:
void SetRxOnWhenIdle(bool aRxOnWhenIdle); void SetRxOnWhenIdle(bool aRxOnWhenIdle);
#if OPENTHREAD_FTD #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. * Removes and frees messages queued for a child, based on a given predicate.
* *
* The `aChild` can be either sleepy or non-sleepy. * The `aChild` can be either sleepy or non-sleepy.
* *
* @param[in] aChild The child whose messages are to be evaluated. * @param[in] aChild The child whose messages are to be evaluated.
* @param[in] aMessageChecker The predicate function to filter messages. * @param[in] aChecker The predicate function to filter messages.
*/ */
void RemoveMessagesForChild(Child &aChild, MessageChecker aMessageChecker); void RemoveMessagesForChild(Child &aChild, Message::Checker aChecker);
#endif #endif
/** /**
+2 -2
View File
@@ -259,11 +259,11 @@ exit:
return error; return error;
} }
void MeshForwarder::RemoveMessagesForChild(Child &aChild, MessageChecker &aMessageChecker) void MeshForwarder::RemoveMessagesForChild(Child &aChild, Message::Checker aChecker)
{ {
for (Message &message : mSendQueue) for (Message &message : mSendQueue)
{ {
if (!aMessageChecker(message)) if (!aChecker(message))
{ {
continue; continue;
} }
-2
View File
@@ -2429,8 +2429,6 @@ private:
DeclareTmfResponseHandlerIn(Mle, HandleAddressSolicitResponse); DeclareTmfResponseHandlerIn(Mle, HandleAddressSolicitResponse);
static bool IsMessageMleSubType(const Message &aMessage);
static bool IsMessageChildUpdateRequest(const Message &aMessage);
static void HandleAdvertiseTrickleTimer(TrickleTimer &aTimer); static void HandleAdvertiseTrickleTimer(TrickleTimer &aTimer);
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
+4 -10
View File
@@ -2022,13 +2022,6 @@ exit:
return error; 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) void Mle::HandleChildIdRequest(RxInfo &aRxInfo)
{ {
Error error = kErrorNone; Error error = kErrorNone;
@@ -2059,7 +2052,7 @@ void Mle::HandleChildIdRequest(RxInfo &aRxInfo)
SuccessOrExit(error = aRxInfo.mMessage.ReadAndMatchResponseTlvWith(child->GetChallenge())); 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)); 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 // to the sleepy child if there is one already
// queued. // 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); VerifyOrExit((message = NewMleMessage(kCommandChildUpdateRequest)) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = message->AppendSourceAddressAndLeaderDataTlvs()); SuccessOrExit(error = message->AppendSourceAddressAndLeaderDataTlvs());