[mle] rate-limit scheduled discovery responses (#13086)

This commit introduces a cap on the number of concurrently scheduled
discovery responses in `Mle::DelayedSender`.

By adding the `CountMatchingSchedules()` method, we can now track how
many discovery responses are currently queued. The newly defined
constant `kMaxScheduledDiscoveryResponse` sets this limit to 16. If
the limit is reached, further `ScheduleDiscoveryResponse()` requests
are ignored.

This change protects the device from resource exhaustion (RAM, CPU,
and network) if it is flooded with discovery requests, preventing
potential Denial of Service (DoS) conditions.
This commit is contained in:
Abtin Keshavarzian
2026-05-08 13:02:44 -07:00
committed by GitHub
parent e6d9a13144
commit 294eb9a065
2 changed files with 36 additions and 9 deletions
+25
View File
@@ -3294,7 +3294,14 @@ void Mle::DelayedSender::ScheduleDiscoveryResponse(const Ip6::Address &
const DiscoveryResponseInfo &aInfo,
uint32_t aDelay)
{
RemoveMatchingSchedules(kTypeDiscoveryResponse, aDestination);
VerifyOrExit(CountMatchingSchedules(kTypeDiscoveryResponse) < kMaxScheduledDiscoveryResponse);
AddSchedule(kTypeDiscoveryResponse, aDestination, aDelay, &aInfo, sizeof(aInfo));
exit:
return;
}
#endif // OPENTHREAD_FTD
@@ -3490,6 +3497,24 @@ void Mle::DelayedSender::RemoveMatchingSchedules(MessageType aMessageType, const
}
}
uint32_t Mle::DelayedSender::CountMatchingSchedules(MessageType aMessageType) const
{
uint32_t count = 0;
Ip6::Address unspecifiedAddr;
unspecifiedAddr.Clear();
for (const Schedule &schedule : mSchedules)
{
if (Match(schedule, aMessageType, unspecifiedAddr))
{
count++;
}
}
return count;
}
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void Mle::DelayedSender::LogRemove(const Schedule &aSchedule)
{
+11 -9
View File
@@ -1347,6 +1347,7 @@ private:
static constexpr uint8_t kRouterDowngradeThreshold = 23;
static constexpr uint8_t kRouterUpgradeThreshold = 16;
static constexpr uint16_t kDiscoveryMaxJitter = 250; // Max jitter delay Discovery Responses (in msec).
static constexpr uint32_t kMaxScheduledDiscoveryResponse = 16; // Rate-limit Discovery response.
static constexpr uint16_t kUnsolicitedDataResponseJitter = 500; // Max delay for unsol Data Response (in msec).
static constexpr uint8_t kLeaderDowngradeExtraDelay = 10; // Extra delay to downgrade leader (in sec).
static constexpr uint8_t kDefaultLeaderWeight = 64;
@@ -1776,15 +1777,16 @@ private:
MessageType mMessageType;
};
void AddSchedule(MessageType aMessageType,
const Ip6::Address &aDestination,
uint32_t aDelay,
const void *aInfo,
uint16_t aInfoSize);
void Execute(const Schedule &aSchedule);
bool HasMatchingSchedule(MessageType aMessageType, const Ip6::Address &aDestination) const;
void RemoveMatchingSchedules(MessageType aMessageType, const Ip6::Address &aDestination);
void LogRemove(const Schedule &aSchedule);
void AddSchedule(MessageType aMessageType,
const Ip6::Address &aDestination,
uint32_t aDelay,
const void *aInfo,
uint16_t aInfoSize);
void Execute(const Schedule &aSchedule);
bool HasMatchingSchedule(MessageType aMessageType, const Ip6::Address &aDestination) const;
void RemoveMatchingSchedules(MessageType aMessageType, const Ip6::Address &aDestination);
uint32_t CountMatchingSchedules(MessageType aMessageType) const;
void LogRemove(const Schedule &aSchedule);
static bool Match(const Schedule &aSchedule, MessageType aMessageType, const Ip6::Address &aDestination);