blob: 31438a1d19bb72800058d827b8491381181a336b [file] [log] [blame]
/*
* Copyright (c) 2017, 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 "common/code_utils.hpp"
#include "common/instance.hpp"
#include "thread/network_data_leader.hpp"
#include "thread/network_data_local.hpp"
#include "thread/network_data_service.hpp"
#include "test_platform.h"
#include "test_util.hpp"
namespace ot {
namespace NetworkData {
void PrintExternalRouteConfig(const ExternalRouteConfig &aConfig)
{
printf("\nprefix:");
for (uint8_t b : aConfig.mPrefix.mPrefix.mFields.m8)
{
printf("%02x", b);
}
printf(", length:%d, rloc16:%04x, preference:%d, nat64:%d, stable:%d, nexthop:%d", aConfig.mPrefix.mLength,
aConfig.mRloc16, aConfig.mPreference, aConfig.mNat64, aConfig.mStable, aConfig.mNextHopIsThisDevice);
}
// Returns true if the two given ExternalRouteConfig match (intentionally ignoring mNextHopIsThisDevice).
bool CompareExternalRouteConfig(const otExternalRouteConfig &aConfig1, const otExternalRouteConfig &aConfig2)
{
return (memcmp(aConfig1.mPrefix.mPrefix.mFields.m8, aConfig2.mPrefix.mPrefix.mFields.m8,
sizeof(aConfig1.mPrefix.mPrefix)) == 0) &&
(aConfig1.mPrefix.mLength == aConfig2.mPrefix.mLength) && (aConfig1.mRloc16 == aConfig2.mRloc16) &&
(aConfig1.mPreference == aConfig2.mPreference) && (aConfig1.mStable == aConfig2.mStable);
}
void TestNetworkDataIterator(void)
{
ot::Instance * instance;
Iterator iter = kIteratorInit;
ExternalRouteConfig config;
instance = testInitInstance();
VerifyOrQuit(instance != nullptr);
{
const uint8_t kNetworkData[] = {
0x08, 0x04, 0x0B, 0x02, 0x00, 0x00, 0x03, 0x14, 0x00, 0x40, 0xFD, 0x00, 0x12, 0x34,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC8, 0x00, 0x40, 0x01, 0x03, 0x54, 0x00, 0x00,
};
otExternalRouteConfig routes[] = {
{
{
{{{0xfd, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0xc800, // mRloc16
1, // mPreference
false, // mNat64
false, // mStable
false, // mNextHopIsThisDevice
},
{
{
{{{0xfd, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0x5400, // mRloc16
0, // mPreference
false, // mNat64
true, // mStable
false, // mNextHopIsThisDevice
},
};
NetworkData netData(*instance, kNetworkData, sizeof(kNetworkData));
iter = OT_NETWORK_DATA_ITERATOR_INIT;
printf("\nTest #1: Network data 1");
printf("\n-------------------------------------------------");
for (const auto &route : routes)
{
SuccessOrQuit(netData.GetNextExternalRoute(iter, config));
PrintExternalRouteConfig(config);
VerifyOrQuit(CompareExternalRouteConfig(config, route));
}
}
{
const uint8_t kNetworkData[] = {
0x08, 0x04, 0x0B, 0x02, 0x00, 0x00, 0x03, 0x1E, 0x00, 0x40, 0xFD, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00,
0x07, 0x02, 0x11, 0x40, 0x00, 0x03, 0x10, 0x00, 0x40, 0x01, 0x03, 0x54, 0x00, 0x00, 0x05, 0x04, 0x54, 0x00,
0x31, 0x00, 0x02, 0x0F, 0x00, 0x40, 0xFD, 0x00, 0xAB, 0xBA, 0xCD, 0xDC, 0x00, 0x00, 0x00, 0x03, 0x10, 0x00,
0x20, 0x03, 0x0E, 0x00, 0x20, 0xFD, 0x00, 0xAB, 0xBA, 0x01, 0x06, 0x54, 0x00, 0x00, 0x04, 0x00, 0x00,
};
otExternalRouteConfig routes[] = {
{
{
{{{0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0x1000, // mRloc16
1, // mPreference
false, // mNat64
false, // mStable
false, // mNextHopIsThisDevice
},
{
{
{{{0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0x5400, // mRloc16
0, // mPreference
false, // mNat64
true, // mStable
false, // mNextHopIsThisDevice
},
{
{
{{{0xfd, 0x00, 0xab, 0xba, 0xcd, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0x1000, // mRloc16
0, // mPreference
true, // mNat64
false, // mStable
false, // mNextHopIsThisDevice
},
{
{
{{{0xfd, 0x00, 0xab, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
32,
},
0x5400, // mRloc16
0, // mPreference
false, // mNat64
true, // mStable
false, // mNextHopIsThisDevice
},
{
{
{{{0xfd, 0x00, 0xab, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
32,
},
0x0400, // mRloc16
0, // mPreference
false, // mNat64
true, // mStable
false, // mNextHopIsThisDevice
},
};
NetworkData netData(*instance, kNetworkData, sizeof(kNetworkData));
iter = OT_NETWORK_DATA_ITERATOR_INIT;
printf("\nTest #2: Network data 2");
printf("\n-------------------------------------------------");
for (const auto &route : routes)
{
SuccessOrQuit(netData.GetNextExternalRoute(iter, config));
PrintExternalRouteConfig(config);
VerifyOrQuit(CompareExternalRouteConfig(config, route));
}
}
testFreeInstance(instance);
}
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
class TestNetworkData : public Local
{
public:
explicit TestNetworkData(ot::Instance &aInstance)
: Local(aInstance)
{
}
Error AddService(const ServiceData &aServiceData)
{
return Local::AddService(ServiceTlv::kThreadEnterpriseNumber, aServiceData, true, ServerData());
}
Error ValidateServiceData(const ServiceTlv *aServiceTlv, const ServiceData &aServiceData) const
{
Error error = kErrorFailed;
ServiceData serviceData;
VerifyOrExit(aServiceTlv != nullptr);
aServiceTlv->GetServiceData(serviceData);
VerifyOrExit(aServiceData == serviceData);
error = kErrorNone;
exit:
return error;
}
void Test(void)
{
const uint8_t kServiceData1[] = {0x02};
const uint8_t kServiceData2[] = {0xab};
const uint8_t kServiceData3[] = {0xab, 0x00};
const uint8_t kServiceData4[] = {0x02, 0xab, 0xcd, 0xef};
const uint8_t kServiceData5[] = {0x02, 0xab, 0xcd};
const ServiceTlv *tlv;
ServiceData serviceData1;
ServiceData serviceData2;
ServiceData serviceData3;
ServiceData serviceData4;
ServiceData serviceData5;
serviceData1.InitFrom(kServiceData1);
serviceData2.InitFrom(kServiceData2);
serviceData3.InitFrom(kServiceData3);
serviceData4.InitFrom(kServiceData4);
serviceData5.InitFrom(kServiceData5);
SuccessOrQuit(AddService(serviceData1));
SuccessOrQuit(AddService(serviceData2));
SuccessOrQuit(AddService(serviceData3));
SuccessOrQuit(AddService(serviceData4));
SuccessOrQuit(AddService(serviceData5));
DumpBuffer("netdata", GetBytes(), GetLength());
// Iterate through all entries that start with { 0x02 } (kServiceData1)
tlv = nullptr;
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData1, kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, serviceData1));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData1, kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, serviceData4));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData1, kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, serviceData5));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData1, kServicePrefixMatch);
VerifyOrQuit(tlv == nullptr, "FindNextService() returned extra TLV");
// Iterate through all entries that start with { 0xab } (serviceData2)
tlv = nullptr;
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData2, kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, serviceData2));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData2, kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, serviceData3));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData2, kServicePrefixMatch);
VerifyOrQuit(tlv == nullptr, "FindNextService() returned extra TLV");
// Iterate through all entries that start with serviceData5
tlv = nullptr;
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData5, kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, serviceData4));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData5, kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, serviceData5));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, serviceData5, kServicePrefixMatch);
VerifyOrQuit(tlv == nullptr, "FindNextService() returned extra TLV");
}
};
void TestNetworkDataFindNextService(void)
{
ot::Instance *instance;
printf("\n\n-------------------------------------------------");
printf("\nTestNetworkDataFindNextService()\n");
instance = testInitInstance();
VerifyOrQuit(instance != nullptr);
{
TestNetworkData netData(*instance);
netData.Test();
}
}
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
void TestNetworkDataDsnSrpServices(void)
{
class TestLeader : public Leader
{
public:
void Populate(const uint8_t *aTlvs, uint8_t aTlvsLength)
{
memcpy(GetBytes(), aTlvs, aTlvsLength);
SetLength(aTlvsLength);
}
};
ot::Instance *instance;
printf("\n\n-------------------------------------------------");
printf("\nTestNetworkDataDsnSrpServices()\n");
instance = testInitInstance();
VerifyOrQuit(instance != nullptr);
{
struct AnycastEntry
{
uint16_t mAloc16;
uint8_t mSequenceNumber;
bool Matches(Service::DnsSrpAnycast::Info aInfo) const
{
VerifyOrQuit(aInfo.mAnycastAddress.GetIid().IsAnycastServiceLocator());
return (aInfo.mAnycastAddress.GetIid().GetLocator() == mAloc16) &&
(aInfo.mSequenceNumber == mSequenceNumber);
}
};
struct UnicastEntry
{
const char *mAddress;
uint16_t mPort;
bool Matches(Service::DnsSrpUnicast::Info aInfo) const
{
Ip6::SockAddr sockAddr;
SuccessOrQuit(sockAddr.GetAddress().FromString(mAddress));
sockAddr.SetPort(mPort);
return (aInfo.mSockAddr == sockAddr);
}
};
const uint8_t kNetworkData[] = {
0x0b, 0x08, 0x80, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x28, 0x00, 0x0b, 0x08, 0x81, 0x02, 0x5c, 0xff, 0x0d, 0x02,
0x6c, 0x00, 0x0b, 0x09, 0x82, 0x02, 0x5c, 0x03, 0x0d, 0x03, 0x4c, 0x00, 0xaa, 0x0b, 0x35, 0x83, 0x13, 0x5d,
0xfd, 0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0x00, 0x2d, 0x0e, 0xc6, 0x27, 0x55, 0x56, 0x18, 0xd9, 0x12, 0x34,
0x0d, 0x02, 0x00, 0x00, 0x0d, 0x14, 0x6c, 0x00, 0xfd, 0x00, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11,
0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xab, 0xcd, 0x0d, 0x04, 0x28, 0x00, 0x56, 0x78, 0x0b, 0x23, 0x84, 0x01,
0x5d, 0x0d, 0x02, 0x00, 0x00, 0x0d, 0x14, 0x4c, 0x00, 0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde,
0xf0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0x00, 0x0e, 0x0d, 0x04, 0x6c, 0x00, 0xcd, 0x12,
};
const AnycastEntry kAnycastEntries[] = {
{0xfc10, 0x02},
{0xfc11, 0xff},
{0xfc12, 0x03},
};
const UnicastEntry kUnicastEntries[] = {
{"fdde:ad00:beef:0:2d0e:c627:5556:18d9", 0x1234}, {"fd00:aabb:ccdd:eeff:11:2233:4455:6677", 0xabcd},
{"fdde:ad00:beef:0:0:ff:fe00:2800", 0x5678}, {"fd00:1234:5678:9abc:def0:123:4567:89ab", 0x0e},
{"fdde:ad00:beef:0:0:ff:fe00:6c00", 0xcd12},
};
const uint8_t kPreferredAnycastEntryIndex = 2;
Service::Manager & manager = instance->Get<Service::Manager>();
Service::Manager::Iterator iterator;
Service::DnsSrpAnycast::Info anycastInfo;
Service::DnsSrpUnicast::Info unicastInfo;
reinterpret_cast<TestLeader &>(instance->Get<Leader>()).Populate(kNetworkData, sizeof(kNetworkData));
DumpBuffer("netdata", kNetworkData, sizeof(kNetworkData));
// Verify all the "DNS/SRP Anycast Service" entries in Network Data
printf("\n- - - - - - - - - - - - - - - - - - - -");
printf("\nDNS/SRP Anycast Service entries\n");
for (const AnycastEntry &entry : kAnycastEntries)
{
SuccessOrQuit(manager.GetNextDnsSrpAnycastInfo(iterator, anycastInfo));
printf("\nanycastInfo { %s, seq:%d }", anycastInfo.mAnycastAddress.ToString().AsCString(),
anycastInfo.mSequenceNumber);
VerifyOrQuit(entry.Matches(anycastInfo), "GetNextDnsSrpAnycastInfo() returned incorrect info");
}
VerifyOrQuit(manager.GetNextDnsSrpAnycastInfo(iterator, anycastInfo) == kErrorNotFound,
"GetNextDnsSrpAnycastInfo() returned unexpected extra entry");
// Find the preferred "DNS/SRP Anycast Service" entries in Network Data
SuccessOrQuit(manager.FindPreferredDnsSrpAnycastInfo(anycastInfo));
printf("\n\nPreferred anycastInfo { %s, seq:%d }", anycastInfo.mAnycastAddress.ToString().AsCString(),
anycastInfo.mSequenceNumber);
VerifyOrQuit(kAnycastEntries[kPreferredAnycastEntryIndex].Matches(anycastInfo),
"FindPreferredDnsSrpAnycastInfo() returned invalid info");
printf("\n\n- - - - - - - - - - - - - - - - - - - -");
printf("\nDNS/SRP Unicast Service entries\n");
iterator.Clear();
for (const UnicastEntry &entry : kUnicastEntries)
{
SuccessOrQuit(manager.GetNextDnsSrpUnicastInfo(iterator, unicastInfo));
printf("\nunicastInfo %s", unicastInfo.mSockAddr.ToString().AsCString());
VerifyOrQuit(entry.Matches(unicastInfo), "GetNextDnsSrpUnicastInfo() returned incorrect info");
}
VerifyOrQuit(manager.GetNextDnsSrpUnicastInfo(iterator, unicastInfo) == kErrorNotFound,
"GetNextDnsSrpUnicastInfo() returned unexpected extra entry");
printf("\n");
}
testFreeInstance(instance);
}
} // namespace NetworkData
} // namespace ot
int main(void)
{
ot::NetworkData::TestNetworkDataIterator();
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
ot::NetworkData::TestNetworkDataFindNextService();
#endif
ot::NetworkData::TestNetworkDataDsnSrpServices();
printf("\nAll tests passed\n");
return 0;
}