mirror of
https://github.com/espressif/openthread.git
synced 2026-09-13 12:40:05 +00:00
[dataset] add ValidateTlvs(), helper methods, and unit test (#10111)
This commit enhances dataset handling: - Adds `ValidateTlvs()` which parses and validates all known TLVs within the `Dataset` and checks for any duplicates. - Introduces a set of `SetFrom()` methods for constructing a `Dataset` from various types of inputs, e.g., other `Dataset`, TLV sequences, `DatasetInfo` structures, bytes read from `Message`. Now they consistently clear the `Dataset` before setting it. - Adds `WriteTlvsFrom()` to update a `Dataset` replacing/appending a set of TLVs. - Adds `AppendTlvsFrom()` to append an already encoded sequence of TLVs without validating/checking the format. - Renames `Get/SetSize()` to `Get/SetLength()` for consistency. - Adds `test_dataset.cpp` unit test for basic `Dataset` validation.
This commit is contained in:
@@ -589,7 +589,7 @@ otError otNetworkNameFromString(otNetworkName *aNetworkName, const char *aNameSt
|
||||
* @param[out] aDataset A pointer to where the dataset will be placed.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set @p aDataset from @p aDatasetTlvs.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aDatasetTlvs is invalid.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aDatasetTlvs's length is longer than `OT_OPERATIONAL_DATASET_MAX_LENGTH`.
|
||||
*
|
||||
*/
|
||||
otError otDatasetParseTlvs(const otOperationalDatasetTlvs *aDatasetTlvs, otOperationalDataset *aDataset);
|
||||
@@ -600,11 +600,8 @@ otError otDatasetParseTlvs(const otOperationalDatasetTlvs *aDatasetTlvs, otOpera
|
||||
* @param[in] aDataset An Operational dataset to convert to TLVs.
|
||||
* @param[out] aDatasetTlvs A pointer to dataset TLVs to return the result.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully converted @p aDataset and updated @p aDatasetTlvs.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aDataset is invalid, does not contain active or pending timestamps.
|
||||
*
|
||||
*/
|
||||
otError otDatasetConvertToTlvs(const otOperationalDataset *aDataset, otOperationalDatasetTlvs *aDatasetTlvs);
|
||||
void otDatasetConvertToTlvs(const otOperationalDataset *aDataset, otOperationalDatasetTlvs *aDatasetTlvs);
|
||||
|
||||
/**
|
||||
* Updates a given Operational Dataset.
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (410)
|
||||
#define OPENTHREAD_API_VERSION (411)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -612,7 +612,7 @@ template <> otError Dataset::Process<Cmd("init")>(Arg aArgs[])
|
||||
otOperationalDataset dataset;
|
||||
|
||||
SuccessOrExit(error = otDatasetCreateNewNetwork(GetInstancePtr(), &dataset));
|
||||
SuccessOrExit(error = otDatasetConvertToTlvs(&dataset, &sDatasetTlvs));
|
||||
otDatasetConvertToTlvs(&dataset, &sDatasetTlvs);
|
||||
}
|
||||
#endif
|
||||
else if (aArgs[0] == "tlvs")
|
||||
@@ -1105,7 +1105,7 @@ template <> otError Dataset::Process<Cmd("set")>(Arg aArgs[])
|
||||
{
|
||||
otOperationalDataset dataset;
|
||||
otOperationalDatasetTlvs datasetTlvs;
|
||||
uint16_t tlvsLength = MeshCoP::Dataset::kMaxSize;
|
||||
uint16_t tlvsLength = OT_OPERATIONAL_DATASET_MAX_LENGTH;
|
||||
|
||||
SuccessOrExit(error = aArgs[1].ParseAsHexString(tlvsLength, datasetTlvs.mTlvs));
|
||||
datasetTlvs.mLength = static_cast<uint8_t>(tlvsLength);
|
||||
|
||||
@@ -161,26 +161,22 @@ otError otDatasetParseTlvs(const otOperationalDatasetTlvs *aDatasetTlvs, otOpera
|
||||
|
||||
AssertPointerIsNotNull(aDatasetTlvs);
|
||||
|
||||
dataset.SetFrom(*aDatasetTlvs);
|
||||
VerifyOrExit(dataset.IsValid(), error = kErrorInvalidArgs);
|
||||
SuccessOrExit(error = dataset.SetFrom(*aDatasetTlvs));
|
||||
VerifyOrExit(dataset.ValidateTlvs() == kErrorNone, error = kErrorInvalidArgs);
|
||||
dataset.ConvertTo(AsCoreType(aDataset));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otDatasetConvertToTlvs(const otOperationalDataset *aDataset, otOperationalDatasetTlvs *aDatasetTlvs)
|
||||
void otDatasetConvertToTlvs(const otOperationalDataset *aDataset, otOperationalDatasetTlvs *aDatasetTlvs)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
MeshCoP::Dataset dataset;
|
||||
|
||||
AssertPointerIsNotNull(aDatasetTlvs);
|
||||
|
||||
SuccessOrExit(error = dataset.SetFrom(AsCoreType(aDataset)));
|
||||
dataset.SetFrom(AsCoreType(aDataset));
|
||||
dataset.ConvertTo(*aDatasetTlvs);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otDatasetUpdateTlvs(const otOperationalDataset *aDataset, otOperationalDatasetTlvs *aDatasetTlvs)
|
||||
@@ -190,8 +186,8 @@ otError otDatasetUpdateTlvs(const otOperationalDataset *aDataset, otOperationalD
|
||||
|
||||
AssertPointerIsNotNull(aDatasetTlvs);
|
||||
|
||||
dataset.SetFrom(*aDatasetTlvs);
|
||||
SuccessOrExit(error = dataset.SetFrom(AsCoreType(aDataset)));
|
||||
SuccessOrExit(error = dataset.SetFrom(*aDatasetTlvs));
|
||||
SuccessOrExit(error = dataset.WriteTlvsFrom(AsCoreType(aDataset)));
|
||||
dataset.ConvertTo(*aDatasetTlvs);
|
||||
|
||||
exit:
|
||||
|
||||
@@ -224,7 +224,7 @@ Settings::Key Settings::KeyForDatasetType(MeshCoP::Dataset::Type aType)
|
||||
Error Settings::SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshCoP::Dataset &aDataset)
|
||||
{
|
||||
Key key = KeyForDatasetType(aType);
|
||||
Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetSize());
|
||||
Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetLength());
|
||||
|
||||
Log(kActionSave, error, key);
|
||||
|
||||
@@ -234,12 +234,12 @@ Error Settings::SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshC
|
||||
Error Settings::ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Dataset &aDataset) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
uint16_t length = MeshCoP::Dataset::kMaxSize;
|
||||
uint16_t length = MeshCoP::Dataset::kMaxLength;
|
||||
|
||||
SuccessOrExit(error = Get<SettingsDriver>().Get(KeyForDatasetType(aType), aDataset.GetBytes(), &length));
|
||||
VerifyOrExit(length <= MeshCoP::Dataset::kMaxSize, error = kErrorNotFound);
|
||||
VerifyOrExit(length <= MeshCoP::Dataset::kMaxLength, error = kErrorNotFound);
|
||||
|
||||
aDataset.SetSize(length);
|
||||
aDataset.SetLength(static_cast<uint8_t>(length));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
|
||||
+168
-110
@@ -157,26 +157,34 @@ exit:
|
||||
}
|
||||
|
||||
Dataset::Dataset(void)
|
||||
: mUpdateTime(0)
|
||||
, mLength(0)
|
||||
: mLength(0)
|
||||
, mUpdateTime(0)
|
||||
{
|
||||
ClearAllBytes(mTlvs);
|
||||
}
|
||||
|
||||
void Dataset::Clear(void) { mLength = 0; }
|
||||
|
||||
bool Dataset::IsValid(void) const
|
||||
Error Dataset::ValidateTlvs(void) const
|
||||
{
|
||||
bool rval = true;
|
||||
const Tlv *end = GetTlvsEnd();
|
||||
Error error = kErrorParse;
|
||||
const Tlv *end = GetTlvsEnd();
|
||||
uint16_t validatedLength;
|
||||
|
||||
for (const Tlv *cur = GetTlvsStart(); cur < end; cur = cur->GetNext())
|
||||
VerifyOrExit(mLength <= kMaxLength);
|
||||
|
||||
for (const Tlv *tlv = GetTlvsStart(); tlv < end; tlv = tlv->GetNext())
|
||||
{
|
||||
VerifyOrExit(!cur->IsExtended() && (cur + 1) <= end && cur->GetNext() <= end && IsTlvValid(*cur), rval = false);
|
||||
VerifyOrExit(!tlv->IsExtended() && ((tlv + 1) <= end) && (tlv->GetNext() <= end));
|
||||
VerifyOrExit(IsTlvValid(*tlv));
|
||||
|
||||
// Ensure there are no duplicate TLVs.
|
||||
validatedLength = static_cast<uint16_t>(reinterpret_cast<const uint8_t *>(tlv) - mTlvs);
|
||||
VerifyOrExit(Tlv::FindTlv(mTlvs, validatedLength, tlv->GetType()) == nullptr);
|
||||
}
|
||||
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return rval;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Dataset::IsTlvValid(const Tlv &aTlv)
|
||||
@@ -308,110 +316,50 @@ void Dataset::ConvertTo(Tlvs &aTlvs) const
|
||||
aTlvs.mLength = static_cast<uint8_t>(mLength);
|
||||
}
|
||||
|
||||
void Dataset::Set(Type aType, const Dataset &aDataset)
|
||||
void Dataset::SetFrom(const Dataset &aDataset)
|
||||
{
|
||||
memcpy(mTlvs, aDataset.mTlvs, aDataset.mLength);
|
||||
mLength = aDataset.mLength;
|
||||
|
||||
if (aType == kActive)
|
||||
{
|
||||
RemoveTlv(Tlv::kPendingTimestamp);
|
||||
RemoveTlv(Tlv::kDelayTimer);
|
||||
}
|
||||
|
||||
mLength = aDataset.mLength;
|
||||
mUpdateTime = aDataset.GetUpdateTime();
|
||||
}
|
||||
|
||||
void Dataset::SetFrom(const Tlvs &aTlvs)
|
||||
{
|
||||
mLength = aTlvs.mLength;
|
||||
memcpy(mTlvs, aTlvs.mTlvs, mLength);
|
||||
}
|
||||
Error Dataset::SetFrom(const Tlvs &aTlvs) { return SetFrom(aTlvs.mTlvs, aTlvs.mLength); }
|
||||
|
||||
Error Dataset::SetFrom(const Info &aDatasetInfo)
|
||||
Error Dataset::SetFrom(const uint8_t *aTlvs, uint8_t aLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
if (aDatasetInfo.IsPresent<kActiveTimestamp>())
|
||||
{
|
||||
Timestamp activeTimestamp;
|
||||
VerifyOrExit(aLength <= kMaxLength, error = kErrorInvalidArgs);
|
||||
|
||||
aDatasetInfo.Get<kActiveTimestamp>(activeTimestamp);
|
||||
IgnoreError(Write<ActiveTimestampTlv>(activeTimestamp));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kPendingTimestamp>())
|
||||
{
|
||||
Timestamp pendingTimestamp;
|
||||
|
||||
aDatasetInfo.Get<kPendingTimestamp>(pendingTimestamp);
|
||||
IgnoreError(Write<PendingTimestampTlv>(pendingTimestamp));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kDelay>())
|
||||
{
|
||||
IgnoreError(Write<DelayTimerTlv>(aDatasetInfo.Get<kDelay>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kChannel>())
|
||||
{
|
||||
ChannelTlvValue channelValue;
|
||||
|
||||
channelValue.SetChannelAndPage(aDatasetInfo.Get<kChannel>());
|
||||
IgnoreError(Write<ChannelTlv>(channelValue));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kChannelMask>())
|
||||
{
|
||||
ChannelMaskTlv::Value value;
|
||||
|
||||
ChannelMaskTlv::PrepareValue(value, aDatasetInfo.Get<kChannelMask>());
|
||||
IgnoreError(WriteTlv(Tlv::kChannelMask, value.mData, value.mLength));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kExtendedPanId>())
|
||||
{
|
||||
IgnoreError(Write<ExtendedPanIdTlv>(aDatasetInfo.Get<kExtendedPanId>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kMeshLocalPrefix>())
|
||||
{
|
||||
IgnoreError(Write<MeshLocalPrefixTlv>(aDatasetInfo.Get<kMeshLocalPrefix>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kNetworkKey>())
|
||||
{
|
||||
IgnoreError(Write<NetworkKeyTlv>(aDatasetInfo.Get<kNetworkKey>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kNetworkName>())
|
||||
{
|
||||
NameData nameData = aDatasetInfo.Get<kNetworkName>().GetAsData();
|
||||
|
||||
IgnoreError(WriteTlv(Tlv::kNetworkName, nameData.GetBuffer(), nameData.GetLength()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kPanId>())
|
||||
{
|
||||
IgnoreError(Write<PanIdTlv>(aDatasetInfo.Get<kPanId>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kPskc>())
|
||||
{
|
||||
IgnoreError(Write<PskcTlv>(aDatasetInfo.Get<kPskc>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kSecurityPolicy>())
|
||||
{
|
||||
SecurityPolicyTlv tlv;
|
||||
|
||||
tlv.Init();
|
||||
tlv.SetSecurityPolicy(aDatasetInfo.Get<kSecurityPolicy>());
|
||||
IgnoreError(WriteTlv(tlv));
|
||||
}
|
||||
mLength = aLength;
|
||||
memcpy(mTlvs, aTlvs, mLength);
|
||||
|
||||
mUpdateTime = TimerMilli::GetNow();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Dataset::SetFrom(const Info &aDatasetInfo)
|
||||
{
|
||||
Clear();
|
||||
IgnoreError(WriteTlvsFrom(aDatasetInfo));
|
||||
|
||||
// `mUpdateTime` is already set by `WriteTlvsFrom()`.
|
||||
}
|
||||
|
||||
Error Dataset::SetFrom(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(aLength <= kMaxLength, error = kErrorInvalidArgs);
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(aOffset, mTlvs, aLength));
|
||||
mLength = static_cast<uint8_t>(aLength);
|
||||
|
||||
mUpdateTime = TimerMilli::GetNow();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -451,19 +399,129 @@ exit:
|
||||
|
||||
Error Dataset::WriteTlv(const Tlv &aTlv) { return WriteTlv(aTlv.GetType(), aTlv.GetValue(), aTlv.GetLength()); }
|
||||
|
||||
Error Dataset::ReadFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
|
||||
Error Dataset::WriteTlvsFrom(const Dataset &aDataset)
|
||||
{
|
||||
Error error = kErrorParse;
|
||||
Error error;
|
||||
|
||||
VerifyOrExit(aLength <= kMaxSize);
|
||||
SuccessOrExit(error = aDataset.ValidateTlvs());
|
||||
|
||||
SuccessOrExit(aMessage.Read(aOffset, mTlvs, aLength));
|
||||
mLength = aLength;
|
||||
for (const Tlv *tlv = aDataset.GetTlvsStart(); tlv < aDataset.GetTlvsEnd(); tlv = tlv->GetNext())
|
||||
{
|
||||
SuccessOrExit(error = WriteTlv(*tlv));
|
||||
}
|
||||
|
||||
VerifyOrExit(IsValid(), error = kErrorParse);
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
mUpdateTime = TimerMilli::GetNow();
|
||||
error = kErrorNone;
|
||||
Error Dataset::WriteTlvsFrom(const uint8_t *aTlvs, uint8_t aLength)
|
||||
{
|
||||
Error error;
|
||||
Dataset dataset;
|
||||
|
||||
SuccessOrExit(error = dataset.SetFrom(aTlvs, aLength));
|
||||
error = WriteTlvsFrom(dataset);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Dataset::WriteTlvsFrom(const Dataset::Info &aDatasetInfo)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
if (aDatasetInfo.IsPresent<kActiveTimestamp>())
|
||||
{
|
||||
Timestamp activeTimestamp;
|
||||
|
||||
aDatasetInfo.Get<kActiveTimestamp>(activeTimestamp);
|
||||
SuccessOrExit(error = Write<ActiveTimestampTlv>(activeTimestamp));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kPendingTimestamp>())
|
||||
{
|
||||
Timestamp pendingTimestamp;
|
||||
|
||||
aDatasetInfo.Get<kPendingTimestamp>(pendingTimestamp);
|
||||
SuccessOrExit(error = Write<PendingTimestampTlv>(pendingTimestamp));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kDelay>())
|
||||
{
|
||||
SuccessOrExit(error = Write<DelayTimerTlv>(aDatasetInfo.Get<kDelay>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kChannel>())
|
||||
{
|
||||
ChannelTlvValue channelValue;
|
||||
|
||||
channelValue.SetChannelAndPage(aDatasetInfo.Get<kChannel>());
|
||||
SuccessOrExit(error = Write<ChannelTlv>(channelValue));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kChannelMask>())
|
||||
{
|
||||
ChannelMaskTlv::Value value;
|
||||
|
||||
ChannelMaskTlv::PrepareValue(value, aDatasetInfo.Get<kChannelMask>());
|
||||
SuccessOrExit(error = WriteTlv(Tlv::kChannelMask, value.mData, value.mLength));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kExtendedPanId>())
|
||||
{
|
||||
SuccessOrExit(error = Write<ExtendedPanIdTlv>(aDatasetInfo.Get<kExtendedPanId>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kMeshLocalPrefix>())
|
||||
{
|
||||
SuccessOrExit(error = Write<MeshLocalPrefixTlv>(aDatasetInfo.Get<kMeshLocalPrefix>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kNetworkKey>())
|
||||
{
|
||||
SuccessOrExit(error = Write<NetworkKeyTlv>(aDatasetInfo.Get<kNetworkKey>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kNetworkName>())
|
||||
{
|
||||
NameData nameData = aDatasetInfo.Get<kNetworkName>().GetAsData();
|
||||
|
||||
SuccessOrExit(error = WriteTlv(Tlv::kNetworkName, nameData.GetBuffer(), nameData.GetLength()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kPanId>())
|
||||
{
|
||||
SuccessOrExit(error = Write<PanIdTlv>(aDatasetInfo.Get<kPanId>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kPskc>())
|
||||
{
|
||||
SuccessOrExit(error = Write<PskcTlv>(aDatasetInfo.Get<kPskc>()));
|
||||
}
|
||||
|
||||
if (aDatasetInfo.IsPresent<kSecurityPolicy>())
|
||||
{
|
||||
SecurityPolicyTlv tlv;
|
||||
|
||||
tlv.Init();
|
||||
tlv.SetSecurityPolicy(aDatasetInfo.Get<kSecurityPolicy>());
|
||||
SuccessOrExit(error = WriteTlv(tlv));
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Dataset::AppendTlvsFrom(const uint8_t *aTlvs, uint8_t aLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
uint16_t newLength = mLength;
|
||||
|
||||
newLength += aLength;
|
||||
VerifyOrExit(newLength <= kMaxLength, error = kErrorNoBufs);
|
||||
|
||||
memcpy(mTlvs + mLength, aTlvs, aLength);
|
||||
mLength += aLength;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -496,7 +554,7 @@ Error Dataset::ApplyConfiguration(Instance &aInstance, bool &aIsNetworkKeyUpdate
|
||||
KeyManager &keyManager = aInstance.Get<KeyManager>();
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(IsValid(), error = kErrorParse);
|
||||
SuccessOrExit(error = ValidateTlvs());
|
||||
|
||||
aIsNetworkKeyUpdated = false;
|
||||
|
||||
|
||||
+114
-39
@@ -61,7 +61,7 @@ class Dataset
|
||||
friend class DatasetLocal;
|
||||
|
||||
public:
|
||||
static constexpr uint8_t kMaxSize = OT_OPERATIONAL_DATASET_MAX_LENGTH; ///< Max size of MeshCoP Dataset (bytes)
|
||||
static constexpr uint8_t kMaxLength = OT_OPERATIONAL_DATASET_MAX_LENGTH; ///< Max length of Dataset (bytes)
|
||||
static constexpr uint8_t kMaxValueSize = 16; ///< Max size of a TLV value (bytes)
|
||||
|
||||
/**
|
||||
@@ -242,15 +242,21 @@ public:
|
||||
* Clears the Dataset.
|
||||
*
|
||||
*/
|
||||
void Clear(void);
|
||||
void Clear(void) { mLength = 0; }
|
||||
|
||||
/**
|
||||
* Indicates whether or not the dataset appears to be well-formed.
|
||||
* Parses and validates all TLVs contained within the Dataset.
|
||||
*
|
||||
* @returns TRUE if the dataset appears to be well-formed, FALSE otherwise.
|
||||
* Performs the following checks all TLVs in the Dataset:
|
||||
* - Ensures correct TLV format and expected minimum length for known TLV types that may appear in a Dataset.
|
||||
* - Validates TLV value when applicable (e.g., Channel TLV using a supported channel).
|
||||
* - Ensures no duplicate occurrence of same TLV type.
|
||||
*
|
||||
* @retval kErrorNone Successfully validated all the TLVs in the Dataset.
|
||||
* @retval kErrorParse Dataset TLVs is not well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const;
|
||||
Error ValidateTlvs(void) const;
|
||||
|
||||
/**
|
||||
* Validates the format and value of a given MeshCoP TLV used in Dataset.
|
||||
@@ -429,6 +435,66 @@ public:
|
||||
return WriteTlv(static_cast<Tlv::Type>(UintTlvType::kType), &value, sizeof(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes TLVs parsed from a given Dataset into this Dataset.
|
||||
*
|
||||
* TLVs from @p aDataset are parsed and written in the current Dataset. If the same TLV already exists, it will be
|
||||
* replaced. Otherwise, the TLV will be appended.
|
||||
*
|
||||
* @param[in] aDataset A Dataset.
|
||||
*
|
||||
* @retval kErrorNone Successfully merged TLVs from @p Dataset into this Dataset.
|
||||
* @retval kErrorParse The @p aDataset is not valid.
|
||||
* @retval kErrorNoBufs Could not add the TLVs due to insufficient buffer space.
|
||||
*
|
||||
*/
|
||||
Error WriteTlvsFrom(const Dataset &aDataset);
|
||||
|
||||
/**
|
||||
* Writes TLVs parsed from a given buffer containing a sequence of TLVs into this Dataset.
|
||||
*
|
||||
* TLVs from @p aTlvs buffer are parsed and written in the current Dataset. If the same TLV already exists, it will
|
||||
* be replaced. Otherwise, the TLV will be appended.
|
||||
*
|
||||
* @param[in] aTlvs A pointer to a buffer containing TLVs.
|
||||
* @param[in] aLength Number of bytes in @p aTlvs buffer.
|
||||
*
|
||||
* @retval kErrorNone Successfully merged TLVs from @p Dataset into this Dataset.
|
||||
* @retval kErrorParse The @p aTlvs is not valid.
|
||||
* @retval kErrorNoBufs Could not add the TLVs due to insufficient buffer space.
|
||||
*
|
||||
*/
|
||||
Error WriteTlvsFrom(const uint8_t *aTlvs, uint8_t aLength);
|
||||
|
||||
/**
|
||||
* Writes TLVs corresponding to the components in a given `Dataset::Info` into this Dataset.
|
||||
*
|
||||
* If the same TLV already exists, it will be replaced. Otherwise the TLV will be appended.
|
||||
*
|
||||
* @param[in] aDataseInfo A `Dataset::Info`.
|
||||
*
|
||||
* @retval kErrorNone Successfully merged TLVs from @p aDataseInfo into this Dataset.
|
||||
* @retval kErrorNoBufs Could not add the TLVs due to insufficient buffer space.
|
||||
*
|
||||
*/
|
||||
Error WriteTlvsFrom(const Dataset::Info &aDatasetInfo);
|
||||
|
||||
/**
|
||||
* Appends a given sequence of TLVs to the Dataset.
|
||||
*
|
||||
* @note Unlike `WriteTlvsFrom()`, this method does not validate the @p aTlvs to be well-formed or check that there
|
||||
* are no duplicates. It is up to caller to validate the resulting `Dataset` (e.g., using `ValidateTlvs()`) if
|
||||
* desired.
|
||||
*
|
||||
* @param[in] aTlvs A pointer to a buffer containing TLVs.
|
||||
* @param[in] aLength Number of bytes in @p aTlvs buffer.
|
||||
*
|
||||
* @retval kErrorNone Successfully merged TLVs from @p Dataset into this Dataset.
|
||||
* @retval kErrorNoBufs Could not append the TLVs due to insufficient buffer space.
|
||||
*
|
||||
*/
|
||||
Error AppendTlvsFrom(const uint8_t *aTlvs, uint8_t aLength);
|
||||
|
||||
/**
|
||||
* Removes a TLV from the Dataset.
|
||||
*
|
||||
@@ -472,12 +538,12 @@ public:
|
||||
void ConvertTo(Tlvs &aTlvs) const;
|
||||
|
||||
/**
|
||||
* Returns the Dataset size in bytes.
|
||||
* Returns the Dataset length in bytes.
|
||||
*
|
||||
* @returns The Dataset size in bytes.
|
||||
* @returns The Dataset length in bytes.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSize(void) const { return mLength; }
|
||||
uint8_t GetLength(void) const { return mLength; }
|
||||
|
||||
/**
|
||||
* Sets the Dataset size in bytes.
|
||||
@@ -485,7 +551,7 @@ public:
|
||||
* @param[in] aSize The Dataset size in bytes.
|
||||
*
|
||||
*/
|
||||
void SetSize(uint16_t aSize) { mLength = aSize; }
|
||||
void SetLength(uint8_t aLength) { mLength = aLength; }
|
||||
|
||||
/**
|
||||
* Returns the local time the dataset was last updated.
|
||||
@@ -496,48 +562,57 @@ public:
|
||||
TimeMilli GetUpdateTime(void) const { return mUpdateTime; }
|
||||
|
||||
/**
|
||||
* Reads the Dataset from a given message and checks that it is well-formed and valid.
|
||||
* Sets this Dataset using an existing Dataset.
|
||||
*
|
||||
* @param[in] aMessage The message to read from.
|
||||
* @param[in] aOffset The offset in @p aMessage to start reading the Dataset TLVs.
|
||||
* @param[in] aLength The dataset length in bytes.
|
||||
*
|
||||
* @retval kErrorNone Successfully read and validated the Dataset.
|
||||
* @retval kErrorParse Could not read or parse the dataset from @p aMessage.
|
||||
*
|
||||
*/
|
||||
Error ReadFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* Sets the Dataset using an existing Dataset.
|
||||
*
|
||||
* If this Dataset is an Active Dataset, any Pending Timestamp and Delay Timer TLVs will be omitted in the copy
|
||||
* from @p aDataset.
|
||||
*
|
||||
* @param[in] aType The type of the dataset, active or pending.
|
||||
* @param[in] aDataset The input Dataset.
|
||||
*
|
||||
*/
|
||||
void Set(Type aType, const Dataset &aDataset);
|
||||
void SetFrom(const Dataset &aDataset);
|
||||
|
||||
/**
|
||||
* Sets the Dataset from a given structure representation.
|
||||
*
|
||||
* @param[in] aDatasetInfo The input Dataset as `Dataset::Info`.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the Dataset.
|
||||
* @retval kErrorInvalidArgs Dataset is missing Active and/or Pending Timestamp.
|
||||
*
|
||||
*/
|
||||
Error SetFrom(const Info &aDatasetInfo);
|
||||
void SetFrom(const Info &aDatasetInfo);
|
||||
|
||||
/**
|
||||
* Sets the Dataset using @p aDataset.
|
||||
* Sets the Dataset from a given sequence of TLVs.
|
||||
*
|
||||
* @param[in] aDataset The input Dataset as `Tlvs`.
|
||||
* @param[in] aTlvs The input Dataset as `Tlvs`.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the Dataset.
|
||||
* @retval kErrorInvalidArgs The @p aTlvs is invalid and its length is longer than `kMaxLength`.
|
||||
*
|
||||
*/
|
||||
void SetFrom(const Tlvs &aTlvs);
|
||||
Error SetFrom(const Tlvs &aTlvs);
|
||||
|
||||
/**
|
||||
* Sets the Dataset from a buffer containing a sequence of TLVs.
|
||||
*
|
||||
* @param[in] aTlvs A pointer to a buffer containing TLVs.
|
||||
* @param[in] aLength Number of bytes in @p aTlvs buffer.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the Dataset.
|
||||
* @retval kErrorInvalidArgs @p aLength is longer than `kMaxLength`.
|
||||
*
|
||||
*/
|
||||
Error SetFrom(const uint8_t *aTlvs, uint8_t aLength);
|
||||
|
||||
/**
|
||||
* Sets the Dataset by reading the TLVs bytes from given message.
|
||||
*
|
||||
* @param[in] aMessage The message to read from.
|
||||
* @param[in] aOffset The offset in @p aMessage to start reading the Dataset TLVs.
|
||||
* @param[in] aLength The dataset length in bytes.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the Dataset.
|
||||
* @retval kInvalidArgs The @p aLength is longer than `kMaxLength`.
|
||||
* @retval kErrorParse Could not read or parse the dataset from @p aMessage.
|
||||
*
|
||||
*/
|
||||
Error SetFrom(const Message &aMessage, uint16_t aOffset, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* Applies the Active or Pending Dataset to the Thread interface.
|
||||
@@ -565,7 +640,7 @@ public:
|
||||
/**
|
||||
* Converts a Pending Dataset to an Active Dataset.
|
||||
*
|
||||
* Removes the Delay Timer and Pending Timestamp TLVs
|
||||
* Removes the Delay Timer and Pending Timestamp TLVs.
|
||||
*
|
||||
*/
|
||||
void ConvertToActive(void);
|
||||
@@ -646,9 +721,9 @@ public:
|
||||
private:
|
||||
void RemoveTlv(Tlv *aTlv);
|
||||
|
||||
uint8_t mTlvs[kMaxSize]; ///< The Dataset buffer
|
||||
TimeMilli mUpdateTime; ///< Local time last updated
|
||||
uint16_t mLength; ///< The number of valid bytes in @var mTlvs
|
||||
uint8_t mTlvs[kMaxLength];
|
||||
uint8_t mLength;
|
||||
TimeMilli mUpdateTime; // Local time last updated
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -151,7 +151,7 @@ Error DatasetLocal::Save(const Dataset::Info &aDatasetInfo)
|
||||
Error error;
|
||||
Dataset dataset;
|
||||
|
||||
SuccessOrExit(error = dataset.SetFrom(aDatasetInfo));
|
||||
dataset.SetFrom(aDatasetInfo);
|
||||
SuccessOrExit(error = Save(dataset));
|
||||
|
||||
exit:
|
||||
@@ -160,11 +160,14 @@ exit:
|
||||
|
||||
Error DatasetLocal::Save(const Dataset::Tlvs &aDatasetTlvs)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Dataset dataset;
|
||||
|
||||
dataset.SetFrom(aDatasetTlvs);
|
||||
SuccessOrExit(error = dataset.SetFrom(aDatasetTlvs));
|
||||
error = Save(dataset);
|
||||
|
||||
return Save(dataset);
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error DatasetLocal::Save(const Dataset &aDataset)
|
||||
@@ -175,7 +178,7 @@ Error DatasetLocal::Save(const Dataset &aDataset)
|
||||
DestroySecurelyStoredKeys();
|
||||
#endif
|
||||
|
||||
if (aDataset.GetSize() == 0)
|
||||
if (aDataset.GetLength() == 0)
|
||||
{
|
||||
// do not propagate error back
|
||||
IgnoreError(Get<Settings>().DeleteOperationalDataset(mType));
|
||||
@@ -188,7 +191,7 @@ Error DatasetLocal::Save(const Dataset &aDataset)
|
||||
// Store the network key and PSKC in the secure storage instead of settings.
|
||||
Dataset dataset;
|
||||
|
||||
dataset.Set(GetType(), aDataset);
|
||||
dataset.SetFrom(aDataset);
|
||||
MoveKeysToSecureStorage(dataset);
|
||||
SuccessOrExit(error = Get<Settings>().SaveOperationalDataset(mType, dataset));
|
||||
#else
|
||||
@@ -258,7 +261,7 @@ void DatasetLocal::EmplaceSecurelyStoredKeys(Dataset &aDataset) const
|
||||
{
|
||||
Dataset dataset;
|
||||
|
||||
dataset.Set(GetType(), aDataset);
|
||||
dataset.SetFrom(aDataset);
|
||||
MoveKeysToSecureStorage(dataset);
|
||||
SuccessOrAssert(Get<Settings>().SaveOperationalDataset(mType, dataset));
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@ public:
|
||||
* @param[in] aDatasetTlvs The Dataset to save as `Dataset::Tlvs`.
|
||||
*
|
||||
* @retval kErrorNone Successfully saved the dataset.
|
||||
* @retval kErrorInvalidArgs The dataset TLVs is invalid, its length is longer than `Dataset::kMaxLength`.
|
||||
* @retval kErrorNotImplemented The platform does not implement settings functionality.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -273,7 +273,7 @@ void DatasetManager::SendSet(void)
|
||||
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
|
||||
|
||||
IgnoreError(Read(dataset));
|
||||
SuccessOrExit(error = message->AppendBytes(dataset.GetBytes(), dataset.GetSize()));
|
||||
SuccessOrExit(error = message->AppendBytes(dataset.GetBytes(), dataset.GetLength()));
|
||||
|
||||
IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
|
||||
SuccessOrExit(
|
||||
@@ -410,14 +410,10 @@ exit:
|
||||
|
||||
Error DatasetManager::AppendDatasetToMessage(const Dataset::Info &aDatasetInfo, Message &aMessage) const
|
||||
{
|
||||
Error error;
|
||||
Dataset dataset;
|
||||
|
||||
SuccessOrExit(error = dataset.SetFrom(aDatasetInfo));
|
||||
error = aMessage.AppendBytes(dataset.GetBytes(), dataset.GetSize());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
dataset.SetFrom(aDatasetInfo);
|
||||
return aMessage.AppendBytes(dataset.GetBytes(), dataset.GetLength());
|
||||
}
|
||||
|
||||
Error DatasetManager::SendSetRequest(const Dataset::Info &aDatasetInfo,
|
||||
@@ -605,7 +601,8 @@ Error ActiveDatasetManager::Save(const Timestamp &aTimestamp,
|
||||
Error error = kErrorNone;
|
||||
Dataset dataset;
|
||||
|
||||
SuccessOrExit(error = dataset.ReadFromMessage(aMessage, aOffset, aLength));
|
||||
SuccessOrExit(error = dataset.SetFrom(aMessage, aOffset, aLength));
|
||||
SuccessOrExit(error = dataset.ValidateTlvs());
|
||||
SuccessOrExit(error = dataset.Write<ActiveTimestampTlv>(aTimestamp));
|
||||
error = DatasetManager::Save(dataset);
|
||||
|
||||
@@ -686,7 +683,8 @@ Error PendingDatasetManager::Save(const Timestamp &aTimestamp,
|
||||
Error error = kErrorNone;
|
||||
Dataset dataset;
|
||||
|
||||
SuccessOrExit(error = dataset.ReadFromMessage(aMessage, aOffset, aLength));
|
||||
SuccessOrExit(error = dataset.SetFrom(aMessage, aOffset, aLength));
|
||||
SuccessOrExit(error = dataset.ValidateTlvs());
|
||||
SuccessOrExit(dataset.Write<PendingTimestampTlv>(aTimestamp));
|
||||
SuccessOrExit(error = DatasetManager::Save(dataset));
|
||||
StartDelayTimer();
|
||||
|
||||
@@ -75,7 +75,7 @@ Error DatasetManager::AppendMleDatasetTlv(Message &aMessage) const
|
||||
|
||||
dataset.RemoveTlv(IsActiveDataset() ? Tlv::kActiveTimestamp : Tlv::kPendingTimestamp);
|
||||
|
||||
return Tlv::AppendTlv(aMessage, mleTlvType, dataset.GetBytes(), static_cast<uint8_t>(dataset.GetSize()));
|
||||
return Tlv::AppendTlv(aMessage, mleTlvType, dataset.GetBytes(), dataset.GetLength());
|
||||
}
|
||||
|
||||
Error DatasetManager::HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
@@ -104,7 +104,7 @@ Error DatasetManager::HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo
|
||||
}
|
||||
|
||||
// verify that does not overflow dataset buffer
|
||||
VerifyOrExit((offset - aMessage.GetOffset()) <= Dataset::kMaxSize);
|
||||
VerifyOrExit((offset - aMessage.GetOffset()) <= Dataset::kMaxLength);
|
||||
|
||||
// verify the request includes a timestamp that is ahead of the locally stored value
|
||||
SuccessOrExit(Tlv::Find<ActiveTimestampTlv>(aMessage, activeTimestamp));
|
||||
|
||||
@@ -117,7 +117,7 @@ void DatasetUpdater::PreparePendingDataset(void)
|
||||
ExitNow(error = kErrorNone);
|
||||
}
|
||||
|
||||
IgnoreError(dataset.SetFrom(requestedDataset));
|
||||
SuccessOrExit(dataset.WriteTlvsFrom(requestedDataset));
|
||||
|
||||
if (!requestedDataset.IsPresent<Dataset::kDelay>())
|
||||
{
|
||||
|
||||
@@ -465,7 +465,8 @@ Error TcatAgent::HandleSetActiveOperationalDataset(const Message &aIncommingMess
|
||||
Dataset::Tlvs datasetTlvs;
|
||||
Error error;
|
||||
|
||||
SuccessOrExit(error = dataset.ReadFromMessage(aIncommingMessage, aOffset, aLength));
|
||||
SuccessOrExit(error = dataset.SetFrom(aIncommingMessage, aOffset, aLength));
|
||||
SuccessOrExit(error = dataset.ValidateTlvs());
|
||||
|
||||
if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mApplicationFlags,
|
||||
mDeviceAuthorizationField.mApplicationFlags, &dataset))
|
||||
|
||||
@@ -173,6 +173,7 @@ ot_unit_test(child)
|
||||
ot_unit_test(child_table)
|
||||
ot_unit_test(cmd_line_parser)
|
||||
ot_unit_test(data)
|
||||
ot_unit_test(dataset)
|
||||
ot_unit_test(dns)
|
||||
ot_unit_test(dns_client)
|
||||
ot_unit_test(dso)
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 2024, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <openthread/config.h>
|
||||
|
||||
#include "test_platform.h"
|
||||
#include "test_util.hpp"
|
||||
|
||||
#include "meshcop/dataset.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace MeshCoP {
|
||||
|
||||
void TestDataset(void)
|
||||
{
|
||||
static const uint8_t kTlvBytes[] = {
|
||||
0x0e, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x35, 0x06, 0x00,
|
||||
0x04, 0x00, 0x1f, 0xff, 0xe0, 0x02, 0x08, 0x1d, 0xe5, 0xbf, 0xec, 0xd5, 0x16, 0x5b, 0x8f, 0x07, 0x08, 0xfd,
|
||||
0xe2, 0x1f, 0x0c, 0x8a, 0x13, 0xe8, 0xe7, 0x05, 0x10, 0xea, 0xf9, 0x14, 0x9f, 0xdc, 0x73, 0x78, 0x77, 0x06,
|
||||
0x98, 0xd5, 0x91, 0x80, 0x22, 0x19, 0x58, 0x03, 0x0f, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x68, 0x72, 0x65, 0x61,
|
||||
0x64, 0x2d, 0x61, 0x61, 0x63, 0x33, 0x01, 0x02, 0xfa, 0xce, 0x04, 0x10, 0x2e, 0xaa, 0xe2, 0x94, 0x84, 0x38,
|
||||
0x8e, 0x31, 0x19, 0x58, 0x1a, 0x7b, 0x5a, 0x94, 0x8c, 0x07, 0x0c, 0x04, 0x02, 0xa0, 0xf7, 0xf8,
|
||||
};
|
||||
|
||||
static const otNetworkKey kNetworkKey = {
|
||||
{0xea, 0xf9, 0x14, 0x9f, 0xdc, 0x73, 0x78, 0x77, 0x06, 0x98, 0xd5, 0x91, 0x80, 0x22, 0x19, 0x58}};
|
||||
|
||||
static const otNetworkKey kNewNetworkKey = {
|
||||
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}};
|
||||
|
||||
static const uint8_t kDuplicateChannels[] = {
|
||||
0x00, 0x03, 0x00, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x00, 0x1a,
|
||||
};
|
||||
|
||||
static const Tlv::Type kDatasetTlvTypes[] = {
|
||||
Tlv::kChannel, Tlv::kPanId, Tlv::kExtendedPanId, Tlv::kNetworkName, Tlv::kPskc,
|
||||
Tlv::kNetworkKey, Tlv::kMeshLocalPrefix, Tlv::kSecurityPolicy, Tlv::kActiveTimestamp,
|
||||
};
|
||||
|
||||
Dataset dataset;
|
||||
Dataset dataset2;
|
||||
Dataset::Tlvs datasetTlvs;
|
||||
Dataset::Info datasetInfo;
|
||||
uint16_t panId;
|
||||
NetworkKey networkKey;
|
||||
|
||||
SuccessOrQuit(dataset.SetFrom(kTlvBytes, sizeof(kTlvBytes)));
|
||||
|
||||
VerifyOrQuit(dataset.GetLength() == sizeof(kTlvBytes));
|
||||
|
||||
SuccessOrQuit(dataset.ValidateTlvs());
|
||||
|
||||
for (Tlv::Type tlvType : kDatasetTlvTypes)
|
||||
{
|
||||
VerifyOrQuit(dataset.ContainsTlv(tlvType));
|
||||
}
|
||||
|
||||
// Converting to `Dataset::Tlvs`
|
||||
|
||||
dataset.ConvertTo(datasetTlvs);
|
||||
VerifyOrQuit(datasetTlvs.mLength == sizeof(kTlvBytes));
|
||||
VerifyOrQuit(memcmp(datasetTlvs.mTlvs, kTlvBytes, sizeof(kTlvBytes)) == 0);
|
||||
|
||||
// Converting to `Dataset::Info`
|
||||
|
||||
dataset.ConvertTo(datasetInfo);
|
||||
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsActiveTimestampPresent);
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsNetworkKeyPresent);
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsNetworkNamePresent);
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsExtendedPanIdPresent);
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsMeshLocalPrefixPresent);
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsPanIdPresent);
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsChannelPresent);
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsPskcPresent);
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsSecurityPolicyPresent);
|
||||
VerifyOrQuit(datasetInfo.mComponents.mIsChannelMaskPresent);
|
||||
VerifyOrQuit(!datasetInfo.mComponents.mIsPendingTimestampPresent);
|
||||
VerifyOrQuit(!datasetInfo.mComponents.mIsDelayPresent);
|
||||
|
||||
VerifyOrQuit(datasetInfo.mPanId == 0xface);
|
||||
VerifyOrQuit(AsCoreType(&datasetInfo.mNetworkKey) == AsCoreType(&kNetworkKey));
|
||||
|
||||
// Finding, reading TLVs
|
||||
|
||||
VerifyOrQuit(dataset.Contains<PanIdTlv>());
|
||||
VerifyOrQuit(dataset.FindTlv(Tlv::kPanId) != nullptr);
|
||||
SuccessOrQuit(dataset.Read<PanIdTlv>(panId));
|
||||
VerifyOrQuit(panId == 0xface);
|
||||
|
||||
VerifyOrQuit(dataset.Contains<NetworkKeyTlv>());
|
||||
VerifyOrQuit(dataset.FindTlv(Tlv::kNetworkKey) != nullptr);
|
||||
SuccessOrQuit(dataset.Read<NetworkKeyTlv>(networkKey));
|
||||
VerifyOrQuit(networkKey == AsCoreType(&kNetworkKey));
|
||||
|
||||
// Change PAN ID TLV
|
||||
|
||||
SuccessOrQuit(dataset.Write<PanIdTlv>(0xcafe));
|
||||
|
||||
SuccessOrQuit(dataset.ValidateTlvs());
|
||||
|
||||
VerifyOrQuit(dataset.Contains<PanIdTlv>());
|
||||
VerifyOrQuit(dataset.FindTlv(Tlv::kPanId) != nullptr);
|
||||
SuccessOrQuit(dataset.Read<PanIdTlv>(panId));
|
||||
VerifyOrQuit(panId == 0xcafe);
|
||||
|
||||
for (Tlv::Type tlvType : kDatasetTlvTypes)
|
||||
{
|
||||
VerifyOrQuit(dataset.ContainsTlv(tlvType));
|
||||
}
|
||||
|
||||
// Change Network Key TLV
|
||||
|
||||
SuccessOrQuit(dataset.Write<NetworkKeyTlv>(AsCoreType(&kNewNetworkKey)));
|
||||
VerifyOrQuit(dataset.Contains<NetworkKeyTlv>());
|
||||
VerifyOrQuit(dataset.FindTlv(Tlv::kNetworkKey) != nullptr);
|
||||
SuccessOrQuit(dataset.Read<NetworkKeyTlv>(networkKey));
|
||||
VerifyOrQuit(networkKey == AsCoreType(&kNewNetworkKey));
|
||||
|
||||
for (Tlv::Type tlvType : kDatasetTlvTypes)
|
||||
{
|
||||
VerifyOrQuit(dataset.ContainsTlv(tlvType));
|
||||
}
|
||||
|
||||
// Remove PAN ID TLV
|
||||
|
||||
dataset.RemoveTlv(Tlv::kPanId);
|
||||
VerifyOrQuit(!dataset.Contains<PanIdTlv>());
|
||||
VerifyOrQuit(dataset.FindTlv(Tlv::kPanId) == nullptr);
|
||||
VerifyOrQuit(dataset.Read<PanIdTlv>(panId) == kErrorNotFound);
|
||||
|
||||
SuccessOrQuit(dataset.ValidateTlvs());
|
||||
|
||||
// Invalid datasets
|
||||
|
||||
SuccessOrQuit(dataset.SetFrom(kTlvBytes, sizeof(kTlvBytes) - 1));
|
||||
VerifyOrQuit(dataset.ValidateTlvs() == kErrorParse);
|
||||
|
||||
SuccessOrQuit(dataset.SetFrom(kDuplicateChannels, sizeof(kDuplicateChannels)));
|
||||
VerifyOrQuit(dataset.ValidateTlvs() == kErrorParse);
|
||||
|
||||
SuccessOrQuit(dataset.SetFrom(kDuplicateChannels, sizeof(kDuplicateChannels) / 2));
|
||||
SuccessOrQuit(dataset.ValidateTlvs());
|
||||
|
||||
// Combining/Merging TLVs from two Datasets.
|
||||
|
||||
SuccessOrQuit(dataset.SetFrom(kTlvBytes, sizeof(kTlvBytes)));
|
||||
|
||||
datasetInfo.Clear();
|
||||
datasetInfo.mComponents.mIsPanIdPresent = true;
|
||||
datasetInfo.mComponents.mIsNetworkKeyPresent = true;
|
||||
datasetInfo.mPanId = 0xcafe;
|
||||
datasetInfo.mNetworkKey = kNewNetworkKey;
|
||||
|
||||
dataset2.SetFrom(datasetInfo);
|
||||
SuccessOrQuit(dataset2.ValidateTlvs());
|
||||
|
||||
SuccessOrQuit(dataset.WriteTlvsFrom(dataset2));
|
||||
|
||||
SuccessOrQuit(dataset.ValidateTlvs());
|
||||
|
||||
VerifyOrQuit(dataset.Contains<PanIdTlv>());
|
||||
VerifyOrQuit(dataset.FindTlv(Tlv::kPanId) != nullptr);
|
||||
SuccessOrQuit(dataset.Read<PanIdTlv>(panId));
|
||||
VerifyOrQuit(panId == 0xcafe);
|
||||
|
||||
VerifyOrQuit(dataset.Contains<NetworkKeyTlv>());
|
||||
VerifyOrQuit(dataset.FindTlv(Tlv::kNetworkKey) != nullptr);
|
||||
SuccessOrQuit(dataset.Read<NetworkKeyTlv>(networkKey));
|
||||
VerifyOrQuit(networkKey == AsCoreType(&kNewNetworkKey));
|
||||
|
||||
// Combining/Merging TLVs from two Datasets (using `Dataset::Info`).
|
||||
|
||||
SuccessOrQuit(dataset.SetFrom(kTlvBytes, sizeof(kTlvBytes)));
|
||||
|
||||
SuccessOrQuit(dataset.WriteTlvsFrom(datasetInfo));
|
||||
|
||||
SuccessOrQuit(dataset.ValidateTlvs());
|
||||
|
||||
VerifyOrQuit(dataset.Contains<PanIdTlv>());
|
||||
VerifyOrQuit(dataset.FindTlv(Tlv::kPanId) != nullptr);
|
||||
SuccessOrQuit(dataset.Read<PanIdTlv>(panId));
|
||||
VerifyOrQuit(panId == 0xcafe);
|
||||
|
||||
VerifyOrQuit(dataset.Contains<NetworkKeyTlv>());
|
||||
VerifyOrQuit(dataset.FindTlv(Tlv::kNetworkKey) != nullptr);
|
||||
SuccessOrQuit(dataset.Read<NetworkKeyTlv>(networkKey));
|
||||
VerifyOrQuit(networkKey == AsCoreType(&kNewNetworkKey));
|
||||
|
||||
// Append TLVs
|
||||
|
||||
SuccessOrQuit(dataset.SetFrom(kTlvBytes, sizeof(kTlvBytes)));
|
||||
VerifyOrQuit(dataset.GetLength() == sizeof(kTlvBytes));
|
||||
VerifyOrQuit(memcmp(dataset.GetBytes(), kTlvBytes, sizeof(kTlvBytes)) == 0);
|
||||
|
||||
SuccessOrQuit(dataset.AppendTlvsFrom(kTlvBytes, sizeof(kTlvBytes)));
|
||||
VerifyOrQuit(dataset.GetLength() == 2 * sizeof(kTlvBytes));
|
||||
VerifyOrQuit(memcmp(dataset.GetBytes(), kTlvBytes, sizeof(kTlvBytes)) == 0);
|
||||
VerifyOrQuit(memcmp(dataset.GetBytes() + sizeof(kTlvBytes), kTlvBytes, sizeof(kTlvBytes)) == 0);
|
||||
|
||||
VerifyOrQuit(dataset.ValidateTlvs() == kErrorParse);
|
||||
}
|
||||
|
||||
} // namespace MeshCoP
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::MeshCoP::TestDataset();
|
||||
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -208,7 +208,7 @@ void InitTest(void)
|
||||
otOperationalDatasetTlvs datasetTlvs;
|
||||
|
||||
SuccessOrQuit(otDatasetCreateNewNetwork(sInstance, &dataset));
|
||||
SuccessOrQuit(otDatasetConvertToTlvs(&dataset, &datasetTlvs));
|
||||
otDatasetConvertToTlvs(&dataset, &datasetTlvs);
|
||||
SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs));
|
||||
|
||||
SuccessOrQuit(otIp6SetEnabled(sInstance, true));
|
||||
|
||||
@@ -1185,7 +1185,7 @@ void InitTest(bool aEnablBorderRouting = false, bool aAfterReset = false)
|
||||
|
||||
otOperationalDatasetTlvs datasetTlvs;
|
||||
|
||||
SuccessOrQuit(otDatasetConvertToTlvs(&kDataset, &datasetTlvs));
|
||||
otDatasetConvertToTlvs(&kDataset, &datasetTlvs);
|
||||
SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs));
|
||||
|
||||
SuccessOrQuit(otIp6SetEnabled(sInstance, true));
|
||||
|
||||
@@ -537,7 +537,7 @@ void InitTest(void)
|
||||
otOperationalDatasetTlvs datasetTlvs;
|
||||
|
||||
SuccessOrQuit(otDatasetCreateNewNetwork(sInstance, &dataset));
|
||||
SuccessOrQuit(otDatasetConvertToTlvs(&dataset, &datasetTlvs));
|
||||
otDatasetConvertToTlvs(&dataset, &datasetTlvs);
|
||||
SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs));
|
||||
|
||||
SuccessOrQuit(otIp6SetEnabled(sInstance, true));
|
||||
|
||||
@@ -205,7 +205,7 @@ void InitTest(void)
|
||||
otOperationalDatasetTlvs datasetTlvs;
|
||||
|
||||
SuccessOrQuit(otDatasetCreateNewNetwork(sInstance, &dataset));
|
||||
SuccessOrQuit(otDatasetConvertToTlvs(&dataset, &datasetTlvs));
|
||||
otDatasetConvertToTlvs(&dataset, &datasetTlvs);
|
||||
SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs));
|
||||
|
||||
SuccessOrQuit(otIp6SetEnabled(sInstance, true));
|
||||
|
||||
Reference in New Issue
Block a user