[network-data] add FindNextMatchingService() (#6473)

This commit adds a new method in `NetworkData` class to find and
iterate over all Service TLVs that start with a given Service Data.
Unlike the existing `FindService()` method which searches for a
Service TLV with an exact match with the given Service Data,  this
method performs a relaxed check allowing a matching Service TLV to
contain additional bytes after given data bytes to search for.

This commit also updates `test_network_data` unit test to add new
test to cover the behavior of newly added method.
This commit is contained in:
Abtin Keshavarzian
2021-04-19 21:27:33 -07:00
committed by GitHub
parent 31cbb28d84
commit 0eeab8844a
3 changed files with 175 additions and 12 deletions
+36 -1
View File
@@ -724,6 +724,17 @@ const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
uint8_t aServiceDataLength,
const uint8_t *aTlvs,
uint8_t aTlvsLength)
{
return FindService(aEnterpriseNumber, aServiceData, aServiceDataLength, /* aExactServiceDataMatch */ true, aTlvs,
aTlvsLength);
}
const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
const uint8_t *aServiceData,
uint8_t aServiceDataLength,
bool aExactServiceDataMatch,
const uint8_t *aTlvs,
uint8_t aTlvsLength)
{
const NetworkDataTlv *start = reinterpret_cast<const NetworkDataTlv *>(aTlvs);
const NetworkDataTlv *end = reinterpret_cast<const NetworkDataTlv *>(aTlvs + aTlvsLength);
@@ -736,7 +747,8 @@ const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
VerifyOrExit(serviceTlv != nullptr);
if ((serviceTlv->GetEnterpriseNumber() == aEnterpriseNumber) &&
(serviceTlv->GetServiceDataLength() == aServiceDataLength) &&
(serviceTlv->GetServiceDataLength() >= aServiceDataLength) &&
(!aExactServiceDataMatch || (serviceTlv->GetServiceDataLength() == aServiceDataLength)) &&
(memcmp(serviceTlv->GetServiceData(), aServiceData, aServiceDataLength) == 0))
{
ExitNow();
@@ -751,6 +763,29 @@ exit:
return serviceTlv;
}
const ServiceTlv *NetworkData::FindNextMatchingService(const ServiceTlv *aPrevServiceTlv,
uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength) const
{
const uint8_t *tlvs;
uint8_t length;
if (aPrevServiceTlv == nullptr)
{
tlvs = mTlvs;
length = mLength;
}
else
{
tlvs = reinterpret_cast<const uint8_t *>(aPrevServiceTlv->GetNext());
length = static_cast<uint8_t>((mTlvs + mLength) - tlvs);
}
return FindService(aEnterpriseNumber, aServiceData, aServiceDataLength, /* aExactServiceDataMatch */ false, tlvs,
length);
}
NetworkDataTlv *NetworkData::AppendTlv(uint16_t aTlvSize)
{
NetworkDataTlv *tlv;
+32
View File
@@ -748,6 +748,31 @@ protected:
const uint8_t *aTlvs,
uint8_t aTlvsLength);
/**
* This method returns the next pointer to a matching Service TLV.
*
* This method can be used to iterate over all Service TLVs that start with a given Service Data.
*
* Unlike `FindService()` method which searches for a Service TLV with an exact match with the given Service Data,
* this method performs a relaxed check allowing a matching Service TLV to contain additional bytes after
* @p aServiceData, i.e., a Service TLV is considered to match if its Service Data length is larger than or equal
* to @p aServiceDataLength and its first @p aServiceDataLength Service Data bytes are equal to @p aServiceData.
*
* @param[in] aPrevServiceTlv Set to nullptr to start from the beginning of the TLVs (finding the first
* matching Service TLV), or a pointer to the previous Service TLV returned from
* this method to iterate to the next matching Service TLV.
* @param[in] aEnterpriseNumber Enterprise Number.
* @param[in] aServiceData A pointer to a Service Data to match with Service TLVs.
* @param[in] aServiceDataLength The Service Data length pointed to by @p aServiceData.
*
* @returns A pointer to the next matching Service TLV if one is found or nullptr if it cannot be found.
*
*/
const ServiceTlv *FindNextMatchingService(const ServiceTlv *aPrevServiceTlv,
uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength) const;
/**
* This method indicates whether there is space in Network Data to insert/append new info and grow it by a given
* number of bytes.
@@ -1033,6 +1058,13 @@ private:
ServiceConfig * mService;
};
static const ServiceTlv *FindService(uint32_t aEnterpriseNumber,
const uint8_t *aServiceData,
uint8_t aServiceDataLength,
bool aExactServiceDataMatch,
const uint8_t *aTlvs,
uint8_t aTlvsLength);
Error Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfig) const;
static void RemoveTemporaryData(uint8_t *aData, uint8_t &aDataLength, PrefixTlv &aPrefix);
+107 -11
View File
@@ -38,17 +38,6 @@
namespace ot {
namespace NetworkData {
class TestNetworkData : public NetworkData::NetworkData
{
public:
TestNetworkData(ot::Instance *aInstance, const uint8_t *aTlvs, uint8_t aTlvsLength)
: NetworkData::NetworkData(*aInstance, kTypeLeader)
{
memcpy(mTlvs, aTlvs, aTlvsLength);
mLength = aTlvsLength;
}
};
void PrintExternalRouteConfig(const ExternalRouteConfig &aConfig)
{
printf("\nprefix:");
@@ -73,6 +62,17 @@ bool CompareExternalRouteConfig(const otExternalRouteConfig &aConfig1, const otE
void TestNetworkDataIterator(void)
{
class TestNetworkData : public NetworkData
{
public:
TestNetworkData(ot::Instance *aInstance, const uint8_t *aTlvs, uint8_t aTlvsLength)
: NetworkData(*aInstance, kTypeLeader)
{
memcpy(mTlvs, aTlvs, aTlvsLength);
mLength = aTlvsLength;
}
};
ot::Instance * instance;
Iterator iter = kIteratorInit;
ExternalRouteConfig config;
@@ -172,12 +172,108 @@ void TestNetworkDataIterator(void)
testFreeInstance(instance);
}
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
class TestNetworkData : public Local
{
public:
explicit TestNetworkData(ot::Instance &aInstance)
: Local(aInstance)
{
}
template <uint8_t kSize> Error AddService(const uint8_t (&aServiceData)[kSize])
{
return Local::AddService(ServiceTlv::kThreadEnterpriseNumber, aServiceData, kSize, true, nullptr, 0);
}
template <uint8_t kSize>
Error ValidateServiceData(const ServiceTlv *aServiceTlv, const uint8_t (&aServiceData)[kSize]) const
{
return
((aServiceTlv != nullptr) && (aServiceTlv->GetServiceDataLength() == kSize) &&
(memcmp(aServiceTlv->GetServiceData(), aServiceData, kSize) == 0))
? kErrorNone
: kErrorFailed;
}
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;
SuccessOrQuit(AddService(kServiceData1), "AddService() failed");
SuccessOrQuit(AddService(kServiceData2), "AddService() failed");
SuccessOrQuit(AddService(kServiceData3), "AddService() failed");
SuccessOrQuit(AddService(kServiceData4), "AddService() failed");
SuccessOrQuit(AddService(kServiceData5), "AddService() failed");
DumpBuffer("netdata", mTlvs, mLength);
// Iterate through all entries that start with { 0x02 } (kServiceData1)
tlv = nullptr;
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1));
SuccessOrQuit(ValidateServiceData(tlv, kServiceData1), "FindNextMatchingService() failed");
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1));
SuccessOrQuit(ValidateServiceData(tlv, kServiceData4), "FindNextMatchingService() failed");
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1));
SuccessOrQuit(ValidateServiceData(tlv, kServiceData5), "FindNextMatchingService() failed");
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1));
VerifyOrQuit(tlv == nullptr, "FindNextMatchingService() returned extra TLV");
// Iterate through all entries that start with { 0xab } (kServiceData2)
tlv = nullptr;
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData2, sizeof(kServiceData2));
SuccessOrQuit(ValidateServiceData(tlv, kServiceData2), "FindNextMatchingService() failed");
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData2, sizeof(kServiceData2));
SuccessOrQuit(ValidateServiceData(tlv, kServiceData3), "FindNextMatchingService() failed");
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData2, sizeof(kServiceData2));
VerifyOrQuit(tlv == nullptr, "FindNextMatchingService() returned extra TLV");
// Iterate through all entries that start with kServiceData5
tlv = nullptr;
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData5, sizeof(kServiceData5));
SuccessOrQuit(ValidateServiceData(tlv, kServiceData4), "FindNextMatchingService() failed");
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData5, sizeof(kServiceData5));
SuccessOrQuit(ValidateServiceData(tlv, kServiceData5), "FindNextMatchingService() failed");
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData5, sizeof(kServiceData5));
VerifyOrQuit(tlv == nullptr, "FindNextMatchingService() returned extra TLV");
}
};
void TestNetworkDataFindNextService(void)
{
ot::Instance *instance;
printf("\n\n-------------------------------------------------");
printf("\nTestNetworkDataFindNextService()\n");
instance = testInitInstance();
VerifyOrQuit(instance != nullptr, "Null OpenThread instance\n");
{
TestNetworkData netData(*instance);
netData.Test();
}
}
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
} // namespace NetworkData
} // namespace ot
int main(void)
{
ot::NetworkData::TestNetworkDataIterator();
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
ot::NetworkData::TestNetworkDataFindNextService();
#endif
printf("\nAll tests passed\n");
return 0;