diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp index e382b9215..142666dae 100644 --- a/src/core/thread/network_data.cpp +++ b/src/core/thread/network_data.cpp @@ -150,6 +150,10 @@ Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfi Error error = kErrorNotFound; NetworkDataIterator iterator(aIterator); + bool shouldIterateOverPrefixTlvs; + + shouldIterateOverPrefixTlvs = ((aConfig.mOnMeshPrefix != nullptr) || (aConfig.mExternalRoute != nullptr) || + (aConfig.mLowpanContext != nullptr)); for (const NetworkDataTlv *cur; cur = iterator.GetTlv(mTlvs), (cur + 1 <= GetTlvsEnd()) && (cur->GetNext() <= GetTlvsEnd()); @@ -160,14 +164,13 @@ Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfi switch (cur->GetType()) { case NetworkDataTlv::kTypePrefix: - if ((aConfig.mOnMeshPrefix != nullptr) || (aConfig.mExternalRoute != nullptr) || - (aConfig.mLowpanContext != nullptr)) + if (shouldIterateOverPrefixTlvs && As(cur)->IsValid()) { subTlvs = As(cur)->GetSubTlvs(); } break; case NetworkDataTlv::kTypeService: - if (aConfig.mService != nullptr) + if ((aConfig.mService != nullptr) && As(cur)->IsValid()) { subTlvs = As(cur)->GetSubTlvs(); } @@ -249,7 +252,7 @@ Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfi { const ContextTlv *contextTlv = As(subCur); - if (aConfig.mLowpanContext == nullptr) + if ((aConfig.mLowpanContext == nullptr) || !contextTlv->IsValid()) { continue; } @@ -285,7 +288,7 @@ Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfi { const ServerTlv *server = As(subCur); - if (!iterator.IsNewEntry()) + if (!iterator.IsNewEntry() || !server->IsValid()) { continue; } diff --git a/src/core/thread/network_data_tlvs.cpp b/src/core/thread/network_data_tlvs.cpp index 8a4330a03..b097a151a 100644 --- a/src/core/thread/network_data_tlvs.cpp +++ b/src/core/thread/network_data_tlvs.cpp @@ -39,13 +39,40 @@ namespace NetworkData { //--------------------------------------------------------------------------------------------------------------------- // NetworkDataTlv +bool NetworkDataTlv::IsTlvValid(const NetworkDataTlv *aTlv) +{ + bool isValid = true; + + switch (aTlv->GetType()) + { + case kTypePrefix: + isValid = As(aTlv)->IsValid(); + break; + case kTypeContext: + isValid = As(aTlv)->IsValid(); + break; + case kTypeService: + isValid = As(aTlv)->IsValid(); + break; + case kTypeServer: + isValid = As(aTlv)->IsValid(); + break; + case kTypeHasRoute: + case kTypeBorderRouter: + case kTypeCommissioningData: + break; + } + + return isValid; +} + const NetworkDataTlv *NetworkDataTlv::Find(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd, Type aType) { const NetworkDataTlv *tlv; for (tlv = aStart; (tlv + 1 <= aEnd) && (tlv->GetNext() <= aEnd); tlv = tlv->GetNext()) { - if (tlv->GetType() == aType) + if ((tlv->GetType() == aType) && IsTlvValid(tlv)) { ExitNow(); } @@ -66,7 +93,7 @@ const NetworkDataTlv *NetworkDataTlv::Find(const NetworkDataTlv *aStart, for (tlv = aStart; (tlv + 1 <= aEnd) && (tlv->GetNext() <= aEnd); tlv = tlv->GetNext()) { - if ((tlv->GetType() == aType) && (tlv->IsStable() == aStable)) + if ((tlv->GetType() == aType) && (tlv->IsStable() == aStable) && IsTlvValid(tlv)) { ExitNow(); } diff --git a/src/core/thread/network_data_tlvs.hpp b/src/core/thread/network_data_tlvs.hpp index 73fd6cd3a..d51a8e5f9 100644 --- a/src/core/thread/network_data_tlvs.hpp +++ b/src/core/thread/network_data_tlvs.hpp @@ -363,6 +363,8 @@ private: static constexpr uint8_t kTypeMask = 0x7f << kTypeOffset; static constexpr uint8_t kStableMask = 1 << 0; + static bool IsTlvValid(const NetworkDataTlv *aTlv); + uint8_t mType; uint8_t mLength; } OT_TOOL_PACKED_END; @@ -1119,6 +1121,14 @@ public: mContextLength = aContextLength; } + /** + * Indicates whether or not the TLV appears to be well-formed. + * + * @retval TRUE If the TLV appears to be well-formed. + * @retval FALSE If the TLV does not appear to be well-formed. + */ + bool IsValid(void) const { return GetLength() >= sizeof(*this) - sizeof(NetworkDataTlv); } + /** * Indicates whether or not the Compress flag is set. * diff --git a/tests/unit/test_network_data.cpp b/tests/unit/test_network_data.cpp index 589e162be..87f4e72e2 100644 --- a/tests/unit/test_network_data.cpp +++ b/tests/unit/test_network_data.cpp @@ -117,9 +117,25 @@ void TestNetworkDataIterator(void) VerifyOrQuit(instance != nullptr); { + // Network Data: + // - An invalid TLV type. + // - An invalid Prefix TLV with prefix length of 129 (and two HasRoute sub-TLVs). + // - An invalid Prefix TLV with short length (length = 1) + // - An invalid Prefix TLV with no prefix. + // - A valid Prefix TLV with two HasRoute sub-TLVs + 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, + 0xff, 0x03, 0x01, 0x02, 0x03, + + 0x03, 0x1D, 0x00, 0x81, 0xFD, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, + 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x03, 0xb8, 0x00, 0x40, 0x01, 0x03, 0x14, 0x00, 0x00, + + 0x03, 0x01, 0x00, + + 0x03, 0x02, 0x00, 0x40, + + 0x03, 0x14, 0x00, 0x40, 0xFD, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC8, 0x00, + 0x40, 0x01, 0x03, 0x54, 0x00, 0x00, }; otExternalRouteConfig routes[] = { @@ -168,6 +184,8 @@ void TestNetworkDataIterator(void) VerifyOrQuit(CompareExternalRouteConfig(rconfig, route)); } + VerifyOrQuit(netData.GetNextExternalRoute(iter, rconfig) == kErrorNotFound); + netData.FindRlocs(kAnyBrOrServer, kAnyRole, rlocs); VerifyRlocsArray(rlocs, kRlocs); @@ -667,7 +685,9 @@ void TestNetworkDataDsnSrpServices(void) }; const uint8_t kNetworkData[] = { - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x28, 0x00, + 0x0b, 0x01, 0x00, + + 0x0b, 0x0b, 0x80, 0x02, 0x5c, 0x02, 0x0d, 0x01, 0x00, 0x0d, 0x02, 0x28, 0x00, 0x0b, 0x09, 0x81, 0x02, 0x5c, 0xff, 0x0d, 0x03, 0x6c, 0x00, 0x05,