Skip to content

Commit

Permalink
[dataset] enforce maximum delay timer value and improve handling (ope…
Browse files Browse the repository at this point in the history
…nthread#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).
  • Loading branch information
abtink authored Apr 15, 2024
1 parent f68eda9 commit 43cb7a0
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 65 deletions.
14 changes: 2 additions & 12 deletions src/core/meshcop/dataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
19 changes: 2 additions & 17 deletions src/core/meshcop/dataset_local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
24 changes: 1 addition & 23 deletions src/core/meshcop/dataset_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -739,35 +736,16 @@ void PendingDatasetManager::StartDelayTimer(void)

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();

Get<ActiveDatasetManager>().Save(dataset);

Clear();

exit:
return;
}

template <>
Expand Down
6 changes: 0 additions & 6 deletions src/core/meshcop/dataset_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,6 @@ class DatasetManager : public InstanceLocator
#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.
*
Expand Down
6 changes: 3 additions & 3 deletions src/core/meshcop/dataset_manager_ftd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
4 changes: 2 additions & 2 deletions src/core/meshcop/meshcop_leader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ RegisterLogModule("MeshCoPLeader");
Leader::Leader(Instance &aInstance)
: InstanceLocator(aInstance)
, mTimer(aInstance)
, mDelayTimerMinimal(kMinDelayTimer)
, mDelayTimerMinimal(DelayTimerTlv::kMinDelay)
, mSessionId(Random::NonCrypto::GetUint16())
{
}
Expand Down Expand Up @@ -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:
Expand Down
1 change: 0 additions & 1 deletion src/core/meshcop/meshcop_leader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ class Leader : public InstanceLocator, private NonCopyable
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
Expand Down
17 changes: 17 additions & 0 deletions src/core/meshcop/meshcop_tlvs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
43 changes: 42 additions & 1 deletion src/core/meshcop/meshcop_tlvs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 43cb7a0

Please sign in to comment.