[dataset] enforce maximum delay timer value and improve handling (#10023)

This commit makes the following improvements to Delay Timer TLV
handling in Pending Operational Datasets:

- Enforces maximum delay adhering to the Thread spec's maximum Delay
  Timer value (72 hours), clamping larger values.
- Defines min, max, and default delay timer constants in
  `DelayTimerTlv`.
- Adds `CalculateRemainingDelay()` helper method to calculate
  remaining delay.
- Removes code handling delay values exceeding the OpenThread `Timer`
  limitation (now redundant due to the stricter 72-hour maximum).
This commit is contained in:
Abtin Keshavarzian
2024-04-15 12:25:30 -07:00
committed by GitHub
parent f68eda9660
commit 43cb7a09cf
9 changed files with 69 additions and 65 deletions
+2 -12
View File
@@ -473,19 +473,9 @@ Error Dataset::AppendMleDatasetTlv(Type aType, Message &aMessage) const
}
else if (cur->GetType() == Tlv::kDelayTimer)
{
uint32_t elapsed = TimerMilli::GetNow() - mUpdateTime;
uint32_t delayTimer = cur->ReadValueAs<DelayTimerTlv>();
uint32_t remainingDelay = DelayTimerTlv::CalculateRemainingDelay(*cur, mUpdateTime);
if (delayTimer > elapsed)
{
delayTimer -= elapsed;
}
else
{
delayTimer = 0;
}
SuccessOrExit(error = Tlv::Append<DelayTimerTlv>(aMessage, delayTimer));
SuccessOrExit(error = Tlv::Append<DelayTimerTlv>(aMessage, remainingDelay));
}
else
{
+2 -17
View File
@@ -106,25 +106,10 @@ Error DatasetLocal::Read(Dataset &aDataset) const
}
else
{
uint32_t elapsed;
uint32_t delayTimer;
Tlv *tlv = aDataset.FindTlv(Tlv::kDelayTimer);
Tlv *tlv = aDataset.FindTlv(Tlv::kDelayTimer);
VerifyOrExit(tlv != nullptr);
elapsed = TimerMilli::GetNow() - mUpdateTime;
delayTimer = tlv->ReadValueAs<DelayTimerTlv>();
if (delayTimer > elapsed)
{
delayTimer -= elapsed;
}
else
{
delayTimer = 0;
}
tlv->WriteValueAs<DelayTimerTlv>(delayTimer);
tlv->WriteValueAs<DelayTimerTlv>(DelayTimerTlv::CalculateRemainingDelay(*tlv, mUpdateTime));
}
aDataset.mUpdateTime = TimerMilli::GetNow();
+1 -23
View File
@@ -725,10 +725,7 @@ void PendingDatasetManager::StartDelayTimer(void)
tlv = dataset.FindTlv(Tlv::kDelayTimer);
VerifyOrExit(tlv != nullptr);
delay = tlv->ReadValueAs<DelayTimerTlv>();
// the Timer implementation does not support the full 32 bit range
delay = Min(delay, Timer::kMaxDelay);
delay = Min(tlv->ReadValueAs<DelayTimerTlv>(), DelayTimerTlv::kMaxDelay);
mDelayTimer.StartAt(dataset.GetUpdateTime(), delay);
LogInfo("delay timer started %lu", ToUlong(delay));
@@ -739,25 +736,9 @@ exit:
void PendingDatasetManager::HandleDelayTimer(void)
{
Tlv *tlv;
Dataset dataset;
IgnoreError(Read(dataset));
// if the Delay Timer value is larger than what our Timer implementation can handle, we have to compute
// the remainder and wait some more.
if ((tlv = dataset.FindTlv(Tlv::kDelayTimer)) != nullptr)
{
uint32_t elapsed = mDelayTimer.GetFireTime() - dataset.GetUpdateTime();
uint32_t delay = tlv->ReadValueAs<DelayTimerTlv>();
if (elapsed < delay)
{
mDelayTimer.StartAt(mDelayTimer.GetFireTime(), delay - elapsed);
ExitNow();
}
}
LogInfo("pending delay timer expired");
dataset.ConvertToActive();
@@ -765,9 +746,6 @@ void PendingDatasetManager::HandleDelayTimer(void)
Get<ActiveDatasetManager>().Save(dataset);
Clear();
exit:
return;
}
template <>
-6
View File
@@ -182,12 +182,6 @@ public:
#endif
protected:
/**
* Default Delay Timer value for a Pending Operational Dataset (ms)
*
*/
static constexpr uint32_t kDefaultDelayTimer = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_DEFAULT_DELAY;
/**
* Defines a generic Dataset TLV to read from a message.
*
+3 -3
View File
@@ -202,11 +202,11 @@ Error DatasetManager::HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo
case Tlv::kDelayTimer:
{
uint32_t delayTimer = datasetTlv.ReadValueAs<DelayTimerTlv>();
uint32_t delayTimer = Min(datasetTlv.ReadValueAs<DelayTimerTlv>(), DelayTimerTlv::kMaxDelay);
if (doesAffectNetworkKey && delayTimer < kDefaultDelayTimer)
if (doesAffectNetworkKey && delayTimer < DelayTimerTlv::kDefaultDelay)
{
delayTimer = kDefaultDelayTimer;
delayTimer = DelayTimerTlv::kDefaultDelay;
}
else
{
+2 -2
View File
@@ -58,7 +58,7 @@ RegisterLogModule("MeshCoPLeader");
Leader::Leader(Instance &aInstance)
: InstanceLocator(aInstance)
, mTimer(aInstance)
, mDelayTimerMinimal(kMinDelayTimer)
, mDelayTimerMinimal(DelayTimerTlv::kMinDelay)
, mSessionId(Random::NonCrypto::GetUint16())
{
}
@@ -218,7 +218,7 @@ Error Leader::SetDelayTimerMinimal(uint32_t aDelayTimerMinimal)
{
Error error = kErrorNone;
VerifyOrExit((aDelayTimerMinimal != 0 && aDelayTimerMinimal < kMinDelayTimer), error = kErrorInvalidArgs);
VerifyOrExit((aDelayTimerMinimal != 0 && aDelayTimerMinimal < DelayTimerTlv::kMinDelay), error = kErrorInvalidArgs);
mDelayTimerMinimal = aDelayTimerMinimal;
exit:
-1
View File
@@ -104,7 +104,6 @@ public:
void SetEmptyCommissionerData(void);
private:
static constexpr uint32_t kMinDelayTimer = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_MINIMUM_DELAY; // (msec)
static constexpr uint32_t kTimeoutLeaderPetition = 50; // TIMEOUT_LEAD_PET (seconds)
OT_TOOL_PACKED_BEGIN
+17
View File
@@ -158,6 +158,23 @@ const char *StateTlv::StateToString(State aState)
return aState == kReject ? kStateStrings[2] : kStateStrings[aState];
}
uint32_t DelayTimerTlv::CalculateRemainingDelay(const Tlv &aDelayTimerTlv, TimeMilli aUpdateTime)
{
uint32_t delay = Min(aDelayTimerTlv.ReadValueAs<DelayTimerTlv>(), kMaxDelay);
uint32_t elapsed = TimerMilli::GetNow() - aUpdateTime;
if (delay > elapsed)
{
delay -= elapsed;
}
else
{
delay = 0;
}
return delay;
}
bool ChannelMaskTlv::IsValid(void) const
{
uint32_t channelMask;
+42 -1
View File
@@ -611,7 +611,48 @@ typedef SimpleTlvInfo<Tlv::kPendingTimestamp, Timestamp> PendingTimestampTlv;
* Defines Delay Timer TLV constants and types.
*
*/
typedef UintTlvInfo<Tlv::kDelayTimer, uint32_t> DelayTimerTlv;
class DelayTimerTlv : public UintTlvInfo<Tlv::kDelayTimer, uint32_t>
{
public:
/**
* Minimum Delay Timer value (in msec).
*
*/
static constexpr uint32_t kMinDelay = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_MINIMUM_DELAY;
/**
* Maximum Delay Timer value (in msec).
*
*/
static constexpr uint32_t kMaxDelay = (72 * Time::kOneHourInMsec);
/**
* Default Delay Timer value (in msec).
*
*/
static constexpr uint32_t kDefaultDelay = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_DEFAULT_DELAY;
/**
* Calculates the remaining delay in milliseconds, based on the value read from a Delay Timer TLV and the specified
* update time.
*
* Ensures that the calculated delay does not exceed `kMaxDelay`. Also accounts for time already elapsed since
* @p aUpdateTime.
*
* Caller MUST ensure that @p aDelayTimerTlv is a Delay Timer TLV, otherwise behavior is undefined.
*
* @param[in] aDelayTimerTlv The delay timer TLV to read delay from.
* @param[in] aUpdateTimer The update time of the Dataset.
*
* @return The remaining delay (in msec).
*
*/
static uint32_t CalculateRemainingDelay(const Tlv &aDelayTimerTlv, TimeMilli aUpdateTime);
static_assert(kMinDelay <= kMaxDelay, "TMF_PENDING_DATASET_MINIMUM_DELAY is larger than max allowed");
static_assert(kDefaultDelay <= kMaxDelay, "TMF_PENDING_DATASET_DEFAULT_DELAY is larger than max allowed");
static_assert(kDefaultDelay >= kMinDelay, "TMF_PENDING_DATASET_DEFAULT_DELAY is smaller than min allowed");
};
/**
* Implements Channel Mask TLV generation and parsing.