Skip to content

Commit

Permalink
[tlvs] add ReadValueAs() & WriteValueAs() to simplify `MeshCop::T…
Browse files Browse the repository at this point in the history
…lv` (openthread#9661)

This commit introduces template methods `ReadValueAs<>()` and
`WriteValueAs<>()` in `Tlv` class for handling simple TLV types
(single value and uint value). These methods are employed to simplify
the handling of `MeshCoP::Tlv` in `Dataset`. Specifically, the
following TLVs are simplified:

- `PanIdTlv`
- `ExtendedPanIdTlv`
- `PskcTlv`
- `NetworkKeyTlv`
- `MeshLocalPrefixTlv`
- `ActiveTimestampTlv`
- `PendingTimestampTlv`
- `DelayTimerTlv`
- `NetworkKeySequenceTlv`
- `JoinerUdpPortTlv`

These enhance the code by reducing repeated boilerplate code for the
these simple TLVs.
  • Loading branch information
abtink authored Nov 29, 2023
1 parent 1f7ab82 commit 63424e2
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 562 deletions.
66 changes: 66 additions & 0 deletions src/core/common/encoding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ inline uint64_t ReadUint64(const uint8_t *aBuffer)
(static_cast<uint64_t>(aBuffer[6]) << 8) | (static_cast<uint64_t>(aBuffer[7]) << 0));
}

/**
* Reads a `UintType` integer value from a given buffer assuming big-endian encoding.
*
* @tparam UintType The unsigned int type.
*
* @param[in] aBuffer Pointer to the buffer to read from.
*
* @returns The `UintType` value read from the buffer.
*
*/
template <typename UintType> UintType Read(const uint8_t *aBuffer);

template <> inline uint8_t Read(const uint8_t *aBuffer) { return *aBuffer; }
template <> inline uint16_t Read(const uint8_t *aBuffer) { return ReadUint16(aBuffer); }
template <> inline uint32_t Read(const uint8_t *aBuffer) { return ReadUint32(aBuffer); }
template <> inline uint64_t Read(const uint8_t *aBuffer) { return ReadUint64(aBuffer); }

/**
* Writes a `uint16_t` value to a given buffer using big-endian encoding.
*
Expand Down Expand Up @@ -228,6 +245,22 @@ inline void WriteUint64(uint64_t aValue, uint8_t *aBuffer)
aBuffer[7] = (aValue >> 0) & 0xff;
}

/**
* Writes a `UintType` integer value to a given buffer assuming big-endian encoding.
*
* @tparam UintType The unsigned int type.
*
* @param[in] aValue The value to write to buffer.
* @param[in] aBuffer Pointer to the buffer to write to.
*
*/
template <typename UintType> void Write(UintType aValue, uint8_t *aBuffer);

template <> inline void Write(uint8_t aValue, uint8_t *aBuffer) { *aBuffer = aValue; }
template <> inline void Write(uint16_t aValue, uint8_t *aBuffer) { WriteUint16(aValue, aBuffer); }
template <> inline void Write(uint32_t aValue, uint8_t *aBuffer) { WriteUint32(aValue, aBuffer); }
template <> inline void Write(uint64_t aValue, uint8_t *aBuffer) { WriteUint64(aValue, aBuffer); }

} // namespace BigEndian

namespace LittleEndian {
Expand Down Expand Up @@ -317,6 +350,23 @@ inline uint64_t ReadUint64(const uint8_t *aBuffer)
(static_cast<uint64_t>(aBuffer[6]) << 48) | (static_cast<uint64_t>(aBuffer[7]) << 56));
}

/**
* Reads a `UintType` integer value from a given buffer assuming little-endian encoding.
*
* @tparam UintType The unsigned int type.
*
* @param[in] aBuffer Pointer to the buffer to read from.
*
* @returns The `UintType` value read from the buffer.
*
*/
template <typename UintType> UintType Read(const uint8_t *aBuffer);

template <> inline uint8_t Read(const uint8_t *aBuffer) { return *aBuffer; }
template <> inline uint16_t Read(const uint8_t *aBuffer) { return ReadUint16(aBuffer); }
template <> inline uint32_t Read(const uint8_t *aBuffer) { return ReadUint32(aBuffer); }
template <> inline uint64_t Read(const uint8_t *aBuffer) { return ReadUint64(aBuffer); }

/**
* Writes a `uint16_t` value to a given buffer using little-endian encoding.
*
Expand Down Expand Up @@ -378,6 +428,22 @@ inline void WriteUint64(uint64_t aValue, uint8_t *aBuffer)
aBuffer[7] = (aValue >> 56) & 0xff;
}

/**
* Writes a `UintType` integer value to a given buffer assuming little-endian encoding.
*
* @tparam UintType The unsigned int type.
*
* @param[in] aValue The value to write to buffer.
* @param[in] aBuffer Pointer to the buffer to write to.
*
*/
template <typename UintType> void Write(UintType aValue, uint8_t *aBuffer);

template <> inline void Write(uint8_t aValue, uint8_t *aBuffer) { *aBuffer = aValue; }
template <> inline void Write(uint16_t aValue, uint8_t *aBuffer) { WriteUint16(aValue, aBuffer); }
template <> inline void Write(uint32_t aValue, uint8_t *aBuffer) { WriteUint32(aValue, aBuffer); }
template <> inline void Write(uint64_t aValue, uint8_t *aBuffer) { WriteUint64(aValue, aBuffer); }

} // namespace LittleEndian

} // namespace ot
Expand Down
68 changes: 68 additions & 0 deletions src/core/common/tlvs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,74 @@ class Tlv
*/
Error AppendTo(Message &aMessage) const;

/**
* Reads the value of TLV treating it as a given simple TLV type.
*
* This method requires the TLV to be already validated, in particular, its length MUST NOT be less than the
* required size of the value type. The TLV MUST NOT be extended. If these conditions are not met, the behavior of
* this method is undefined.
*
* @tparam SimpleTlvType The simple TLV type to read (must be a sub-class of `SimpleTlvInfo`).
*
* @returns The TLV value as `SimpleTlvType::ValueType`.
*
*/
template <typename SimpleTlvType> const typename SimpleTlvType::ValueType &ReadValueAs(void) const
{
return *reinterpret_cast<const typename SimpleTlvType::ValueType *>(this + 1);
}

/**
* Reads the value of TLV treating it as a given integer-value TLV type.
*
* This method requires the TLV to be already validated, in particular, its length MUST NOT be less than the
* required size of the value type. The TLV MUST NOT be extended. If these conditions are not met, the behavior of
* this method is undefined.
*
* @tparam UintTlvType The integer simple TLV type to read (must be a sub-class of `UintTlvInfo`).
*
* @returns The TLV value as `UintTlvInfo::UintValueType`.
*
*/
template <typename UintTlvType> typename UintTlvType::UintValueType ReadValueAs(void) const
{
return BigEndian::Read<typename UintTlvType::UintValueType>(reinterpret_cast<const uint8_t *>(this + 1));
}

/**
* Writes the value of TLV treating it as a given simple TLV type.
*
* This method requires the TLV to be already validated, in particular, its length MUST NOT be less than the
* required size of the value type. The TLV MUST NOT be extended. If these conditions are not met, the behavior of
* this method is undefined.
*
* @tparam SimpleTlvType The simple TLV type to read (must be a sub-class of `SimpleTlvInfo`).
*
* @param[in] aValue The new TLV value.
*
*/
template <typename SimpleTlvType> void WriteValueAs(const typename SimpleTlvType::ValueType &aValue)
{
memcpy(this + 1, &aValue, sizeof(aValue));
}

/**
* Writes the value of TLV treating it as a given integer-value TLV type.
*
* This method requires the TLV to be already validated, in particular, its length MUST NOT be less than the
* required size of the value type. The TLV MUST NOT be extended. If these conditions are not met, the behavior of
* this method is undefined.
*
* @tparam UintTlvType The integer simple TLV type to read (must be a sub-class of `UintTlvInfo`).
*
* @param[in] aValue The new TLV value.
*
*/
template <typename UintTlvType> void WriteValueAs(typename UintTlvType::UintValueType aValue)
{
return BigEndian::Write<typename UintTlvType::UintValueType>(aValue, reinterpret_cast<uint8_t *>(this + 1));
}

//------------------------------------------------------------------------------------------------------------------
// Static methods for reading/finding/appending TLVs in a `Message`.

Expand Down
56 changes: 27 additions & 29 deletions src/core/meshcop/dataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ void Dataset::ConvertTo(Info &aDatasetInfo) const
switch (cur->GetType())
{
case Tlv::kActiveTimestamp:
aDatasetInfo.SetActiveTimestamp(As<ActiveTimestampTlv>(cur)->GetTimestamp());
aDatasetInfo.SetActiveTimestamp(cur->ReadValueAs<ActiveTimestampTlv>());
break;

case Tlv::kChannel:
Expand All @@ -210,35 +210,35 @@ void Dataset::ConvertTo(Info &aDatasetInfo) const
}

case Tlv::kDelayTimer:
aDatasetInfo.SetDelay(As<DelayTimerTlv>(cur)->GetDelayTimer());
aDatasetInfo.SetDelay(cur->ReadValueAs<DelayTimerTlv>());
break;

case Tlv::kExtendedPanId:
aDatasetInfo.SetExtendedPanId(As<ExtendedPanIdTlv>(cur)->GetExtendedPanId());
aDatasetInfo.SetExtendedPanId(cur->ReadValueAs<ExtendedPanIdTlv>());
break;

case Tlv::kMeshLocalPrefix:
aDatasetInfo.SetMeshLocalPrefix(As<MeshLocalPrefixTlv>(cur)->GetMeshLocalPrefix());
aDatasetInfo.SetMeshLocalPrefix(cur->ReadValueAs<MeshLocalPrefixTlv>());
break;

case Tlv::kNetworkKey:
aDatasetInfo.SetNetworkKey(As<NetworkKeyTlv>(cur)->GetNetworkKey());
aDatasetInfo.SetNetworkKey(cur->ReadValueAs<NetworkKeyTlv>());
break;

case Tlv::kNetworkName:
aDatasetInfo.SetNetworkName(As<NetworkNameTlv>(cur)->GetNetworkName());
break;

case Tlv::kPanId:
aDatasetInfo.SetPanId(As<PanIdTlv>(cur)->GetPanId());
aDatasetInfo.SetPanId(cur->ReadValueAs<PanIdTlv>());
break;

case Tlv::kPendingTimestamp:
aDatasetInfo.SetPendingTimestamp(As<PendingTimestampTlv>(cur)->GetTimestamp());
aDatasetInfo.SetPendingTimestamp(cur->ReadValueAs<PendingTimestampTlv>());
break;

case Tlv::kPskc:
aDatasetInfo.SetPskc(As<PskcTlv>(cur)->GetPskc());
aDatasetInfo.SetPskc(cur->ReadValueAs<PskcTlv>());
break;

case Tlv::kSecurityPolicy:
Expand Down Expand Up @@ -366,21 +366,20 @@ Error Dataset::SetFrom(const Info &aDatasetInfo)

Error Dataset::GetTimestamp(Type aType, Timestamp &aTimestamp) const
{
Error error = kErrorNone;
Error error = kErrorNone;
const Tlv *tlv;

if (aType == kActive)
{
const ActiveTimestampTlv *tlv = GetTlv<ActiveTimestampTlv>();

tlv = GetTlv(Tlv::kActiveTimestamp);
VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
aTimestamp = tlv->GetTimestamp();
aTimestamp = tlv->ReadValueAs<ActiveTimestampTlv>();
}
else
{
const PendingTimestampTlv *tlv = GetTlv<PendingTimestampTlv>();

tlv = GetTlv(Tlv::kPendingTimestamp);
VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
aTimestamp = tlv->GetTimestamp();
aTimestamp = tlv->ReadValueAs<PendingTimestampTlv>();
}

exit:
Expand Down Expand Up @@ -479,19 +478,19 @@ Error Dataset::AppendMleDatasetTlv(Type aType, Message &aMessage) const
}
else if (cur->GetType() == Tlv::kDelayTimer)
{
uint32_t elapsed = TimerMilli::GetNow() - mUpdateTime;
DelayTimerTlv delayTimer = *As<DelayTimerTlv>(cur);
uint32_t elapsed = TimerMilli::GetNow() - mUpdateTime;
uint32_t delayTimer = cur->ReadValueAs<DelayTimerTlv>();

if (delayTimer.GetDelayTimer() > elapsed)
if (delayTimer > elapsed)
{
delayTimer.SetDelayTimer(delayTimer.GetDelayTimer() - elapsed);
delayTimer -= elapsed;
}
else
{
delayTimer.SetDelayTimer(0);
delayTimer = 0;
}

SuccessOrExit(error = delayTimer.AppendTo(aMessage));
SuccessOrExit(error = Tlv::Append<DelayTimerTlv>(aMessage, delayTimer));
}
else
{
Expand Down Expand Up @@ -545,11 +544,11 @@ Error Dataset::ApplyConfiguration(Instance &aInstance, bool *aIsNetworkKeyUpdate
}

case Tlv::kPanId:
mac.SetPanId(As<PanIdTlv>(cur)->GetPanId());
mac.SetPanId(cur->ReadValueAs<PanIdTlv>());
break;

case Tlv::kExtendedPanId:
aInstance.Get<ExtendedPanIdManager>().SetExtPanId(As<ExtendedPanIdTlv>(cur)->GetExtendedPanId());
aInstance.Get<ExtendedPanIdManager>().SetExtPanId(cur->ReadValueAs<ExtendedPanIdTlv>());
break;

case Tlv::kNetworkName:
Expand All @@ -558,30 +557,29 @@ Error Dataset::ApplyConfiguration(Instance &aInstance, bool *aIsNetworkKeyUpdate

case Tlv::kNetworkKey:
{
const NetworkKeyTlv *key = As<NetworkKeyTlv>(cur);
NetworkKey networkKey;
NetworkKey networkKey;

keyManager.GetNetworkKey(networkKey);

if (aIsNetworkKeyUpdated && (key->GetNetworkKey() != networkKey))
if (aIsNetworkKeyUpdated && (cur->ReadValueAs<NetworkKeyTlv>() != networkKey))
{
*aIsNetworkKeyUpdated = true;
}

keyManager.SetNetworkKey(key->GetNetworkKey());
keyManager.SetNetworkKey(cur->ReadValueAs<NetworkKeyTlv>());
break;
}

#if OPENTHREAD_FTD

case Tlv::kPskc:
keyManager.SetPskc(As<PskcTlv>(cur)->GetPskc());
keyManager.SetPskc(cur->ReadValueAs<PskcTlv>());
break;

#endif

case Tlv::kMeshLocalPrefix:
aInstance.Get<Mle::MleRouter>().SetMeshLocalPrefix(As<MeshLocalPrefixTlv>(cur)->GetMeshLocalPrefix());
aInstance.Get<Mle::MleRouter>().SetMeshLocalPrefix(cur->ReadValueAs<MeshLocalPrefixTlv>());
break;

case Tlv::kSecurityPolicy:
Expand Down
22 changes: 13 additions & 9 deletions src/core/meshcop/dataset_local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ Error DatasetLocal::Restore(Dataset &aDataset)

Error DatasetLocal::Read(Dataset &aDataset) const
{
DelayTimerTlv *delayTimer;
uint32_t elapsed;
Error error;
Error error;

error = Get<Settings>().ReadOperationalDataset(mType, aDataset);
VerifyOrExit(error == kErrorNone, aDataset.mLength = 0);
Expand All @@ -108,19 +106,25 @@ Error DatasetLocal::Read(Dataset &aDataset) const
}
else
{
delayTimer = aDataset.GetTlv<DelayTimerTlv>();
VerifyOrExit(delayTimer);
uint32_t elapsed;
uint32_t delayTimer;
Tlv *tlv = aDataset.GetTlv(Tlv::kDelayTimer);

VerifyOrExit(tlv != nullptr);

elapsed = TimerMilli::GetNow() - mUpdateTime;
elapsed = TimerMilli::GetNow() - mUpdateTime;
delayTimer = tlv->ReadValueAs<DelayTimerTlv>();

if (delayTimer->GetDelayTimer() > elapsed)
if (delayTimer > elapsed)
{
delayTimer->SetDelayTimer(delayTimer->GetDelayTimer() - elapsed);
delayTimer -= elapsed;
}
else
{
delayTimer->SetDelayTimer(0);
delayTimer = 0;
}

tlv->WriteValueAs<DelayTimerTlv>(delayTimer);
}

aDataset.mUpdateTime = TimerMilli::GetNow();
Expand Down
Loading

0 comments on commit 63424e2

Please sign in to comment.