[backbone-router] relax matching BBR dataset (#6752)

This commit relaxes BBR dataset matching to only compare the first
byte of Service Data (i.e. 0x01).

This commit also requires all Service TLV searching methods to
explicitly specify aExactServiceDataMatch argument, helping to reduce
unconscious mistakes.
This commit is contained in:
Simon Lin
2021-07-20 23:08:56 -07:00
committed by GitHub
parent cbd9661308
commit 5e23211e04
7 changed files with 158 additions and 106 deletions
+46 -30
View File
@@ -565,39 +565,27 @@ const PrefixTlv *NetworkData::FindPrefix(const uint8_t *aPrefix,
return prefixTlv;
}
const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
const uint8_t *aServiceData,
uint8_t aServiceDataLength) const
const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode) const
{
return FindService(aEnterpriseNumber, aServiceData, aServiceDataLength, mTlvs, mLength);
return FindService(aEnterpriseNumber, aServiceData, aServiceDataLength, aServiceMatchMode, mTlvs, mLength);
}
const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
const uint8_t *aServiceData,
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 ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode,
const uint8_t * aTlvs,
uint8_t aTlvsLength)
{
TlvIterator tlvIterator(aTlvs, aTlvsLength);
const ServiceTlv *serviceTlv;
while ((serviceTlv = tlvIterator.Iterate<ServiceTlv>()) != nullptr)
{
if ((serviceTlv->GetEnterpriseNumber() == aEnterpriseNumber) &&
(serviceTlv->GetServiceDataLength() >= aServiceDataLength) &&
(!aExactServiceDataMatch || (serviceTlv->GetServiceDataLength() == aServiceDataLength)) &&
(memcmp(serviceTlv->GetServiceData(), aServiceData, aServiceDataLength) == 0))
if (MatchService(*serviceTlv, aEnterpriseNumber, aServiceData, aServiceDataLength, aServiceMatchMode))
{
break;
}
@@ -606,10 +594,11 @@ const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
return serviceTlv;
}
const ServiceTlv *NetworkData::FindNextMatchingService(const ServiceTlv *aPrevServiceTlv,
uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength) const
const ServiceTlv *NetworkData::FindNextService(const ServiceTlv *aPrevServiceTlv,
uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode) const
{
const uint8_t *tlvs;
uint8_t length;
@@ -625,8 +614,35 @@ const ServiceTlv *NetworkData::FindNextMatchingService(const ServiceTlv *aPrevSe
length = static_cast<uint8_t>((mTlvs + mLength) - tlvs);
}
return FindService(aEnterpriseNumber, aServiceData, aServiceDataLength, /* aExactServiceDataMatch */ false, tlvs,
length);
return FindService(aEnterpriseNumber, aServiceData, aServiceDataLength, aServiceMatchMode, tlvs, length);
}
bool NetworkData::MatchService(const ServiceTlv &aServiceTlv,
uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode)
{
bool match = false;
VerifyOrExit(aServiceTlv.GetEnterpriseNumber() == aEnterpriseNumber &&
aServiceTlv.GetServiceDataLength() >= aServiceDataLength);
switch (aServiceMatchMode)
{
case kServiceExactMatch:
VerifyOrExit(aServiceTlv.GetServiceDataLength() == aServiceDataLength);
OT_FALL_THROUGH;
case kServicePrefixMatch:
VerifyOrExit(memcmp(aServiceTlv.GetServiceData(), aServiceData, aServiceDataLength) == 0);
break;
}
match = true;
exit:
return match;
}
NetworkDataTlv *NetworkData::AppendTlv(uint16_t aTlvSize)
+55 -38
View File
@@ -308,6 +308,16 @@ public:
Error GetNextServer(Iterator &aIterator, uint16_t &aRloc16) const;
protected:
/**
* This enumeration defines Service Data match mode.
*
*/
enum ServiceMatchMode : uint8_t
{
kServicePrefixMatch, ///< Match the Service Data by prefix.
kServiceExactMatch, ///< Match the full Service Data exactly.
};
/**
* This method returns a pointer to the start of Network Data TLV sequence.
*
@@ -427,14 +437,18 @@ protected:
* @param[in] aEnterpriseNumber Enterprise Number.
* @param[in] aServiceData A pointer to a Service Data.
* @param[in] aServiceDataLength The Service Data length pointed to by @p aServiceData.
* @param[in] aServiceMatchMode The Service Data match mode.
*
* @returns A pointer to the Service TLV if one is found or nullptr if no matching Service TLV exists.
*
*/
ServiceTlv *FindService(uint32_t aEnterpriseNumber, const uint8_t *aServiceData, uint8_t aServiceDataLength)
ServiceTlv *FindService(uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode)
{
return const_cast<ServiceTlv *>(
const_cast<const NetworkData *>(this)->FindService(aEnterpriseNumber, aServiceData, aServiceDataLength));
return const_cast<ServiceTlv *>(const_cast<const NetworkData *>(this)->FindService(
aEnterpriseNumber, aServiceData, aServiceDataLength, aServiceMatchMode));
}
/**
@@ -443,78 +457,82 @@ protected:
* @param[in] aEnterpriseNumber Enterprise Number.
* @param[in] aServiceData A pointer to a Service Data.
* @param[in] aServiceDataLength The Service Data length pointed to by @p aServiceData.
* @param[in] aServiceMatchMode The Service Data match mode.
*
* @returns A pointer to the Service TLV if one is found or nullptr if no matching Service TLV exists.
*
*/
const ServiceTlv *FindService(uint32_t aEnterpriseNumber,
const uint8_t *aServiceData,
uint8_t aServiceDataLength) const;
const ServiceTlv *FindService(uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode) const;
/**
* This method returns a pointer to a Service TLV in a specified tlvs buffer.
*
* @param[in] aEnterpriseNumber Enterprise Number.
* @param[in] aServiceData A pointer to an Service Data.
* @param[in] aServiceData A pointer to a Service Data.
* @param[in] aServiceDataLength The Service Data length pointed to by @p aServiceData.
* @param[in] aServiceMatchMode The Service Data match mode.
* @param[in] aTlvs A pointer to a specified tlvs buffer.
* @param[in] aTlvsLength The specified tlvs buffer length pointed to by @p aTlvs.
*
* @returns A pointer to the Service TLV if one is found or nullptr if no matching Service TLV exists.
*
*/
static ServiceTlv *FindService(uint32_t aEnterpriseNumber,
const uint8_t *aServiceData,
uint8_t aServiceDataLength,
uint8_t * aTlvs,
uint8_t aTlvsLength)
static ServiceTlv *FindService(uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode,
uint8_t * aTlvs,
uint8_t aTlvsLength)
{
return const_cast<ServiceTlv *>(FindService(aEnterpriseNumber, aServiceData, aServiceDataLength,
const_cast<const uint8_t *>(aTlvs), aTlvsLength));
aServiceMatchMode, const_cast<const uint8_t *>(aTlvs),
aTlvsLength));
}
/**
* This method returns a pointer to a Service TLV in a specified tlvs buffer.
*
* @param[in] aEnterpriseNumber Enterprise Number.
* @param[in] aServiceData A pointer to an Service Data.
* @param[in] aServiceData A pointer to a Service Data.
* @param[in] aServiceDataLength The Service Data length pointed to by @p aServiceData.
* @param[in] aServiceMatchMode The Service Data match mode.
* @param[in] aTlvs A pointer to a specified tlvs buffer.
* @param[in] aTlvsLength The specified tlvs buffer length pointed to by @p aTlvs.
*
* @returns A pointer to the Service TLV if one is found or nullptr if no matching Service TLV exists.
*
*/
static const ServiceTlv *FindService(uint32_t aEnterpriseNumber,
const uint8_t *aServiceData,
uint8_t aServiceDataLength,
const uint8_t *aTlvs,
uint8_t aTlvsLength);
static const ServiceTlv *FindService(uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode,
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] 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.
* @param[in] aServiceMatchMode The Service Data match mode.
*
* @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;
const ServiceTlv *FindNextService(const ServiceTlv *aPrevServiceTlv,
uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode) const;
/**
* This method indicates whether there is space in Network Data to insert/append new info and grow it by a given
@@ -668,13 +686,6 @@ 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);
@@ -683,6 +694,12 @@ private:
static void Remove(uint8_t *aData, uint8_t &aDataLength, uint8_t *aRemoveStart, uint8_t aRemoveLength);
static void RemoveTlv(uint8_t *aData, uint8_t &aDataLength, NetworkDataTlv *aTlv);
static bool MatchService(const ServiceTlv &aServiceTlv,
uint32_t aEnterpriseNumber,
const uint8_t * aServiceData,
uint8_t aServiceDataLength,
ServiceMatchMode aServiceMatchMode);
const Type mType;
};
+5 -5
View File
@@ -433,7 +433,7 @@ Error Leader::Validate(const uint8_t *aTlvs, uint8_t aTlvsLength, uint16_t aRloc
// Ensure there is no duplicate Service TLV with same
// Enterprise Number and Service Data.
VerifyOrExit(FindService(service->GetEnterpriseNumber(), service->GetServiceData(),
service->GetServiceDataLength(), aTlvs, offset) == nullptr,
service->GetServiceDataLength(), kServiceExactMatch, aTlvs, offset) == nullptr,
error = kErrorParse);
SuccessOrExit(error = ValidateService(*service, aRloc16));
@@ -786,9 +786,9 @@ exit:
Error Leader::AddService(const ServiceTlv &aService, ChangedFlags &aChangedFlags)
{
Error error = kErrorNone;
ServiceTlv *dstService =
FindService(aService.GetEnterpriseNumber(), aService.GetServiceData(), aService.GetServiceDataLength());
Error error = kErrorNone;
ServiceTlv * dstService = FindService(aService.GetEnterpriseNumber(), aService.GetServiceData(),
aService.GetServiceDataLength(), kServiceExactMatch);
const ServerTlv *server;
if (dstService == nullptr)
@@ -1080,7 +1080,7 @@ void Leader::RemoveRloc(uint16_t aRloc16,
ServiceTlv * service = static_cast<ServiceTlv *>(cur);
const ServiceTlv *excludeService =
FindService(service->GetEnterpriseNumber(), service->GetServiceData(), service->GetServiceDataLength(),
aExcludeTlvs, aExcludeTlvsLength);
kServiceExactMatch, aExcludeTlvs, aExcludeTlvsLength);
RemoveRlocInService(*service, aRloc16, aMatchMode, excludeService, aChangedFlags);
+2 -1
View File
@@ -236,7 +236,8 @@ Error Local::RemoveService(uint32_t aEnterpriseNumber, const uint8_t *aServiceDa
Error error = kErrorNone;
ServiceTlv *tlv;
VerifyOrExit((tlv = FindService(aEnterpriseNumber, aServiceData, aServiceDataLength)) != nullptr,
VerifyOrExit((tlv = FindService(aEnterpriseNumber, aServiceData, aServiceDataLength, kServiceExactMatch)) !=
nullptr,
error = kErrorNotFound);
RemoveTlv(tlv);
+25 -18
View File
@@ -100,29 +100,35 @@ void Manager::GetBackboneRouterPrimary(ot::BackboneRouter::BackboneRouterConfig
{
const ServerTlv * rvalServerTlv = nullptr;
const BackboneRouter::ServerData *rvalServerData = nullptr;
Iterator iterator;
const ServiceTlv * serviceTlv = nullptr;
aConfig.mServer16 = Mac::kShortAddrInvalid;
iterator.mServiceTlv = Get<Leader>().FindService(kThreadEnterpriseNumber, &BackboneRouter::kServiceData,
sizeof(BackboneRouter::kServiceData));
while (IterateToNextServer(iterator) == kErrorNone)
while ((serviceTlv = Get<Leader>().FindNextService(
serviceTlv, kThreadEnterpriseNumber, &BackboneRouter::kServiceData, BackboneRouter::kServiceDataMinSize,
NetworkData::kServicePrefixMatch)) != nullptr)
{
const BackboneRouter::ServerData *serverData;
Iterator iterator;
if (iterator.mServerSubTlv->GetServerDataLength() < sizeof(BackboneRouter::ServerData))
iterator.mServiceTlv = serviceTlv;
while (IterateToNextServer(iterator) == kErrorNone)
{
continue;
}
const BackboneRouter::ServerData *serverData;
serverData = reinterpret_cast<const BackboneRouter::ServerData *>(iterator.mServerSubTlv->GetServerData());
if (iterator.mServerSubTlv->GetServerDataLength() < sizeof(BackboneRouter::ServerData))
{
continue;
}
if (rvalServerTlv == nullptr ||
IsBackboneRouterPreferredTo(*iterator.mServerSubTlv, *serverData, *rvalServerTlv, *rvalServerData))
{
rvalServerTlv = iterator.mServerSubTlv;
rvalServerData = serverData;
serverData = reinterpret_cast<const BackboneRouter::ServerData *>(iterator.mServerSubTlv->GetServerData());
if (rvalServerTlv == nullptr ||
IsBackboneRouterPreferredTo(*iterator.mServerSubTlv, *serverData, *rvalServerTlv, *rvalServerData))
{
rvalServerTlv = iterator.mServerSubTlv;
rvalServerData = serverData;
}
}
}
@@ -165,7 +171,8 @@ Error Manager::GetNextDnsSrpAnycastInfo(Iterator &aIterator, DnsSrpAnycast::Info
do
{
tlv = Get<Leader>().FindNextMatchingService(tlv, kThreadEnterpriseNumber, &serviceData, sizeof(serviceData));
tlv = Get<Leader>().FindNextService(tlv, kThreadEnterpriseNumber, &serviceData, sizeof(serviceData),
NetworkData::kServicePrefixMatch);
VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
} while (tlv->GetServiceDataLength() < sizeof(DnsSrpAnycast::ServiceData));
@@ -238,8 +245,8 @@ Error Manager::GetNextDnsSrpUnicastInfo(Iterator &aIterator, DnsSrpUnicast::Info
// Find the next matching Service TLV.
aIterator.mServiceTlv =
Get<Leader>().FindNextMatchingService(aIterator.mServiceTlv, kThreadEnterpriseNumber,
&DnsSrpUnicast::kServiceData, sizeof(DnsSrpUnicast::kServiceData));
Get<Leader>().FindNextService(aIterator.mServiceTlv, kThreadEnterpriseNumber, &DnsSrpUnicast::kServiceData,
sizeof(DnsSrpUnicast::kServiceData), NetworkData::kServicePrefixMatch);
VerifyOrExit(aIterator.mServiceTlv != nullptr, error = kErrorNotFound);
+2 -1
View File
@@ -72,7 +72,8 @@ public:
* The service data contains only the service number (THREAD_SERVICE_DATA_BBR) as a single byte.
*
*/
static const uint8_t kServiceData = 0x01;
static const uint8_t kServiceData = 0x01;
static constexpr uint8_t kServiceDataMinSize = 1;
/**
* This class implements the generation and parsing of "Backbone Router Service" server data.
+23 -13
View File
@@ -265,32 +265,42 @@ public:
// Iterate through all entries that start with { 0x02 } (kServiceData1)
tlv = nullptr;
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1),
kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, kServiceData1));
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1),
kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, kServiceData4));
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1),
kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, kServiceData5));
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1));
VerifyOrQuit(tlv == nullptr, "FindNextMatchingService() returned extra TLV");
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData1, sizeof(kServiceData1),
kServicePrefixMatch);
VerifyOrQuit(tlv == nullptr, "FindNextService() returned extra TLV");
// Iterate through all entries that start with { 0xab } (kServiceData2)
tlv = nullptr;
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData2, sizeof(kServiceData2));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData2, sizeof(kServiceData2),
kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, kServiceData2));
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData2, sizeof(kServiceData2));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData2, sizeof(kServiceData2),
kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, kServiceData3));
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData2, sizeof(kServiceData2));
VerifyOrQuit(tlv == nullptr, "FindNextMatchingService() returned extra TLV");
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData2, sizeof(kServiceData2),
kServicePrefixMatch);
VerifyOrQuit(tlv == nullptr, "FindNextService() returned extra TLV");
// Iterate through all entries that start with kServiceData5
tlv = nullptr;
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData5, sizeof(kServiceData5));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData5, sizeof(kServiceData5),
kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, kServiceData4));
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData5, sizeof(kServiceData5));
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData5, sizeof(kServiceData5),
kServicePrefixMatch);
SuccessOrQuit(ValidateServiceData(tlv, kServiceData5));
tlv = FindNextMatchingService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData5, sizeof(kServiceData5));
VerifyOrQuit(tlv == nullptr, "FindNextMatchingService() returned extra TLV");
tlv = FindNextService(tlv, ServiceTlv::kThreadEnterpriseNumber, kServiceData5, sizeof(kServiceData5),
kServicePrefixMatch);
VerifyOrQuit(tlv == nullptr, "FindNextService() returned extra TLV");
}
};