mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 07:37:46 +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:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user