mirror of
https://github.com/espressif/openthread.git
synced 2026-08-16 07:37:47 +00:00
[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:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user