From 9cc1cd9e58995f8fb0748b1b2264a45f3dd13242 Mon Sep 17 00:00:00 2001 From: Cristian Bulacu <127317648+Cristib05@users.noreply.github.com> Date: Sat, 8 Jun 2024 00:01:50 +0300 Subject: [PATCH 01/65] [mdns] add support for legacy unicast response feature (#10053) Signed-off-by: Cristib05 --- src/core/net/mdns.cpp | 143 ++++++++++++++----- src/core/net/mdns.hpp | 37 +++-- tests/unit/test_mdns.cpp | 293 ++++++++++++++++++++++++++++++++++----- 3 files changed, 391 insertions(+), 82 deletions(-) diff --git a/src/core/net/mdns.cpp b/src/core/net/mdns.cpp index 8fe50f77e..75ae2acef 100644 --- a/src/core/net/mdns.cpp +++ b/src/core/net/mdns.cpp @@ -391,12 +391,13 @@ bool Core::NameMatch(const Heap::String &aFirst, const Heap::String &aSecond) return !aSecond.IsNull() && NameMatch(aFirst, aSecond.AsCString()); } -void Core::UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord, Section aSection) +void Core::UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord, Section aSection, bool aIsLegacyUnicast) { - // Do not set the cache-flush flag is the record is - // appended in Authority Section in a probe message. + // Do not set the cache-flush flag if the record is + // appended in Authority Section in a probe message, + // or is intended for a Legacy Unicast response. - if (aSection != kAuthoritySection) + if (aSection != kAuthoritySection && !aIsLegacyUnicast) { aResourceRecord.SetClass(aResourceRecord.GetClass() | kClassCacheFlushFlag); } @@ -579,6 +580,11 @@ void Core::RecordInfo::UpdateProperty(AddressArray &aAddrProperty, const Ip6::Ad } } +uint32_t Core::RecordInfo::GetTtl(bool aIsLegacyUnicast) const +{ + return aIsLegacyUnicast ? Min(kMaxLegacyUnicastTtl, mTtl) : mTtl; +} + void Core::RecordInfo::UpdateTtl(uint32_t aTtl) { return UpdateProperty(mTtl, aTtl); } void Core::RecordInfo::StartAnnouncing(void) @@ -596,7 +602,7 @@ void Core::RecordInfo::ScheduleAnswer(const AnswerInfo &aInfo) { VerifyOrExit(CanAnswer()); - if (aInfo.mUnicastResponse) + if (aInfo.mUnicastResponse || aInfo.mLegacyUnicastResponse) { mUnicastAnswerPending = true; ExitNow(); @@ -647,6 +653,7 @@ bool Core::RecordInfo::ShouldAppendTo(TxMessage &aResponse, TimeMilli aNow) cons break; case TxMessage::kUnicastResponse: + case TxMessage::kLegacyUnicastResponse: shouldAppend = mUnicastAnswerPending; break; @@ -693,6 +700,7 @@ void Core::RecordInfo::UpdateStateAfterAnswer(const TxMessage &aResponse) break; case TxMessage::kUnicastResponse: + case TxMessage::kLegacyUnicastResponse: VerifyOrExit(IsAppended()); VerifyOrExit(mAppendSection == kAnswerSection); mUnicastAnswerPending = false; @@ -765,6 +773,7 @@ void Core::RecordInfo::MarkAsAppended(TxMessage &aTxMessage, Section aSection) break; case TxMessage::kUnicastResponse: + case TxMessage::kLegacyUnicastResponse: mAppendState = kAppendedInUnicastMsg; break; @@ -1229,7 +1238,6 @@ template void Core::Entry::HandleTimer(EntryTimerContext &a case kRemoving: ExitNow(); } - thisAsEntryType->DetermineNextFireTime(); exit: @@ -1258,6 +1266,7 @@ void Core::Entry::AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection, Nam { Message *message; ResourceRecord record; + bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse); VerifyOrExit(mKeyRecord.CanAppend()); mKeyRecord.MarkAsAppended(aTxMessage, aSection); @@ -1270,9 +1279,9 @@ void Core::Entry::AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection, Nam aNameAppender(*this, aTxMessage, aSection); record.Init(ResourceRecord::kTypeKey); - record.SetTtl(mKeyRecord.GetTtl()); record.SetLength(mKeyData.GetLength()); - UpdateCacheFlushFlagIn(record, aSection); + record.SetTtl(mKeyRecord.GetTtl(isLegacyUnicast)); + UpdateCacheFlushFlagIn(record, aSection, isLegacyUnicast); SuccessOrAssert(message->Append(record)); SuccessOrAssert(message->AppendBytes(mKeyData.GetBytes(), mKeyData.GetLength())); @@ -1292,10 +1301,11 @@ void Core::Entry::AppendNsecRecordTo(TxMessage &aTxMessage, NsecRecord nsec; NsecRecord::TypeBitMap bitmap; uint16_t offset; + bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse); nsec.Init(); - nsec.SetTtl(kNsecTtl); - UpdateCacheFlushFlagIn(nsec, aSection); + nsec.SetTtl(isLegacyUnicast ? kLegacyUnicastNsecTtl : kNsecTtl); + UpdateCacheFlushFlagIn(nsec, aSection, isLegacyUnicast); bitmap.Clear(); @@ -1606,6 +1616,7 @@ void Core::HostEntry::DetermineNextFireTime(void) void Core::HostEntry::AppendAddressRecordsTo(TxMessage &aTxMessage, Section aSection) { Message *message; + bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse); VerifyOrExit(mAddrRecord.CanAppend()); mAddrRecord.MarkAsAppended(aTxMessage, aSection); @@ -1617,9 +1628,9 @@ void Core::HostEntry::AppendAddressRecordsTo(TxMessage &aTxMessage, Section aSec AaaaRecord aaaaRecord; aaaaRecord.Init(); - aaaaRecord.SetTtl(mAddrRecord.GetTtl()); aaaaRecord.SetAddress(address); - UpdateCacheFlushFlagIn(aaaaRecord, aSection); + aaaaRecord.SetTtl(mAddrRecord.GetTtl(isLegacyUnicast)); + UpdateCacheFlushFlagIn(aaaaRecord, aSection, isLegacyUnicast); AppendNameTo(aTxMessage, aSection); SuccessOrAssert(message->Append(aaaaRecord)); @@ -2383,6 +2394,7 @@ void Core::ServiceEntry::AppendSrvRecordTo(TxMessage &aTxMessage, Section aSecti Message *message; SrvRecord srv; uint16_t offset; + bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse); VerifyOrExit(mSrvRecord.CanAppend()); mSrvRecord.MarkAsAppended(aTxMessage, aSection); @@ -2390,13 +2402,17 @@ void Core::ServiceEntry::AppendSrvRecordTo(TxMessage &aTxMessage, Section aSecti message = &aTxMessage.SelectMessageFor(aSection); srv.Init(); - srv.SetTtl(mSrvRecord.GetTtl()); srv.SetPriority(mPriority); srv.SetWeight(mWeight); srv.SetPort(mPort); - UpdateCacheFlushFlagIn(srv, aSection); + srv.SetTtl(mSrvRecord.GetTtl(isLegacyUnicast)); + UpdateCacheFlushFlagIn(srv, aSection, isLegacyUnicast); + + // RFC6762, Section 18.14 Name Compression: + // In legacy unicast responses generated to answer legacy queries, name + // compression MUST NOT be performed on SRV records. + AppendServiceNameTo(aTxMessage, aSection, /* aPerformNameCompression */ !isLegacyUnicast); - AppendServiceNameTo(aTxMessage, aSection); offset = message->GetLength(); SuccessOrAssert(message->Append(srv)); AppendHostNameTo(aTxMessage, aSection); @@ -2412,6 +2428,7 @@ void Core::ServiceEntry::AppendTxtRecordTo(TxMessage &aTxMessage, Section aSecti { Message *message; TxtRecord txt; + bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse); VerifyOrExit(mTxtRecord.CanAppend()); mTxtRecord.MarkAsAppended(aTxMessage, aSection); @@ -2419,9 +2436,9 @@ void Core::ServiceEntry::AppendTxtRecordTo(TxMessage &aTxMessage, Section aSecti message = &aTxMessage.SelectMessageFor(aSection); txt.Init(); - txt.SetTtl(mTxtRecord.GetTtl()); txt.SetLength(mTxtData.GetLength()); - UpdateCacheFlushFlagIn(txt, aSection); + txt.SetTtl(mTxtRecord.GetTtl(isLegacyUnicast)); + UpdateCacheFlushFlagIn(txt, aSection, isLegacyUnicast); AppendServiceNameTo(aTxMessage, aSection); SuccessOrAssert(message->Append(txt)); @@ -2442,6 +2459,7 @@ void Core::ServiceEntry::AppendPtrRecordTo(TxMessage &aTxMessage, Section aSecti RecordInfo &ptrRecord = (aSubType == nullptr) ? mPtrRecord : aSubType->mPtrRecord; PtrRecord ptr; uint16_t offset; + bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse); VerifyOrExit(ptrRecord.CanAppend()); ptrRecord.MarkAsAppended(aTxMessage, aSection); @@ -2449,7 +2467,7 @@ void Core::ServiceEntry::AppendPtrRecordTo(TxMessage &aTxMessage, Section aSecti message = &aTxMessage.SelectMessageFor(aSection); ptr.Init(); - ptr.SetTtl(ptrRecord.GetTtl()); + ptr.SetTtl(ptrRecord.GetTtl(isLegacyUnicast)); if (aSubType == nullptr) { @@ -2506,12 +2524,22 @@ void Core::ServiceEntry::AppendEntryName(Entry &aEntry, TxMessage &aTxMessage, S static_cast(aEntry).AppendServiceNameTo(aTxMessage, aSection); } -void Core::ServiceEntry::AppendServiceNameTo(TxMessage &aTxMessage, Section aSection) +void Core::ServiceEntry::AppendServiceNameTo(TxMessage &aTxMessage, Section aSection, bool aPerformNameCompression) { AppendOutcome outcome; - outcome = aTxMessage.AppendLabel(aSection, mServiceInstance.AsCString(), mServiceNameOffset); - VerifyOrExit(outcome != kAppendedFullNameAsCompressed); + if (!aPerformNameCompression) + { + uint16_t compressOffset = kUnspecifiedOffset; + + outcome = aTxMessage.AppendLabel(aSection, mServiceInstance.AsCString(), compressOffset); + VerifyOrExit(outcome == kAppendedLabels); + } + else + { + outcome = aTxMessage.AppendLabel(aSection, mServiceInstance.AsCString(), mServiceNameOffset); + VerifyOrExit(outcome != kAppendedFullNameAsCompressed); + } AppendServiceTypeTo(aTxMessage, aSection); @@ -2775,7 +2803,14 @@ void Core::ServiceType::AppendPtrRecordTo(TxMessage &aResponse, uint16_t aServic message = &aResponse.SelectMessageFor(kAnswerSection); ptr.Init(); - ptr.SetTtl(mServicesPtr.GetTtl()); + if (aResponse.GetType() == TxMessage::kLegacyUnicastResponse) + { + ptr.SetTtl(Min(Core::RecordInfo::kMaxLegacyUnicastTtl, mServicesPtr.GetTtl())); + } + else + { + ptr.SetTtl(mServicesPtr.GetTtl()); + } aResponse.AppendServicesDnssdName(kAnswerSection); offset = message->GetLength(); @@ -2792,19 +2827,19 @@ void Core::ServiceType::AppendPtrRecordTo(TxMessage &aResponse, uint16_t aServic //---------------------------------------------------------------------------------------------------------------------- // Core::TxMessage -Core::TxMessage::TxMessage(Instance &aInstance, Type aType) +Core::TxMessage::TxMessage(Instance &aInstance, Type aType, uint16_t aQueryId) : InstanceLocator(aInstance) { - Init(aType); + Init(aType, aQueryId); } -Core::TxMessage::TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest) - : TxMessage(aInstance, aType) +Core::TxMessage::TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest, uint16_t aQueryId) + : TxMessage(aInstance, aType, aQueryId) { mUnicastDest = aUnicastDest; } -void Core::TxMessage::Init(Type aType) +void Core::TxMessage::Init(Type aType, uint16_t aMessageId) { Header header; @@ -2837,7 +2872,9 @@ void Core::TxMessage::Init(Type aType) break; case kMulticastResponse: case kUnicastResponse: + case kLegacyUnicastResponse: header.SetType(Header::kTypeResponse); + header.SetMessageId(aMessageId); break; } @@ -2864,9 +2901,9 @@ Message &Core::TxMessage::SelectMessageFor(Section aSection) mainSection = kQuestionSection; extraSection = kAnswerSection; break; - - case kMulticastResponse: + case kLegacyUnicastResponse: case kUnicastResponse: + case kMulticastResponse: break; } @@ -3022,6 +3059,16 @@ void Core::TxMessage::AppendServicesDnssdName(Section aSection) return; } +void Core::TxMessage::AddQuestionFrom(const Message &aMessage) +{ + uint16_t offset = sizeof(Header); + + IgnoreError(Name::ParseName(aMessage, offset)); + offset += sizeof(ot::Dns::Question); + SuccessOrAssert(mMsgPtr->AppendBytesFromMessage(aMessage, sizeof(Header), offset - sizeof(Header))); + IncrementRecordCount(kQuestionSection); +} + void Core::TxMessage::SaveOffset(uint16_t &aCompressOffset, const Message &aMessage, Section aSection) { // Saves the current message offset in `aCompressOffset` for name @@ -3147,6 +3194,7 @@ void Core::TxMessage::Send(void) break; case kUnicastResponse: + case kLegacyUnicastResponse: otPlatMdnsSendUnicast(&GetInstance(), mMsgPtr.Release(), &mUnicastDest); break; } @@ -3215,6 +3263,8 @@ void Core::TxMessage::Reinit(void) // compress offset since the host name should not be used // in any other query question. + break; + case kLegacyUnicastResponse: break; } } @@ -3297,11 +3347,12 @@ Error Core::RxMessage::Init(Instance &aInstance, if (aSenderAddress.mPort != kUdpPort) { - if (mIsQuery) + // Simple DNS resolver does not allow more than one question in a query message + if (mIsQuery && header.GetQuestionCount() == 1) { // Section 6.7 Legacy Unicast - LogInfo("We do not yet support legacy unicast message (source port not matching mDNS port)"); - ExitNow(error = kErrorNotCapable); + mIsLegacyUnicast = true; + mQueryId = header.GetMessageId(); } else { @@ -3427,13 +3478,18 @@ Core::RxMessage::ProcessOutcome Core::RxMessage::ProcessQuery(bool aShouldProces { canAnswer = true; - if (question.mUnicastResponse) + if (question.mUnicastResponse || mIsLegacyUnicast) { needUnicastResponse = true; } } } + if (mIsLegacyUnicast) + { + shouldDelay = false; + } + VerifyOrExit(canAnswer); if (mTruncated && !aShouldProcessTruncated) @@ -3569,10 +3625,11 @@ void Core::RxMessage::AnswerQuestion(const Question &aQuestion, TimeMilli aAnswe VerifyOrExit(aQuestion.mCanAnswer); - answerInfo.mQuestionRrType = aQuestion.mRrType; - answerInfo.mAnswerTime = aAnswerTime; - answerInfo.mIsProbe = aQuestion.mIsProbe; - answerInfo.mUnicastResponse = aQuestion.mUnicastResponse; + answerInfo.mQuestionRrType = aQuestion.mRrType; + answerInfo.mAnswerTime = aAnswerTime; + answerInfo.mIsProbe = aQuestion.mIsProbe; + answerInfo.mUnicastResponse = aQuestion.mUnicastResponse; + answerInfo.mLegacyUnicastResponse = mIsLegacyUnicast; if (aQuestion.mIsForAllServicesDnssd) { @@ -3790,7 +3847,17 @@ bool Core::RxMessage::ShouldSuppressKnownAnswer(const Question &aQuestion, const void Core::RxMessage::SendUnicastResponse(const AddressInfo &aUnicastDest) { - TxMessage response(GetInstance(), TxMessage::kUnicastResponse, aUnicastDest); + TxMessage response(GetInstance(), + mIsLegacyUnicast ? TxMessage::kLegacyUnicastResponse : TxMessage::kUnicastResponse, aUnicastDest, + mIsLegacyUnicast ? mQueryId : 0); + + if (mIsLegacyUnicast) + { + // RFC6762, section 6.7: + // Legacy Unicast Response must repeat the question + response.AddQuestionFrom(*mMessagePtr); + } + TimeMilli now = TimerMilli::GetNow(); for (HostEntry &entry : Get().mHostEntries) diff --git a/src/core/net/mdns.hpp b/src/core/net/mdns.hpp index 1065bf160..5a8ede1ec 100644 --- a/src/core/net/mdns.hpp +++ b/src/core/net/mdns.hpp @@ -759,11 +759,12 @@ class Core : public InstanceLocator, private NonCopyable static constexpr uint32_t kMaxInitialQueryDelay = 120; // msec static constexpr uint32_t kRandomDelayReuseInterval = 2; // msec - static constexpr uint32_t kUnspecifiedTtl = 0; - static constexpr uint32_t kDefaultTtl = 120; - static constexpr uint32_t kDefaultKeyTtl = kDefaultTtl; - static constexpr uint32_t kNsecTtl = 4500; - static constexpr uint32_t kServicesPtrTtl = 4500; + static constexpr uint32_t kUnspecifiedTtl = 0; + static constexpr uint32_t kDefaultTtl = 120; + static constexpr uint32_t kDefaultKeyTtl = kDefaultTtl; + static constexpr uint32_t kLegacyUnicastNsecTtl = 10; + static constexpr uint32_t kNsecTtl = 4500; + static constexpr uint32_t kServicesPtrTtl = 4500; static constexpr uint16_t kClassQuestionUnicastFlag = (1U << 15); static constexpr uint16_t kClassCacheFlushFlag = (1U << 15); @@ -858,6 +859,7 @@ class Core : public InstanceLocator, private NonCopyable TimeMilli mAnswerTime; bool mIsProbe; bool mUnicastResponse; + bool mLegacyUnicastResponse; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -896,16 +898,19 @@ class Core : public InstanceLocator, private NonCopyable public: // Keeps track of record state and timings. + static constexpr uint32_t kMaxLegacyUnicastTtl = 10; // seconds + RecordInfo(void) { Clear(); } - bool IsPresent(void) const { return mIsPresent; } - uint32_t GetTtl(void) const { return mTtl; } + bool IsPresent(void) const { return mIsPresent; } template void UpdateProperty(UintType &aProperty, UintType aValue); void UpdateProperty(AddressArray &aAddrProperty, const Ip6::Address *aAddrs, uint16_t aNumAddrs); void UpdateProperty(Heap::String &aStringProperty, const char *aString); void UpdateProperty(Heap::Data &aDataProperty, const uint8_t *aData, uint16_t aLength); - void UpdateTtl(uint32_t aTtl); + + uint32_t GetTtl(bool aIsLegacyUnicast = false) const; + void UpdateTtl(uint32_t aTtl); void StartAnnouncing(void); bool ShouldAppendTo(TxMessage &aResponse, TimeMilli aNow) const; @@ -1162,7 +1167,7 @@ class Core : public InstanceLocator, private NonCopyable void AppendPtrRecordTo(TxMessage &aTxMessage, Section aSection, SubType *aSubType = nullptr); void AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection); void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection); - void AppendServiceNameTo(TxMessage &TxMessage, Section aSection); + void AppendServiceNameTo(TxMessage &TxMessage, Section aSection, bool aPerformNameCompression = true); void AppendServiceTypeTo(TxMessage &aTxMessage, Section aSection); void AppendSubServiceTypeTo(TxMessage &aTxMessage, Section aSection); void AppendSubServiceNameTo(TxMessage &aTxMessage, Section aSection, SubType &aSubType); @@ -1239,10 +1244,11 @@ class Core : public InstanceLocator, private NonCopyable kMulticastQuery, kMulticastResponse, kUnicastResponse, + kLegacyUnicastResponse, }; - TxMessage(Instance &aInstance, Type aType); - TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest); + TxMessage(Instance &aInstance, Type aType, uint16_t aQueryId = 0); + TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest, uint16_t aQueryId = 0); Type GetType(void) const { return mType; } Message &SelectMessageFor(Section aSection); AppendOutcome AppendLabel(Section aSection, const char *aLabel, uint16_t &aCompressOffset); @@ -1250,6 +1256,7 @@ class Core : public InstanceLocator, private NonCopyable void AppendServiceType(Section aSection, const char *aServiceType, uint16_t &aCompressOffset); void AppendDomainName(Section aSection); void AppendServicesDnssdName(Section aSection); + void AddQuestionFrom(const Message &aMessage); void IncrementRecordCount(Section aSection) { mRecordCounts.Increment(aSection); } void CheckSizeLimitToPrepareAgain(bool &aPrepareAgain); void SaveCurrentState(void); @@ -1259,7 +1266,7 @@ class Core : public InstanceLocator, private NonCopyable private: static constexpr bool kIsSingleLabel = true; - void Init(Type aType); + void Init(Type aType, uint16_t aMessageId = 0); void Reinit(void); bool IsOverSizeLimit(void) const; AppendOutcome AppendLabels(Section aSection, @@ -1382,8 +1389,10 @@ class Core : public InstanceLocator, private NonCopyable AddressInfo mSenderAddress; RecordCounts mRecordCounts; uint16_t mStartOffset[kNumSections]; + uint16_t mQueryId; bool mIsQuery : 1; bool mIsUnicast : 1; + bool mIsLegacyUnicast : 1; bool mTruncated : 1; bool mIsSelfOriginating : 1; }; @@ -1984,7 +1993,9 @@ class Core : public InstanceLocator, private NonCopyable static uint32_t DetermineTtl(uint32_t aTtl, uint32_t aDefaultTtl); static bool NameMatch(const Heap::String &aHeapString, const char *aName); static bool NameMatch(const Heap::String &aFirst, const Heap::String &aSecond); - static void UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord, Section aSection); + static void UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord, + Section aSection, + bool aIsLegacyUnicast = false); static void UpdateRecordLengthInMessage(ResourceRecord &aRecord, Message &aMessage, uint16_t aOffset); static void UpdateCompressOffset(uint16_t &aOffset, uint16_t aNewOffse); static bool QuestionMatches(uint16_t aQuestionRrType, uint16_t aRrType); diff --git a/tests/unit/test_mdns.cpp b/tests/unit/test_mdns.cpp index 1dd114e96..2f1fb562b 100644 --- a/tests/unit/test_mdns.cpp +++ b/tests/unit/test_mdns.cpp @@ -62,17 +62,20 @@ namespace Multicast { //--------------------------------------------------------------------------------------------------------------------- // Constants -static constexpr uint16_t kClassQueryUnicastFlag = (1U << 15); -static constexpr uint16_t kClassCacheFlushFlag = (1U << 15); -static constexpr uint16_t kClassMask = 0x7fff; -static constexpr uint16_t kStringSize = 300; -static constexpr uint16_t kMaxDataSize = 400; -static constexpr uint16_t kNumAnnounces = 3; -static constexpr uint16_t kNumInitalQueries = 3; -static constexpr uint16_t kNumRefreshQueries = 4; -static constexpr bool kCacheFlush = true; -static constexpr uint16_t kMdnsPort = 5353; -static constexpr uint32_t kInfraIfIndex = 1; +static constexpr uint16_t kClassQueryUnicastFlag = (1U << 15); +static constexpr uint16_t kClassCacheFlushFlag = (1U << 15); +static constexpr uint16_t kClassMask = 0x7fff; +static constexpr uint16_t kStringSize = 300; +static constexpr uint16_t kMaxDataSize = 400; +static constexpr uint16_t kNumAnnounces = 3; +static constexpr uint16_t kNumInitalQueries = 3; +static constexpr uint16_t kNumRefreshQueries = 4; +static constexpr bool kCacheFlush = true; +static constexpr uint16_t kMdnsPort = 5353; +static constexpr uint16_t kEphemeralPort = 49152; +static constexpr uint16_t kLegacyUnicastMessageId = 1; +static constexpr uint16_t kMaxLegacyUnicastTtl = 10; +static constexpr uint32_t kInfraIfIndex = 1; static const char kDeviceIp6Address[] = "fd01::1"; @@ -209,6 +212,7 @@ enum TtlCheckMode : uint8_t { kZeroTtl, kNonZeroTtl, + kLegacyUnicastTtl, }; enum Section : uint8_t @@ -372,6 +376,9 @@ struct DnsRecord : public Allocatable, public LinkedListEntry 0); break; + case kLegacyUnicastTtl: + VerifyOrQuit(mTtl <= kMaxLegacyUnicastTtl); + break; } matches = true; @@ -571,6 +578,7 @@ enum DnsMessageType : uint8_t kMulticastQuery, kMulticastResponse, kUnicastResponse, + kLegacyUnicastResponse, }; struct DnsMessage : public Allocatable, public LinkedListEntry @@ -682,9 +690,15 @@ struct DnsMessage : public Allocatable, public LinkedListEntry, public LinkedListEntry, public LinkedListEntry, public LinkedListEntry, public LinkedListEntry, public LinkedListEntry, public LinkedListEntry, public LinkedListEntrymType = kUnicastResponse; + msg->mType = (aUnicastDest->mPort == kEphemeralPort) ? kLegacyUnicastResponse : kUnicastResponse; msg->mUnicastDest = *aUnicastDest; } } @@ -1045,8 +1090,9 @@ static void ParseMessage(const Message &aMessage, const Core::AddressInfo *aUnic static void SendQuery(const char *aName, uint16_t aRecordType, - uint16_t aRecordClass = ResourceRecord::kClassInternet, - bool aTruncated = false) + uint16_t aRecordClass = ResourceRecord::kClassInternet, + bool aTruncated = false, + bool aLegacyUnicastQuery = false) { Message *message; Header header; @@ -1059,6 +1105,11 @@ static void SendQuery(const char *aName, header.SetType(Header::kTypeQuery); header.SetQuestionCount(1); + if (aLegacyUnicastQuery) + { + header.SetMessageId(kLegacyUnicastMessageId); + } + if (aTruncated) { header.SetTruncationFlag(); @@ -1069,7 +1120,7 @@ static void SendQuery(const char *aName, SuccessOrQuit(message->Append(Question(aRecordType, aRecordClass))); SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address)); - senderAddrInfo.mPort = kMdnsPort; + senderAddrInfo.mPort = aLegacyUnicastQuery ? kEphemeralPort : kMdnsPort; senderAddrInfo.mInfraIfIndex = 0; Log("Sending query for %s %s", aName, RecordTypeToString(aRecordType)); @@ -1077,7 +1128,11 @@ static void SendQuery(const char *aName, otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo); } -static void SendQueryForTwo(const char *aName1, uint16_t aRecordType1, const char *aName2, uint16_t aRecordType2) +static void SendQueryForTwo(const char *aName1, + uint16_t aRecordType1, + const char *aName2, + uint16_t aRecordType2, + bool aIsLegacyUnicast = false) { // Send query with two questions. @@ -1099,7 +1154,7 @@ static void SendQueryForTwo(const char *aName1, uint16_t aRecordType1, const cha SuccessOrQuit(message->Append(Question(aRecordType2, ResourceRecord::kClassInternet))); SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address)); - senderAddrInfo.mPort = kMdnsPort; + senderAddrInfo.mPort = aIsLegacyUnicast ? kEphemeralPort : kMdnsPort; senderAddrInfo.mInfraIfIndex = 0; Log("Sending query for %s %s and %s %s", aName1, RecordTypeToString(aRecordType1), aName2, @@ -6877,6 +6932,181 @@ void TestPassiveCache(void) testFreeInstance(sInstance); } +void TestLegacyUnicastResponse(void) +{ + Core *mdns = InitTest(); + Core::Host host; + Core::Service service; + const DnsMessage *dnsMsg; + uint16_t heapAllocations; + DnsNameString fullServiceName; + DnsNameString fullServiceType; + DnsNameString hostFullName; + Ip6::Address hostAddresses[2]; + + Log("-------------------------------------------------------------------------------------------"); + Log("TestLegacyUnicastResponse"); + + AdvanceTime(1); + + heapAllocations = sHeapAllocatedPtrs.GetLength(); + SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex)); + + SuccessOrQuit(hostAddresses[0].FromString("fd00::1:aaaa")); + SuccessOrQuit(hostAddresses[1].FromString("fd00::1:bbbb")); + host.mHostName = "host"; + host.mAddresses = hostAddresses; + host.mAddressesLength = 2; + host.mTtl = 1500; + hostFullName.Append("%s.local.", host.mHostName); + + service.mHostName = host.mHostName; + service.mServiceInstance = "myservice"; + service.mServiceType = "_srv._udp"; + service.mSubTypeLabels = nullptr; + service.mSubTypeLabelsLength = 0; + service.mTxtData = kTxtData1; + service.mTxtDataLength = sizeof(kTxtData1); + service.mPort = 1234; + service.mPriority = 1; + service.mWeight = 2; + service.mTtl = 1000; + + fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType); + fullServiceType.Append("%s.local.", service.mServiceType); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + + sDnsMessages.Clear(); + + for (RegCallback ®Callbck : sRegCallbacks) + { + regCallbck.Reset(); + } + + SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback)); + SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback)); + + AdvanceTime(10 * 1000); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + Log("Send a query with two questions (SRV for service1 and AAAA for host). Validate that no response is sent"); + + AdvanceTime(2000); + + sDnsMessages.Clear(); + SendQueryForTwo(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, hostFullName.AsCString(), + ResourceRecord::kTypeAaaa, /* aIsLegacyUnicast */ true); + + AdvanceTime(200); + + dnsMsg = sDnsMessages.GetHead(); + VerifyOrQuit(dnsMsg == nullptr); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + Log("Send a query for SRV record and validate the response"); + + AdvanceTime(2000); + + sDnsMessages.Clear(); + SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, ResourceRecord::kClassInternet, + /* aTruncated */ false, + /* aLegacyUnicastQuery */ true); + + AdvanceTime(1000); + + dnsMsg = sDnsMessages.GetHead(); + VerifyOrQuit(dnsMsg != nullptr); + dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 3); + dnsMsg->Validate(service, kInAnswerSection, kCheckSrv); + dnsMsg->Validate(host, kInAdditionalSection); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + Log("Send a query for TXT record and validate the response"); + + AdvanceTime(2000); + + sDnsMessages.Clear(); + SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeTxt, ResourceRecord::kClassInternet, + /* aTruncated */ false, + /* aLegacyUnicastQuery */ true); + + AdvanceTime(1000); + + dnsMsg = sDnsMessages.GetHead(); + VerifyOrQuit(dnsMsg != nullptr); + dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1); + dnsMsg->Validate(service, kInAnswerSection, kCheckTxt); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + Log("Send a query for ANY record and validate the response"); + + AdvanceTime(2000); + + sDnsMessages.Clear(); + SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeAny, ResourceRecord::kClassInternet, + /* aTruncated */ false, + /* aLegacyUnicastQuery */ true); + + AdvanceTime(1000); + + dnsMsg = sDnsMessages.GetHead(); + VerifyOrQuit(dnsMsg != nullptr); + dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 3); + dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt); + dnsMsg->Validate(host, kInAdditionalSection); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + Log("Send a query for PTR record for service type and validate the response"); + + AdvanceTime(2000); + + sDnsMessages.Clear(); + SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet, + /* aTruncated */ false, + /* aLegacyUnicastQuery */ true); + + AdvanceTime(1000); + + dnsMsg = sDnsMessages.GetHead(); + VerifyOrQuit(dnsMsg != nullptr); + dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4); + dnsMsg->Validate(service, kInAnswerSection, kCheckPtr); + dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt); + dnsMsg->Validate(host, kInAdditionalSection); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + Log("Send a query for non-existing record and validate the response with NSEC"); + + AdvanceTime(2000); + + sDnsMessages.Clear(); + SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeA, ResourceRecord::kClassInternet, /* aTruncated */ false, + /* aLegacyUnicastQuery */ true); + + AdvanceTime(1000); + + dnsMsg = sDnsMessages.GetHead(); + VerifyOrQuit(dnsMsg != nullptr); + dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1); + VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeAaaa)); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + + sDnsMessages.Clear(); + + SuccessOrQuit(mdns->UnregisterHost(host)); + + AdvanceTime(15000); + + SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex)); + VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations); + + Log("End of test"); + + testFreeInstance(sInstance); +} + } // namespace Multicast } // namespace Dns } // namespace ot @@ -6904,6 +7134,7 @@ int main(void) ot::Dns::Multicast::TestTxtResolver(); ot::Dns::Multicast::TestIp6AddrResolver(); ot::Dns::Multicast::TestPassiveCache(); + ot::Dns::Multicast::TestLegacyUnicastResponse(); printf("All tests passed\n"); #else From 22ee728ac77531422fbdf25a8fe7a31964ad7358 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Sat, 8 Jun 2024 05:03:45 +0800 Subject: [PATCH 02/65] [ncp] add property to instruct NCP to leave gracefully (#10337) This commit adds a new property SPINEL_PROP_NET_LEAVE_GRACEFULLY. The host can trigger otThreadDetachGracefully by setting this spinel property. Hence a SetProperty handler is implemented for this property. A GetProperty handler is also added for this property for a property response. --- src/lib/spinel/spinel.c | 1 + src/lib/spinel/spinel.h | 6 ++++++ src/ncp/changed_props_set.cpp | 1 + src/ncp/ncp_base.hpp | 4 ++++ src/ncp/ncp_base_dispatcher.cpp | 4 ++++ src/ncp/ncp_base_mtd.cpp | 18 ++++++++++++++++++ 6 files changed, 34 insertions(+) diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index 683e58fdf..03c107c5a 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1287,6 +1287,7 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) {SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING, "NET_REQUIRE_JOIN_EXISTING"}, {SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME, "NET_KEY_SWITCH_GUARDTIME"}, {SPINEL_PROP_NET_PSKC, "NET_PSKC"}, + {SPINEL_PROP_NET_LEAVE_GRACEFULLY, "NET_LEAVE_GRACEFULLY"}, {SPINEL_PROP_THREAD_LEADER_ADDR, "THREAD_LEADER_ADDR"}, {SPINEL_PROP_THREAD_PARENT, "THREAD_PARENT"}, {SPINEL_PROP_THREAD_CHILD_TABLE, "THREAD_CHILD_TABLE"}, diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index 4d5fc28d9..9941dba75 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -2370,6 +2370,12 @@ enum */ SPINEL_PROP_NET_PSKC = SPINEL_PROP_NET__BEGIN + 11, + /// Instruct NCP to leave the current network gracefully + /** Format Empty - Write only + * + */ + SPINEL_PROP_NET_LEAVE_GRACEFULLY = SPINEL_PROP_NET__BEGIN + 12, + SPINEL_PROP_NET__END = 0x50, SPINEL_PROP_NET_EXT__BEGIN = 0x1400, diff --git a/src/ncp/changed_props_set.cpp b/src/ncp/changed_props_set.cpp index 9e847f05c..f81bbf0d1 100644 --- a/src/ncp/changed_props_set.cpp +++ b/src/ncp/changed_props_set.cpp @@ -77,6 +77,7 @@ const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] = { {SPINEL_PROP_NET_XPANID, SPINEL_STATUS_OK, true}, {SPINEL_PROP_NET_NETWORK_KEY, SPINEL_STATUS_OK, true}, {SPINEL_PROP_NET_PSKC, SPINEL_STATUS_OK, true}, + {SPINEL_PROP_NET_LEAVE_GRACEFULLY, SPINEL_STATUS_OK, false}, {SPINEL_PROP_PHY_CHAN_SUPPORTED, SPINEL_STATUS_OK, true}, #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE {SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_STATUS_OK, true}, diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 7b8d94f87..676b7b3ba 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -615,6 +615,10 @@ class NcpBase #endif // OPENTHREAD_ENABLE_NCP_VENDOR_HOOK + static void ThreadDetachGracefullyHandler(void *aContext); + + void ThreadDetachGracefullyHandler(void); + protected: static NcpBase *sNcpInstance; static spinel_status_t ThreadErrorToSpinelStatus(otError aError); diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index 112f5022f..167b7348a 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -100,6 +100,7 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) #if OPENTHREAD_FTD OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_NET_PSKC), #endif + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_NET_LEAVE_GRACEFULLY), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_THREAD_LEADER_ADDR), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_THREAD_PARENT), #if OPENTHREAD_FTD @@ -452,6 +453,9 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME), #if OPENTHREAD_FTD OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_NET_PSKC), +#endif + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_NET_LEAVE_GRACEFULLY), +#if OPENTHREAD_FTD OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT), #endif OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_ASSISTING_PORTS), diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 227ce61ce..07047217f 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -4552,6 +4552,24 @@ template <> otError NcpBase::HandlePropertySet(voi return error; } +template <> otError NcpBase::HandlePropertyGet(void) { return OT_ERROR_NONE; } + +template <> otError NcpBase::HandlePropertySet(void) +{ + return otThreadDetachGracefully(mInstance, ThreadDetachGracefullyHandler, this); +} + +void NcpBase::ThreadDetachGracefullyHandler(void *aContext) +{ + static_cast(aContext)->ThreadDetachGracefullyHandler(); +} + +void NcpBase::ThreadDetachGracefullyHandler(void) +{ + mChangedPropsSet.AddProperty(SPINEL_PROP_NET_LEAVE_GRACEFULLY); + mUpdateChangedPropsTask.Post(); +} + // ---------------------------------------------------------------------------- // MARK: Property/Status Changed // ---------------------------------------------------------------------------- From dd1e5f426db3f5a350b80aaf350a7224429144d8 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 7 Jun 2024 14:04:32 -0700 Subject: [PATCH 03/65] [mle] add `Mle::RxMessage::ReadAndSave{Active/Pending}Dataset()` (#10348) This commit adds `ReadAndSave{Active/Pending}Dataset()` helper methods to `Mle::RxMessage` to read the Active or Pending Dataset from a received MLE message and save it in the corresponding `DatasetManager`. This commit also refactors the code for parsing the MLE TLVs, moving it from `DatasetManager` to the `Mle` class for better alignment of responsibilities. --- src/core/meshcop/dataset_manager.cpp | 16 ------- src/core/meshcop/dataset_manager.hpp | 17 ------- src/core/thread/mle.cpp | 69 ++++++++++++++++++++-------- src/core/thread/mle.hpp | 5 +- 4 files changed, 53 insertions(+), 54 deletions(-) diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index ec6e89077..87fddbaf7 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -267,22 +267,6 @@ void DatasetManager::Clear(void) SignalDatasetChange(); } -Error DatasetManager::Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength) -{ - Error error = kErrorNone; - Dataset dataset; - - SuccessOrExit(error = dataset.SetFrom(aMessage, aOffset, aLength)); - SuccessOrExit(error = dataset.ValidateTlvs()); - - SuccessOrExit(error = dataset.WriteTimestamp(mType, aTimestamp)); - - error = Save(dataset); - -exit: - return error; -} - Error DatasetManager::Save(const Dataset &aDataset, bool aAllowOlderTimestamp) { Error error = kErrorNone; diff --git a/src/core/meshcop/dataset_manager.hpp b/src/core/meshcop/dataset_manager.hpp index 87c9544e6..edb63f5c0 100644 --- a/src/core/meshcop/dataset_manager.hpp +++ b/src/core/meshcop/dataset_manager.hpp @@ -162,23 +162,6 @@ class DatasetManager : public InstanceLocator */ Error Save(const Dataset &aDataset) { return Save(aDataset, /* aAllowOlderTimestamp */ false); } - /** - * Sets the Operational Dataset for the partition read from a given message. - * - * Also updates the non-volatile local version if the partition's Operational Dataset is newer. If Active - * Operational Dataset is changed, applies the configuration to to Thread interface. - * - * @param[in] aTimestamp The timestamp for the Operational Dataset. - * @param[in] aMessage The message to read from. - * @param[in] aOffset The offset where the Operational Dataset begins. - * @param[in] aLength The length of the Operational Dataset. - * - * @retval kErrorNone Successfully parsed the Dataset from the @p aMessage and saved it. - * @retval kErrorParse Could not parse the Dataset from @p aMessage. - * - */ - Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength); - /** * Retrieves the channel mask from local dataset. * diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 516a4f9b6..838ff8ef2 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -2999,19 +2999,16 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo) { // We previously confirmed the message contains an // Active or a Pending Dataset TLV before setting the - // corresponding `saveDataset` flag, so we can safely - // `IgnoreError()` on `FindTlvValueOffset()`. + // corresponding `saveDataset` flag. if (saveActiveDataset) { - IgnoreError(Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kActiveDataset, offset, length)); - IgnoreError(Get().Save(activeTimestamp, aRxInfo.mMessage, offset, length)); + IgnoreError(aRxInfo.mMessage.ReadAndSaveActiveDataset(activeTimestamp)); } if (savePendingDataset) { - IgnoreError(Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kPendingDataset, offset, length)); - IgnoreError(Get().Save(pendingTimestamp, aRxInfo.mMessage, offset, length)); + IgnoreError(aRxInfo.mMessage.ReadAndSavePendingDataset(pendingTimestamp)); } } @@ -3313,8 +3310,6 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) MeshCoP::Timestamp timestamp; uint16_t networkDataOffset; uint16_t networkDataLength; - uint16_t offset; - uint16_t length; SuccessOrExit(error = Tlv::Find(aRxInfo.mMessage, sourceAddress)); @@ -3335,11 +3330,9 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) switch (Tlv::Find(aRxInfo.mMessage, timestamp)) { case kErrorNone: - if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kActiveDataset, offset, length) == kErrorNone) - { - SuccessOrExit(error = - Get().Save(timestamp, aRxInfo.mMessage, offset, length)); - } + error = aRxInfo.mMessage.ReadAndSaveActiveDataset(timestamp); + error = (error == kErrorNotFound) ? kErrorNone : error; + SuccessOrExit(error); break; case kErrorNotFound: @@ -3358,10 +3351,7 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) switch (Tlv::Find(aRxInfo.mMessage, timestamp)) { case kErrorNone: - if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kPendingDataset, offset, length) == kErrorNone) - { - IgnoreError(Get().Save(timestamp, aRxInfo.mMessage, offset, length)); - } + IgnoreError(aRxInfo.mMessage.ReadAndSavePendingDataset(timestamp)); break; case kErrorNotFound: @@ -4907,13 +4897,13 @@ Error Mle::TxMessage::AppendActiveDatasetTlv(void) { return AppendDatasetTlv(Mes Error Mle::TxMessage::AppendPendingDatasetTlv(void) { return AppendDatasetTlv(MeshCoP::Dataset::kPending); } -Error Mle::TxMessage::AppendDatasetTlv(MeshCoP::Dataset::Type mDatasetType) +Error Mle::TxMessage::AppendDatasetTlv(MeshCoP::Dataset::Type aDatasetType) { Error error = kErrorNotFound; Tlv::Type tlvType; MeshCoP::Dataset dataset; - switch (mDatasetType) + switch (aDatasetType) { case MeshCoP::Dataset::kActive: error = Get().Read(dataset); @@ -4938,7 +4928,7 @@ Error Mle::TxMessage::AppendDatasetTlv(MeshCoP::Dataset::Type mDatasetType) // message. The Timestamp is appended as its own MLE TLV to the // message. - dataset.RemoveTimestamp(mDatasetType); + dataset.RemoveTimestamp(aDatasetType); error = Tlv::AppendTlv(*this, tlvType, dataset.GetBytes(), dataset.GetLength()); @@ -5074,6 +5064,45 @@ Error Mle::RxMessage::ReadLeaderDataTlv(LeaderData &aLeaderData) const return error; } +Error Mle::RxMessage::ReadAndSaveActiveDataset(const MeshCoP::Timestamp &aActiveTimestamp) const +{ + return ReadAndSaveDataset(MeshCoP::Dataset::kActive, aActiveTimestamp); +} + +Error Mle::RxMessage::ReadAndSavePendingDataset(const MeshCoP::Timestamp &aPendingTimestamp) const +{ + return ReadAndSaveDataset(MeshCoP::Dataset::kPending, aPendingTimestamp); +} + +Error Mle::RxMessage::ReadAndSaveDataset(MeshCoP::Dataset::Type aDatasetType, + const MeshCoP::Timestamp &aTimestamp) const +{ + Error error = kErrorNone; + Tlv::Type tlvType = (aDatasetType == MeshCoP::Dataset::kActive) ? Tlv::kActiveDataset : Tlv::kPendingDataset; + MeshCoP::Dataset dataset; + uint16_t offset; + uint16_t length; + + SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, tlvType, offset, length)); + + SuccessOrExit(error = dataset.SetFrom(*this, offset, length)); + SuccessOrExit(error = dataset.ValidateTlvs()); + SuccessOrExit(error = dataset.WriteTimestamp(aDatasetType, aTimestamp)); + + switch (aDatasetType) + { + case MeshCoP::Dataset::kActive: + error = Get().Save(dataset); + break; + case MeshCoP::Dataset::kPending: + error = Get().Save(dataset); + break; + } + +exit: + return error; +} + Error Mle::RxMessage::ReadTlvRequestTlv(TlvList &aTlvList) const { Error error; diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 7633ffbd2..318648b5e 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1055,7 +1055,7 @@ class Mle : public InstanceLocator, private NonCopyable private: Error AppendCompressedAddressEntry(uint8_t aContextId, const Ip6::Address &aAddress); Error AppendAddressEntry(const Ip6::Address &aAddress); - Error AppendDatasetTlv(MeshCoP::Dataset::Type mDatasetType); + Error AppendDatasetTlv(MeshCoP::Dataset::Type aDatasetType); }; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1072,6 +1072,8 @@ class Mle : public InstanceLocator, private NonCopyable Error ReadFrameCounterTlvs(uint32_t &aLinkFrameCounter, uint32_t &aMleFrameCounter) const; Error ReadTlvRequestTlv(TlvList &aTlvList) const; Error ReadLeaderDataTlv(LeaderData &aLeaderData) const; + Error ReadAndSaveActiveDataset(const MeshCoP::Timestamp &aActiveTimestamp) const; + Error ReadAndSavePendingDataset(const MeshCoP::Timestamp &aPendingTimestamp) const; #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE Error ReadCslClockAccuracyTlv(Mac::CslAccuracy &aCslAccuracy) const; #endif @@ -1081,6 +1083,7 @@ class Mle : public InstanceLocator, private NonCopyable private: Error ReadChallengeOrResponse(uint8_t aTlvType, RxChallenge &aRxChallenge) const; + Error ReadAndSaveDataset(MeshCoP::Dataset::Type aDatasetType, const MeshCoP::Timestamp &aTimestamp) const; }; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From a8f07b57cf2514775e2d523904b7c60f3e28a7e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 09:11:26 -0700 Subject: [PATCH 04/65] github-actions: bump docker/login-action from 3.1.0 to 3.2.0 (#10356) Bumps [docker/login-action](https://github.com/docker/login-action) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/e92390c5fb421da1463c202d546fed0ec5c39f20...0d4c9c5ea7693da7b068278f7b52bda2a190a446) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index bc4cf09e1..45bc98021 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -91,7 +91,7 @@ jobs: - name: Login to DockerHub if: success() && github.repository == 'openthread/openthread' && github.event_name != 'pull_request' - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 + uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} From 5dbbab175b7bce8ace84c42ebc1e0b26e729dc48 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 10 Jun 2024 12:16:24 -0700 Subject: [PATCH 05/65] [dnssd-server] implement DNS-SD discovery proxy functionality in core (#10050) This commit implements a generic discovery proxy in the DNS-SD server. It uses a set of newly added `otPlatDnssd` platform DNS-SD(mDNS) APIs to start or stop browsers, SRV/TXT resolvers, and IPv6/IPv4 address resolvers. These APIs closely match the native OpenThread mDNS implementation. OpenThread DNS-SD's existing `QueryCallback` mechanism, enabling customized discovery proxy implementations, remains supported. This commit includes a comprehensive unit test. This test validates the discovery proxy's behavior, covering: standard use cases, request timeout, s hared resolver/browser usage for multiple queries with the same name, filtering of invalid addresses, and various edge cases. --- etc/cmake/options.cmake | 1 + examples/platforms/simulation/dnssd.c | 60 + include/openthread/instance.h | 2 +- include/openthread/mdns.h | 130 +- include/openthread/platform/dnssd.h | 344 ++- script/check-scan-build | 2 + script/make-pretty | 1 + src/core/border_router/infra_if.cpp | 4 + src/core/config/dnssd_server.h | 10 + src/core/net/dnssd.cpp | 230 +- src/core/net/dnssd.hpp | 135 + src/core/net/dnssd_server.cpp | 861 +++++- src/core/net/dnssd_server.hpp | 154 +- ...openthread-core-toranj-config-simulation.h | 2 + tests/unit/CMakeLists.txt | 1 + tests/unit/test_dnssd_discovery_proxy.cpp | 2723 +++++++++++++++++ tests/unit/test_platform.cpp | 60 + 17 files changed, 4599 insertions(+), 121 deletions(-) create mode 100644 tests/unit/test_dnssd_discovery_proxy.cpp diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index f1b1eb0cd..3eba447c2 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -201,6 +201,7 @@ ot_option(OT_DNS_CLIENT OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE "DNS client") ot_option(OT_DNS_CLIENT_OVER_TCP OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE "Enable dns query over tcp") ot_option(OT_DNS_DSO OPENTHREAD_CONFIG_DNS_DSO_ENABLE "DNS Stateful Operations (DSO)") ot_option(OT_DNS_UPSTREAM_QUERY OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE "Allow sending DNS queries to upstream") +ot_option(OT_DNSSD_DISCOVERY_PROXY OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE "DNS-SD discovery proxy") ot_option(OT_DNSSD_SERVER OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE "DNS-SD server") ot_option(OT_DUA OPENTHREAD_CONFIG_DUA_ENABLE "Domain Unicast Address (DUA)") ot_option(OT_ECDSA OPENTHREAD_CONFIG_ECDSA_ENABLE "ECDSA") diff --git a/examples/platforms/simulation/dnssd.c b/examples/platforms/simulation/dnssd.c index 7967dd487..84fd8a6cf 100644 --- a/examples/platforms/simulation/dnssd.c +++ b/examples/platforms/simulation/dnssd.c @@ -104,4 +104,64 @@ void otPlatDnssdUnregisterKey(otInstance *aInstance, OT_UNUSED_VARIABLE(aCallback); } +void otPlatDnssdStartBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aBrowser); +} + +void otPlatDnssdStopBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aBrowser); +} + +void otPlatDnssdStartSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +void otPlatDnssdStopSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +void otPlatDnssdStartTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +void otPlatDnssdStopTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +void otPlatDnssdStartIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +void otPlatDnssdStopIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +void otPlatDnssdStartIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +void otPlatDnssdStopIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + #endif // OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE diff --git a/include/openthread/instance.h b/include/openthread/instance.h index b6a0cafab..5c69dfe8a 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (419) +#define OPENTHREAD_API_VERSION (420) /** * @addtogroup api-instance diff --git a/include/openthread/mdns.h b/include/openthread/mdns.h index 56ffff09c..c2a63f0fc 100644 --- a/include/openthread/mdns.h +++ b/include/openthread/mdns.h @@ -500,158 +500,94 @@ otError otMdnsGetNextService(otInstance *aInstance, */ otError otMdnsGetNextKey(otInstance *aInstance, otMdnsIterator *aIterator, otMdnsKey *aKey, otMdnsEntryState *aState); -typedef struct otMdnsBrowseResult otMdnsBrowseResult; -typedef struct otMdnsSrvResult otMdnsSrvResult; -typedef struct otMdnsTxtResult otMdnsTxtResult; -typedef struct otMdnsAddressResult otMdnsAddressResult; - /** - * Represents the callback function used to report a browse result. + * Represents a service browser. * - * @param[in] aInstance The OpenThread instance. - * @param[in] aResult The browse result. + * Refer to `otPlatDnssdBrowser` for documentation of member fields and `otMdnsStartBrowser()` for how they are used. * */ -typedef void (*otMdnsBrowseCallback)(otInstance *aInstance, const otMdnsBrowseResult *aResult); +typedef otPlatDnssdBrowser otMdnsBrowser; /** - * Represents the callback function used to report an SRV resolve result. - * - * @param[in] aInstance The OpenThread instance. - * @param[in] aResult The SRV resolve result. + * Represents the callback function pointer type used to report a browse result. * */ -typedef void (*otMdnsSrvCallback)(otInstance *aInstance, const otMdnsSrvResult *aResult); +typedef otPlatDnssdBrowseCallback otMdnsBrowseCallback; /** - * Represents the callback function used to report a TXT resolve result. - * - * @param[in] aInstance The OpenThread instance. - * @param[in] aResult The TXT resolve result. + * Represents a browse result. * */ -typedef void (*otMdnsTxtCallback)(otInstance *aInstance, const otMdnsTxtResult *aResult); +typedef otPlatDnssdBrowseResult otMdnsBrowseResult; /** - * Represents the callback function use to report a IPv6/IPv4 address resolve result. + * Represents an SRV service resolver. * - * @param[in] aInstance The OpenThread instance. - * @param[in] aResult The address resolve result. + * Refer to `otPlatDnssdSrvResolver` for documentation of member fields and `otMdnsStartSrvResolver()` for how they are + * used. * */ -typedef void (*otMdnsAddressCallback)(otInstance *aInstance, const otMdnsAddressResult *aResult); +typedef otPlatDnssdSrvResolver otMdnsSrvResolver; /** - * Represents a service browser. + * Represents the callback function pointer type used to report an SRV resolve result. * */ -typedef struct otMdnsBrowser -{ - const char *mServiceType; ///< The service type (e.g., "_mt._udp"). MUST NOT include domain name. - const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise. - uint32_t mInfraIfIndex; ///< The infrastructure network interface index. - otMdnsBrowseCallback mCallback; ///< The callback to report result. -} otMdnsBrowser; +typedef otPlatDnssdSrvCallback otMdnsSrvCallback; /** - * Represents a browse result. + * Represents an SRV resolver result. * */ -struct otMdnsBrowseResult -{ - const char *mServiceType; ///< The service type (e.g., "_mt._udp"). - const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise. - const char *mServiceInstance; ///< Service instance label. - uint32_t mTtl; ///< TTL in seconds. Zero TTL indicates that service is removed. - uint32_t mInfraIfIndex; ///< The infrastructure network interface index. -}; +typedef otPlatDnssdSrvResult otMdnsSrvResult; /** - * Represents an SRV service resolver. + * Represents a TXT service resolver. + * + * Refer to `otPlatDnssdTxtResolver` for documentation of member fields and `otMdnsStartTxtResolver()` for how they are + * used. * */ -typedef struct otMdnsSrvResolver -{ - const char *mServiceInstance; ///< The service instance label. - const char *mServiceType; ///< The service type. - uint32_t mInfraIfIndex; ///< The infrastructure network interface index. - otMdnsSrvCallback mCallback; ///< The callback to report result. -} otMdnsSrvResolver; +typedef otPlatDnssdTxtResolver otMdnsTxtResolver; /** - * Represents an SRV resolver result. + * Represents the callback function pointer type used to report a TXT resolve result. * */ -struct otMdnsSrvResult -{ - const char *mServiceInstance; ///< The service instance name label. - const char *mServiceType; ///< The service type. - const char *mHostName; ///< The host name (e.g., "myhost"). Can be NULL when `mTtl` is zero. - uint16_t mPort; ///< The service port number. - uint16_t mPriority; ///< The service priority. - uint16_t mWeight; ///< The service weight. - uint32_t mTtl; ///< The service TTL in seconds. Zero TTL indicates SRV record is removed. - uint32_t mInfraIfIndex; ///< The infrastructure network interface index. -}; +typedef otPlatDnssdTxtCallback otMdnsTxtCallback; /** - * Represents a TXT service resolver. + * Represents a TXT resolver result. * */ -typedef struct otMdnsTxtResolver -{ - const char *mServiceInstance; ///< Service instance label. - const char *mServiceType; ///< Service type. - uint32_t mInfraIfIndex; ///< The infrastructure network interface index. - otMdnsTxtCallback mCallback; -} otMdnsTxtResolver; +typedef otPlatDnssdTxtResult otMdnsTxtResult; /** - * Represents a TXT resolver result. + * Represents an address resolver. + * + * Refer to `otPlatDnssdAddressResolver` for documentation of member fields and `otMdnsStartIp6AddressResolver()` or + * `otMdnsStartIp4AddressResolver()` for how they are used. * */ -struct otMdnsTxtResult -{ - const char *mServiceInstance; ///< The service instance name label. - const char *mServiceType; ///< The service type. - const uint8_t *mTxtData; ///< Encoded TXT data bytes. Can be NULL when `mTtl` is zero. - uint16_t mTxtDataLength; ///< Length of TXT data. - uint32_t mTtl; ///< The TXT data TTL in seconds. Zero TTL indicates record is removed. - uint32_t mInfraIfIndex; ///< The infrastructure network interface index. -}; +typedef otPlatDnssdAddressResolver otMdnsAddressResolver; /** - * Represents an address resolver. + * Represents the callback function pointer type use to report an IPv6/IPv4 address resolve result. * */ -typedef struct otMdnsAddressResolver -{ - const char *mHostName; ///< The host name (e.g., "myhost"). MUST NOT contain domain name. - uint32_t mInfraIfIndex; ///< The infrastructure network interface index. - otMdnsAddressCallback mCallback; ///< The callback to report result. -} otMdnsAddressResolver; +typedef otPlatDnssdAddressCallback otMdnsAddressCallback; /** * Represents a discovered host address and its TTL. * */ -typedef struct otMdnsAddressAndTtl -{ - otIp6Address mAddress; ///< The IPv6 address. For IPv4 address the IPv4-mapped IPv6 address format is used. - uint32_t mTtl; ///< The TTL in seconds. -} otMdnsAddressAndTtl; +typedef otPlatDnssdAddressAndTtl otMdnsAddressAndTtl; /** * Represents address resolver result. * */ -struct otMdnsAddressResult -{ - const char *mHostName; ///< The host name. - const otMdnsAddressAndTtl *mAddresses; ///< Array of host addresses and their TTL. Can be NULL if empty. - uint16_t mAddressesLength; ///< Number of entries in `mAddresses` array. - uint32_t mInfraIfIndex; ///< The infrastructure network interface index. -}; +typedef otPlatDnssdAddressResult otMdnsAddressResult; /** * Starts a service browser. diff --git a/include/openthread/platform/dnssd.h b/include/openthread/platform/dnssd.h index e7a2a7f0b..894dff561 100644 --- a/include/openthread/platform/dnssd.h +++ b/include/openthread/platform/dnssd.h @@ -65,7 +65,7 @@ extern "C" { */ typedef enum otPlatDnssdState { - OT_PLAT_DNSSD_STOPPED, ///< Stopped and unable to register any service or host. + OT_PLAT_DNSSD_STOPPED, ///< Stopped and unable to register any service or host, or start any browser/resolver. OT_PLAT_DNSSD_READY, ///< Running and ready to register service or host. } otPlatDnssdState; @@ -149,6 +149,9 @@ typedef struct otPlatDnssdKey * The OpenThread stack will call `otPlatDnssdGetState()` (from this callback or later) to get the new state. The * platform MUST therefore ensure that the returned state from `otPlatDnssdGetState()` is updated before calling this. * + * When the platform signals a state change to `OT_PLAT_DNSSD_STOPPED` using this callback, all active browsers and + * resolvers are considered to be stopped, and any previously registered host, service, key entries as removed. + * * @param[in] aInstance The OpenThread instance structure. * */ @@ -415,6 +418,345 @@ void otPlatDnssdUnregisterKey(otInstance *aInstance, otPlatDnssdRequestId aRequestId, otPlatDnssdRegisterCallback aCallback); +//====================================================================================================================== + +/** + * Represents a browse result. + * + */ +typedef struct otPlatDnssdBrowseResult +{ + const char *mServiceType; ///< The service type (e.g., "_mt._udp"). + const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise. + const char *mServiceInstance; ///< Service instance label. + uint32_t mTtl; ///< TTL in seconds. Zero TTL indicates that service is removed. + uint32_t mInfraIfIndex; ///< The infrastructure network interface index. +} otPlatDnssdBrowseResult; + +/** + * Represents the callback function used to report a browse result. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResult The browse result. + * + */ +typedef void (*otPlatDnssdBrowseCallback)(otInstance *aInstance, const otPlatDnssdBrowseResult *aResult); + +/** + * Represents a service browser. + * + */ +typedef struct otPlatDnssdBrowser +{ + const char *mServiceType; ///< The service type (e.g., "_mt._udp"). MUST NOT include domain name. + const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise. + uint32_t mInfraIfIndex; ///< The infrastructure network interface index. + otPlatDnssdBrowseCallback mCallback; ///< The callback to report result. +} otPlatDnssdBrowser; + +/** + * Represents an SRV resolver result. + * + */ +typedef struct otPlatDnssdSrvResult +{ + const char *mServiceInstance; ///< The service instance name label. + const char *mServiceType; ///< The service type. + const char *mHostName; ///< The host name (e.g., "myhost"). Can be NULL when `mTtl` is zero. + uint16_t mPort; ///< The service port number. + uint16_t mPriority; ///< The service priority. + uint16_t mWeight; ///< The service weight. + uint32_t mTtl; ///< The service TTL in seconds. Zero TTL indicates SRV record is removed. + uint32_t mInfraIfIndex; ///< The infrastructure network interface index. +} otPlatDnssdSrvResult; + +/** + * Represents the callback function used to report an SRV resolve result. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResult The SRV resolve result. + * + */ +typedef void (*otPlatDnssdSrvCallback)(otInstance *aInstance, const otPlatDnssdSrvResult *aResult); + +/** + * Represents an SRV service resolver. + * + */ +typedef struct otPlatDnssdSrvResolver +{ + const char *mServiceInstance; ///< The service instance label. + const char *mServiceType; ///< The service type. + uint32_t mInfraIfIndex; ///< The infrastructure network interface index. + otPlatDnssdSrvCallback mCallback; ///< The callback to report result. +} otPlatDnssdSrvResolver; + +/** + * Represents a TXT resolver result. + * + */ +typedef struct otPlatDnssdTxtResult +{ + const char *mServiceInstance; ///< The service instance name label. + const char *mServiceType; ///< The service type. + const uint8_t *mTxtData; ///< Encoded TXT data bytes. Can be NULL when `mTtl` is zero. + uint16_t mTxtDataLength; ///< Length of TXT data. + uint32_t mTtl; ///< The TXT data TTL in seconds. Zero TTL indicates record is removed. + uint32_t mInfraIfIndex; ///< The infrastructure network interface index. +} otPlatDnssdTxtResult; + +/** + * Represents the callback function used to report a TXT resolve result. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResult The TXT resolve result. + * + */ +typedef void (*otPlatDnssdTxtCallback)(otInstance *aInstance, const otPlatDnssdTxtResult *aResult); + +/** + * Represents a TXT service resolver. + * + */ +typedef struct otPlatDnssdTxtResolver +{ + const char *mServiceInstance; ///< Service instance label. + const char *mServiceType; ///< Service type. + uint32_t mInfraIfIndex; ///< The infrastructure network interface index. + otPlatDnssdTxtCallback mCallback; +} otPlatDnssdTxtResolver; + +/** + * Represents a discovered host address and its TTL. + * + */ +typedef struct otPlatDnssdAddressAndTtl +{ + otIp6Address mAddress; ///< The IPv6 address. For IPv4 address the IPv4-mapped IPv6 address format is used. + uint32_t mTtl; ///< The TTL in seconds. +} otPlatDnssdAddressAndTtl; + +/** + * Represents address resolver result. + * + */ +typedef struct otPlatDnssdAddressResult +{ + const char *mHostName; ///< The host name. + const otPlatDnssdAddressAndTtl *mAddresses; ///< Array of host addresses and their TTL. Can be NULL if empty. + uint16_t mAddressesLength; ///< Number of entries in `mAddresses` array. + uint32_t mInfraIfIndex; ///< The infrastructure network interface index. +} otPlatDnssdAddressResult; + +/** + * Represents the callback function use to report a IPv6/IPv4 address resolve result. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResult The address resolve result. + * + */ +typedef void (*otPlatDnssdAddressCallback)(otInstance *aInstance, const otPlatDnssdAddressResult *aResult); + +/** + * Represents an address resolver. + * + */ +typedef struct otPlatDnssdAddressResolver +{ + const char *mHostName; ///< The host name (e.g., "myhost"). MUST NOT contain domain name. + uint32_t mInfraIfIndex; ///< The infrastructure network interface index. + otPlatDnssdAddressCallback mCallback; ///< The callback to report result. +} otPlatDnssdAddressResolver; + +/** + * Starts a service browser. + * + * Initiates a continuous search for the specified `mServiceType` in @p aBrowser. For sub-type services, + * `mSubTypeLabel` specifies the sub-type, for base services, `mSubTypeLabel` is set to NULL. + * + * Discovered services should be reported through the `mCallback` function in @p aBrowser. Services that have been + * removed are reported with a TTL value of zero. The callback may be invoked immediately with cached information + * (if available) and potentially before this function returns. When cached results are used, the reported TTL value + * should reflect the original TTL from the last received response. + * + * Multiple browsers can be started for the same service, provided they use different callback functions. + * + * The @p aBrowser and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aBrowser The browser to be started. + * + */ +void otPlatDnssdStartBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser); + +/** + * Stops a service browser. + * + * No action is performed if no matching browser with the same service and callback is currently active. + * + * The @p aBrowser and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aBrowser The browser to stop. + * + */ +void otPlatDnssdStopBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser); + +/** + * Starts an SRV record resolver. + * + * Initiates a continuous SRV record resolver for the specified service in @p aResolver. + * + * Discovered information should be reported through the `mCallback` function in @p aResolver. When the service is + * removed it is reported with a TTL value of zero. In this case, `mHostName` may be NULL and other result fields (such + * as `mPort`) will be ignored by the OpenThread stack. + * + * The callback may be invoked immediately with cached information (if available) and potentially before this function + * returns. When cached result is used, the reported TTL value should reflect the original TTL from the last received + * response. + * + * Multiple resolvers can be started for the same service, provided they use different callback functions. + * + * The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResolver The resolver to be started. + * + */ +void otPlatDnssdStartSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver); + +/** + * Stops an SRV record resolver. + * + * No action is performed if no matching resolver with the same service and callback is currently active. + * + * The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResolver The resolver to stop. + * + */ +void otPlatDnssdStopSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver); + +/** + * Starts a TXT record resolver. + * + * Initiates a continuous TXT record resolver for the specified service in @p aResolver. + * + * Discovered information should be reported through the `mCallback` function in @p aResolver. When the TXT record is + * removed it is reported with a TTL value of zero. In this case, `mTxtData` may be NULL, and other result fields + * (such as `mTxtDataLength`) will be ignored by the OpenThread stack. + * + * The callback may be invoked immediately with cached information (if available) and potentially before this function + * returns. When cached result is used, the reported TTL value should reflect the original TTL from the last received + * response. + * + * Multiple resolvers can be started for the same service, provided they use different callback functions. + * + * The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResolver The resolver to be started. + * + */ +void otPlatDnssdStartTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver); + +/** + * Stops a TXT record resolver. + * + * No action is performed if no matching resolver with the same service and callback is currently active. + * + * The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResolver The resolver to stop. + * + */ +void otPlatDnssdStopTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver); + +/** + * Starts an IPv6 address resolver. + * + * Initiates a continuous IPv6 address resolver for the specified host name in @p aResolver. + * + * Discovered addresses should be reported through the `mCallback` function in @p aResolver. The callback should be + * invoked whenever addresses are added or removed, providing an updated list. If all addresses are removed, the + * callback should be invoked with an empty list (`mAddressesLength` set to zero). + * + * The callback may be invoked immediately with cached information (if available) and potentially before this function + * returns. When cached result is used, the reported TTL values should reflect the original TTL from the last received + * response. + * + * Multiple resolvers can be started for the same host name, provided they use different callback functions. + * + * The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResolver The resolver to be started. + * + */ +void otPlatDnssdStartIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver); + +/** + * Stops an IPv6 address resolver. + * + * No action is performed if no matching resolver with the same host name and callback is currently active. + * + * The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResolver The resolver to stop. + * + */ +void otPlatDnssdStopIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver); + +/** + * Starts an IPv4 address resolver. + * + * Initiates a continuous IPv4 address resolver for the specified host name in @p aResolver. + * + * Discovered addresses should be reported through the `mCallback` function in @p aResolver. The IPv4 addresses are + * represented using the IPv4-mapped IPv6 address format in `mAddresses` array. The callback should be invoked + * whenever addresses are added or removed, providing an updated list. If all addresses are removed, the callback + * should be invoked with an empty list (`mAddressesLength` set to zero). + * + * The callback may be invoked immediately with cached information (if available) and potentially before this function + * returns. When cached result is used, the reported TTL values will reflect the original TTL from the last received + * response. + * + * Multiple resolvers can be started for the same host name, provided they use different callback functions. + * + * The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResolver The resolver to be started. + * + */ +void otPlatDnssdStartIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver); + +/** + * Stops an IPv4 address resolver. + * + * No action is performed if no matching resolver with the same host name and callback is currently active. + * + * The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save + * a copy of the information if it wants to retain the information after returning from this function. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aResolver The resolver to stop. + * + */ +void otPlatDnssdStopIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver); + /** * @} * diff --git a/script/check-scan-build b/script/check-scan-build index 56925d08a..2d855fb16 100755 --- a/script/check-scan-build +++ b/script/check-scan-build @@ -52,6 +52,8 @@ OT_BUILD_OPTIONS=( "-DOT_DHCP6_CLIENT=ON" "-DOT_DHCP6_SERVER=ON" "-DOT_DIAGNOSTIC=ON" + "-DOT_DNSSD_DISCOVERY_PROXY=ON" + "-DOT_DNSSD_SERVER=ON" "-DOT_DNS_CLIENT=ON" "-DOT_DNS_DSO=ON" "-DOT_ECDSA=ON" diff --git a/script/make-pretty b/script/make-pretty index 84b6204c5..67885d8b0 100755 --- a/script/make-pretty +++ b/script/make-pretty @@ -110,6 +110,7 @@ OT_CLANG_TIDY_BUILD_OPTS=( '-DOT_DNS_CLIENT=ON' '-DOT_DNS_DSO=ON' '-DOT_DNS_UPSTREAM_QUERY=ON' + "-DOT_DNSSD_DISCOVERY_PROXY=ON" '-DOT_DNSSD_SERVER=ON' '-DOT_DUA=ON' '-DOT_MLR=ON' diff --git a/src/core/border_router/infra_if.cpp b/src/core/border_router/infra_if.cpp index 0b44ee24f..25efee5b8 100644 --- a/src/core/border_router/infra_if.cpp +++ b/src/core/border_router/infra_if.cpp @@ -156,6 +156,10 @@ Error InfraIf::HandleStateChanged(uint32_t aIfIndex, bool aIsRunning) Get().HandleInfraIfStateChanged(); #endif +#if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + Get().HandleInfraIfStateChanged(); +#endif + #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF Get().HandleInfraIfStateChanged(); #endif diff --git a/src/core/config/dnssd_server.h b/src/core/config/dnssd_server.h index 36b5620f3..fb5aa3f00 100644 --- a/src/core/config/dnssd_server.h +++ b/src/core/config/dnssd_server.h @@ -85,6 +85,16 @@ #define OPENTHREAD_CONFIG_DNSSD_QUERY_TIMEOUT 6000 #endif +/** + * @def OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + * + * Define to 1 to enable DNS-SD Discovery Proxy support. + * + */ +#ifndef OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE +#define OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE 0 +#endif + /** * @def OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE * diff --git a/src/core/net/dnssd.cpp b/src/core/net/dnssd.cpp index 5e068b906..6d54b5e99 100644 --- a/src/core/net/dnssd.cpp +++ b/src/core/net/dnssd.cpp @@ -255,29 +255,255 @@ void Dnssd::UnregisterKey(const Key &aKey, RequestId aRequestId, RegisterCallbac return; } +void Dnssd::StartBrowser(const Browser &aBrowser) +{ + VerifyOrExit(IsReady()); + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE -void Dnssd::HandleMdnsCoreStateChange(void) + { + IgnoreError(Get().StartBrowser(aBrowser)); + ExitNow(); + } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStartBrowser(&GetInstance(), &aBrowser); +#endif + +exit: + return; +} + +void Dnssd::StopBrowser(const Browser &aBrowser) { + VerifyOrExit(IsReady()); + #if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION if (mUseNativeMdns) #endif +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE { - HandleStateChange(); + IgnoreError(Get().StopBrowser(aBrowser)); + ExitNow(); + } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStopBrowser(&GetInstance(), &aBrowser); +#endif + +exit: + return; +} + +void Dnssd::StartSrvResolver(const SrvResolver &aResolver) +{ + VerifyOrExit(IsReady()); + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE + { + IgnoreError(Get().StartSrvResolver(aResolver)); + ExitNow(); + } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStartSrvResolver(&GetInstance(), &aResolver); +#endif + +exit: + return; +} + +void Dnssd::StopSrvResolver(const SrvResolver &aResolver) +{ + VerifyOrExit(IsReady()); + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE + { + IgnoreError(Get().StopSrvResolver(aResolver)); + ExitNow(); + } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStopSrvResolver(&GetInstance(), &aResolver); +#endif + +exit: + return; +} + +void Dnssd::StartTxtResolver(const TxtResolver &aResolver) +{ + VerifyOrExit(IsReady()); + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE + { + IgnoreError(Get().StartTxtResolver(aResolver)); + ExitNow(); + } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStartTxtResolver(&GetInstance(), &aResolver); +#endif + +exit: + return; +} + +void Dnssd::StopTxtResolver(const TxtResolver &aResolver) +{ + VerifyOrExit(IsReady()); + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE + { + IgnoreError(Get().StopTxtResolver(aResolver)); + ExitNow(); } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStopTxtResolver(&GetInstance(), &aResolver); +#endif + +exit: + return; +} + +void Dnssd::StartIp6AddressResolver(const AddressResolver &aResolver) +{ + VerifyOrExit(IsReady()); + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE + { + IgnoreError(Get().StartIp6AddressResolver(aResolver)); + ExitNow(); + } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStartIp6AddressResolver(&GetInstance(), &aResolver); +#endif + +exit: + return; } + +void Dnssd::StopIp6AddressResolver(const AddressResolver &aResolver) +{ + VerifyOrExit(IsReady()); + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE + { + IgnoreError(Get().StopIp6AddressResolver(aResolver)); + ExitNow(); + } #endif +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStopIp6AddressResolver(&GetInstance(), &aResolver); +#endif + +exit: + return; +} + +void Dnssd::StartIp4AddressResolver(const AddressResolver &aResolver) +{ + VerifyOrExit(IsReady()); + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE + { + IgnoreError(Get().StartIp4AddressResolver(aResolver)); + ExitNow(); + } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStartIp4AddressResolver(&GetInstance(), &aResolver); +#endif + +exit: + return; +} + +void Dnssd::StopIp4AddressResolver(const AddressResolver &aResolver) +{ + VerifyOrExit(IsReady()); + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE + { + IgnoreError(Get().StopIp4AddressResolver(aResolver)); + ExitNow(); + } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + otPlatDnssdStopIp4AddressResolver(&GetInstance(), &aResolver); +#endif + +exit: + return; +} + void Dnssd::HandleStateChange(void) { #if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE Get().HandleDnssdPlatformStateChange(); #endif + +#if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + Get().HandleDnssdPlatformStateChange(); +#endif +} + +#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE +void Dnssd::HandleMdnsCoreStateChange(void) +{ +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION + if (mUseNativeMdns) +#endif + { + HandleStateChange(); + } } +#endif +#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE extern "C" void otPlatDnssdStateHandleStateChange(otInstance *aInstance) { AsCoreType(aInstance).Get().HandleStateChange(); } +#endif } // namespace ot diff --git a/src/core/net/dnssd.hpp b/src/core/net/dnssd.hpp index 9bf19aa81..1864a377c 100644 --- a/src/core/net/dnssd.hpp +++ b/src/core/net/dnssd.hpp @@ -93,6 +93,15 @@ class Dnssd : public InstanceLocator, private NonCopyable typedef otPlatDnssdRequestId RequestId; ///< A request ID. typedef otPlatDnssdRegisterCallback RegisterCallback; ///< The registration request callback + typedef otPlatDnssdBrowseCallback BrowseCallback; ///< Browser callback. + typedef otPlatDnssdSrvCallback SrvCallback; ///< SRV callback. + typedef otPlatDnssdTxtCallback TxtCallback; ///< TXT callback. + typedef otPlatDnssdAddressCallback AddressCallback; ///< Address callback + typedef otPlatDnssdBrowseResult BrowseResult; ///< Browser result. + typedef otPlatDnssdSrvResult SrvResult; ///< SRV result. + typedef otPlatDnssdTxtResult TxtResult; ///< TXT result. + typedef otPlatDnssdAddressResult AddressResult; ///< Address result. + typedef otPlatDnssdAddressAndTtl AddressAndTtl; ///< Address and TTL. class Host : public otPlatDnssdHost, public Clearable ///< Host information. { @@ -106,6 +115,22 @@ class Dnssd : public InstanceLocator, private NonCopyable { }; + class Browser : public otPlatDnssdBrowser, public Clearable ///< Browser. + { + }; + + class SrvResolver : public otPlatDnssdSrvResolver, public Clearable ///< SRV resolver. + { + }; + + class TxtResolver : public otPlatDnssdTxtResolver, public Clearable ///< TXT resolver. + { + }; + + class AddressResolver : public otPlatDnssdAddressResolver, public Clearable ///< Address resolver. + { + }; + /** * Represents a range of `RequestId` values. * @@ -274,6 +299,116 @@ class Dnssd : public InstanceLocator, private NonCopyable */ void UnregisterKey(const Key &aKey, RequestId aRequestId, RegisterCallback aCallback); + /** + * Starts a service browser. + * + * Refer to the documentation for `otPlatDnssdStartBrowser()` for a more detailed description of the behavior + * of this method. + * + * @param[in] aBrowser The browser to be started. + * + */ + void StartBrowser(const Browser &aBrowser); + + /** + * Stops a service browser. + * + * Refer to the documentation for `otPlatDnssdStopBrowser()` for a more detailed description of the behavior + * of this method. + * + * @param[in] aBrowser The browser to stop. + * + */ + void StopBrowser(const Browser &aBrowser); + + /** + * Starts an SRV record resolver. + * + * Refer to the documentation for `otPlatDnssdStartSrvResolver()` for a more detailed description of the behavior + * of this method. + * + * @param[in] aResolver The resolver to be started. + * + */ + void StartSrvResolver(const SrvResolver &aResolver); + + /** + * Stops an SRV record resolver. + * + * Refer to the documentation for `otPlatDnssdStopSrvResolver()` for a more detailed description of the behavior + * of this method. + * + * @param[in] aResolver The resolver to stop. + * + */ + void StopSrvResolver(const SrvResolver &aResolver); + + /** + * Starts a TXT record resolver. + * + * Refer to the documentation for `otPlatDnssdStartTxtResolver()` for a more detailed description of the behavior + * of this method. + * + * @param[in] aResolver The resolver to be started. + * + */ + void StartTxtResolver(const TxtResolver &aResolver); + + /** + * Stops a TXT record resolver. + * + * Refer to the documentation for `otPlatDnssdStopTxtResolver()` for a more detailed description of the behavior + * of this method. + * + * @param[in] aResolver The resolver to stop. + * + */ + void StopTxtResolver(const TxtResolver &aResolver); + + /** + * Starts an IPv6 address resolver. + * + * Refer to the documentation for `otPlatDnssdStartIp6AddressResolver()` for a more detailed description of the + * behavior of this method. + * + * @param[in] aResolver The resolver to be started. + * + */ + void StartIp6AddressResolver(const AddressResolver &aResolver); + + /** + * Stops an IPv6 address resolver. + * + * Refer to the documentation for `otPlatDnssdStopIp6AddressResolver()` for a more detailed description of the + * behavior of this method. + * + * @param[in] aResolver The resolver to stop. + * + */ + void StopIp6AddressResolver(const AddressResolver &aResolver); + + /** + * Starts an IPv4 address resolver. + * + * Refer to the documentation for `otPlatDnssdStartIp4AddressResolver()` for a more detailed description of the + * behavior of this method. + * + * @param[in] aResolver The resolver to be started. + * + */ + void StartIp4AddressResolver(const AddressResolver &aResolver); + + /** + * Stops an IPv4 address resolver. + * + * Refer to the documentation for `otPlatDnssdStopIp4AddressResolver()` for a more detailed description of the + * behavior of this method. + * + * @param[in] aResolver The resolver to stop. + * + */ + void StopIp4AddressResolver(const AddressResolver &aResolver); + #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE /** * Handles native mDNS state change. diff --git a/src/core/net/dnssd_server.cpp b/src/core/net/dnssd_server.cpp index af24fe95e..9f177db4b 100644 --- a/src/core/net/dnssd_server.cpp +++ b/src/core/net/dnssd_server.cpp @@ -64,6 +64,9 @@ const char *Server::kBlockedDomains[] = {"ipv4only.arpa."}; Server::Server(Instance &aInstance) : InstanceLocator(aInstance) , mSocket(aInstance) +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + , mDiscoveryProxy(aInstance) +#endif #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE , mEnableUpstreamQuery(false) #endif @@ -88,6 +91,10 @@ Error Server::Start(void) LogInfo("Started"); +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + mDiscoveryProxy.UpdateState(); +#endif + exit: if (error != kErrorNone) { @@ -104,6 +111,10 @@ void Server::Stop(void) Finalize(query, Header::kResponseServerFailure); } +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + mDiscoveryProxy.Stop(); +#endif + #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE for (UpstreamQueryTransaction &txn : mUpstreamQueryTransactions) { @@ -586,17 +597,25 @@ Error Server::Response::AppendHostAddresses(const Ip6::Address *aAddrs, uint16_t for (uint16_t index = 0; index < aAddrsLength; index++) { - AaaaRecord aaaaRecord; + SuccessOrExit(error = AppendAaaaRecord(aAddrs[index], aTtl)); + } + +exit: + return error; +} - aaaaRecord.Init(); - aaaaRecord.SetTtl(aTtl); - aaaaRecord.SetAddress(aAddrs[index]); +Error Server::Response::AppendAaaaRecord(const Ip6::Address &aAddress, uint32_t aTtl) +{ + Error error; + AaaaRecord aaaaRecord; - SuccessOrExit(error = Name::AppendPointerLabel(mOffsets.mHostName, *mMessage)); - SuccessOrExit(error = mMessage->Append(aaaaRecord)); + aaaaRecord.Init(); + aaaaRecord.SetTtl(aTtl); + aaaaRecord.SetAddress(aAddress); - IncResourceRecordCount(); - } + SuccessOrExit(error = Name::AppendPointerLabel(mOffsets.mHostName, *mMessage)); + SuccessOrExit(error = mMessage->Append(aaaaRecord)); + IncResourceRecordCount(); exit: return error; @@ -915,9 +934,12 @@ void Server::ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessag { ProxyQuery *query; ProxyQueryInfo info; - Name::Buffer name; +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + VerifyOrExit(mQuerySubscribe.IsSet() || mDiscoveryProxy.IsRunning()); +#else VerifyOrExit(mQuerySubscribe.IsSet()); +#endif // We try to convert `aResponse.mMessage` to a `ProxyQuery` by // appending `ProxyQueryInfo` to it. @@ -927,6 +949,10 @@ void Server::ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessag info.mExpireTime = TimerMilli::GetNow() + kQueryTimeout; info.mOffsets = aResponse.mOffsets; +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + info.mAction = kNoAction; +#endif + if (aResponse.mMessage->Append(info) != kErrorNone) { aResponse.SetResponseCode(Header::kResponseServerFailure); @@ -943,8 +969,21 @@ void Server::ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessag mTimer.FireAtIfEarlier(info.mExpireTime); - ReadQueryName(*query, name); - mQuerySubscribe.Invoke(name); +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + if (mQuerySubscribe.IsSet()) +#endif + { + Name::Buffer name; + + ReadQueryName(*query, name); + mQuerySubscribe.Invoke(name); + } +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + else + { + mDiscoveryProxy.Resolve(*query, info); + } +#endif exit: return; @@ -964,6 +1003,91 @@ bool Server::QueryNameMatches(const Message &aQuery, const char *aName) return (Name::CompareName(aQuery, offset, aName) == kErrorNone); } +void Server::ReadQueryInstanceName(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Name::Buffer &aName) +{ + uint16_t offset = aInfo.mOffsets.mInstanceName; + + IgnoreError(Name::ReadName(aQuery, offset, aName, sizeof(aName))); +} + +void Server::ReadQueryInstanceName(const ProxyQuery &aQuery, + const ProxyQueryInfo &aInfo, + Name::LabelBuffer &aInstanceLabel, + Name::Buffer &aServiceType) +{ + // Reads the service instance label and service type with domain + // name stripped. + + uint16_t offset = aInfo.mOffsets.mInstanceName; + uint8_t labelLength = sizeof(aInstanceLabel); + + IgnoreError(Dns::Name::ReadLabel(aQuery, offset, aInstanceLabel, labelLength)); + IgnoreError(Dns::Name::ReadName(aQuery, offset, aServiceType)); + IgnoreError(StripDomainName(aServiceType)); +} + +bool Server::QueryInstanceNameMatches(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, const char *aName) +{ + uint16_t offset = aInfo.mOffsets.mInstanceName; + + return (Name::CompareName(aQuery, offset, aName) == kErrorNone); +} + +void Server::ReadQueryHostName(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Name::Buffer &aName) +{ + uint16_t offset = aInfo.mOffsets.mHostName; + + IgnoreError(Name::ReadName(aQuery, offset, aName, sizeof(aName))); +} + +bool Server::QueryHostNameMatches(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, const char *aName) +{ + uint16_t offset = aInfo.mOffsets.mHostName; + + return (Name::CompareName(aQuery, offset, aName) == kErrorNone); +} + +Error Server::StripDomainName(Name::Buffer &aName) +{ + // In-place removes the domain name from `aName`. + + return Name::StripName(aName, kDefaultDomainName); +} + +Error Server::StripDomainName(const char *aFullName, Name::Buffer &aLabels) +{ + // Remove the domain name from `aFullName` and copies + // the result into `aLabels`. + + return Name::ExtractLabels(aFullName, kDefaultDomainName, aLabels, sizeof(aLabels)); +} + +void Server::ConstructFullName(const char *aLabels, Name::Buffer &aFullName) +{ + // Construct a full name by appending the default domain name + // to `aLabels`. + + StringWriter fullName(aFullName, sizeof(aFullName)); + + fullName.Append("%s.%s", aLabels, kDefaultDomainName); +} + +void Server::ConstructFullInstanceName(const char *aInstanceLabel, const char *aServiceType, Name::Buffer &aFullName) +{ + StringWriter fullName(aFullName, sizeof(aFullName)); + + fullName.Append("%s.%s.%s", aInstanceLabel, aServiceType, kDefaultDomainName); +} + +void Server::ConstructFullServiceSubTypeName(const char *aServiceType, + const char *aSubTypeLabel, + Name::Buffer &aFullName) +{ + StringWriter fullName(aFullName, sizeof(aFullName)); + + fullName.Append("%s._sub.%s.%s", aSubTypeLabel, aServiceType, kDefaultDomainName); +} + void Server::ProxyQueryInfo::ReadFrom(const ProxyQuery &aQuery) { SuccessOrAssert(aQuery.Read(aQuery.GetLength() - sizeof(ProxyQueryInfo), *this)); @@ -987,15 +1111,22 @@ Error Server::Response::ExtractServiceInstanceLabel(const char *aInstanceName, N return Name::ExtractLabels(aInstanceName, serviceName, aLabel); } -void Server::RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Response &aResponse) +void Server::RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, ProxyQueryInfo &aInfo, Response &aResponse) { - Name::Buffer name; +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + mDiscoveryProxy.CancelAction(aQuery, aInfo); +#endif mProxyQueries.Dequeue(aQuery); aInfo.RemoveFrom(aQuery); - ReadQueryName(aQuery, name); - mQueryUnsubscribe.InvokeIfSet(name); + if (mQueryUnsubscribe.IsSet()) + { + Name::Buffer name; + + ReadQueryName(aQuery, name); + mQueryUnsubscribe.Invoke(name); + } aResponse.InitFrom(aQuery, aInfo); } @@ -1282,6 +1413,706 @@ void Server::ResetUpstreamQueryTransaction(UpstreamQueryTransaction &aTxn, Error } #endif +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + +Server::DiscoveryProxy::DiscoveryProxy(Instance &aInstance) + : InstanceLocator(aInstance) + , mIsRunning(false) +{ +} + +void Server::DiscoveryProxy::UpdateState(void) +{ + if (Get().IsRunning() && Get().IsReady() && Get().IsRunning()) + { + Start(); + } + else + { + Stop(); + } +} + +void Server::DiscoveryProxy::Start(void) +{ + VerifyOrExit(!mIsRunning); + mIsRunning = true; + LogInfo("Started discovery proxy"); + +exit: + return; +} + +void Server::DiscoveryProxy::Stop(void) +{ + VerifyOrExit(mIsRunning); + + for (ProxyQuery &query : Get().mProxyQueries) + { + Get().Finalize(query, Header::kResponseSuccess); + } + + mIsRunning = false; + LogInfo("Stopped discovery proxy"); + +exit: + return; +} + +void Server::DiscoveryProxy::Resolve(ProxyQuery &aQuery, ProxyQueryInfo &aInfo) +{ + ProxyAction action = kNoAction; + + switch (aInfo.mType) + { + case kPtrQuery: + action = kBrowsing; + break; + + case kSrvQuery: + case kSrvTxtQuery: + action = kResolvingSrv; + break; + + case kTxtQuery: + action = kResolvingTxt; + break; + + case kAaaaQuery: + action = kResolvingIp6Address; + break; + } + + Perform(action, aQuery, aInfo); +} + +void Server::DiscoveryProxy::Perform(ProxyAction aAction, ProxyQuery &aQuery, ProxyQueryInfo &aInfo) +{ + bool shouldStart; + Name::Buffer name; + + VerifyOrExit(aAction != kNoAction); + + // The order of the steps below is crucial. First, we read the + // name associated with the action. Then we check if another + // query has an active browser/resolver for the same name. This + // helps us determine if a new browser/resolver is needed. Then, + // we update the `ProxyQueryInfo` within `aQuery` to reflect the + // `aAction` being performed. Finally, if necessary, we start the + // proper browser/resolver on DNS-SD/mDNS. Placing this last + // ensures correct processing even if a DNS-SD/mDNS callback is + // invoked immediately. + + ReadNameFor(aAction, aQuery, aInfo, name); + + shouldStart = !HasActive(aAction, name); + + aInfo.mAction = aAction; + aInfo.UpdateIn(aQuery); + + VerifyOrExit(shouldStart); + UpdateProxy(kStart, aAction, aQuery, aInfo, name); + +exit: + return; +} + +void Server::DiscoveryProxy::ReadNameFor(ProxyAction aAction, + ProxyQuery &aQuery, + ProxyQueryInfo &aInfo, + Name::Buffer &aName) const +{ + // Read the name corresponding to `aAction` from `aQuery`. + + switch (aAction) + { + case kNoAction: + break; + case kBrowsing: + ReadQueryName(aQuery, aName); + break; + case kResolvingSrv: + case kResolvingTxt: + ReadQueryInstanceName(aQuery, aInfo, aName); + break; + case kResolvingIp6Address: + ReadQueryHostName(aQuery, aInfo, aName); + break; + } +} + +void Server::DiscoveryProxy::CancelAction(ProxyQuery &aQuery, ProxyQueryInfo &aInfo) +{ + // Cancel the current action for a given `aQuery`, then + // determine if we need to stop any browser/resolver + // on infrastructure. + + ProxyAction action = aInfo.mAction; + Name::Buffer name; + + VerifyOrExit(mIsRunning); + VerifyOrExit(action != kNoAction); + + // We first update the `aInfo` on `aQuery` before calling + // `HasActive()`. This ensures that the current query is not + // taken into account when we try to determine if any query + // is waiting for same `aAction` browser/resolver. + + ReadNameFor(action, aQuery, aInfo, name); + + aInfo.mAction = kNoAction; + aInfo.UpdateIn(aQuery); + + VerifyOrExit(!HasActive(action, name)); + UpdateProxy(kStop, action, aQuery, aInfo, name); + +exit: + return; +} + +void Server::DiscoveryProxy::UpdateProxy(Command aCommand, + ProxyAction aAction, + const ProxyQuery &aQuery, + const ProxyQueryInfo &aInfo, + Name::Buffer &aName) +{ + // Start or stop browser/resolver corresponding to `aAction`. + // `aName` may be changed. + + switch (aAction) + { + case kNoAction: + break; + case kBrowsing: + StartOrStopBrowser(aCommand, aName); + break; + case kResolvingSrv: + StartOrStopSrvResolver(aCommand, aQuery, aInfo); + break; + case kResolvingTxt: + StartOrStopTxtResolver(aCommand, aQuery, aInfo); + break; + case kResolvingIp6Address: + StartOrStopIp6Resolver(aCommand, aName); + break; + } +} + +void Server::DiscoveryProxy::StartOrStopBrowser(Command aCommand, Name::Buffer &aServiceName) +{ + // Start or stop a service browser for a given service type + // or sub-type. + + static const char kFullSubLabel[] = "._sub."; + + Dnssd::Browser browser; + char *ptr; + + browser.Clear(); + + IgnoreError(StripDomainName(aServiceName)); + + // Check if the service name is a sub-type with name + // format: "._sub.. + + ptr = AsNonConst(StringFind(aServiceName, kFullSubLabel, kStringCaseInsensitiveMatch)); + + if (ptr != nullptr) + { + *ptr = kNullChar; + ptr += sizeof(kFullSubLabel) - 1; + + browser.mServiceType = ptr; + browser.mSubTypeLabel = aServiceName; + } + else + { + browser.mServiceType = aServiceName; + browser.mSubTypeLabel = nullptr; + } + + browser.mInfraIfIndex = Get().GetIfIndex(); + browser.mCallback = HandleBrowseResult; + + switch (aCommand) + { + case kStart: + Get().StartBrowser(browser); + break; + + case kStop: + Get().StopBrowser(browser); + break; + } +} + +void Server::DiscoveryProxy::StartOrStopSrvResolver(Command aCommand, + const ProxyQuery &aQuery, + const ProxyQueryInfo &aInfo) +{ + // Start or stop an SRV record resolver for a given query. + + Dnssd::SrvResolver resolver; + Name::LabelBuffer instanceLabel; + Name::Buffer serviceType; + + ReadQueryInstanceName(aQuery, aInfo, instanceLabel, serviceType); + + resolver.Clear(); + + resolver.mServiceInstance = instanceLabel; + resolver.mServiceType = serviceType; + resolver.mInfraIfIndex = Get().GetIfIndex(); + resolver.mCallback = HandleSrvResult; + + switch (aCommand) + { + case kStart: + Get().StartSrvResolver(resolver); + break; + + case kStop: + Get().StopSrvResolver(resolver); + break; + } +} + +void Server::DiscoveryProxy::StartOrStopTxtResolver(Command aCommand, + const ProxyQuery &aQuery, + const ProxyQueryInfo &aInfo) +{ + // Start or stop a TXT record resolver for a given query. + + Dnssd::TxtResolver resolver; + Name::LabelBuffer instanceLabel; + Name::Buffer serviceType; + + ReadQueryInstanceName(aQuery, aInfo, instanceLabel, serviceType); + + resolver.Clear(); + + resolver.mServiceInstance = instanceLabel; + resolver.mServiceType = serviceType; + resolver.mInfraIfIndex = Get().GetIfIndex(); + resolver.mCallback = HandleTxtResult; + + switch (aCommand) + { + case kStart: + Get().StartTxtResolver(resolver); + break; + + case kStop: + Get().StopTxtResolver(resolver); + break; + } +} + +void Server::DiscoveryProxy::StartOrStopIp6Resolver(Command aCommand, Name::Buffer &aHostName) +{ + // Start or stop an IPv6 address resolver for a given host name. + + Dnssd::AddressResolver resolver; + + IgnoreError(StripDomainName(aHostName)); + + resolver.mHostName = aHostName; + resolver.mInfraIfIndex = Get().GetIfIndex(); + resolver.mCallback = HandleIp6AddressResult; + + switch (aCommand) + { + case kStart: + Get().StartIp6AddressResolver(resolver); + break; + + case kStop: + Get().StopIp6AddressResolver(resolver); + break; + } +} + +bool Server::DiscoveryProxy::QueryMatches(const ProxyQuery &aQuery, + const ProxyQueryInfo &aInfo, + ProxyAction aAction, + const Name::Buffer &aName) const +{ + // Check whether `aQuery` is performing `aAction` and + // its name matches `aName`. + + bool matches = false; + + VerifyOrExit(aInfo.mAction == aAction); + + switch (aAction) + { + case kBrowsing: + VerifyOrExit(QueryNameMatches(aQuery, aName)); + break; + case kResolvingSrv: + case kResolvingTxt: + VerifyOrExit(QueryInstanceNameMatches(aQuery, aInfo, aName)); + break; + case kResolvingIp6Address: + VerifyOrExit(QueryHostNameMatches(aQuery, aInfo, aName)); + break; + case kNoAction: + ExitNow(); + } + + matches = true; + +exit: + return matches; +} + +bool Server::DiscoveryProxy::HasActive(ProxyAction aAction, const Name::Buffer &aName) const +{ + // Determine whether or not we have an active browser/resolver + // corresponding to `aAction` for `aName`. + + bool has = false; + + for (const ProxyQuery &query : Get().mProxyQueries) + { + ProxyQueryInfo info; + + info.ReadFrom(query); + + if (QueryMatches(query, info, aAction, aName)) + { + has = true; + break; + } + } + + return has; +} + +void Server::DiscoveryProxy::HandleBrowseResult(otInstance *aInstance, const otPlatDnssdBrowseResult *aResult) +{ + AsCoreType(aInstance).Get().mDiscoveryProxy.HandleBrowseResult(*aResult); +} + +void Server::DiscoveryProxy::HandleBrowseResult(const Dnssd::BrowseResult &aResult) +{ + Name::Buffer serviceName; + + VerifyOrExit(mIsRunning); + VerifyOrExit(aResult.mTtl != 0); + VerifyOrExit(aResult.mInfraIfIndex == Get().GetIfIndex()); + + if (aResult.mSubTypeLabel != nullptr) + { + ConstructFullServiceSubTypeName(aResult.mServiceType, aResult.mSubTypeLabel, serviceName); + } + else + { + ConstructFullName(aResult.mServiceType, serviceName); + } + + HandleResult(kBrowsing, serviceName, &Response::AppendPtrRecord, ProxyResult(aResult)); + +exit: + return; +} + +void Server::DiscoveryProxy::HandleSrvResult(otInstance *aInstance, const otPlatDnssdSrvResult *aResult) +{ + AsCoreType(aInstance).Get().mDiscoveryProxy.HandleSrvResult(*aResult); +} + +void Server::DiscoveryProxy::HandleSrvResult(const Dnssd::SrvResult &aResult) +{ + Name::Buffer instanceName; + + VerifyOrExit(mIsRunning); + VerifyOrExit(aResult.mTtl != 0); + VerifyOrExit(aResult.mInfraIfIndex == Get().GetIfIndex()); + + ConstructFullInstanceName(aResult.mServiceInstance, aResult.mServiceType, instanceName); + HandleResult(kResolvingSrv, instanceName, &Response::AppendSrvRecord, ProxyResult(aResult)); + +exit: + return; +} + +void Server::DiscoveryProxy::HandleTxtResult(otInstance *aInstance, const otPlatDnssdTxtResult *aResult) +{ + AsCoreType(aInstance).Get().mDiscoveryProxy.HandleTxtResult(*aResult); +} + +void Server::DiscoveryProxy::HandleTxtResult(const Dnssd::TxtResult &aResult) +{ + Name::Buffer instanceName; + + VerifyOrExit(mIsRunning); + VerifyOrExit(aResult.mTtl != 0); + VerifyOrExit(aResult.mInfraIfIndex == Get().GetIfIndex()); + + ConstructFullInstanceName(aResult.mServiceInstance, aResult.mServiceType, instanceName); + HandleResult(kResolvingTxt, instanceName, &Response::AppendTxtRecord, ProxyResult(aResult)); + +exit: + return; +} + +void Server::DiscoveryProxy::HandleIp6AddressResult(otInstance *aInstance, const otPlatDnssdAddressResult *aResult) +{ + AsCoreType(aInstance).Get().mDiscoveryProxy.HandleIp6AddressResult(*aResult); +} + +void Server::DiscoveryProxy::HandleIp6AddressResult(const Dnssd::AddressResult &aResult) +{ + bool hasValidAddress = false; + Name::Buffer fullHostName; + + VerifyOrExit(mIsRunning); + VerifyOrExit(aResult.mInfraIfIndex == Get().GetIfIndex()); + + for (uint16_t index = 0; index < aResult.mAddressesLength; index++) + { + const Dnssd::AddressAndTtl &entry = aResult.mAddresses[index]; + const Ip6::Address &address = AsCoreType(&entry.mAddress); + + if (entry.mTtl == 0) + { + continue; + } + + if (IsProxyAddressValid(address)) + { + hasValidAddress = true; + break; + } + } + + VerifyOrExit(hasValidAddress); + + ConstructFullName(aResult.mHostName, fullHostName); + HandleResult(kResolvingIp6Address, fullHostName, &Response::AppendHostAddresses, ProxyResult(aResult)); + +exit: + return; +} + +void Server::DiscoveryProxy::HandleResult(ProxyAction aAction, + const Name::Buffer &aName, + ResponseAppender aAppender, + const ProxyResult &aResult) +{ + // Common method that handles result from DNS-SD/mDNS. It + // iterates over all `ProxyQuery` entries and checks if any entry + // is waiting for the result of `aAction` for `aName`. Matching + // queries are updated using the `aAppender` method pointer, + // which appends the corresponding record(s) to the response. We + // then determine the next action to be performed for the + // `ProxyQuery` or if it can be finalized. + + ProxyQueryList nextActionQueries; + ProxyQueryInfo info; + ProxyAction nextAction; + + for (ProxyQuery &query : Get().mProxyQueries) + { + Response response(GetInstance()); + bool shouldFinalize; + + info.ReadFrom(query); + + if (!QueryMatches(query, info, aAction, aName)) + { + continue; + } + + CancelAction(query, info); + + nextAction = kNoAction; + + switch (aAction) + { + case kBrowsing: + nextAction = kResolvingSrv; + break; + case kResolvingSrv: + nextAction = (info.mType == kSrvQuery) ? kResolvingIp6Address : kResolvingTxt; + break; + case kResolvingTxt: + nextAction = (info.mType == kTxtQuery) ? kNoAction : kResolvingIp6Address; + break; + case kNoAction: + case kResolvingIp6Address: + break; + } + + shouldFinalize = (nextAction == kNoAction); + + if ((Get().mTestMode & kTestModeEmptyAdditionalSection) && + IsActionForAdditionalSection(nextAction, info.mType)) + { + shouldFinalize = true; + } + + Get().mProxyQueries.Dequeue(query); + info.RemoveFrom(query); + response.InitFrom(query, info); + + if ((response.*aAppender)(aResult) != kErrorNone) + { + response.SetResponseCode(Header::kResponseServerFailure); + shouldFinalize = true; + } + + if (shouldFinalize) + { + response.Send(info.mMessageInfo); + continue; + } + + // The `query` is not yet finished and we need to perform + // the `nextAction` for it. + + // Reinitialize `response` as a `ProxyQuey` by updating + // and appending `info` to it after the newly appended + // records from `aResult` and saving the `mHeader`. + + info.mOffsets = response.mOffsets; + info.mAction = nextAction; + response.mMessage->Write(0, response.mHeader); + + if (response.mMessage->Append(info) != kErrorNone) + { + response.SetResponseCode(Header::kResponseServerFailure); + response.Send(info.mMessageInfo); + continue; + } + + // Take back ownership of `response.mMessage` as we still + // treat it as a `ProxyQuery`. + + response.mMessage.Release(); + + // We place the `query` in a separate list and add it back to + // the main `mProxyQueries` list after we are done with the + // current iteration. This ensures that other entries in the + // `mProxyQueries` list are not updated or removed due to the + // DNS-SD platform callback being invoked immediately when we + // potentially start a browser or resolver to perform the + // `nextAction` for `query`. + + nextActionQueries.Enqueue(query); + } + + for (ProxyQuery &query : nextActionQueries) + { + nextActionQueries.Dequeue(query); + + info.ReadFrom(query); + + nextAction = info.mAction; + + info.mAction = kNoAction; + info.UpdateIn(query); + + Get().mProxyQueries.Enqueue(query); + Perform(nextAction, query, info); + } +} + +bool Server::DiscoveryProxy::IsActionForAdditionalSection(ProxyAction aAction, QueryType aQueryType) +{ + bool isForAddnlSection = false; + + switch (aAction) + { + case kResolvingSrv: + VerifyOrExit((aQueryType == kSrvQuery) || (aQueryType == kSrvTxtQuery)); + break; + case kResolvingTxt: + VerifyOrExit((aQueryType == kTxtQuery) || (aQueryType == kSrvTxtQuery)); + break; + + case kResolvingIp6Address: + VerifyOrExit(aQueryType == kAaaaQuery); + break; + + case kNoAction: + case kBrowsing: + ExitNow(); + } + + isForAddnlSection = true; + +exit: + return isForAddnlSection; +} + +Error Server::Response::AppendPtrRecord(const ProxyResult &aResult) +{ + const Dnssd::BrowseResult *browseResult = aResult.mBrowseResult; + + mSection = kAnswerSection; + + return AppendPtrRecord(browseResult->mServiceInstance, browseResult->mTtl); +} + +Error Server::Response::AppendSrvRecord(const ProxyResult &aResult) +{ + const Dnssd::SrvResult *srvResult = aResult.mSrvResult; + Name::Buffer fullHostName; + + mSection = ((mType == kSrvQuery) || (mType == kSrvTxtQuery)) ? kAnswerSection : kAdditionalDataSection; + + ConstructFullName(srvResult->mHostName, fullHostName); + + return AppendSrvRecord(fullHostName, srvResult->mTtl, srvResult->mPriority, srvResult->mWeight, srvResult->mPort); +} + +Error Server::Response::AppendTxtRecord(const ProxyResult &aResult) +{ + const Dnssd::TxtResult *txtResult = aResult.mTxtResult; + + mSection = ((mType == kTxtQuery) || (mType == kSrvTxtQuery)) ? kAnswerSection : kAdditionalDataSection; + + return AppendTxtRecord(txtResult->mTxtData, txtResult->mTxtDataLength, txtResult->mTtl); +} + +Error Server::Response::AppendHostAddresses(const ProxyResult &aResult) +{ + Error error = kErrorNone; + const Dnssd::AddressResult *addrResult = aResult.mAddressResult; + + mSection = (mType == kAaaaQuery) ? kAnswerSection : kAdditionalDataSection; + + for (uint16_t index = 0; index < addrResult->mAddressesLength; index++) + { + const Dnssd::AddressAndTtl &entry = addrResult->mAddresses[index]; + const Ip6::Address &address = AsCoreType(&entry.mAddress); + + if (entry.mTtl == 0) + { + continue; + } + + if (!IsProxyAddressValid(address)) + { + continue; + } + + SuccessOrExit(error = AppendAaaaRecord(address, entry.mTtl)); + } + +exit: + return error; +} + +bool Server::IsProxyAddressValid(const Ip6::Address &aAddress) +{ + return !aAddress.IsLinkLocal() && !aAddress.IsMulticast() && !aAddress.IsUnspecified() && !aAddress.IsLoopback(); +} + +#endif // OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + } // namespace ServiceDiscovery } // namespace Dns } // namespace ot diff --git a/src/core/net/dnssd_server.hpp b/src/core/net/dnssd_server.hpp index 4afde1d7d..692239ecb 100644 --- a/src/core/net/dnssd_server.hpp +++ b/src/core/net/dnssd_server.hpp @@ -33,8 +33,20 @@ #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + +#if !OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE && !OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE +#error "OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE requires either PLATFORM_DNSSD_ENABLE or MULTICAST_DNS_ENABLE" +#endif +#if !OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE +#error "OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE requires OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE" +#endif + +#endif // OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + #include +#include "border_router/infra_if.hpp" #include "common/as_core_type.hpp" #include "common/callback.hpp" #include "common/message.hpp" @@ -42,6 +54,7 @@ #include "common/owned_ptr.hpp" #include "common/timer.hpp" #include "net/dns_types.hpp" +#include "net/dnssd.hpp" #include "net/ip6.hpp" #include "net/netif.hpp" #include "net/srp_server.hpp" @@ -71,6 +84,10 @@ namespace ServiceDiscovery { class Server : public InstanceLocator, private NonCopyable { friend class Srp::Server; +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + friend class ot::Dnssd; + friend class ot::BorderRouter::InfraIf; +#endif public: /** @@ -316,6 +333,17 @@ class Server : public InstanceLocator, private NonCopyable kAdditionalDataSection, }; +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + enum ProxyAction : uint8_t + { + kNoAction, + kBrowsing, + kResolvingSrv, + kResolvingTxt, + kResolvingIp6Address, + }; +#endif + struct Request { ResponseCode ParseQuestions(uint8_t aTestMode); @@ -336,6 +364,21 @@ class Server : public InstanceLocator, private NonCopyable uint16_t mHostName; }; +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + union ProxyResult + { + explicit ProxyResult(const Dnssd::BrowseResult &aBrowseResult) { mBrowseResult = &aBrowseResult; } + explicit ProxyResult(const Dnssd::SrvResult &aSrvResult) { mSrvResult = &aSrvResult; } + explicit ProxyResult(const Dnssd::TxtResult &aTxtResult) { mTxtResult = &aTxtResult; } + explicit ProxyResult(const Dnssd::AddressResult &aAddressResult) { mAddressResult = &aAddressResult; } + + const Dnssd::BrowseResult *mBrowseResult; + const Dnssd::SrvResult *mSrvResult; + const Dnssd::TxtResult *mTxtResult; + const Dnssd::AddressResult *mAddressResult; + }; +#endif + class Response : public InstanceLocator, private NonCopyable { public: @@ -360,6 +403,7 @@ class Server : public InstanceLocator, private NonCopyable Error AppendHostAddresses(const HostInfo &aHostInfo); Error AppendHostAddresses(const ServiceInstanceInfo &aInstanceInfo); Error AppendHostAddresses(const Ip6::Address *aAddrs, uint16_t aAddrsLength, uint32_t aTtl); + Error AppendAaaaRecord(const Ip6::Address &aAddress, uint32_t aTtl); void UpdateRecordLength(ResourceRecord &aRecord, uint16_t aOffset); void IncResourceRecordCount(void); void Send(const Ip6::MessageInfo &aMessageInfo); @@ -373,6 +417,14 @@ class Server : public InstanceLocator, private NonCopyable Error AppendTxtRecord(const Srp::Server::Service &aService); Error AppendHostAddresses(const Srp::Server::Host &aHost); #endif +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + Error AppendPtrRecord(const ProxyResult &aResult); + Error AppendSrvRecord(const ProxyResult &aResult); + Error AppendTxtRecord(const ProxyResult &aResult); + + Error AppendHostAddresses(const ProxyResult &aResult); +#endif + #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) void Log(void) const; static const char *QueryTypeToString(QueryType aType); @@ -395,18 +447,106 @@ class Server : public InstanceLocator, private NonCopyable Ip6::MessageInfo mMessageInfo; TimeMilli mExpireTime; NameOffsets mOffsets; +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + ProxyAction mAction; +#endif }; +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + class DiscoveryProxy : public InstanceLocator, private NonCopyable + { + friend ot::Dnssd; + + public: + explicit DiscoveryProxy(Instance &aInstance); + + bool IsRunning(void) const { return mIsRunning; } + void UpdateState(void); + void Start(void); + void Stop(void); + void Resolve(ProxyQuery &aQuery, ProxyQueryInfo &aInfo); + void CancelAction(ProxyQuery &aQuery, ProxyQueryInfo &aInfo); + + private: + enum Command : uint8_t + { + kStart, + kStop, + }; + + typedef Error (Response::*ResponseAppender)(const ProxyResult &aResult); + + void Perform(ProxyAction aAction, ProxyQuery &aQuery, ProxyQueryInfo &aInfo); + void ReadNameFor(ProxyAction aAction, ProxyQuery &aQuery, ProxyQueryInfo &aInfo, Name::Buffer &aName) const; + bool HasActive(ProxyAction aAction, const Name::Buffer &aName) const; + bool QueryMatches(const ProxyQuery &aQuery, + const ProxyQueryInfo &aInfo, + ProxyAction aAction, + const Name::Buffer &aName) const; + void UpdateProxy(Command aCommand, + ProxyAction aAction, + const ProxyQuery &aQuery, + const ProxyQueryInfo &aInfo, + Name::Buffer &aName); + void StartOrStopBrowser(Command aCommand, Name::Buffer &aServiceName); + void StartOrStopSrvResolver(Command aCommand, const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo); + void StartOrStopTxtResolver(Command aCommand, const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo); + void StartOrStopIp6Resolver(Command aCommand, Name::Buffer &aHostName); + + static void HandleBrowseResult(otInstance *aInstance, const otPlatDnssdBrowseResult *aResult); + static void HandleSrvResult(otInstance *aInstance, const otPlatDnssdSrvResult *aResult); + static void HandleTxtResult(otInstance *aInstance, const otPlatDnssdTxtResult *aResult); + static void HandleIp6AddressResult(otInstance *aInstance, const otPlatDnssdAddressResult *aResult); + + void HandleBrowseResult(const Dnssd::BrowseResult &aResult); + void HandleSrvResult(const Dnssd::SrvResult &aResult); + void HandleTxtResult(const Dnssd::TxtResult &aResult); + void HandleIp6AddressResult(const Dnssd::AddressResult &aResult); + void HandleResult(ProxyAction aAction, + const Name::Buffer &aName, + ResponseAppender aAppender, + const ProxyResult &aResult); + + static bool IsActionForAdditionalSection(ProxyAction aAction, QueryType aQueryType); + + bool mIsRunning; + }; +#endif + bool IsRunning(void) const { return mSocket.IsBound(); } static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void ProcessQuery(Request &aRequest); - void ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessageInfo); - void RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Response &aResponse); - void Finalize(ProxyQuery &aQuery, ResponseCode aResponseCode); - static void ReadQueryName(const Message &aQuery, Name::Buffer &aName); - static bool QueryNameMatches(const Message &aQuery, const char *aName); + void ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessageInfo); + void RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, ProxyQueryInfo &aInfo, Response &aResponse); + void Finalize(ProxyQuery &aQuery, ResponseCode aResponseCode); + + static void ReadQueryName(const Message &aQuery, Name::Buffer &aName); + static bool QueryNameMatches(const Message &aQuery, const char *aName); + static void ReadQueryInstanceName(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Name::Buffer &aName); + static void ReadQueryInstanceName(const ProxyQuery &aQuery, + const ProxyQueryInfo &aInfo, + Name::LabelBuffer &aInstanceLabel, + Name::Buffer &aServiceType); + static bool QueryInstanceNameMatches(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, const char *aName); + static void ReadQueryHostName(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Name::Buffer &aName); + static bool QueryHostNameMatches(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, const char *aName); + static Error StripDomainName(const char *aFullName, Name::Buffer &aLabels); + static Error StripDomainName(Name::Buffer &aName); + static void ConstructFullName(const char *aLabels, Name::Buffer &aFullName); + static void ConstructFullInstanceName(const char *aInstanceLabel, + const char *aServiceType, + Name::Buffer &aFullName); + static void ConstructFullServiceSubTypeName(const char *aServiceType, + const char *aSubTypeLabel, + Name::Buffer &aFullName); + +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + void HandleInfraIfStateChanged(void) { mDiscoveryProxy.UpdateState(); } + void HandleDnssdPlatformStateChange(void) { mDiscoveryProxy.UpdateState(); } + static bool IsProxyAddressValid(const Ip6::Address &aAddress); +#endif #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE static bool ShouldForwardToUpstream(const Request &aRequest); @@ -434,6 +574,10 @@ class Server : public InstanceLocator, private NonCopyable Callback mQuerySubscribe; Callback mQueryUnsubscribe; +#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE + DiscoveryProxy mDiscoveryProxy; +#endif + #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE bool mEnableUpstreamQuery; UpstreamQueryTransaction mUpstreamQueryTransactions[kMaxConcurrentUpstreamQueries]; diff --git a/tests/toranj/openthread-core-toranj-config-simulation.h b/tests/toranj/openthread-core-toranj-config-simulation.h index e0f030e57..88b958615 100644 --- a/tests/toranj/openthread-core-toranj-config-simulation.h +++ b/tests/toranj/openthread-core-toranj-config-simulation.h @@ -76,6 +76,8 @@ #define OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE +#define OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + #define OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE 1 #define OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE 1 diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index a8364f7a7..92aad7622 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -176,6 +176,7 @@ ot_unit_test(data) ot_unit_test(dataset) ot_unit_test(dns) ot_unit_test(dns_client) +ot_unit_test(dnssd_discovery_proxy) ot_unit_test(dso) ot_unit_test(ecdsa) ot_unit_test(flash) diff --git a/tests/unit/test_dnssd_discovery_proxy.cpp b/tests/unit/test_dnssd_discovery_proxy.cpp new file mode 100644 index 000000000..c2dfc0d04 --- /dev/null +++ b/tests/unit/test_dnssd_discovery_proxy.cpp @@ -0,0 +1,2723 @@ +/* + * Copyright (c) 2023, 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 + +#include "test_platform.h" +#include "test_util.hpp" + +#include +#include +#include +#include +#include + +#include "common/arg_macros.hpp" +#include "common/array.hpp" +#include "common/clearable.hpp" +#include "common/string.hpp" +#include "common/time.hpp" +#include "instance/instance.hpp" + +#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE && OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE && \ + OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE && OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && \ + OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && \ + OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION && OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && \ + !OPENTHREAD_CONFIG_TIME_SYNC_ENABLE && !OPENTHREAD_PLATFORM_POSIX +#define ENABLE_DISCOVERY_PROXY_TEST 1 +#else +#define ENABLE_DISCOVERY_PROXY_TEST 0 +#endif + +#if ENABLE_DISCOVERY_PROXY_TEST + +using namespace ot; + +// Logs a message and adds current time (sNow) as "::." +#define Log(...) \ + printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 36000000), (sNow / 60000) % 60, \ + (sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__)) + +static constexpr uint16_t kMaxRaSize = 800; + +static ot::Instance *sInstance; + +static uint32_t sNow = 0; +static uint32_t sAlarmTime; +static bool sAlarmOn = false; + +static otRadioFrame sRadioTxFrame; +static uint8_t sRadioTxFramePsdu[OT_RADIO_FRAME_MAX_SIZE]; +static bool sRadioTxOngoing = false; + +//---------------------------------------------------------------------------------------------------------------------- +// Function prototypes + +void ProcessRadioTxAndTasklets(void); +void AdvanceTime(uint32_t aDuration); + +//---------------------------------------------------------------------------------------------------------------------- +// `otPlatRadio` + +extern "C" { + +otRadioCaps otPlatRadioGetCaps(otInstance *) { return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF; } + +otError otPlatRadioTransmit(otInstance *, otRadioFrame *) +{ + sRadioTxOngoing = true; + + return OT_ERROR_NONE; +} + +otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *) { return &sRadioTxFrame; } + +//---------------------------------------------------------------------------------------------------------------------- +// `otPlatAlaram` + +void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; } + +void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt) +{ + sAlarmOn = true; + sAlarmTime = aT0 + aDt; +} + +uint32_t otPlatAlarmMilliGetNow(void) { return sNow; } + +//---------------------------------------------------------------------------------------------------------------------- + +Array sHeapAllocatedPtrs; + +#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +void *otPlatCAlloc(size_t aNum, size_t aSize) +{ + void *ptr = calloc(aNum, aSize); + + SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr)); + + return ptr; +} + +void otPlatFree(void *aPtr) +{ + if (aPtr != nullptr) + { + void **entry = sHeapAllocatedPtrs.Find(aPtr); + + VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice"); + sHeapAllocatedPtrs.Remove(*entry); + } + + free(aPtr); +} +#endif + +#if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED +void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...) +{ + OT_UNUSED_VARIABLE(aLogLevel); + OT_UNUSED_VARIABLE(aLogRegion); + + va_list args; + + printf(" "); + va_start(args, aFormat); + vprintf(aFormat, args); + va_end(args); + printf("\n"); +} +#endif + +} // extern "C" + +//--------------------------------------------------------------------------------------------------------------------- + +void ProcessRadioTxAndTasklets(void) +{ + do + { + if (sRadioTxOngoing) + { + sRadioTxOngoing = false; + otPlatRadioTxStarted(sInstance, &sRadioTxFrame); + otPlatRadioTxDone(sInstance, &sRadioTxFrame, nullptr, OT_ERROR_NONE); + } + + otTaskletsProcess(sInstance); + } while (otTaskletsArePending(sInstance)); +} + +void AdvanceTime(uint32_t aDuration) +{ + uint32_t time = sNow + aDuration; + + Log("AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000); + + while (TimeMilli(sAlarmTime) <= TimeMilli(time)) + { + ProcessRadioTxAndTasklets(); + sNow = sAlarmTime; + otPlatAlarmMilliFired(sInstance); + } + + ProcessRadioTxAndTasklets(); + sNow = time; +} + +void InitTest(void) +{ + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Initialize OT instance. + + sNow = 0; + sAlarmOn = false; + sInstance = static_cast(testInitInstance()); + + memset(&sRadioTxFrame, 0, sizeof(sRadioTxFrame)); + sRadioTxFrame.mPsdu = sRadioTxFramePsdu; + sRadioTxOngoing = false; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Initialize Border Router and start Thread operation. + + otOperationalDataset dataset; + otOperationalDatasetTlvs datasetTlvs; + + SuccessOrQuit(otDatasetCreateNewNetwork(sInstance, &dataset)); + otDatasetConvertToTlvs(&dataset, &datasetTlvs); + SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs)); + + SuccessOrQuit(otIp6SetEnabled(sInstance, true)); + SuccessOrQuit(otThreadSetEnabled(sInstance, true)); + + // Configure the `Dnssd` module to use `otPlatDnssd` APIs. + + sInstance->Get().SetUseNativeMdns(false); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Ensure device starts as leader. + + AdvanceTime(10000); + + VerifyOrQuit(otThreadGetDeviceRole(sInstance) == OT_DEVICE_ROLE_LEADER); +} + +void FinalizeTest(void) +{ + SuccessOrQuit(otIp6SetEnabled(sInstance, false)); + SuccessOrQuit(otThreadSetEnabled(sInstance, false)); + // Make sure there is no message/buffer leak + VerifyOrQuit(sInstance->Get().GetFreeBufferCount() == + sInstance->Get().GetTotalBufferCount()); + SuccessOrQuit(otInstanceErasePersistentInfo(sInstance)); + testFreeInstance(sInstance); +} + +//--------------------------------------------------------------------------------------------------------------------- +// DNS Client callback + +void LogServiceInfo(const Dns::Client::ServiceInfo &aInfo) +{ + Log(" TTL: %u", aInfo.mTtl); + Log(" Port: %u", aInfo.mPort); + Log(" Weight: %u", aInfo.mWeight); + Log(" HostName: %s", aInfo.mHostNameBuffer); + Log(" HostAddr: %s", AsCoreType(&aInfo.mHostAddress).ToString().AsCString()); + Log(" TxtDataLength: %u", aInfo.mTxtDataSize); + Log(" TxtDataTTL: %u", aInfo.mTxtDataTtl); +} + +const char *ServiceModeToString(Dns::Client::QueryConfig::ServiceMode aMode) +{ + static const char *const kServiceModeStrings[] = { + "unspec", // kServiceModeUnspecified (0) + "srv", // kServiceModeSrv (1) + "txt", // kServiceModeTxt (2) + "srv_txt", // kServiceModeSrvTxt (3) + "srv_txt_sep", // kServiceModeSrvTxtSeparate (4) + "srv_txt_opt", // kServiceModeSrvTxtOptimize (5) + }; + + static_assert(Dns::Client::QueryConfig::kServiceModeUnspecified == 0, "Unspecified value is incorrect"); + static_assert(Dns::Client::QueryConfig::kServiceModeSrv == 1, "Srv value is incorrect"); + static_assert(Dns::Client::QueryConfig::kServiceModeTxt == 2, "Txt value is incorrect"); + static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxt == 3, "SrvTxt value is incorrect"); + static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxtSeparate == 4, "SrvTxtSeparate value is incorrect"); + static_assert(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize == 5, "SrvTxtOptimize value is incorrect"); + + return kServiceModeStrings[aMode]; +} + +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +struct BrowseInfo +{ + void Reset(void) { mCallbackCount = 0; } + + uint16_t mCallbackCount; + Error mError; + char mServiceName[Dns::Name::kMaxNameSize]; + char mInstanceLabel[Dns::Name::kMaxLabelSize]; + uint16_t mNumInstances; + Dns::Client::ServiceInfo mServiceInfo; + char mHostNameBuffer[Dns::Name::kMaxNameSize]; + uint8_t mTxtBuffer[255]; +}; + +static BrowseInfo sBrowseInfo; + +void BrowseCallback(otError aError, const otDnsBrowseResponse *aResponse, void *aContext) +{ + const Dns::Client::BrowseResponse &response = AsCoreType(aResponse); + + Log("BrowseCallback"); + Log(" Error: %s", ErrorToString(aError)); + + VerifyOrQuit(aContext == sInstance); + + sBrowseInfo.mCallbackCount++; + sBrowseInfo.mError = aError; + + SuccessOrExit(aError); + + SuccessOrQuit(response.GetServiceName(sBrowseInfo.mServiceName, sizeof(sBrowseInfo.mServiceName))); + Log(" ServiceName: %s", sBrowseInfo.mServiceName); + + for (uint16_t index = 0;; index++) + { + Error error; + + error = response.GetServiceInstance(index, sBrowseInfo.mInstanceLabel, sizeof(sBrowseInfo.mInstanceLabel)); + + if (error == kErrorNotFound) + { + sBrowseInfo.mNumInstances = index; + break; + } + + SuccessOrQuit(error); + + Log(" %2u) %s", index + 1, sBrowseInfo.mInstanceLabel); + } + + if (sBrowseInfo.mNumInstances == 1) + { + sBrowseInfo.mServiceInfo.mHostNameBuffer = sBrowseInfo.mHostNameBuffer; + sBrowseInfo.mServiceInfo.mHostNameBufferSize = sizeof(sBrowseInfo.mHostNameBuffer); + sBrowseInfo.mServiceInfo.mTxtData = sBrowseInfo.mTxtBuffer; + sBrowseInfo.mServiceInfo.mTxtDataSize = sizeof(sBrowseInfo.mTxtBuffer); + + SuccessOrExit(response.GetServiceInfo(sBrowseInfo.mInstanceLabel, sBrowseInfo.mServiceInfo)); + LogServiceInfo(sBrowseInfo.mServiceInfo); + } + +exit: + return; +} + +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static constexpr uint8_t kMaxHostAddresses = 10; +static constexpr uint16_t kMaxTxtBuffer = 256; + +struct ResolveServiceInfo +{ + void Reset(void) + { + memset(this, 0, sizeof(*this)); + mInfo.mHostNameBuffer = mNameBuffer; + mInfo.mHostNameBufferSize = sizeof(mNameBuffer); + mInfo.mTxtData = mTxtBuffer; + mInfo.mTxtDataSize = sizeof(mTxtBuffer); + }; + + uint16_t mCallbackCount; + Error mError; + Dns::Client::ServiceInfo mInfo; + char mNameBuffer[Dns::Name::kMaxNameSize]; + uint8_t mTxtBuffer[kMaxTxtBuffer]; + Ip6::Address mHostAddresses[kMaxHostAddresses]; + uint8_t mNumHostAddresses; +}; + +static ResolveServiceInfo sResolveServiceInfo; + +void ServiceCallback(otError aError, const otDnsServiceResponse *aResponse, void *aContext) +{ + const Dns::Client::ServiceResponse &response = AsCoreType(aResponse); + char instLabel[Dns::Name::kMaxLabelSize]; + char serviceName[Dns::Name::kMaxNameSize]; + + Log("ServiceCallback"); + Log(" Error: %s", ErrorToString(aError)); + + VerifyOrQuit(aContext == sInstance); + + SuccessOrQuit(response.GetServiceName(instLabel, sizeof(instLabel), serviceName, sizeof(serviceName))); + Log(" InstLabel: %s", instLabel); + Log(" ServiceName: %s", serviceName); + + sResolveServiceInfo.mCallbackCount++; + sResolveServiceInfo.mError = aError; + + SuccessOrExit(aError); + + aError = response.GetServiceInfo(sResolveServiceInfo.mInfo); + + if (aError == kErrorNotFound) + { + sResolveServiceInfo.mError = aError; + ExitNow(); + } + + SuccessOrQuit(aError); + + for (uint8_t index = 0; index < kMaxHostAddresses; index++) + { + Error error; + uint32_t ttl; + + error = response.GetHostAddress(sResolveServiceInfo.mInfo.mHostNameBuffer, index, + sResolveServiceInfo.mHostAddresses[index], ttl); + + if (error == kErrorNotFound) + { + sResolveServiceInfo.mNumHostAddresses = index; + break; + } + + SuccessOrQuit(error); + } + + LogServiceInfo(sResolveServiceInfo.mInfo); + Log(" NumHostAddresses: %u", sResolveServiceInfo.mNumHostAddresses); + + for (uint8_t index = 0; index < sResolveServiceInfo.mNumHostAddresses; index++) + { + Log(" %s", sResolveServiceInfo.mHostAddresses[index].ToString().AsCString()); + } + +exit: + return; +} + +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +struct ResolveAddressInfo +{ + void Reset(void) { memset(this, 0, sizeof(*this)); }; + + uint16_t mCallbackCount; + Error mError; + char mHostName[Dns::Name::kMaxNameSize]; + Ip6::Address mHostAddresses[kMaxHostAddresses]; + uint8_t mNumHostAddresses; + uint32_t mTtl; +}; + +static ResolveAddressInfo sResolveAddressInfo; + +void AddressCallback(otError aError, const otDnsAddressResponse *aResponse, void *aContext) +{ + const Dns::Client::AddressResponse &response = AsCoreType(aResponse); + + Log("AddressCallback"); + Log(" Error: %s", ErrorToString(aError)); + + VerifyOrQuit(aContext == sInstance); + + sResolveAddressInfo.mCallbackCount++; + sResolveAddressInfo.mError = aError; + + SuccessOrExit(aError); + + SuccessOrQuit(response.GetHostName(sResolveAddressInfo.mHostName, sizeof(sResolveAddressInfo.mHostName))); + Log(" HostName: %s", sResolveAddressInfo.mHostName); + + for (uint8_t index = 0; index < kMaxHostAddresses; index++) + { + Error error; + uint32_t ttl; + + error = response.GetAddress(index, sResolveAddressInfo.mHostAddresses[index], sResolveAddressInfo.mTtl); + + if (error == kErrorNotFound) + { + sResolveAddressInfo.mNumHostAddresses = index; + break; + } + + SuccessOrQuit(error); + } + + Log(" NumHostAddresses: %u", sResolveAddressInfo.mNumHostAddresses); + + for (uint8_t index = 0; index < sResolveAddressInfo.mNumHostAddresses; index++) + { + Log(" %s", sResolveAddressInfo.mHostAddresses[index].ToString().AsCString()); + } + +exit: + return; +} + +//---------------------------------------------------------------------------------------------------------------------- +// otPlatDnssd APIs + +constexpr uint32_t kInfraIfIndex = 1; + +static otPlatDnssdState sDnssdState = OT_PLAT_DNSSD_READY; + +template void CopyString(char (&aStringBuffer)[kSize], const char *aString) +{ + if (aString == nullptr) + { + memset(aStringBuffer, 0, kSize); + } + else + { + uint16_t length = StringLength(aString, kSize); + + VerifyOrQuit(length < kSize); + memcpy(aStringBuffer, aString, length + 1); + } +} + +struct BrowserInfo : public Clearable +{ + bool ServiceTypeMatches(const char *aType) const { return !strcmp(mServiceType, aType); } + bool SubTypeMatches(const char *aSubType) const { return !strcmp(mSubTypeLabel, aSubType); } + + void UpdateFrom(const otPlatDnssdBrowser *aBrowser) + { + mCallCount++; + CopyString(mServiceType, aBrowser->mServiceType); + CopyString(mSubTypeLabel, aBrowser->mSubTypeLabel); + mCallback = aBrowser->mCallback; + } + + uint16_t mCallCount; + char mServiceType[Dns::Name::kMaxNameSize]; + char mSubTypeLabel[Dns::Name::kMaxNameSize]; + otPlatDnssdBrowseCallback mCallback; +}; + +struct SrvResolverInfo : public Clearable +{ + bool ServiceTypeMatches(const char *aType) const { return !strcmp(mServiceType, aType); } + bool ServiceInstanceMatches(const char *aInstance) const { return !strcmp(mServiceInstance, aInstance); } + + void UpdateFrom(const otPlatDnssdSrvResolver *aResolver) + { + mCallCount++; + CopyString(mServiceInstance, aResolver->mServiceInstance); + CopyString(mServiceType, aResolver->mServiceType); + mCallback = aResolver->mCallback; + } + + uint16_t mCallCount; + char mServiceInstance[Dns::Name::kMaxLabelSize]; + char mServiceType[Dns::Name::kMaxNameSize]; + otPlatDnssdSrvCallback mCallback; +}; + +struct TxtResolverInfo : public Clearable +{ + bool ServiceTypeMatches(const char *aType) const { return !strcmp(mServiceType, aType); } + bool ServiceInstanceMatches(const char *aInstance) const { return !strcmp(mServiceInstance, aInstance); } + + void UpdateFrom(const otPlatDnssdTxtResolver *aResolver) + { + mCallCount++; + CopyString(mServiceInstance, aResolver->mServiceInstance); + CopyString(mServiceType, aResolver->mServiceType); + mCallback = aResolver->mCallback; + } + + uint16_t mCallCount; + char mServiceInstance[Dns::Name::kMaxLabelSize]; + char mServiceType[Dns::Name::kMaxNameSize]; + otPlatDnssdTxtCallback mCallback; +}; + +struct Ip6AddrResolverInfo : public Clearable +{ + bool HostNameMatches(const char *aName) const { return !strcmp(mHostName, aName); } + + void UpdateFrom(const otPlatDnssdAddressResolver *aResolver) + { + mCallCount++; + CopyString(mHostName, aResolver->mHostName); + mCallback = aResolver->mCallback; + } + + uint16_t mCallCount; + char mHostName[Dns::Name::kMaxNameSize]; + otPlatDnssdAddressCallback mCallback; +}; + +struct InvokeOnStart : public Clearable +{ + // When not null, these entries are used to invoke callback + // directly from `otPlatDnssdStart{Browser/Resolver}()` APIs. + // This is used in `TestProxyInvokeCallbackFromStartApi()`. + + const otPlatDnssdBrowseResult *mBrowseResult; + const otPlatDnssdSrvResult *mSrvResult; + const otPlatDnssdTxtResult *mTxtResult; + const otPlatDnssdAddressResult *mIp6AddrResult; +}; + +static BrowserInfo sStartBrowserInfo; +static BrowserInfo sStopBrowserInfo; +static SrvResolverInfo sStartSrvResolverInfo; +static SrvResolverInfo sStopSrvResolverInfo; +static TxtResolverInfo sStartTxtResolverInfo; +static TxtResolverInfo sStopTxtResolverInfo; +static Ip6AddrResolverInfo sStartIp6AddrResolverInfo; +static Ip6AddrResolverInfo sStopIp6AddrResolverInfo; + +static InvokeOnStart sInvokeOnStart; + +void ResetPlatDnssdApiInfo(void) +{ + sStartBrowserInfo.Clear(); + sStopBrowserInfo.Clear(); + sStartSrvResolverInfo.Clear(); + sStopSrvResolverInfo.Clear(); + sStartTxtResolverInfo.Clear(); + sStopTxtResolverInfo.Clear(); + sStartIp6AddrResolverInfo.Clear(); + sStopIp6AddrResolverInfo.Clear(); + sInvokeOnStart.Clear(); +} + +const char *StringNullCheck(const char *aString) { return (aString != nullptr) ? aString : "(null)"; } + +void InvokeBrowserCallback(otPlatDnssdBrowseCallback aCallback, const otPlatDnssdBrowseResult &aResult) +{ + Log("Invoking browser callback"); + Log(" serviceType : \"%s\"", StringNullCheck(aResult.mServiceType)); + Log(" subType : \"%s\"", StringNullCheck(aResult.mSubTypeLabel)); + Log(" serviceInstance: \"%s\"", StringNullCheck(aResult.mServiceInstance)); + Log(" ttl : %u", aResult.mTtl); + Log(" if-index : %u", aResult.mInfraIfIndex); + + aCallback(sInstance, &aResult); +} + +void InvokeSrvResolverCallback(otPlatDnssdSrvCallback aCallback, const otPlatDnssdSrvResult &aResult) +{ + Log("Invoking SRV resolver callback"); + Log(" serviceInstance: %s", StringNullCheck(aResult.mServiceInstance)); + Log(" serviceType : %s", StringNullCheck(aResult.mServiceType)); + Log(" hostName : %s", StringNullCheck(aResult.mHostName)); + Log(" port : %u", aResult.mPort); + Log(" priority : %u", aResult.mPriority); + Log(" weight : %u", aResult.mWeight); + Log(" ttl : %u", aResult.mTtl); + Log(" if-index : %u", aResult.mInfraIfIndex); + + aCallback(sInstance, &aResult); +} + +void InvokeTxtResolverCallback(otPlatDnssdTxtCallback aCallback, const otPlatDnssdTxtResult &aResult) +{ + Log("Invoking TXT resolver callback"); + Log(" serviceInstance: %s", StringNullCheck(aResult.mServiceInstance)); + Log(" serviceType : %s", StringNullCheck(aResult.mServiceType)); + Log(" txt-data-len : %u", aResult.mTxtDataLength); + Log(" ttl : %u", aResult.mTtl); + Log(" if-index : %u", aResult.mInfraIfIndex); + + aCallback(sInstance, &aResult); +} + +void InvokeIp6AddrResolverCallback(const otPlatDnssdAddressCallback aCallback, const otPlatDnssdAddressResult &aResult) +{ + Log("Invoking Ip6 resolver callback"); + Log(" hostName : %s", aResult.mHostName); + Log(" if-index : %u", aResult.mInfraIfIndex); + Log(" numAddresses : %u", aResult.mAddressesLength); + for (uint16_t index = 0; index < aResult.mAddressesLength; index++) + { + Log(" address[%u] : %s", index, AsCoreType(&aResult.mAddresses[index].mAddress).ToString().AsCString()); + Log(" ttl[%u] : %u", index, aResult.mAddresses[index].mTtl); + } + + aCallback(sInstance, &aResult); +} + +otPlatDnssdState otPlatDnssdGetState(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return sDnssdState; +} + +void otPlatDnssdStartBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser) +{ + VerifyOrQuit(aBrowser != nullptr); + + Log("otPlatDnssdStartBrowser(\"%s\", sub-type:\"%s\")", aBrowser->mServiceType, aBrowser->mSubTypeLabel); + + VerifyOrQuit(aInstance == sInstance); + VerifyOrQuit(aBrowser->mInfraIfIndex == kInfraIfIndex); + + sStartBrowserInfo.UpdateFrom(aBrowser); + + if (sInvokeOnStart.mBrowseResult != nullptr) + { + InvokeBrowserCallback(aBrowser->mCallback, *sInvokeOnStart.mBrowseResult); + } +} + +void otPlatDnssdStopBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser) +{ + VerifyOrQuit(aBrowser != nullptr); + + Log("otPlatDnssdStopBrowser(\"%s\", sub-type:\"%s\")", aBrowser->mServiceType, aBrowser->mSubTypeLabel); + + VerifyOrQuit(aInstance == sInstance); + VerifyOrQuit(aBrowser->mInfraIfIndex == kInfraIfIndex); + + sStopBrowserInfo.UpdateFrom(aBrowser); +} + +void otPlatDnssdStartSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver) +{ + VerifyOrQuit(aResolver != nullptr); + + Log("otPlatDnssdStartSrvResolver(\"%s\", \"%s\")", aResolver->mServiceInstance, aResolver->mServiceType); + + VerifyOrQuit(aInstance == sInstance); + VerifyOrQuit(aResolver->mInfraIfIndex == kInfraIfIndex); + + sStartSrvResolverInfo.UpdateFrom(aResolver); + + if (sInvokeOnStart.mSrvResult != nullptr) + { + InvokeSrvResolverCallback(aResolver->mCallback, *sInvokeOnStart.mSrvResult); + } +} + +void otPlatDnssdStopSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver) +{ + VerifyOrQuit(aResolver != nullptr); + + Log("otPlatDnssdStopSrvResolver(\"%s\", \"%s\")", aResolver->mServiceInstance, aResolver->mServiceType); + + VerifyOrQuit(aInstance == sInstance); + VerifyOrQuit(aResolver->mInfraIfIndex == kInfraIfIndex); + + sStopSrvResolverInfo.UpdateFrom(aResolver); +} + +void otPlatDnssdStartTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver) +{ + VerifyOrQuit(aResolver != nullptr); + + Log("otPlatDnssdStartTxtResolver(\"%s\", \"%s\")", aResolver->mServiceInstance, aResolver->mServiceType); + + VerifyOrQuit(aInstance == sInstance); + VerifyOrQuit(aResolver->mInfraIfIndex == kInfraIfIndex); + + sStartTxtResolverInfo.UpdateFrom(aResolver); + + if (sInvokeOnStart.mTxtResult != nullptr) + { + InvokeTxtResolverCallback(aResolver->mCallback, *sInvokeOnStart.mTxtResult); + } +} + +void otPlatDnssdStopTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver) +{ + VerifyOrQuit(aResolver != nullptr); + + Log("otPlatDnssdStopTxtResolver(\"%s\", \"%s\")", aResolver->mServiceInstance, aResolver->mServiceType); + + VerifyOrQuit(aInstance == sInstance); + VerifyOrQuit(aResolver->mInfraIfIndex == kInfraIfIndex); + + sStopTxtResolverInfo.UpdateFrom(aResolver); +} + +void otPlatDnssdStartIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + VerifyOrQuit(aResolver != nullptr); + + Log("otPlatDnssdStartIp6AddressResolver(\"%s\")", aResolver->mHostName); + + VerifyOrQuit(aInstance == sInstance); + VerifyOrQuit(aResolver->mInfraIfIndex == kInfraIfIndex); + + sStartIp6AddrResolverInfo.UpdateFrom(aResolver); + + if (sInvokeOnStart.mIp6AddrResult != nullptr) + { + InvokeIp6AddrResolverCallback(aResolver->mCallback, *sInvokeOnStart.mIp6AddrResult); + } +} + +void otPlatDnssdStopIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + VerifyOrQuit(aResolver != nullptr); + + Log("otPlatDnssdStopIp6AddressResolver(\"%s\")", aResolver->mHostName); + + VerifyOrQuit(aInstance == sInstance); + VerifyOrQuit(aResolver->mInfraIfIndex == kInfraIfIndex); + + sStopIp6AddrResolverInfo.UpdateFrom(aResolver); + + if (sInvokeOnStart.mIp6AddrResult != nullptr) + { + InvokeIp6AddrResolverCallback(aResolver->mCallback, *sInvokeOnStart.mIp6AddrResult); + } +} + +//---------------------------------------------------------------------------------------------------------------------- + +void TestProxyBasic(void) +{ + static constexpr uint32_t kTtl = 300; + + const uint8_t kTxtData[] = {3, 'A', '=', '1', 0}; + + Srp::Server *srpServer; + Srp::Client *srpClient; + Dns::Client *dnsClient; + Dns::ServiceDiscovery::Server *dnsServer; + Dnssd::BrowseResult browseResult; + Dnssd::SrvResult srvResult; + Dnssd::TxtResult txtResult; + Dnssd::AddressResult ip6AddrrResult; + Dnssd::AddressAndTtl addressAndTtl; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestProxyBasic"); + + InitTest(); + + srpServer = &sInstance->Get(); + srpClient = &sInstance->Get(); + dnsClient = &sInstance->Get(); + dnsServer = &sInstance->Get(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP server. + + SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); + + SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); + + srpServer->SetEnabled(true); + VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); + + AdvanceTime(10000); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP client. + + srpClient->EnableAutoStartMode(nullptr, nullptr); + VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); + + AdvanceTime(2000); + VerifyOrQuit(srpClient->IsRunning()); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sBrowseInfo.Reset(); + ResetPlatDnssdApiInfo(); + + Log("Browse()"); + SuccessOrQuit(dnsClient->Browse("_avenger._udp.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_avenger._udp")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Browser callback"); + + browseResult.mServiceType = "_avenger._udp"; + browseResult.mSubTypeLabel = nullptr; + browseResult.mServiceInstance = "hulk"; + browseResult.mTtl = kTtl; + browseResult.mInfraIfIndex = kInfraIfIndex; + + InvokeBrowserCallback(sStartBrowserInfo.mCallback, browseResult); + + AdvanceTime(10); + + // Check that browser is stopped and a service resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopBrowserInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStopBrowserInfo.mCallback == sStartBrowserInfo.mCallback); + + VerifyOrQuit(sStartSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartSrvResolverInfo.ServiceInstanceMatches("hulk")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke SRV resolver callback"); + + srvResult.mServiceInstance = "hulk"; + srvResult.mServiceType = "_avenger._udp"; + srvResult.mHostName = "compound"; + srvResult.mPort = 7777; + srvResult.mTtl = kTtl; + srvResult.mInfraIfIndex = kInfraIfIndex; + + InvokeSrvResolverCallback(sStartSrvResolverInfo.mCallback, srvResult); + + AdvanceTime(10); + + // Check that SRV resolver is stopped and a TXT resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStopSrvResolverInfo.ServiceInstanceMatches("hulk")); + VerifyOrQuit(sStopSrvResolverInfo.mCallback == sStartSrvResolverInfo.mCallback); + + VerifyOrQuit(sStartTxtResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartTxtResolverInfo.ServiceInstanceMatches("hulk")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke TXT resolver callback"); + + txtResult.mServiceInstance = "hulk"; + txtResult.mServiceType = "_avenger._udp"; + txtResult.mTxtData = kTxtData; + txtResult.mTxtDataLength = sizeof(kTxtData); + txtResult.mTtl = kTtl; + txtResult.mInfraIfIndex = kInfraIfIndex; + + InvokeTxtResolverCallback(sStartTxtResolverInfo.mCallback, txtResult); + + AdvanceTime(10); + + // Check that TXT resolver is stopped and an address resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopTxtResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStopTxtResolverInfo.ServiceInstanceMatches("hulk")); + VerifyOrQuit(sStopTxtResolverInfo.mCallback == sStartTxtResolverInfo.mCallback); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("compound")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Address Resolver callback"); + + SuccessOrQuit(AsCoreType(&addressAndTtl.mAddress).FromString("fd00::1234")); + addressAndTtl.mTtl = kTtl; + + ip6AddrrResult.mHostName = "compound"; + ip6AddrrResult.mInfraIfIndex = kInfraIfIndex; + ip6AddrrResult.mAddresses = &addressAndTtl; + ip6AddrrResult.mAddressesLength = 1; + + InvokeIp6AddrResolverCallback(sStartIp6AddrResolverInfo.mCallback, ip6AddrrResult); + + AdvanceTime(10); + + // Check that address resolver is stopped + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("compound")); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallback == sStartIp6AddrResolverInfo.mCallback); + + // Check that response is sent to client and validate it + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); + SuccessOrQuit(sBrowseInfo.mError); + VerifyOrQuit(sBrowseInfo.mNumInstances == 1); + + VerifyOrQuit(!strcmp(sBrowseInfo.mServiceName, "_avenger._udp.default.service.arpa.")); + VerifyOrQuit(!strcmp(sBrowseInfo.mInstanceLabel, "hulk")); + VerifyOrQuit(!strcmp(sBrowseInfo.mServiceInfo.mHostNameBuffer, "compound.default.service.arpa.")); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mPort == 7777); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTtl == kTtl); + VerifyOrQuit(AsCoreType(&sBrowseInfo.mServiceInfo.mHostAddress) == AsCoreType(&addressAndTtl.mAddress)); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mHostAddressTtl == kTtl); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTxtDataSize == sizeof(kTxtData)); + VerifyOrQuit(!memcmp(sBrowseInfo.mServiceInfo.mTxtData, kTxtData, sizeof(kTxtData))); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTxtDataTtl == kTtl); + VerifyOrQuit(!sBrowseInfo.mServiceInfo.mTxtDataTruncated); + + Log("--------------------------------------------------------------------------------------------"); + + ResetPlatDnssdApiInfo(); + sResolveServiceInfo.Reset(); + + Log("ResolveService() with dot `.` character in service instance label"); + SuccessOrQuit( + dnsClient->ResolveService("iron.man", "_avenger._udp.default.service.arpa.", ServiceCallback, sInstance)); + + AdvanceTime(10); + + // Check that a service resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartSrvResolverInfo.ServiceInstanceMatches("iron.man")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke SRV Resolver callback for wrong name"); + + srvResult.mServiceInstance = "hulk"; + srvResult.mServiceType = "_avenger._udp"; + srvResult.mHostName = "compound"; + srvResult.mPort = 7777; + srvResult.mTtl = kTtl; + srvResult.mInfraIfIndex = kInfraIfIndex; + + InvokeSrvResolverCallback(sStartSrvResolverInfo.mCallback, srvResult); + + AdvanceTime(10); + + // Check that no changes to browsers/resolvers + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 0); + + Log("Invoke SRV Resolver callback for correct name"); + + srvResult.mServiceInstance = "iron.man"; + srvResult.mServiceType = "_avenger._udp"; + srvResult.mHostName = "starktower"; + srvResult.mPort = 1024; + srvResult.mTtl = kTtl; + srvResult.mInfraIfIndex = kInfraIfIndex; + + InvokeSrvResolverCallback(sStartSrvResolverInfo.mCallback, srvResult); + + AdvanceTime(10); + + // Check that SRV resolver is stopped and TXT resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 0); + + VerifyOrQuit(sStopSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStopSrvResolverInfo.ServiceInstanceMatches("iron.man")); + VerifyOrQuit(sStopSrvResolverInfo.mCallback == sStartSrvResolverInfo.mCallback); + + VerifyOrQuit(sStartTxtResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartTxtResolverInfo.ServiceInstanceMatches("iron.man")); + + Log("Invoke TXT Resolver callback"); + + txtResult.mServiceInstance = "iron.man"; + txtResult.mServiceType = "_avenger._udp"; + txtResult.mTxtData = kTxtData; + txtResult.mTxtDataLength = sizeof(kTxtData); + txtResult.mTtl = kTtl; + txtResult.mInfraIfIndex = kInfraIfIndex; + + InvokeTxtResolverCallback(sStartTxtResolverInfo.mCallback, txtResult); + AdvanceTime(10); + + // Check that TXT resolver is stopped and addr resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 0); + + VerifyOrQuit(sStopTxtResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStopTxtResolverInfo.ServiceInstanceMatches("iron.man")); + VerifyOrQuit(sStopTxtResolverInfo.mCallback == sStartTxtResolverInfo.mCallback); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("starktower")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Address Resolver callback"); + + ip6AddrrResult.mHostName = "starktower"; + + InvokeIp6AddrResolverCallback(sStartIp6AddrResolverInfo.mCallback, ip6AddrrResult); + AdvanceTime(10); + + // Check that address resolver is stopped + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("starktower")); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallback == sStartIp6AddrResolverInfo.mCallback); + + // Check that response is sent to client and validate it + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); + VerifyOrQuit(sResolveServiceInfo.mError == kErrorNone); + + VerifyOrQuit(!strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, "starktower.default.service.arpa.")); + VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == 1024); + VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl == kTtl); + VerifyOrQuit(AsCoreType(&sResolveServiceInfo.mInfo.mHostAddress) == AsCoreType(&addressAndTtl.mAddress)); + VerifyOrQuit(sResolveServiceInfo.mInfo.mHostAddressTtl == kTtl); + VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize == sizeof(kTxtData)); + VerifyOrQuit(!memcmp(sResolveServiceInfo.mInfo.mTxtData, kTxtData, sizeof(kTxtData))); + VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl == kTtl); + VerifyOrQuit(!sResolveServiceInfo.mInfo.mTxtDataTruncated); + + Log("--------------------------------------------------------------------------------------------"); + + ResetPlatDnssdApiInfo(); + sResolveAddressInfo.Reset(); + + Log("ResolveAddress()"); + SuccessOrQuit(dnsClient->ResolveAddress("earth.default.service.arpa.", AddressCallback, sInstance)); + AdvanceTime(10); + + // Check that an address resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("earth")); + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Address Resolver callback"); + + SuccessOrQuit(AsCoreType(&addressAndTtl.mAddress).FromString("fd00::7777")); + addressAndTtl.mTtl = kTtl; + ip6AddrrResult.mHostName = "earth"; + ip6AddrrResult.mInfraIfIndex = kInfraIfIndex; + ip6AddrrResult.mAddresses = &addressAndTtl; + ip6AddrrResult.mAddressesLength = 1; + + InvokeIp6AddrResolverCallback(sStartIp6AddrResolverInfo.mCallback, ip6AddrrResult); + + AdvanceTime(10); + + // Check that the address resolver is stopped + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("earth")); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallback == sStartIp6AddrResolverInfo.mCallback); + + // Check that response is sent to client and validate it + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 1); + SuccessOrQuit(sResolveAddressInfo.mError); + + VerifyOrQuit(!strcmp(sResolveAddressInfo.mHostName, "earth.default.service.arpa.")); + VerifyOrQuit(sResolveAddressInfo.mNumHostAddresses == 1); + VerifyOrQuit(sResolveAddressInfo.mHostAddresses[0] == AsCoreType(&addressAndTtl.mAddress)); + VerifyOrQuit(sResolveAddressInfo.mTtl == kTtl); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Stop DNS-SD server"); + + dnsServer->Stop(); + + AdvanceTime(10); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Finalize OT instance and validate all heap allocations are freed. + + Log("Finalizing OT instance"); + FinalizeTest(); + + Log("End of TestProxyBasic"); +} + +//---------------------------------------------------------------------------------------------------------------------- + +void TestProxySubtypeBrowse(void) +{ + static constexpr uint32_t kTtl = 300; + + const uint8_t kTxtData[] = {3, 'G', '=', '0', 0}; + + Srp::Server *srpServer; + Srp::Client *srpClient; + Dns::Client *dnsClient; + Dns::ServiceDiscovery::Server *dnsServer; + Dnssd::BrowseResult browseResult; + Dnssd::SrvResult srvResult; + Dnssd::TxtResult txtResult; + Dnssd::AddressResult ip6AddrrResult; + Dnssd::AddressAndTtl addressAndTtl; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestProxySubtypeBrowse"); + + InitTest(); + + srpServer = &sInstance->Get(); + srpClient = &sInstance->Get(); + dnsClient = &sInstance->Get(); + dnsServer = &sInstance->Get(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP server. + + SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); + + SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); + + srpServer->SetEnabled(true); + VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); + + AdvanceTime(10000); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP client. + + srpClient->EnableAutoStartMode(nullptr, nullptr); + VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); + + AdvanceTime(2000); + VerifyOrQuit(srpClient->IsRunning()); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sBrowseInfo.Reset(); + ResetPlatDnssdApiInfo(); + + Log("Browse() for sub-type service"); + SuccessOrQuit(dnsClient->Browse("_god._sub._avenger._udp.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartBrowserInfo.SubTypeMatches("_god")); + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Browser callback"); + + browseResult.mServiceType = "_avenger._udp"; + browseResult.mSubTypeLabel = "_god"; + browseResult.mServiceInstance = "thor"; + browseResult.mTtl = kTtl; + browseResult.mInfraIfIndex = kInfraIfIndex; + + InvokeBrowserCallback(sStartBrowserInfo.mCallback, browseResult); + + AdvanceTime(10); + + // Check that browser is stopped and a service resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopBrowserInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStopBrowserInfo.SubTypeMatches("_god")); + VerifyOrQuit(sStopBrowserInfo.mCallback == sStartBrowserInfo.mCallback); + + // Check that the SRV resolver is correctly using the base service type + // and not the sub-type name + + VerifyOrQuit(sStartSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartSrvResolverInfo.ServiceInstanceMatches("thor")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Service Resolver callback"); + + srvResult.mServiceInstance = "thor"; + srvResult.mServiceType = "_avenger._udp"; + srvResult.mHostName = "asgard"; + srvResult.mPort = 1234; + srvResult.mTtl = kTtl; + srvResult.mInfraIfIndex = kInfraIfIndex; + + InvokeSrvResolverCallback(sStartSrvResolverInfo.mCallback, srvResult); + + AdvanceTime(10); + + // Check that SRV resolver is stopped and a TXT resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStopSrvResolverInfo.ServiceInstanceMatches("thor")); + VerifyOrQuit(sStopSrvResolverInfo.mCallback == sStartSrvResolverInfo.mCallback); + + VerifyOrQuit(sStartTxtResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartTxtResolverInfo.ServiceInstanceMatches("thor")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Service Resolver callback"); + + txtResult.mServiceInstance = "thor"; + txtResult.mServiceType = "_avenger._udp"; + txtResult.mTxtData = kTxtData; + txtResult.mTxtDataLength = sizeof(kTxtData); + txtResult.mTtl = kTtl; + txtResult.mInfraIfIndex = kInfraIfIndex; + + InvokeTxtResolverCallback(sStartTxtResolverInfo.mCallback, txtResult); + AdvanceTime(10); + + // Check that TXT resolver is stopped and an address resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopTxtResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStopTxtResolverInfo.ServiceInstanceMatches("thor")); + VerifyOrQuit(sStopTxtResolverInfo.mCallback == sStartTxtResolverInfo.mCallback); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("asgard")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Address Resolver callback"); + + SuccessOrQuit(AsCoreType(&addressAndTtl.mAddress).FromString("fd00::1234")); + addressAndTtl.mTtl = kTtl; + + ip6AddrrResult.mHostName = "asgard"; + ip6AddrrResult.mInfraIfIndex = kInfraIfIndex; + ip6AddrrResult.mAddresses = &addressAndTtl; + ip6AddrrResult.mAddressesLength = 1; + + InvokeIp6AddrResolverCallback(sStartIp6AddrResolverInfo.mCallback, ip6AddrrResult); + + AdvanceTime(10); + + // Check that address resolver is stopped + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("asgard")); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallback == sStartIp6AddrResolverInfo.mCallback); + + // Check that response is sent to client and validate it + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); + SuccessOrQuit(sBrowseInfo.mError); + VerifyOrQuit(sBrowseInfo.mNumInstances == 1); + + VerifyOrQuit(!strcmp(sBrowseInfo.mServiceName, "_god._sub._avenger._udp.default.service.arpa.")); + VerifyOrQuit(!strcmp(sBrowseInfo.mInstanceLabel, "thor")); + VerifyOrQuit(!strcmp(sBrowseInfo.mServiceInfo.mHostNameBuffer, "asgard.default.service.arpa.")); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mPort == 1234); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTtl == kTtl); + VerifyOrQuit(AsCoreType(&sBrowseInfo.mServiceInfo.mHostAddress) == AsCoreType(&addressAndTtl.mAddress)); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mHostAddressTtl == kTtl); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTxtDataSize == sizeof(kTxtData)); + VerifyOrQuit(!memcmp(sBrowseInfo.mServiceInfo.mTxtData, kTxtData, sizeof(kTxtData))); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTxtDataTtl == kTtl); + VerifyOrQuit(!sBrowseInfo.mServiceInfo.mTxtDataTruncated); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Stop DNS-SD server"); + + dnsServer->Stop(); + + AdvanceTime(10); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Finalize OT instance and validate all heap allocations are freed. + + Log("Finalizing OT instance"); + FinalizeTest(); + + Log("End of TestProxySubtypeBrowse"); +} + +//---------------------------------------------------------------------------------------------------------------------- + +void TestProxyTimeout(void) +{ + static constexpr uint32_t kTtl = 300; + + Srp::Server *srpServer; + Srp::Client *srpClient; + Dns::Client *dnsClient; + Dns::ServiceDiscovery::Server *dnsServer; + Dns::Client::QueryConfig config; + Dnssd::BrowseResult browseResult; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestProxyTimeout"); + + InitTest(); + + srpServer = &sInstance->Get(); + srpClient = &sInstance->Get(); + dnsClient = &sInstance->Get(); + dnsServer = &sInstance->Get(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP server. + + SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); + + SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); + + srpServer->SetEnabled(true); + VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); + + AdvanceTime(10000); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP client. + + srpClient->EnableAutoStartMode(nullptr, nullptr); + VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); + + AdvanceTime(2000); + VerifyOrQuit(srpClient->IsRunning()); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Increase default response retry timeout on DNS client"); + + config.Clear(); + config.mResponseTimeout = 120 * 1000; // 2 minutes (in msec) + dnsClient->SetDefaultConfig(config); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sBrowseInfo.Reset(); + ResetPlatDnssdApiInfo(); + + Log("Browse()"); + SuccessOrQuit(dnsClient->Browse("_game._ps5.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_game._ps5")); + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Wait for timeout and check empty response on client"); + + AdvanceTime(10 * 1000); + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); + VerifyOrQuit(sBrowseInfo.mNumInstances == 0); + + // Check that the browser is stopped + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + + VerifyOrQuit(sStopBrowserInfo.ServiceTypeMatches("_game._ps5")); + VerifyOrQuit(sStopBrowserInfo.mCallback == sStartBrowserInfo.mCallback); + + Log("--------------------------------------------------------------------------------------------"); + Log("Timeout during service resolution"); + + sBrowseInfo.Reset(); + ResetPlatDnssdApiInfo(); + + SuccessOrQuit(dnsClient->Browse("_avenger._udp.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_avenger._udp")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Browser callback"); + + browseResult.mServiceType = "_avenger._udp"; + browseResult.mSubTypeLabel = nullptr; + browseResult.mServiceInstance = "spiderman"; + browseResult.mTtl = kTtl; + browseResult.mInfraIfIndex = kInfraIfIndex; + + InvokeBrowserCallback(sStartBrowserInfo.mCallback, browseResult); + + AdvanceTime(10); + + // Check that browser is stopped and a service resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopBrowserInfo.ServiceTypeMatches("_avenger._udp")); + + VerifyOrQuit(sStartSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartSrvResolverInfo.ServiceInstanceMatches("spiderman")); + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Wait for timeout"); + + AdvanceTime(10 * 1000); + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); + VerifyOrQuit(sBrowseInfo.mNumInstances == 1); + + // Check that the browser is stopped + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopBrowserInfo.ServiceTypeMatches("_avenger._udp")); + + // Validate the response received by client + + VerifyOrQuit(!strcmp(sBrowseInfo.mServiceName, "_avenger._udp.default.service.arpa.")); + VerifyOrQuit(!strcmp(sBrowseInfo.mInstanceLabel, "spiderman")); + + Log("--------------------------------------------------------------------------------------------"); + Log("Timeout during multiple requests"); + + sBrowseInfo.Reset(); + sResolveServiceInfo.Reset(); + sResolveAddressInfo.Reset(); + ResetPlatDnssdApiInfo(); + + Log("Browse()"); + SuccessOrQuit(dnsClient->Browse("_avenger._udp.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_avenger._udp")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Another Browse()"); + SuccessOrQuit(dnsClient->Browse("_game._udp.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 2); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_game._udp")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("ResolveService()"); + SuccessOrQuit( + dnsClient->ResolveService("wanda", "_avenger._udp.default.service.arpa.", ServiceCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 2); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartSrvResolverInfo.ServiceInstanceMatches("wanda")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("ResolveAddress()"); + SuccessOrQuit(dnsClient->ResolveAddress("earth.default.service.arpa.", AddressCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 2); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("earth")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Wait for timeout for all requests"); + + AdvanceTime(10 * 1000); + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 2); + VerifyOrQuit(sBrowseInfo.mNumInstances == 0); + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); + VerifyOrQuit(sResolveServiceInfo.mError == kErrorNotFound); + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 1); + VerifyOrQuit(sResolveAddressInfo.mNumHostAddresses == 0); + + // Check that all browsers/resolvers are stopped. + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 2); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 2); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStopSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStopSrvResolverInfo.ServiceInstanceMatches("wanda")); + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("earth")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Stop DNS-SD server"); + + dnsServer->Stop(); + + AdvanceTime(10); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Finalize OT instance and validate all heap allocations are freed. + + Log("Finalizing OT instance"); + FinalizeTest(); + + Log("End of TestProxyTimeout"); +} + +void TestProxySharedResolver(void) +{ + static constexpr uint32_t kTtl = 300; + + const uint8_t kTxtData[] = {3, 'A', '=', '1', 0}; + + Srp::Server *srpServer; + Srp::Client *srpClient; + Dns::Client *dnsClient; + Dns::ServiceDiscovery::Server *dnsServer; + Dnssd::BrowseResult browseResult; + Dnssd::SrvResult srvResult; + Dnssd::TxtResult txtResult; + Dnssd::AddressResult ip6AddrrResult; + Dnssd::AddressAndTtl addressAndTtl[2]; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestProxySharedResolver"); + + InitTest(); + + srpServer = &sInstance->Get(); + srpClient = &sInstance->Get(); + dnsClient = &sInstance->Get(); + dnsServer = &sInstance->Get(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP server. + + SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); + + SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); + + srpServer->SetEnabled(true); + VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); + + AdvanceTime(10000); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP client. + + srpClient->EnableAutoStartMode(nullptr, nullptr); + VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); + + AdvanceTime(2000); + VerifyOrQuit(srpClient->IsRunning()); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sBrowseInfo.Reset(); + sResolveServiceInfo.Reset(); + sResolveAddressInfo.Reset(); + ResetPlatDnssdApiInfo(); + + Log("ResolveAddress()"); + SuccessOrQuit(dnsClient->ResolveAddress("knowhere.default.service.arpa.", AddressCallback, sInstance)); + AdvanceTime(10); + + Log("ResolveService()"); + SuccessOrQuit( + dnsClient->ResolveService("starlord", "_guardian._glaxy.default.service.arpa.", ServiceCallback, sInstance)); + AdvanceTime(10); + + Log("Browse()"); + SuccessOrQuit(dnsClient->Browse("_guardian._glaxy.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_guardian._glaxy")); + + VerifyOrQuit(sStartSrvResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStartSrvResolverInfo.ServiceInstanceMatches("starlord")); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("knowhere")); + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 0); + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Browser callback"); + + browseResult.mServiceType = "_guardian._glaxy"; + browseResult.mSubTypeLabel = nullptr; + browseResult.mServiceInstance = "starlord"; + browseResult.mTtl = kTtl; + browseResult.mInfraIfIndex = kInfraIfIndex; + + InvokeBrowserCallback(sStartBrowserInfo.mCallback, browseResult); + + AdvanceTime(10); + + // Check that browser is stopped and since the service instance + // name matches an existing resolver, we should not see any new + // resolver starting. + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopBrowserInfo.ServiceTypeMatches("_guardian._glaxy")); + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 0); + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Service Resolver callback"); + + srvResult.mServiceInstance = "starlord"; + srvResult.mServiceType = "_guardian._glaxy"; + srvResult.mHostName = "knowhere"; + srvResult.mPort = 3333; + srvResult.mTtl = kTtl; + srvResult.mInfraIfIndex = kInfraIfIndex; + + InvokeSrvResolverCallback(sStartSrvResolverInfo.mCallback, srvResult); + + AdvanceTime(10); + + // Check that SRV resolver is now stopped and a TXT resolver + // is started for same service. + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopSrvResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStopSrvResolverInfo.ServiceInstanceMatches("starlord")); + + txtResult.mServiceInstance = "starlord"; + txtResult.mServiceType = "_guardian._glaxy"; + txtResult.mTxtData = kTxtData; + txtResult.mTxtDataLength = sizeof(kTxtData); + txtResult.mTtl = kTtl; + txtResult.mInfraIfIndex = kInfraIfIndex; + + InvokeTxtResolverCallback(sStartTxtResolverInfo.mCallback, txtResult); + + AdvanceTime(10); + + // Check that TXT resolver is now stopped but again since the + // host name matches an existing address resolver we should not + // see any new address resolver. + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStopTxtResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStopTxtResolverInfo.ServiceInstanceMatches("starlord")); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Address Resolver callback"); + + SuccessOrQuit(AsCoreType(&addressAndTtl[0].mAddress).FromString("fd00::5555")); + SuccessOrQuit(AsCoreType(&addressAndTtl[1].mAddress).FromString("fd00::1234")); + addressAndTtl[0].mTtl = kTtl; + addressAndTtl[1].mTtl = kTtl; + + ip6AddrrResult.mHostName = "knowhere"; + ip6AddrrResult.mInfraIfIndex = kInfraIfIndex; + ip6AddrrResult.mAddresses = addressAndTtl; + ip6AddrrResult.mAddressesLength = 2; + + InvokeIp6AddrResolverCallback(sStartIp6AddrResolverInfo.mCallback, ip6AddrrResult); + + AdvanceTime(10); + + // Check that the address resolver is now stopped. + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("knowhere")); + + // Check the browse response received on client + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); + SuccessOrQuit(sBrowseInfo.mError); + VerifyOrQuit(sBrowseInfo.mNumInstances == 1); + + VerifyOrQuit(!strcmp(sBrowseInfo.mServiceName, "_guardian._glaxy.default.service.arpa.")); + VerifyOrQuit(!strcmp(sBrowseInfo.mInstanceLabel, "starlord")); + VerifyOrQuit(!strcmp(sBrowseInfo.mServiceInfo.mHostNameBuffer, "knowhere.default.service.arpa.")); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mPort == 3333); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTtl == kTtl); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mHostAddressTtl == kTtl); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTxtDataSize == sizeof(kTxtData)); + VerifyOrQuit(!memcmp(sBrowseInfo.mServiceInfo.mTxtData, kTxtData, sizeof(kTxtData))); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTxtDataTtl == kTtl); + VerifyOrQuit(!sBrowseInfo.mServiceInfo.mTxtDataTruncated); + + // Check the service resolve response received on client + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); + SuccessOrQuit(sResolveServiceInfo.mError); + + VerifyOrQuit(!strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, "knowhere.default.service.arpa.")); + VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == 3333); + VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl == kTtl); + VerifyOrQuit(sResolveServiceInfo.mInfo.mHostAddressTtl == kTtl); + VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize == sizeof(kTxtData)); + VerifyOrQuit(!memcmp(sResolveServiceInfo.mInfo.mTxtData, kTxtData, sizeof(kTxtData))); + VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl == kTtl); + VerifyOrQuit(!sResolveServiceInfo.mInfo.mTxtDataTruncated); + VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == 2); + for (uint16_t index = 0; index < 2; index++) + { + VerifyOrQuit(sResolveServiceInfo.mHostAddresses[index] == AsCoreType(&addressAndTtl[0].mAddress) || + sResolveServiceInfo.mHostAddresses[index] == AsCoreType(&addressAndTtl[1].mAddress)); + } + + // Check the address resolve response received on client + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 1); + SuccessOrQuit(sResolveAddressInfo.mError); + + VerifyOrQuit(!strcmp(sResolveAddressInfo.mHostName, "knowhere.default.service.arpa.")); + VerifyOrQuit(sResolveAddressInfo.mTtl == kTtl); + VerifyOrQuit(sResolveAddressInfo.mNumHostAddresses == 2); + for (uint16_t index = 0; index < 2; index++) + { + VerifyOrQuit(sResolveAddressInfo.mHostAddresses[index] == AsCoreType(&addressAndTtl[0].mAddress) || + sResolveAddressInfo.mHostAddresses[index] == AsCoreType(&addressAndTtl[1].mAddress)); + } + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Stop DNS-SD server"); + + dnsServer->Stop(); + + AdvanceTime(10); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Finalize OT instance and validate all heap allocations are freed. + + Log("Finalizing OT instance"); + FinalizeTest(); + + Log("End of TestProxySharedResolver"); +} + +void TestProxyFilterInvalidAddresses(void) +{ + static constexpr uint32_t kTtl = 300; + + Srp::Server *srpServer; + Srp::Client *srpClient; + Dns::Client *dnsClient; + Dns::ServiceDiscovery::Server *dnsServer; + Dnssd::AddressResult ip6AddrrResult; + Dnssd::AddressAndTtl addressAndTtl[10]; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestProxyFilterInvalidAddresses"); + + InitTest(); + + srpServer = &sInstance->Get(); + srpClient = &sInstance->Get(); + dnsClient = &sInstance->Get(); + dnsServer = &sInstance->Get(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP server. + + SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); + + SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); + + srpServer->SetEnabled(true); + VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); + + AdvanceTime(10000); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP client. + + srpClient->EnableAutoStartMode(nullptr, nullptr); + VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); + + AdvanceTime(2000); + VerifyOrQuit(srpClient->IsRunning()); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sResolveAddressInfo.Reset(); + ResetPlatDnssdApiInfo(); + + Log("ResolveAddress()"); + SuccessOrQuit(dnsClient->ResolveAddress("host.default.service.arpa.", AddressCallback, sInstance)); + AdvanceTime(10); + + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("host")); + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Address Resolver callback with invalid addresses"); + + SuccessOrQuit(AsCoreType(&addressAndTtl[0].mAddress).FromString("::")); // Unspecified + SuccessOrQuit(AsCoreType(&addressAndTtl[1].mAddress).FromString("fe80::1234")); // Link local + SuccessOrQuit(AsCoreType(&addressAndTtl[2].mAddress).FromString("ff00::1234")); // Multicast + SuccessOrQuit(AsCoreType(&addressAndTtl[3].mAddress).FromString("::1")); // Lookback + + for (uint16_t index = 0; index < 5; index++) + { + addressAndTtl[index].mTtl = kTtl; + } + + ip6AddrrResult.mHostName = "host"; + ip6AddrrResult.mInfraIfIndex = kInfraIfIndex; + ip6AddrrResult.mAddresses = addressAndTtl; + ip6AddrrResult.mAddressesLength = 4; + + InvokeIp6AddrResolverCallback(sStartIp6AddrResolverInfo.mCallback, ip6AddrrResult); + + AdvanceTime(10); + + // Check that the address resolver is not stopped, since all addresses where + // invalid address. + + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Invoke Address Resolver callback with invalid addresses with one valid"); + + SuccessOrQuit(AsCoreType(&addressAndTtl[4].mAddress).FromString("f00::1234")); + + ip6AddrrResult.mAddressesLength = 5; + + InvokeIp6AddrResolverCallback(sStartIp6AddrResolverInfo.mCallback, ip6AddrrResult); + + AdvanceTime(10); + + // Check that address resolver is not stopped + + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("host")); + + // Check that response received on client is valid and only contains + // the valid two addresses and filters all others. + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 1); + SuccessOrQuit(sResolveAddressInfo.mError); + + VerifyOrQuit(!strcmp(sResolveAddressInfo.mHostName, "host.default.service.arpa.")); + VerifyOrQuit(sResolveAddressInfo.mTtl == kTtl); + VerifyOrQuit(sResolveAddressInfo.mNumHostAddresses == 1); + VerifyOrQuit(sResolveAddressInfo.mHostAddresses[0] == AsCoreType(&addressAndTtl[4].mAddress)); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Stop DNS-SD server"); + + dnsServer->Stop(); + + AdvanceTime(10); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Finalize OT instance and validate all heap allocations are freed. + + Log("Finalizing OT instance"); + FinalizeTest(); + + Log("End of TestProxyFilterInvalidAddresses"); +} + +void TestProxyStateChanges(void) +{ + static constexpr uint32_t kTtl = 300; + + Srp::Server *srpServer; + Srp::Client *srpClient; + Dns::Client *dnsClient; + Dns::ServiceDiscovery::Server *dnsServer; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestProxyStateChanges"); + + InitTest(); + + srpServer = &sInstance->Get(); + srpClient = &sInstance->Get(); + dnsClient = &sInstance->Get(); + dnsServer = &sInstance->Get(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP server. + + SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); + + SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); + + srpServer->SetEnabled(true); + VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); + + AdvanceTime(10000); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP client. + + srpClient->EnableAutoStartMode(nullptr, nullptr); + VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); + + AdvanceTime(2000); + VerifyOrQuit(srpClient->IsRunning()); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Signal DNS-SD platform state is stopped and not yet ready"); + + sDnssdState = OT_PLAT_DNSSD_STOPPED; + otPlatDnssdStateHandleStateChange(sInstance); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sResolveAddressInfo.Reset(); + ResetPlatDnssdApiInfo(); + + Log("ResolveAddress()"); + SuccessOrQuit(dnsClient->ResolveAddress("host.default.service.arpa.", AddressCallback, sInstance)); + AdvanceTime(10); + + // Check that none of the DNS-SD resolver/browser APIs are called + // since the platform is not yet ready + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 1); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Signal DNS-SD platform state is now ready"); + + sDnssdState = OT_PLAT_DNSSD_READY; + otPlatDnssdStateHandleStateChange(sInstance); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sResolveAddressInfo.Reset(); + ResetPlatDnssdApiInfo(); + + Log("ResolveAddress()"); + SuccessOrQuit(dnsClient->ResolveAddress("host.default.service.arpa.", AddressCallback, sInstance)); + AdvanceTime(10); + + // Check that address resolver is started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("host")); + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sBrowseInfo.Reset(); + + Log("Browse()"); + SuccessOrQuit(dnsClient->Browse("_magic._udp.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + // Check that browser is also started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 0); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 0); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_magic._udp")); + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 0); + VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Signal infra-if is not running"); + + SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, /* aIsRunning */ false)); + + AdvanceTime(10); + + // Check that both address resolver and browser are stopped + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("host")); + VerifyOrQuit(sStopBrowserInfo.ServiceTypeMatches("_magic._udp")); + + // And response is sent to client + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 1); + VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sResolveAddressInfo.Reset(); + + Log("ResolveAddress()"); + SuccessOrQuit(dnsClient->ResolveAddress("earth.default.service.arpa.", AddressCallback, sInstance)); + AdvanceTime(10); + + // Check that no resolver is started. + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 1); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Signal that infra-if is running again "); + + SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, /* aIsRunning */ true)); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + sResolveServiceInfo.Reset(); + Log("ResolveService()"); + SuccessOrQuit(dnsClient->ResolveService("captain.america", "_avenger._udp.default.service.arpa.", ServiceCallback, + sInstance)); + AdvanceTime(10); + + // The proxy should be started again so check that a service resolver + // is started for new request + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStartSrvResolverInfo.ServiceTypeMatches("_avenger._udp")); + VerifyOrQuit(sStartSrvResolverInfo.ServiceInstanceMatches("captain.america")); + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Signal DNS-SD platform state is stopped"); + + sDnssdState = OT_PLAT_DNSSD_STOPPED; + otPlatDnssdStateHandleStateChange(sInstance); + + AdvanceTime(10); + + // This should stop proxy but since DNS-SD platform is stopped + // we assume all browsers/resolvers are also stopped, so there + // should be no explicit call to stop it. + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + // Check that response is sent to client + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Signal DNS-SD platform state is ready again"); + + sDnssdState = OT_PLAT_DNSSD_READY; + otPlatDnssdStateHandleStateChange(sInstance); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + sBrowseInfo.Reset(); + + Log("Browse()"); + SuccessOrQuit(dnsClient->Browse("_magical._udp.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + // Proxy should be started again and we should see a new browser started + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 2); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_magical._udp")); + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 0); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Stop DNS-SD server"); + + dnsServer->Stop(); + + AdvanceTime(10); + + // Check that the browser is stopped + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 2); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 2); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 0); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStopBrowserInfo.ServiceTypeMatches("_magical._udp")); + + // And response is sent to client + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Finalize OT instance and validate all heap allocations are freed. + + Log("Finalizing OT instance"); + FinalizeTest(); + + Log("End of TestProxyStateChanges"); +} + +void TestProxyInvokeCallbackFromStartApi(void) +{ + static constexpr uint32_t kTtl = 300; + + const uint8_t kTxtData[] = {3, 'A', '=', '1', 0}; + + Srp::Server *srpServer; + Srp::Client *srpClient; + Dns::Client *dnsClient; + Dns::ServiceDiscovery::Server *dnsServer; + Dnssd::BrowseResult browseResult; + Dnssd::SrvResult srvResult; + Dnssd::TxtResult txtResult; + Dnssd::AddressResult ip6AddrrResult; + Dnssd::AddressAndTtl addressAndTtl[2]; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestProxyInvokeCallbackFromStartApi"); + + InitTest(); + + srpServer = &sInstance->Get(); + srpClient = &sInstance->Get(); + dnsClient = &sInstance->Get(); + dnsServer = &sInstance->Get(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP server. + + SuccessOrQuit(otBorderRoutingInit(sInstance, /* aInfraIfIndex */ kInfraIfIndex, /* aInfraIfIsRunning */ true)); + + SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicast)); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); + + srpServer->SetEnabled(true); + VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); + + AdvanceTime(10000); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP client. + + srpClient->EnableAutoStartMode(nullptr, nullptr); + VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); + + AdvanceTime(2000); + VerifyOrQuit(srpClient->IsRunning()); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Enable invoking of callback directly from otPlatDnssdStart{Browsers/Resolver} APIs"); + + ResetPlatDnssdApiInfo(); + + sInvokeOnStart.mBrowseResult = &browseResult; + sInvokeOnStart.mSrvResult = &srvResult; + sInvokeOnStart.mTxtResult = &txtResult; + sInvokeOnStart.mIp6AddrResult = &ip6AddrrResult; + + browseResult.mServiceType = "_guardian._glaxy"; + browseResult.mSubTypeLabel = nullptr; + browseResult.mServiceInstance = "mantis"; + browseResult.mTtl = kTtl; + browseResult.mInfraIfIndex = kInfraIfIndex; + + srvResult.mServiceInstance = "mantis"; + srvResult.mServiceType = "_guardian._glaxy"; + srvResult.mHostName = "nova"; + srvResult.mPort = 3333; + srvResult.mTtl = kTtl; + srvResult.mInfraIfIndex = kInfraIfIndex; + + txtResult.mServiceInstance = "mantis"; + txtResult.mServiceType = "_guardian._glaxy"; + txtResult.mTxtData = kTxtData; + txtResult.mTxtDataLength = sizeof(kTxtData); + txtResult.mTtl = kTtl; + txtResult.mInfraIfIndex = kInfraIfIndex; + + SuccessOrQuit(AsCoreType(&addressAndTtl[0].mAddress).FromString("fd00::5555")); + SuccessOrQuit(AsCoreType(&addressAndTtl[1].mAddress).FromString("fd00::1234")); + addressAndTtl[0].mTtl = kTtl; + addressAndTtl[1].mTtl = kTtl; + + ip6AddrrResult.mHostName = "nova"; + ip6AddrrResult.mInfraIfIndex = kInfraIfIndex; + ip6AddrrResult.mAddresses = addressAndTtl; + ip6AddrrResult.mAddressesLength = 2; + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + sBrowseInfo.Reset(); + + Log("Browse()"); + SuccessOrQuit(dnsClient->Browse("_guardian._glaxy.default.service.arpa.", BrowseCallback, sInstance)); + AdvanceTime(10); + + // All browsers/resolvers should be started and stopped + // (since the callbacks are invoked directly from API) + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 1); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 1); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 1); + + VerifyOrQuit(sStartBrowserInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStopBrowserInfo.ServiceTypeMatches("_guardian._glaxy")); + + VerifyOrQuit(sStartSrvResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStartSrvResolverInfo.ServiceInstanceMatches("mantis")); + VerifyOrQuit(sStopSrvResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStopSrvResolverInfo.ServiceInstanceMatches("mantis")); + + VerifyOrQuit(sStartTxtResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStartTxtResolverInfo.ServiceInstanceMatches("mantis")); + VerifyOrQuit(sStopTxtResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStopTxtResolverInfo.ServiceInstanceMatches("mantis")); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("nova")); + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("nova")); + + // Check that response is revived by client and validate it + + VerifyOrQuit(sBrowseInfo.mCallbackCount == 1); + + VerifyOrQuit(!strcmp(sBrowseInfo.mServiceName, "_guardian._glaxy.default.service.arpa.")); + VerifyOrQuit(!strcmp(sBrowseInfo.mInstanceLabel, "mantis")); + VerifyOrQuit(!strcmp(sBrowseInfo.mServiceInfo.mHostNameBuffer, "nova.default.service.arpa.")); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mPort == 3333); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTtl == kTtl); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mHostAddressTtl == kTtl); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTxtDataSize == sizeof(kTxtData)); + VerifyOrQuit(!memcmp(sBrowseInfo.mServiceInfo.mTxtData, kTxtData, sizeof(kTxtData))); + VerifyOrQuit(sBrowseInfo.mServiceInfo.mTxtDataTtl == kTtl); + VerifyOrQuit(!sBrowseInfo.mServiceInfo.mTxtDataTruncated); + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + sResolveServiceInfo.Reset(); + Log("ResolveService()"); + SuccessOrQuit( + dnsClient->ResolveService("mantis", "_guardian._glaxy.default.service.arpa.", ServiceCallback, sInstance)); + AdvanceTime(10); + + // Check that new SRV/TXT resolver and address resolvers are + // started and stopped. + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 2); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 2); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 2); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 2); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 2); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 2); + + VerifyOrQuit(sStartSrvResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStartSrvResolverInfo.ServiceInstanceMatches("mantis")); + VerifyOrQuit(sStopSrvResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStopSrvResolverInfo.ServiceInstanceMatches("mantis")); + + VerifyOrQuit(sStartTxtResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStartTxtResolverInfo.ServiceInstanceMatches("mantis")); + VerifyOrQuit(sStopTxtResolverInfo.ServiceTypeMatches("_guardian._glaxy")); + VerifyOrQuit(sStopTxtResolverInfo.ServiceInstanceMatches("mantis")); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("nova")); + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("nova")); + + // Check the service resolve response received on client + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); + SuccessOrQuit(sResolveServiceInfo.mError); + + VerifyOrQuit(!strcmp(sResolveServiceInfo.mInfo.mHostNameBuffer, "nova.default.service.arpa.")); + VerifyOrQuit(sResolveServiceInfo.mInfo.mPort == 3333); + VerifyOrQuit(sResolveServiceInfo.mInfo.mTtl == kTtl); + VerifyOrQuit(sResolveServiceInfo.mInfo.mHostAddressTtl == kTtl); + VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataSize == sizeof(kTxtData)); + VerifyOrQuit(!memcmp(sResolveServiceInfo.mInfo.mTxtData, kTxtData, sizeof(kTxtData))); + VerifyOrQuit(sResolveServiceInfo.mInfo.mTxtDataTtl == kTtl); + VerifyOrQuit(!sResolveServiceInfo.mInfo.mTxtDataTruncated); + VerifyOrQuit(sResolveServiceInfo.mNumHostAddresses == 2); + for (uint16_t index = 0; index < 2; index++) + { + VerifyOrQuit(sResolveServiceInfo.mHostAddresses[index] == AsCoreType(&addressAndTtl[0].mAddress) || + sResolveServiceInfo.mHostAddresses[index] == AsCoreType(&addressAndTtl[1].mAddress)); + } + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + sResolveAddressInfo.Reset(); + Log("ResolveAddress()"); + SuccessOrQuit(dnsClient->ResolveAddress("nova.default.service.arpa.", AddressCallback, sInstance)); + AdvanceTime(10); + + // Check that new address resolver is started and stopped. + + VerifyOrQuit(sStartBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStopBrowserInfo.mCallCount == 1); + VerifyOrQuit(sStartSrvResolverInfo.mCallCount == 2); + VerifyOrQuit(sStopSrvResolverInfo.mCallCount == 2); + VerifyOrQuit(sStartTxtResolverInfo.mCallCount == 2); + VerifyOrQuit(sStopTxtResolverInfo.mCallCount == 2); + VerifyOrQuit(sStartIp6AddrResolverInfo.mCallCount == 3); + VerifyOrQuit(sStopIp6AddrResolverInfo.mCallCount == 3); + + VerifyOrQuit(sStartIp6AddrResolverInfo.HostNameMatches("nova")); + VerifyOrQuit(sStopIp6AddrResolverInfo.HostNameMatches("nova")); + + // Check the address resolve response received on client + + VerifyOrQuit(sResolveAddressInfo.mCallbackCount == 1); + SuccessOrQuit(sResolveAddressInfo.mError); + + VerifyOrQuit(!strcmp(sResolveAddressInfo.mHostName, "nova.default.service.arpa.")); + VerifyOrQuit(sResolveAddressInfo.mTtl == kTtl); + VerifyOrQuit(sResolveAddressInfo.mNumHostAddresses == 2); + for (uint16_t index = 0; index < 2; index++) + { + VerifyOrQuit(sResolveAddressInfo.mHostAddresses[index] == AsCoreType(&addressAndTtl[0].mAddress) || + sResolveAddressInfo.mHostAddresses[index] == AsCoreType(&addressAndTtl[1].mAddress)); + } + + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + Log("Stop DNS-SD server"); + + dnsServer->Stop(); + + AdvanceTime(10); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Finalize OT instance and validate all heap allocations are freed. + + Log("Finalizing OT instance"); + FinalizeTest(); + + Log("End of TestProxyInvokeCallbackFromStartApi"); +} + +#endif // ENABLE_DISCOVERY_PROXY_TEST + +int main(void) +{ +#if ENABLE_DISCOVERY_PROXY_TEST + TestProxyBasic(); + TestProxySubtypeBrowse(); + TestProxyTimeout(); + TestProxySharedResolver(); + TestProxyFilterInvalidAddresses(); + TestProxyStateChanges(); + TestProxyInvokeCallbackFromStartApi(); + + printf("All tests passed\n"); +#else + printf("DISCOVERY_PROXY feature or a related feature required by this unit test is not enabled\n"); +#endif + + return 0; +} diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp index 78a608965..0cef5796e 100644 --- a/tests/unit/test_platform.cpp +++ b/tests/unit/test_platform.cpp @@ -877,6 +877,66 @@ OT_TOOL_WEAK void otPlatDnssdUnregisterKey(otInstance *aInstance OT_UNUSED_VARIABLE(aCallback); } +OT_TOOL_WEAK void otPlatDnssdStartBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aBrowser); +} + +OT_TOOL_WEAK void otPlatDnssdStopBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aBrowser); +} + +OT_TOOL_WEAK void otPlatDnssdStartSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +OT_TOOL_WEAK void otPlatDnssdStopSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +OT_TOOL_WEAK void otPlatDnssdStartTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +OT_TOOL_WEAK void otPlatDnssdStopTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +OT_TOOL_WEAK void otPlatDnssdStartIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +OT_TOOL_WEAK void otPlatDnssdStopIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +OT_TOOL_WEAK void otPlatDnssdStartIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + +OT_TOOL_WEAK void otPlatDnssdStopIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aResolver); +} + #endif // OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE #if OPENTHREAD_CONFIG_PLATFORM_LOG_CRASH_DUMP_ENABLE From d9bb516f0d4ff7e2581bee688237f576330f49d7 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 11 Jun 2024 08:39:58 -0700 Subject: [PATCH 06/65] [routing-manager] schedule all timers in `RxRaTracker` together (#10343) This commit adds `RxRaTracker::ScheduleAllTimers()`, which is called whenever there is a change in tracked information about routers and their advertised on-link or route prefixes. This method determines the next router expiration time (to initiate NS probes), the next prefix entry expiration, and the next stale time, then schedules all the timers. This centralizes all timer calculations and simplifies the code. --- src/core/border_router/routing_manager.cpp | 58 +++++++++++----------- src/core/border_router/routing_manager.hpp | 2 +- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index d1ab03028..f4c9d9678 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -1490,8 +1490,13 @@ void RoutingManager::RxRaTracker::RemoveOrDeprecateEntriesFromInactiveRouters(vo RemoveExpiredEntries(); } -void RoutingManager::RxRaTracker::ScheduleStaleTimer(void) +void RoutingManager::RxRaTracker::ScheduleAllTimers(void) { + TimeMilli now = TimerMilli::GetNow(); + NextFireTime routerTimeout(now); + NextFireTime entryExpireTime(now); + NextFireTime staleTime(now); + // If multiple routers advertise the same on-link or route prefix, // the stale time for the prefix is determined by the latest stale // time among all corresponding entries. @@ -1502,8 +1507,6 @@ void RoutingManager::RxRaTracker::ScheduleStaleTimer(void) // their entries, `DetermineStaleTimeFor()` will consider all // matching entries and mark "StaleTimeCalculated" flag on them. - NextFireTime staleTime; - for (Router &router : mRouters) { for (OnLinkPrefix &entry : router.mOnLinkPrefixes) @@ -1519,8 +1522,17 @@ void RoutingManager::RxRaTracker::ScheduleStaleTimer(void) for (const Router &router : mRouters) { + if ((router.mNsProbeCount <= Router::kMaxNsProbes) && !router.mIsLocalDevice) + { + // Skip if router is this device or has failed all + // earlier NS probes. + routerTimeout.UpdateIfEarlier(router.mTimeout); + } + for (const OnLinkPrefix &entry : router.mOnLinkPrefixes) { + entryExpireTime.UpdateIfEarlier(entry.GetExpireTime()); + if (!entry.IsStaleTimeCalculated()) { DetermineStaleTimeFor(entry, staleTime); @@ -1529,6 +1541,8 @@ void RoutingManager::RxRaTracker::ScheduleStaleTimer(void) for (const RoutePrefix &entry : router.mRoutePrefixes) { + entryExpireTime.UpdateIfEarlier(entry.GetExpireTime()); + if (!entry.IsStaleTimeCalculated()) { DetermineStaleTimeFor(entry, staleTime); @@ -1548,6 +1562,8 @@ void RoutingManager::RxRaTracker::ScheduleStaleTimer(void) staleTime.UpdateIfEarlier(CalculateExpirationTime(mLocalRaHeaderUpdateTime, interval)); } + mRouterTimer.FireAt(routerTimeout); + mExpirationTimer.FireAt(entryExpireTime); mStaleTimer.FireAt(staleTime); } @@ -1630,12 +1646,12 @@ void RoutingManager::RxRaTracker::HandleExpirationTimer(void) { RemoveExpiredEnt void RoutingManager::RxRaTracker::RemoveExpiredEntries(void) { - NextFireTime nextExpireTime; - bool didRemove = false; + TimeMilli now = TimerMilli::GetNow(); + bool didRemove = false; for (Router &router : mRouters) { - LifetimedPrefix::ExpirationChecker expirationChecker(nextExpireTime.GetNow()); + LifetimedPrefix::ExpirationChecker expirationChecker(now); didRemove |= router.mOnLinkPrefixes.RemoveAndFreeAllMatching(expirationChecker); didRemove |= router.mRoutePrefixes.RemoveAndFreeAllMatching(expirationChecker); @@ -1648,29 +1664,14 @@ void RoutingManager::RxRaTracker::RemoveExpiredEntries(void) SignalTableChanged(); } - // Determine the next expire time and schedule timer. - - for (const Router &router : mRouters) - { - for (const OnLinkPrefix &entry : router.mOnLinkPrefixes) - { - nextExpireTime.UpdateIfEarlier(entry.GetExpireTime()); - } - - for (const RoutePrefix &entry : router.mRoutePrefixes) - { - nextExpireTime.UpdateIfEarlier(entry.GetExpireTime()); - } - } - - mExpirationTimer.FireAt(nextExpireTime); + ScheduleAllTimers(); } void RoutingManager::RxRaTracker::SignalTableChanged(void) { mSignalTask.Post(); } void RoutingManager::RxRaTracker::HandleSignalTask(void) { - ScheduleStaleTimer(); + ScheduleAllTimers(); Get().HandleRaPrefixTableChanged(); } @@ -1702,7 +1703,7 @@ void RoutingManager::RxRaTracker::UpdateRouterOnRx(Router &aRouter) void RoutingManager::RxRaTracker::HandleRouterTimer(void) { - NextFireTime nextTime; + TimeMilli now = TimerMilli::GetNow(); for (Router &router : mRouters) { @@ -1720,7 +1721,7 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void) continue; } - if (router.mTimeout <= nextTime.GetNow()) + if (router.mTimeout <= now) { router.mNsProbeCount++; @@ -1731,19 +1732,16 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void) continue; } - router.mTimeout = - nextTime.GetNow() + ((router.mNsProbeCount < Router::kMaxNsProbes) ? Router::kNsProbeRetryInterval + router.mTimeout = now + ((router.mNsProbeCount < Router::kMaxNsProbes) ? Router::kNsProbeRetryInterval : Router::kNsProbeTimeout); SendNeighborSolicitToRouter(router); } - - nextTime.UpdateIfEarlier(router.mTimeout); } RemoveOrDeprecateEntriesFromInactiveRouters(); - mRouterTimer.FireAt(nextTime); + ScheduleAllTimers(); } void RoutingManager::RxRaTracker::SendNeighborSolicitToRouter(const Router &aRouter) diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 456326e29..1c5be7928 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -918,7 +918,7 @@ class RoutingManager : public InstanceLocator void RemoveRoutersWithNoEntriesOrFlags(void); void RemoveExpiredEntries(void); void SignalTableChanged(void); - void ScheduleStaleTimer(void); + void ScheduleAllTimers(void); void DetermineStaleTimeFor(const OnLinkPrefix &aPrefix, NextFireTime &aStaleTime); void DetermineStaleTimeFor(const RoutePrefix &aPrefix, NextFireTime &aStaleTime); void UpdateRouterOnRx(Router &aRouter); From 7ba7fb2eb6868d15cfe62e3885c39ecf3faeed1c Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 11 Jun 2024 08:43:49 -0700 Subject: [PATCH 07/65] [srp-client] use sequential message IDs & allow older response IDs (#10353) This commit updates `Srp::Client` to use sequential message IDs, replacing the previous model where message IDs were generated randomly. When processing responses from the server, older message IDs are accepted as long as the corresponding older message was identical to the latest one. This helps in situations where the server's response may be delayed (e.g., due to network congestion) and the client retry mechanism is retransmitting the same update message. This commit also adds a unit test `TestSrpClientDelayedResponse()` to validate the new behavior. --- src/core/net/srp_client.cpp | 104 ++++++++++++++----- src/core/net/srp_client.hpp | 21 +++- tests/unit/test_srp_server.cpp | 183 +++++++++++++++++++++++++++++++++ 3 files changed, 276 insertions(+), 32 deletions(-) diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index da697968c..96b647ed3 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -68,13 +68,19 @@ void Client::HostInfo::Clear(void) SetState(kRemoved); } -void Client::HostInfo::SetState(ItemState aState) +bool Client::HostInfo::SetState(ItemState aState) { - if (aState != GetState()) - { - LogInfo("HostInfo %s -> %s", ItemStateToString(GetState()), ItemStateToString(aState)); - mState = MapEnum(aState); - } + bool didChange; + + VerifyOrExit(aState != GetState(), didChange = false); + + LogInfo("HostInfo %s -> %s", ItemStateToString(GetState()), ItemStateToString(aState)); + + mState = MapEnum(aState); + didChange = true; + +exit: + return didChange; } void Client::HostInfo::EnableAutoAddress(void) @@ -121,9 +127,11 @@ Error Client::Service::Init(void) return error; } -void Client::Service::SetState(ItemState aState) +bool Client::Service::SetState(ItemState aState) { - VerifyOrExit(GetState() != aState); + bool didChange; + + VerifyOrExit(GetState() != aState, didChange = false); LogInfo("Service %s -> %s, \"%s\" \"%s\"", ItemStateToString(GetState()), ItemStateToString(aState), GetInstanceName(), GetName()); @@ -150,10 +158,11 @@ void Client::Service::SetState(ItemState aState) GetPriority(), GetNumTxtEntries()); } - mState = MapEnum(aState); + mState = MapEnum(aState); + didChange = true; exit: - return; + return didChange; } bool Client::Service::Matches(const Service &aOther) const @@ -249,7 +258,8 @@ Client::Client(Instance &aInstance) , mServiceKeyRecordEnabled(false) , mUseShortLeaseOption(false) #endif - , mUpdateMessageId(0) + , mNextMessageId(0) + , mResponseMessageId(0) , mAutoHostAddressCount(0) , mRetryWaitInterval(kMinRetryWaitInterval) , mTtl(0) @@ -345,6 +355,7 @@ void Client::Stop(Requester aRequester, StopMode aMode) mShouldRemoveKeyLease = false; mTxFailureRetryCount = 0; + mResponseMessageId = mNextMessageId; if (aMode == kResetRetryInterval) { @@ -739,13 +750,15 @@ void Client::SetState(State aState) return; } -void Client::ChangeHostAndServiceStates(const ItemState *aNewStates, ServiceStateChangeMode aMode) +bool Client::ChangeHostAndServiceStates(const ItemState *aNewStates, ServiceStateChangeMode aMode) { + bool anyChanged; + #if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE ItemState oldHostState = mHostInfo.GetState(); #endif - mHostInfo.SetState(aNewStates[mHostInfo.GetState()]); + anyChanged = mHostInfo.SetState(aNewStates[mHostInfo.GetState()]); for (Service &service : mServices) { @@ -754,7 +767,7 @@ void Client::ChangeHostAndServiceStates(const ItemState *aNewStates, ServiceStat continue; } - service.SetState(aNewStates[service.GetState()]); + anyChanged |= service.SetState(aNewStates[service.GetState()]); } #if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE @@ -781,6 +794,8 @@ void Client::ChangeHostAndServiceStates(const ItemState *aNewStates, ServiceStat } } #endif // OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE + + return anyChanged; } void Client::InvokeCallback(Error aError) const { InvokeCallback(aError, mHostInfo, nullptr); } @@ -806,6 +821,7 @@ void Client::SendUpdate(void) Error error = kErrorNone; Message *message = mSocket.NewMessage(); uint32_t length; + bool anyChanged; VerifyOrExit(message != nullptr, error = kErrorNoBufs); SuccessOrExit(error = PrepareUpdateMessage(*message)); @@ -822,14 +838,35 @@ void Client::SendUpdate(void) SuccessOrExit(error = mSocket.SendTo(*message, Ip6::MessageInfo())); - LogInfo("Send update"); + LogInfo("Send update, msg-id:0x%x", mNextMessageId); // State changes: // kToAdd -> kAdding // kToRefresh -> kRefreshing // kToRemove -> kRemoving - ChangeHostAndServiceStates(kNewStateOnMessageTx, kForServicesAppendedInMessage); + anyChanged = ChangeHostAndServiceStates(kNewStateOnMessageTx, kForServicesAppendedInMessage); + + // `mNextMessageId` tracks the message ID used in the prepared + // update message. It is incremented after a successful + // `mSocket.SendTo()` call. If unsuccessful, the same ID can be + // reused for the next update. + // + // Acceptable response message IDs fall within the range starting + // at `mResponseMessageId ` and ending before `mNextMessageId`. + // + // `anyChanged` tracks if any host or service states have changed. + // If not, the prepared message is identical to the last one with + // the same hosts/services, allowing us to accept earlier message + // IDs. If changes occur, `mResponseMessageId ` is updated to + // ensure only responses to the latest message are accepted. + + if (anyChanged) + { + mResponseMessageId = mNextMessageId; + } + + mNextMessageId++; // Remember the update message tx time to use later to determine the // lease renew time. @@ -902,13 +939,7 @@ Error Client::PrepareUpdateMessage(Message &aMessage) SuccessOrExit(error = ReadOrGenerateKey(info.mKeyPair)); #endif - // Generate random Message ID and ensure it is different from last one - do - { - SuccessOrExit(error = header.SetRandomMessageId()); - } while (header.GetMessageId() == mUpdateMessageId); - - mUpdateMessageId = header.GetMessageId(); + header.SetMessageId(mNextMessageId); // SRP Update (DNS Update) message must have exactly one record in // Zone section, no records in Prerequisite Section, can have @@ -1578,22 +1609,32 @@ void Client::ProcessResponse(Message &aMessage) uint16_t recordCount; LinkedList removedServices; - VerifyOrExit(GetState() == kStateUpdating); + switch (GetState()) + { + case kStateToUpdate: + case kStateUpdating: + case kStateToRetry: + break; + case kStateStopped: + case kStatePaused: + case kStateUpdated: + ExitNow(); + } SuccessOrExit(error = aMessage.Read(offset, header)); VerifyOrExit(header.GetType() == Dns::Header::kTypeResponse, error = kErrorParse); VerifyOrExit(header.GetQueryType() == Dns::Header::kQueryTypeUpdate, error = kErrorParse); - VerifyOrExit(header.GetMessageId() == mUpdateMessageId, error = kErrorDrop); + + VerifyOrExit(IsResponseMessageIdValid(header.GetMessageId()), error = kErrorDrop); + mResponseMessageId = header.GetMessageId() + 1; if (!Get().IsRxOnWhenIdle()) { Get().StopFastPolls(); } - // Response is for the earlier request message. - - LogInfo("Received response"); + LogInfo("Received response, msg-id:0x%x", header.GetMessageId()); #if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SWITCH_SERVER_ON_FAILURE mAutoStart.ResetTimeoutFailureCount(); @@ -1722,6 +1763,13 @@ void Client::ProcessResponse(Message &aMessage) } } +bool Client::IsResponseMessageIdValid(uint16_t aId) const +{ + // Semantically equivalent to `(aId >= mResponseMessageId) && (aId < mNextMessageId)` + + return !SerialNumber::IsLess(aId, mResponseMessageId) && SerialNumber::IsLess(aId, mNextMessageId); +} + void Client::HandleUpdateDone(void) { HostInfo hostInfoCopy = mHostInfo; diff --git a/src/core/net/srp_client.hpp b/src/core/net/srp_client.hpp index 32b1ea0de..8c9cf7e3f 100644 --- a/src/core/net/srp_client.hpp +++ b/src/core/net/srp_client.hpp @@ -167,7 +167,7 @@ class Client : public InstanceLocator, private NonCopyable private: void SetName(const char *aName) { mName = aName; } - void SetState(ItemState aState); + bool SetState(ItemState aState); void SetAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddresses); void EnableAutoAddress(void); }; @@ -303,7 +303,7 @@ class Client : public InstanceLocator, private NonCopyable static constexpr uint32_t kAppendedInMsgFlag = (1U << 31); static constexpr uint32_t kLeaseMask = ~kAppendedInMsgFlag; - void SetState(ItemState aState); + bool SetState(ItemState aState); TimeMilli GetLeaseRenewTime(void) const { return TimeMilli(mData); } void SetLeaseRenewTime(TimeMilli aTime) { mData = aTime.GetValue(); } bool IsAppendedInMessage(void) const { return mLease & kAppendedInMsgFlag; } @@ -788,6 +788,17 @@ class Client : public InstanceLocator, private NonCopyable * */ bool GetUseShortLeaseOption(void) const { return mUseShortLeaseOption; } + + /** + * Set the next DNS message ID for client to use. + * + * This is intended for testing only. + * + * @pram[in] aMessageId A message ID. + * + */ + void SetNextMessageId(uint16_t aMessageId) { mNextMessageId = aMessageId; } + #endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE private: @@ -1007,7 +1018,7 @@ class Client : public InstanceLocator, private NonCopyable void UpdateServiceStateToRemove(Service &aService); State GetState(void) const { return mState; } void SetState(State aState); - void ChangeHostAndServiceStates(const ItemState *aNewStates, ServiceStateChangeMode aMode); + bool ChangeHostAndServiceStates(const ItemState *aNewStates, ServiceStateChangeMode aMode); void InvokeCallback(Error aError) const; void InvokeCallback(Error aError, const HostInfo &aHostInfo, const Service *aRemovedServices) const; void HandleHostInfoOrServiceChange(void); @@ -1031,6 +1042,7 @@ class Client : public InstanceLocator, private NonCopyable void UpdateRecordLengthInMessage(Dns::ResourceRecord &aRecord, uint16_t aOffset, Message &aMessage) const; static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); void ProcessResponse(Message &aMessage); + bool IsResponseMessageIdValid(uint16_t aId) const; void HandleUpdateDone(void); void GetRemovedServices(LinkedList &aRemovedServices); static Error ReadResourceRecord(const Message &aMessage, uint16_t &aOffset, Dns::ResourceRecord &aRecord); @@ -1073,7 +1085,8 @@ class Client : public InstanceLocator, private NonCopyable bool mUseShortLeaseOption : 1; #endif - uint16_t mUpdateMessageId; + uint16_t mNextMessageId; + uint16_t mResponseMessageId; uint16_t mAutoHostAddressCount; uint32_t mRetryWaitInterval; diff --git a/tests/unit/test_srp_server.cpp b/tests/unit/test_srp_server.cpp index 2104ae827..d381ee250 100644 --- a/tests/unit/test_srp_server.cpp +++ b/tests/unit/test_srp_server.cpp @@ -1024,6 +1024,187 @@ void TestUpdateLeaseShortVariant(void) Log("End of TestUpdateLeaseShortVariant"); } +static uint16_t sServerRxCount; +static Ip6::MessageInfo sServerMsgInfo; +static uint16_t sServerLastMsgId; + +void HandleServerUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) +{ + Dns::Header header; + + VerifyOrQuit(aContext == nullptr); + VerifyOrQuit(aMessage != nullptr); + VerifyOrQuit(aMessageInfo != nullptr); + + SuccessOrQuit(AsCoreType(aMessage).Read(0, header)); + + sServerMsgInfo = AsCoreType(aMessageInfo); + sServerLastMsgId = header.GetMessageId(); + sServerRxCount++; + + Log("HandleServerUdpReceive(), message-id: 0x%x", header.GetMessageId()); +} + +void TestSrpClientDelayedResponse(void) +{ + static constexpr uint16_t kServerPort = 53535; + + Srp::Client *srpClient; + Srp::Client::Service service1; + Srp::Client::Service service2; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestSrpClientDelayedResponse"); + + InitTest(); + + srpClient = &sInstance->Get(); + + for (uint8_t testIter = 0; testIter < 3; testIter++) + { + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + Log("testIter = %u", testIter); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Prepare a socket to act as SRP server. + + Ip6::Udp::Socket udpSocket(*sInstance); + Ip6::SockAddr serverSockAddr; + uint16_t firstMsgId; + Message *response; + Dns::UpdateHeader header; + + sServerRxCount = 0; + + SuccessOrQuit(udpSocket.Open(HandleServerUdpReceive, nullptr)); + SuccessOrQuit(udpSocket.Bind(kServerPort, Ip6::kNetifThread)); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Manually start the client with a message ID based on `testIter` + // We use zero in the first iteration, `0xffff` in the second + // iteration to test wrapping of 16-bit message ID. + + switch (testIter) + { + case 0: + srpClient->SetNextMessageId(0); + break; + case 1: + srpClient->SetNextMessageId(0xffff); + break; + case 2: + srpClient->SetNextMessageId(0xaaaa); + break; + } + + serverSockAddr.SetAddress(sInstance->Get().GetMeshLocal16()); + serverSockAddr.SetPort(kServerPort); + SuccessOrQuit(srpClient->Start(serverSockAddr)); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Register a service + + SuccessOrQuit(srpClient->SetHostName(kHostName)); + SuccessOrQuit(srpClient->EnableAutoHostAddress()); + + PrepareService1(service1); + SuccessOrQuit(srpClient->AddService(service1)); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Wait for short time and make sure server receives an SRP + // update message from client. + + AdvanceTime(1 * 1000); + + VerifyOrQuit(sServerRxCount == 1); + firstMsgId = sServerLastMsgId; + + switch (testIter) + { + case 0: + VerifyOrQuit(firstMsgId == 0); + break; + case 1: + VerifyOrQuit(firstMsgId == 0xffff); + break; + case 2: + VerifyOrQuit(firstMsgId == 0xaaaa); + break; + } + + if (testIter == 2) + { + AdvanceTime(2 * 1000); + + PrepareService2(service2); + SuccessOrQuit(srpClient->AddService(service2)); + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Wait for longer to allow client to retry a bunch of times + + AdvanceTime(20 * 1000); + VerifyOrQuit(sServerRxCount > 1); + VerifyOrQuit(sServerLastMsgId != firstMsgId); + + VerifyOrQuit(srpClient->GetHostInfo().GetState() != Srp::Client::kRegistered); + VerifyOrQuit(service1.GetState() != Srp::Client::kRegistered); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Now send a delayed response from server using the first + // message ID. + + response = udpSocket.NewMessage(); + VerifyOrQuit(response != nullptr); + + Log("Sending response with msg-id: 0x%x", firstMsgId); + + header.SetMessageId(firstMsgId); + header.SetType(Dns::UpdateHeader::kTypeResponse); + header.SetResponseCode(Dns::UpdateHeader::kResponseSuccess); + SuccessOrQuit(response->Append(header)); + SuccessOrQuit(udpSocket.SendTo(*response, sServerMsgInfo)); + + AdvanceTime(10); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // In the first two iterations, we ensure that client + // did successfully accept the response with older message ID. + // This should not be the case in the third iteration due to + // changes to client services after first UPdate message was + // sent by client. + + switch (testIter) + { + case 0: + case 1: + VerifyOrQuit(srpClient->GetHostInfo().GetState() == Srp::Client::kRegistered); + VerifyOrQuit(service1.GetState() == Srp::Client::kRegistered); + break; + case 2: + VerifyOrQuit(srpClient->GetHostInfo().GetState() != Srp::Client::kRegistered); + VerifyOrQuit(service1.GetState() != Srp::Client::kRegistered); + break; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Remove service and close socket. + + srpClient->ClearHostAndServices(); + srpClient->Stop(); + + SuccessOrQuit(udpSocket.Close()); + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Finalize OT instance + + Log("Finalizing OT instance"); + FinalizeTest(); + + Log("End of TestSrpClientDelayedResponse"); +} + #endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE #endif // ENABLE_SRP_TEST @@ -1040,7 +1221,9 @@ int main(void) ot::TestSrpServerClientRemove(/* aShouldRemoveKeyLease */ false); #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE ot::TestUpdateLeaseShortVariant(); + ot::TestSrpClientDelayedResponse(); #endif + printf("All tests passed\n"); #else printf("SRP_SERVER or SRP_CLIENT feature is not enabled\n"); From fe0037e67a2456f24c459e3b51bb92d4a74a6f08 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 11 Jun 2024 08:45:11 -0700 Subject: [PATCH 08/65] [mle] add `Mle::RxMessage::ReadAndSetNetworkDataTlv()` (#10358) This commit adds `ReadAndSetNetworkDataTlv()` to `Mle::RxMessage` to read the Network Data TLV from a received MLE message and set it in `NetworkData::Leader`. --- src/core/thread/mle.cpp | 43 ++++++++++++++++++++++++----------------- src/core/thread/mle.hpp | 1 + 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 838ff8ef2..b45d07529 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -2902,8 +2902,6 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo) bool saveActiveDataset = false; bool savePendingDataset = false; bool dataRequest = false; - uint16_t offset; - uint16_t length; SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData)); @@ -2977,16 +2975,15 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo) ExitNow(error = kErrorParse); } - if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kNetworkData, offset, length) == kErrorNone) + switch (error = aRxInfo.mMessage.ReadAndSetNetworkDataTlv(leaderData)) { - error = Get().SetNetworkData(leaderData.GetDataVersion(NetworkData::kFullSet), - leaderData.GetDataVersion(NetworkData::kStableSubset), - GetNetworkDataType(), aRxInfo.mMessage, offset, length); - SuccessOrExit(error); - } - else - { - ExitNow(dataRequest = true); + case kErrorNone: + break; + case kErrorNotFound: + dataRequest = true; + OT_FALL_THROUGH; + default: + ExitNow(); } #if OPENTHREAD_FTD @@ -3308,8 +3305,6 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) uint16_t sourceAddress; uint16_t shortAddress; MeshCoP::Timestamp timestamp; - uint16_t networkDataOffset; - uint16_t networkDataLength; SuccessOrExit(error = Tlv::Find(aRxInfo.mMessage, sourceAddress)); @@ -3324,8 +3319,7 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData)); - SuccessOrExit( - error = Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kNetworkData, networkDataOffset, networkDataLength)); + VerifyOrExit(aRxInfo.mMessage.ContainsTlv(Tlv::kNetworkData)); switch (Tlv::Find(aRxInfo.mMessage, timestamp)) { @@ -3388,9 +3382,7 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) mParent.SetRloc16(sourceAddress); - IgnoreError(Get().SetNetworkData( - leaderData.GetDataVersion(NetworkData::kFullSet), leaderData.GetDataVersion(NetworkData::kStableSubset), - GetNetworkDataType(), aRxInfo.mMessage, networkDataOffset, networkDataLength)); + IgnoreError(aRxInfo.mMessage.ReadAndSetNetworkDataTlv(leaderData)); SetStateChild(shortAddress); @@ -5064,6 +5056,21 @@ Error Mle::RxMessage::ReadLeaderDataTlv(LeaderData &aLeaderData) const return error; } +Error Mle::RxMessage::ReadAndSetNetworkDataTlv(const LeaderData &aLeaderData) const +{ + Error error; + uint16_t offset; + uint16_t length; + + SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, Tlv::kNetworkData, offset, length)); + + error = Get().SetNetworkData(aLeaderData.GetDataVersion(NetworkData::kFullSet), + aLeaderData.GetDataVersion(NetworkData::kStableSubset), + Get().GetNetworkDataType(), *this, offset, length); +exit: + return error; +} + Error Mle::RxMessage::ReadAndSaveActiveDataset(const MeshCoP::Timestamp &aActiveTimestamp) const { return ReadAndSaveDataset(MeshCoP::Dataset::kActive, aActiveTimestamp); diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 318648b5e..a13c5f594 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1072,6 +1072,7 @@ class Mle : public InstanceLocator, private NonCopyable Error ReadFrameCounterTlvs(uint32_t &aLinkFrameCounter, uint32_t &aMleFrameCounter) const; Error ReadTlvRequestTlv(TlvList &aTlvList) const; Error ReadLeaderDataTlv(LeaderData &aLeaderData) const; + Error ReadAndSetNetworkDataTlv(const LeaderData &aLeaderData) const; Error ReadAndSaveActiveDataset(const MeshCoP::Timestamp &aActiveTimestamp) const; Error ReadAndSavePendingDataset(const MeshCoP::Timestamp &aPendingTimestamp) const; #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE From b2141a682271af54a4b4a6dd08bb5db6c3c6dfed Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Wed, 12 Jun 2024 00:09:07 +0800 Subject: [PATCH 09/65] [style] unify using member variable (#10360) --- src/core/mac/mac.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index e70fc982b..9ca72fdba 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -340,7 +340,7 @@ void Mac::PerformEnergyScan(void) } else { - if (!GetRxOnWhenIdle()) + if (!mRxOnWhenIdle) { mLinks.Receive(mScanChannel); } @@ -1316,7 +1316,7 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError) ProcessCsl(*aAckFrame, dstAddr); #endif #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - if (!GetRxOnWhenIdle() && aFrame.GetHeaderIe(CslIe::kHeaderIeId) != nullptr) + if (!mRxOnWhenIdle && aFrame.GetHeaderIe(CslIe::kHeaderIeId) != nullptr) { Get().ResetKeepAliveTimer(); } From 32f462ff34d73d8011d349387f1433d1b9305117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Baczma=C5=84ski?= Date: Tue, 11 Jun 2024 20:13:21 +0200 Subject: [PATCH 10/65] [cmake] add option for `OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US` (#10361) This makes it easier for vendors to tweak scheduling CSL transmission request depending on minimum time to process it (which for example might be higher for RCP architecture). Signed-off-by: Maciej Baczmanski --- etc/cmake/options.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 3eba447c2..c756e9ea7 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -328,6 +328,7 @@ ot_string_option(OT_VENDOR_SW_VERSION OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSI set(OT_POWER_SUPPLY_VALUES "BATTERY" "EXTERNAL" "EXTERNAL_STABLE" "EXTERNAL_UNSTABLE") ot_multi_option(OT_POWER_SUPPLY OT_POWER_SUPPLY_VALUES OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY OT_POWER_SUPPLY_ "set the device power supply config") +ot_int_option(OT_MAC_CSL_REQUEST_AHEAD_US OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US "set time ahead to deliver CSL frame from MAC to SubMac in microseconds") ot_int_option(OT_MLE_MAX_CHILDREN OPENTHREAD_CONFIG_MLE_MAX_CHILDREN "set maximum number of children") ot_int_option(OT_RCP_RESTORATION_MAX_COUNT OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT "set max RCP restoration count") ot_int_option(OT_RCP_TX_WAIT_TIME_SECS OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME_SECS "set RCP TX wait TIME in seconds") From 185b0e18e713e846cff8a381a832e65767aaa7e1 Mon Sep 17 00:00:00 2001 From: Handa Wang <7058128+superwhd@users.noreply.github.com> Date: Wed, 12 Jun 2024 23:26:53 +0800 Subject: [PATCH 11/65] [posix] improve the logging in netif (#10362) This commit improves the logging of `posix/platform/netif.cpp` in following ways: - Fix the false warning log when OT stack adds a unicast address. 1. When OT adds an address, it will add an address on host netif. 2. Then it causes a netlink `RTM_NEWADDR` event. 3. It assumes the newly added address is added by the host, so tries to add the unicast address to OT again by `otIp6AddUnicastAddress`. 4. `otIp6AddUnicastAddress` returns 'invalid arguments' error so it will log `Failed to process event...`. - Improve the logging of `AddRoute` and `DeleteRoute`. Previously they silently sent out the requests so we don't know what the allocated netlink sequence numbers were used for. --- src/posix/platform/netif.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/posix/platform/netif.cpp b/src/posix/platform/netif.cpp index e0a4c49b8..ebb0e79a1 100644 --- a/src/posix/platform/netif.cpp +++ b/src/posix/platform/netif.cpp @@ -652,7 +652,8 @@ template otError AddRoute(const uint8_t (&aAddress)[N], uint8_t aPref char buf[kBufSize]; } req{}; unsigned int netifIdx = otSysGetThreadNetifIndex(); - otError error = OT_ERROR_NONE; + char addrStrBuf[INET6_ADDRSTRLEN]; + otError error = OT_ERROR_NONE; static_assert(N == sizeof(in6_addr) || N == sizeof(in_addr), "aAddress should be 4 octets or 16 octets"); @@ -680,11 +681,18 @@ template otError AddRoute(const uint8_t (&aAddress)[N], uint8_t aPref AddRtAttrUint32(&req.header, sizeof(req), RTA_PRIORITY, aPriority); AddRtAttrUint32(&req.header, sizeof(req), RTA_OIF, netifIdx); + inet_ntop(req.msg.rtm_family, aAddress, addrStrBuf, sizeof(addrStrBuf)); + if (send(sNetlinkFd, &req, sizeof(req), 0) < 0) { + LogInfo("Failed to send request#%u to add route %s/%u", sNetlinkSequence, addrStrBuf, aPrefixLen); VerifyOrExit(errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK, error = OT_ERROR_BUSY); DieNow(OT_EXIT_ERROR_ERRNO); } + else + { + LogInfo("Sent request#%u to add route %s/%u", sNetlinkSequence, addrStrBuf, aPrefixLen); + } exit: return error; } @@ -699,7 +707,8 @@ template otError DeleteRoute(const uint8_t (&aAddress)[N], uint8_t aP char buf[kBufSize]; } req{}; unsigned int netifIdx = otSysGetThreadNetifIndex(); - otError error = OT_ERROR_NONE; + char addrStrBuf[INET6_ADDRSTRLEN]; + otError error = OT_ERROR_NONE; static_assert(N == sizeof(in6_addr) || N == sizeof(in_addr), "aAddress should be 4 octets or 16 octets"); @@ -726,11 +735,18 @@ template otError DeleteRoute(const uint8_t (&aAddress)[N], uint8_t aP AddRtAttr(reinterpret_cast(&req), sizeof(req), RTA_DST, &aAddress, sizeof(aAddress)); AddRtAttrUint32(&req.header, sizeof(req), RTA_OIF, netifIdx); + inet_ntop(req.msg.rtm_family, aAddress, addrStrBuf, sizeof(addrStrBuf)); + if (send(sNetlinkFd, &req, sizeof(req), 0) < 0) { + LogInfo("Failed to send request#%u to delete route %s/%u", sNetlinkSequence, addrStrBuf, aPrefixLen); VerifyOrExit(errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK, error = OT_ERROR_BUSY); DieNow(OT_EXIT_ERROR_ERRNO); } + else + { + LogInfo("Sent request#%u to delete route %s/%u", sNetlinkSequence, addrStrBuf, aPrefixLen); + } exit: return error; @@ -1340,6 +1356,7 @@ static void processNetifAddrEvent(otInstance *aInstance, struct nlmsghdr *aNetli netAddr.mPrefixLength = ifaddr->ifa_prefixlen; error = otIp6AddUnicastAddress(aInstance, &netAddr); + error = (error == OT_ERROR_INVALID_ARGS) ? OT_ERROR_NONE : error; } else { From 9c1f1f3dfb99d8700df6319f20fc9363d4957b3d Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 5 Jun 2024 11:22:46 -0700 Subject: [PATCH 12/65] [key-manager] update how the "Key Switch Guard Timer" is reset (#10347) This commit updates the resetting of the Key Switch Guard Timer. It is now reset under two conditions: - The device itself triggers a key rotation and moves to the next key sequence after the rotation time has passed since the last switch. - The device receives a MAC or MLE message with an incoming key index matching the next key index. Regarding MLE messages, this rule is applied regardless of the message being classified as Authoritative or Peer. --- src/core/api/thread_api.cpp | 3 ++- src/core/mac/mac.cpp | 2 +- src/core/thread/key_manager.cpp | 12 +++++++---- src/core/thread/key_manager.hpp | 28 +++++++++++++++---------- src/core/thread/mle.cpp | 37 +++++++++++++++++++++------------ 5 files changed, 52 insertions(+), 30 deletions(-) diff --git a/src/core/api/thread_api.cpp b/src/core/api/thread_api.cpp index 97e5508f0..b5661df64 100644 --- a/src/core/api/thread_api.cpp +++ b/src/core/api/thread_api.cpp @@ -275,7 +275,8 @@ uint32_t otThreadGetKeySequenceCounter(otInstance *aInstance) void otThreadSetKeySequenceCounter(otInstance *aInstance, uint32_t aKeySequenceCounter) { - AsCoreType(aInstance).Get().SetCurrentKeySequence(aKeySequenceCounter, KeyManager::kForceUpdate); + AsCoreType(aInstance).Get().SetCurrentKeySequence( + aKeySequenceCounter, KeyManager::kForceUpdate | KeyManager::kGuardTimerUnchanged); } uint16_t otThreadGetKeySwitchGuardTime(otInstance *aInstance) diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 9ca72fdba..d1fbd0a8e 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -1641,7 +1641,7 @@ Error Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neig if (keySequence > keyManager.GetCurrentKeySequence()) { - keyManager.SetCurrentKeySequence(keySequence, KeyManager::kApplyKeySwitchGuard); + keyManager.SetCurrentKeySequence(keySequence, KeyManager::kApplySwitchGuard | KeyManager::kResetGuardTimer); } } diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index d38fdb8b5..9f40c9ec2 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -368,11 +368,11 @@ void KeyManager::UpdateKeyMaterial(void) #endif } -void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence, KeySequenceUpdateMode aUpdateMode) +void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence, KeySeqUpdateFlags aFlags) { VerifyOrExit(aKeySequence != mKeySequence, Get().SignalIfFirst(kEventThreadKeySeqCounterChanged)); - if (aUpdateMode == kApplyKeySwitchGuard) + if (aFlags & kApplySwitchGuard) { VerifyOrExit(mKeySwitchGuardTimer == 0); } @@ -384,7 +384,11 @@ void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence, KeySequenceUpdateM mMleFrameCounter = 0; ResetKeyRotationTimer(); - mKeySwitchGuardTimer = mKeySwitchGuardTime; + + if (aFlags & kResetGuardTimer) + { + mKeySwitchGuardTimer = mKeySwitchGuardTime; + } Get().Signal(kEventThreadKeySeqCounterChanged); @@ -528,7 +532,7 @@ void KeyManager::CheckForKeyRotation(void) { if (mHoursSinceKeyRotation >= mSecurityPolicy.mRotationTime) { - SetCurrentKeySequence(mKeySequence + 1, kForceUpdate); + SetCurrentKeySequence(mKeySequence + 1, kForceUpdate | kResetGuardTimer); } } diff --git a/src/core/thread/key_manager.hpp b/src/core/thread/key_manager.hpp index 099854c45..56a64acb3 100644 --- a/src/core/thread/key_manager.hpp +++ b/src/core/thread/key_manager.hpp @@ -221,17 +221,25 @@ class KeyManager : public InstanceLocator, private NonCopyable { public: /** - * Determines whether to apply or ignore key switch guard when updating the key sequence. - * - * Used as input by `SetCurrentKeySequence()`. + * Defines bit-flag constants specifying how to handle key sequence update used in `KeySeqUpdateFlags`. * */ - enum KeySequenceUpdateMode : uint8_t + enum KeySeqUpdateFlag : uint8_t { - kApplyKeySwitchGuard, ///< Apply key switch guard check before setting the new key sequence. - kForceUpdate, ///< Ignore key switch guard check and forcibly update the key sequence to new value. + kApplySwitchGuard = (1 << 0), ///< Apply key switch guard check. + kForceUpdate = (0 << 0), ///< Ignore key switch guard check and forcibly update. + kResetGuardTimer = (1 << 1), ///< On key seq change, reset the guard timer. + kGuardTimerUnchanged = (0 << 1), ///< On key seq change, leave guard timer unchanged. }; + /** + * Represents a combination of `KeySeqUpdateFlag` bits. + * + * Used as input by `SetCurrentKeySequence()`. + * + */ + typedef uint8_t KeySeqUpdateFlags; + /** * Initializes the object. * @@ -342,14 +350,12 @@ class KeyManager : public InstanceLocator, private NonCopyable /** * Sets the current key sequence value. * - * If @p aMode is `kApplyKeySwitchGuard`, the current key switch guard timer is checked and only if it is zero, key - * sequence will be updated. - * * @param[in] aKeySequence The key sequence value. - * @param[in] aUpdateMode Whether or not to apply the key switch guard. + * @param[in] aFlags Specify behavior when updating the key sequence, i.e., whether or not to apply the + * key switch guard or reset guard timer upon change. * */ - void SetCurrentKeySequence(uint32_t aKeySequence, KeySequenceUpdateMode aUpdateMode); + void SetCurrentKeySequence(uint32_t aKeySequence, KeySeqUpdateFlags aFlags); #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE /** diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index b45d07529..76a397fdd 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -371,7 +371,8 @@ void Mle::Restore(void) SuccessOrExit(Get().Read(networkInfo)); - Get().SetCurrentKeySequence(networkInfo.GetKeySequence(), KeyManager::kForceUpdate); + Get().SetCurrentKeySequence(networkInfo.GetKeySequence(), + KeyManager::kForceUpdate | KeyManager::kGuardTimerUnchanged); Get().SetMleFrameCounter(networkInfo.GetMleFrameCounter()); Get().SetAllMacFrameCounters(networkInfo.GetMacFrameCounter(), /* aSetIfLarger */ false); @@ -2721,33 +2722,43 @@ void Mle::ProcessKeySequence(RxInfo &aRxInfo) // neighbor. // Otherwise larger key seq MUST NOT be adopted. + bool isNextKeySeq; + KeyManager::KeySeqUpdateFlags flags = 0; + VerifyOrExit(aRxInfo.mKeySequence > Get().GetCurrentKeySequence()); + isNextKeySeq = (aRxInfo.mKeySequence - Get().GetCurrentKeySequence() == 1); + switch (aRxInfo.mClass) { case RxInfo::kAuthoritativeMessage: - Get().SetCurrentKeySequence(aRxInfo.mKeySequence, KeyManager::kForceUpdate); + flags = KeyManager::kForceUpdate; break; case RxInfo::kPeerMessage: - if ((aRxInfo.mNeighbor != nullptr) && aRxInfo.mNeighbor->IsStateValid()) + VerifyOrExit(aRxInfo.IsNeighborStateValid()); + + if (!isNextKeySeq) { - if (aRxInfo.mKeySequence - Get().GetCurrentKeySequence() == 1) - { - Get().SetCurrentKeySequence(aRxInfo.mKeySequence, KeyManager::kApplyKeySwitchGuard); - } - else - { - LogInfo("Large key seq jump in peer class msg from 0x%04x ", aRxInfo.mNeighbor->GetRloc16()); - ReestablishLinkWithNeighbor(*aRxInfo.mNeighbor); - } + LogInfo("Large key seq jump in peer class msg from 0x%04x ", aRxInfo.mNeighbor->GetRloc16()); + ReestablishLinkWithNeighbor(*aRxInfo.mNeighbor); + ExitNow(); } + + flags = KeyManager::kApplySwitchGuard; break; case RxInfo::kUnknown: - break; + ExitNow(); } + if (isNextKeySeq) + { + flags |= KeyManager::kResetGuardTimer; + } + + Get().SetCurrentKeySequence(aRxInfo.mKeySequence, flags); + exit: return; } From 4a0d6b7b6495a1e4e2e03ab7a4f8baa064df4a6e Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 11 Jun 2024 12:47:48 -0700 Subject: [PATCH 13/65] [test] update key-increment test scripts to align with cert test (#10347) This commit removes the option to set `key_switch_guardtime` when constructing nodes and network topology in test scripts. The following tests are updated to reflect this change: - `Cert_5_8_02_KeyIncrement.py` - `Cert_5_8_03_KeyIncrementRollOver.py` - `Cert_6_6_01_KeyIncrement.py` - `Cert_6_6_02_KeyIncrementRollOver.py` --- tests/scripts/thread-cert/Cert_5_8_02_KeyIncrement.py | 2 -- tests/scripts/thread-cert/Cert_5_8_03_KeyIncrementRollOver.py | 2 -- tests/scripts/thread-cert/Cert_6_6_01_KeyIncrement.py | 2 -- tests/scripts/thread-cert/Cert_6_6_02_KeyIncrementRollOver.py | 2 -- tests/scripts/thread-cert/thread_cert.py | 2 -- 5 files changed, 10 deletions(-) diff --git a/tests/scripts/thread-cert/Cert_5_8_02_KeyIncrement.py b/tests/scripts/thread-cert/Cert_5_8_02_KeyIncrement.py index af305c613..230b3163d 100755 --- a/tests/scripts/thread-cert/Cert_5_8_02_KeyIncrement.py +++ b/tests/scripts/thread-cert/Cert_5_8_02_KeyIncrement.py @@ -42,13 +42,11 @@ class Cert_5_8_2_KeyIncrement(thread_cert.TestCase): TOPOLOGY = { LEADER: { 'name': 'LEADER', - 'key_switch_guardtime': 0, 'mode': 'rdn', 'allowlist': [ROUTER] }, ROUTER: { 'name': 'ROUTER', - 'key_switch_guardtime': 0, 'mode': 'rdn', 'allowlist': [LEADER] }, diff --git a/tests/scripts/thread-cert/Cert_5_8_03_KeyIncrementRollOver.py b/tests/scripts/thread-cert/Cert_5_8_03_KeyIncrementRollOver.py index 382c247aa..68a2bd7a4 100755 --- a/tests/scripts/thread-cert/Cert_5_8_03_KeyIncrementRollOver.py +++ b/tests/scripts/thread-cert/Cert_5_8_03_KeyIncrementRollOver.py @@ -43,13 +43,11 @@ class Cert_5_8_3_KeyIncrementRollOver(thread_cert.TestCase): LEADER: { 'name': 'LEADER', 'key_sequence_counter': 127, - 'key_switch_guardtime': 0, 'mode': 'rdn', 'allowlist': [ROUTER] }, ROUTER: { 'name': 'ROUTER', - 'key_switch_guardtime': 0, 'mode': 'rdn', 'allowlist': [LEADER] }, diff --git a/tests/scripts/thread-cert/Cert_6_6_01_KeyIncrement.py b/tests/scripts/thread-cert/Cert_6_6_01_KeyIncrement.py index 6ad6e6ecc..b1a907188 100755 --- a/tests/scripts/thread-cert/Cert_6_6_01_KeyIncrement.py +++ b/tests/scripts/thread-cert/Cert_6_6_01_KeyIncrement.py @@ -42,14 +42,12 @@ class Cert_6_6_1_KeyIncrement(thread_cert.TestCase): TOPOLOGY = { LEADER: { 'name': 'LEADER', - 'key_switch_guardtime': 0, 'mode': 'rdn', 'allowlist': [ED] }, ED: { 'name': 'ED', 'is_mtd': True, - 'key_switch_guardtime': 0, 'mode': 'rn', 'allowlist': [LEADER] }, diff --git a/tests/scripts/thread-cert/Cert_6_6_02_KeyIncrementRollOver.py b/tests/scripts/thread-cert/Cert_6_6_02_KeyIncrementRollOver.py index d7e078537..812e7f3d8 100755 --- a/tests/scripts/thread-cert/Cert_6_6_02_KeyIncrementRollOver.py +++ b/tests/scripts/thread-cert/Cert_6_6_02_KeyIncrementRollOver.py @@ -43,14 +43,12 @@ class Cert_6_6_2_KeyIncrement1(thread_cert.TestCase): LEADER: { 'name': 'LEADER', 'key_sequence_counter': 127, - 'key_switch_guardtime': 0, 'mode': 'rdn', 'allowlist': [ED] }, ED: { 'name': 'ED', 'is_mtd': True, - 'key_switch_guardtime': 0, 'mode': 'rn', 'allowlist': [LEADER] }, diff --git a/tests/scripts/thread-cert/thread_cert.py b/tests/scripts/thread-cert/thread_cert.py index 9603309ba..6da6dc2cc 100644 --- a/tests/scripts/thread-cert/thread_cert.py +++ b/tests/scripts/thread-cert/thread_cert.py @@ -207,8 +207,6 @@ def _setUp(self): channel=params['pending_dataset'].get('channel'), delay=params['pending_dataset'].get('delay')) - if 'key_switch_guardtime' in params: - self.nodes[i].set_key_switch_guardtime(params['key_switch_guardtime']) if 'key_sequence_counter' in params: self.nodes[i].set_key_sequence_counter(params['key_sequence_counter']) From cb1220d79b827c7b769e20cc5e7853cce10e88e4 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 12 Jun 2024 17:50:48 -0700 Subject: [PATCH 14/65] [cli] fix unused retval warning on `otPlatLogCrashDump()` call (#10369) --- examples/apps/cli/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/apps/cli/main.c b/examples/apps/cli/main.c index d0c6be2dd..6e18b430e 100644 --- a/examples/apps/cli/main.c +++ b/examples/apps/cli/main.c @@ -142,7 +142,7 @@ int main(int argc, char *argv[]) #endif #if OPENTHREAD_CONFIG_PLATFORM_LOG_CRASH_DUMP_ENABLE - otPlatLogCrashDump(); + IgnoreError(otPlatLogCrashDump()); #endif while (!otSysPseudoResetWasRequested()) From fa71a8afa3fa2eac8848c3c0dfda13780484f39a Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Thu, 13 Jun 2024 22:53:48 +0800 Subject: [PATCH 15/65] [diag] specify sending frame (#10359) This commit adds an extra command `diag frame` to specify the frame used for `diag send` and `diag repeat`, so that we can use this command to send arbitrary 802.15.4 frames. --- src/core/diags/README.md | 19 ++++++--- src/core/diags/factory_diags.cpp | 66 ++++++++++++++++++++++++++---- src/core/diags/factory_diags.hpp | 2 + tests/scripts/expect/cli-diags.exp | 29 +++++++++++++ 4 files changed, 104 insertions(+), 12 deletions(-) diff --git a/src/core/diags/README.md b/src/core/diags/README.md index 2ddb658ac..ee447b3f9 100644 --- a/src/core/diags/README.md +++ b/src/core/diags/README.md @@ -77,6 +77,15 @@ Stop transmitting continuous carrier wave. Done ``` +### diag frame \ + +Set the frame (hex encoded) to be used by `diag send` and `diag repeat`. The frame may be overwritten by `diag send` and `diag repeat`. + +```bash +> diag frame 11223344 +Done +``` + ### diag stream start Start transmitting a stream of characters. @@ -143,11 +152,11 @@ RawPowerSetting: 223344 Done ``` -### diag send \ \ +### diag send \ [length] -Transmit a fixed number of packets with fixed length. +Transmit a fixed number of packets. -Length parameter has to be in range [3, 127]. +Send the frame set by `diag frame` if length is omitted. Otherwise overwrite the frame set by `diag frame` and send a frame of the given length(MUST be in range [3, 127]). ```bash > diag send 20 100 @@ -155,11 +164,11 @@ sending 0x14 packet(s), length 0x64 status 0x00 ``` -### diag repeat \ \ +### diag repeat \ [length] Transmit packets repeatedly with a fixed interval. -Length parameter has to be in range [3, 127]. +Send the frame set by `diag frame` if length is omitted. Otherwise overwrite the frame set by `diag frame` and send a frame of the given length (MUST be in range [3, 127]). ```bash > diag repeat 100 100 diff --git a/src/core/diags/factory_diags.cpp b/src/core/diags/factory_diags.cpp index 78845f1aa..03ce33d72 100644 --- a/src/core/diags/factory_diags.cpp +++ b/src/core/diags/factory_diags.cpp @@ -32,6 +32,7 @@ */ #include "factory_diags.hpp" +#include "common/error.hpp" #if OPENTHREAD_CONFIG_DIAG_ENABLE @@ -187,6 +188,7 @@ extern "C" void otPlatDiagAlarmFired(otInstance *aInstance) { otPlatDiagAlarmCal const struct Diags::Command Diags::sCommands[] = { {"channel", &Diags::ProcessChannel}, {"cw", &Diags::ProcessContinuousWave}, + {"frame", &Diags::ProcessFrame}, {"gpio", &Diags::ProcessGpio}, {"power", &Diags::ProcessPower}, {"powersettings", &Diags::ProcessPowerSettings}, @@ -208,12 +210,31 @@ Diags::Diags(Instance &aInstance) , mChannel(20) , mTxPower(0) , mTxLen(0) + , mIsTxPacketSet(false) , mRepeatActive(false) , mDiagSendOn(false) { mStats.Clear(); } +Error Diags::ProcessFrame(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +{ + Error error = kErrorNone; + uint16_t size = OT_RADIO_FRAME_MAX_SIZE; + + VerifyOrExit(aArgsLength == 1, error = kErrorInvalidArgs); + + SuccessOrExit(error = Utils::CmdLineParser::ParseAsHexString(aArgs[0], size, mTxPacket->mPsdu)); + VerifyOrExit(size <= OT_RADIO_FRAME_MAX_SIZE, error = kErrorInvalidArgs); + VerifyOrExit(size >= OT_RADIO_FRAME_MIN_SIZE, error = kErrorInvalidArgs); + mTxPacket->mLength = size; + mIsTxPacketSet = true; + +exit: + AppendErrorResult(error, aOutput, aOutputMaxLen); + return error; +} + Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) { Error error = kErrorNone; @@ -288,12 +309,25 @@ Error Diags::ProcessRepeat(uint8_t aArgsLength, char *aArgs[], char *aOutput, si { long value; - VerifyOrExit(aArgsLength == 2, error = kErrorInvalidArgs); + VerifyOrExit(aArgsLength >= 1, error = kErrorInvalidArgs); SuccessOrExit(error = ParseLong(aArgs[0], value)); mTxPeriod = static_cast(value); - SuccessOrExit(error = ParseLong(aArgs[1], value)); + if (aArgsLength >= 2) + { + SuccessOrExit(error = ParseLong(aArgs[1], value)); + mIsTxPacketSet = false; + } + else if (mIsTxPacketSet) + { + value = mTxPacket->mLength; + } + else + { + ExitNow(error = kErrorInvalidArgs); + } + VerifyOrExit(value <= OT_RADIO_FRAME_MAX_SIZE, error = kErrorInvalidArgs); VerifyOrExit(value >= OT_RADIO_FRAME_MIN_SIZE, error = kErrorInvalidArgs); mTxLen = static_cast(value); @@ -316,12 +350,25 @@ Error Diags::ProcessSend(uint8_t aArgsLength, char *aArgs[], char *aOutput, size long value; VerifyOrExit(otPlatDiagModeGet(), error = kErrorInvalidState); - VerifyOrExit(aArgsLength == 2, error = kErrorInvalidArgs); + VerifyOrExit(aArgsLength >= 1, error = kErrorInvalidArgs); SuccessOrExit(error = ParseLong(aArgs[0], value)); mTxPackets = static_cast(value); - SuccessOrExit(error = ParseLong(aArgs[1], value)); + if (aArgsLength >= 2) + { + SuccessOrExit(ParseLong(aArgs[1], value)); + mIsTxPacketSet = false; + } + else if (mIsTxPacketSet) + { + value = mTxPacket->mLength; + } + else + { + ExitNow(error = kErrorInvalidArgs); + } + VerifyOrExit(value <= OT_RADIO_FRAME_MAX_SIZE, error = kErrorInvalidArgs); VerifyOrExit(value >= OT_RADIO_FRAME_MIN_SIZE, error = kErrorInvalidArgs); mTxLen = static_cast(value); @@ -420,12 +467,16 @@ Error Diags::ProcessStop(uint8_t aArgsLength, char *aArgs[], char *aOutput, size void Diags::TransmitPacket(void) { - mTxPacket->mLength = mTxLen; mTxPacket->mChannel = mChannel; - for (uint8_t i = 0; i < mTxLen; i++) + if (!mIsTxPacketSet) { - mTxPacket->mPsdu[i] = i; + mTxPacket->mLength = mTxLen; + + for (uint8_t i = 0; i < mTxLen; i++) + { + mTxPacket->mPsdu[i] = i; + } } mDiagSendOn = true; @@ -986,4 +1037,5 @@ OT_TOOL_WEAK otError otPlatDiagRadioGetPowerSettings(otInstance *aInstance, return OT_ERROR_NOT_IMPLEMENTED; } + #endif // OPENTHREAD_CONFIG_DIAG_ENABLE diff --git a/src/core/diags/factory_diags.hpp b/src/core/diags/factory_diags.hpp index 1b72a1563..cb1c7b95b 100644 --- a/src/core/diags/factory_diags.hpp +++ b/src/core/diags/factory_diags.hpp @@ -181,6 +181,7 @@ class Diags : public InstanceLocator, private NonCopyable Error ParseCmd(char *aString, uint8_t &aArgsLength, char *aArgs[]); Error ProcessChannel(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); + Error ProcessFrame(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); Error ProcessContinuousWave(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); Error ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); Error ProcessPower(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); @@ -217,6 +218,7 @@ class Diags : public InstanceLocator, private NonCopyable uint8_t mChannel; int8_t mTxPower; uint8_t mTxLen; + bool mIsTxPacketSet; bool mRepeatActive; bool mDiagSendOn; #endif diff --git a/tests/scripts/expect/cli-diags.exp b/tests/scripts/expect/cli-diags.exp index e5d2fbfab..b9ab58071 100755 --- a/tests/scripts/expect/cli-diags.exp +++ b/tests/scripts/expect/cli-diags.exp @@ -126,6 +126,35 @@ expect "start diagnostics mode" expect "status 0x00" expect_line "Done" +send_user "input too short test\n" +send "diag frame 11\n" +expect "Error" + +send_user "input too long test\n" +send "diag frame 11223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900\n" +expect "Error" + +send_user "input odd length test\n" +send "diag frame 123\n" +expect "Error" + +send_user "shortest frame test\n" +send "diag frame 112233\n" +expect "Done" +send "diag send 1\n" +expect "length 0x3" +expect "Done" + +send_user "longest frame test\n" +send "diag frame 11223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677\n" +expect "Done" +send "diag repeat 1\n" +expect "length 0x7f" +expect "Done" + +send "diag repeat stop\n" +expect "Done" + send "diag channel 11\n" expect "set channel to 11" expect "status 0x00" From 6bc3b4de8a9899675707e264a0ab9194b4499a57 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 13 Jun 2024 08:52:16 -0700 Subject: [PATCH 16/65] [mdns] use `NextFireTime` for scheduling timers (#10371) --- src/core/net/mdns.cpp | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/core/net/mdns.cpp b/src/core/net/mdns.cpp index 75ae2acef..2ebad6519 100644 --- a/src/core/net/mdns.cpp +++ b/src/core/net/mdns.cpp @@ -4111,11 +4111,10 @@ void Core::MultiPacketRxMessages::AddNew(OwnedPtr &aRxMessagePtr) void Core::MultiPacketRxMessages::HandleTimer(void) { - TimeMilli now = TimerMilli::GetNow(); - TimeMilli nextTime = now.GetDistantFuture(); + NextFireTime nextTime; OwningList expiredEntries; - mRxMsgEntries.RemoveAllMatching(ExpireChecker(now), expiredEntries); + mRxMsgEntries.RemoveAllMatching(ExpireChecker(nextTime.GetNow()), expiredEntries); for (RxMsgEntry &expiredEntry : expiredEntries) { @@ -4124,13 +4123,10 @@ void Core::MultiPacketRxMessages::HandleTimer(void) for (const RxMsgEntry &msgEntry : mRxMsgEntries) { - nextTime = Min(nextTime, msgEntry.mProcessTime); + nextTime.UpdateIfEarlier(msgEntry.mProcessTime); } - if (nextTime != now.GetDistantFuture()) - { - mTimer.FireAtIfEarlier(nextTime); - } + mTimer.FireAtIfEarlier(nextTime); } void Core::MultiPacketRxMessages::Clear(void) @@ -4254,20 +4250,16 @@ void Core::TxMessageHistory::CalculateHash(const Message &aMessage, Hash &aHash) void Core::TxMessageHistory::HandleTimer(void) { - TimeMilli now = TimerMilli::GetNow(); - TimeMilli nextTime = now.GetDistantFuture(); + NextFireTime nextTime; - mHashEntries.RemoveAndFreeAllMatching(ExpireChecker(now)); + mHashEntries.RemoveAndFreeAllMatching(ExpireChecker(nextTime.GetNow())); for (const HashEntry &entry : mHashEntries) { - nextTime = Min(nextTime, entry.mExpireTime); + nextTime.UpdateIfEarlier(entry.mExpireTime); } - if (nextTime != now.GetDistantFuture()) - { - mTimer.FireAtIfEarlier(nextTime); - } + mTimer.FireAtIfEarlier(nextTime); } template From 69924eaa78a03c11185288e0b4d1f93e057f67c9 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 14 Jun 2024 09:58:22 -0700 Subject: [PATCH 17/65] [cli] update `service add` command to allow empty server data (#10377) --- src/cli/README.md | 4 ++-- src/cli/cli.cpp | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/cli/README.md b/src/cli/README.md index 272d4063f..e93c91bfd 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -3533,13 +3533,13 @@ Done Module for controlling service registration in Network Data. Each change in service registration must be sent to leader by `netdata register` command before taking effect. -### service add \ \ \ +### service add \ \ [\] Add service to the Network Data. - enterpriseNumber: IANA enterprise number - serviceData: hex-encoded binary service data -- serverData: hex-encoded binary server data +- serverData: hex-encoded binary server data (empty if not provided) ```bash > service add 44970 112233 aabbcc diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index d70978872..e50326011 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -4596,13 +4596,13 @@ template <> otError Interpreter::Process(Arg aArgs[]) * netdata register * Done * @endcode - * @cparam service add @ca{enterpriseNumber} @ca{serviceData} @ca{serverData} + * @cparam service add @ca{enterpriseNumber} @ca{serviceData} [@ca{serverData}] * @par * Adds service to the network data. * @par * - enterpriseNumber: IANA enterprise number * - serviceData: Hex-encoded binary service data - * - serverData: Hex-encoded binary server data + * - serverData: Hex-encoded binary server data (empty if not provided) * @par * Note: For each change in service registration to take effect, run * the `netdata register` command after running the `service add` command to notify the leader. @@ -4611,10 +4611,17 @@ template <> otError Interpreter::Process(Arg aArgs[]) */ if (aArgs[0] == "add") { - length = sizeof(cfg.mServerConfig.mServerData); - SuccessOrExit(error = aArgs[3].ParseAsHexString(length, cfg.mServerConfig.mServerData)); - VerifyOrExit(length > 0, error = OT_ERROR_INVALID_ARGS); - cfg.mServerConfig.mServerDataLength = static_cast(length); + if (!aArgs[3].IsEmpty()) + { + length = sizeof(cfg.mServerConfig.mServerData); + SuccessOrExit(error = aArgs[3].ParseAsHexString(length, cfg.mServerConfig.mServerData)); + VerifyOrExit(length > 0, error = OT_ERROR_INVALID_ARGS); + cfg.mServerConfig.mServerDataLength = static_cast(length); + } + else + { + cfg.mServerConfig.mServerDataLength = 0; + } cfg.mServerConfig.mStable = true; From fb24bec8738e1d42f63b7f228bf0f3bfe23bad0d Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 14 Jun 2024 09:58:57 -0700 Subject: [PATCH 18/65] [mle] add `TxMessage::AppendLinkAndMleFrameCounterTlvs()` (#10378) This commit adds `AppendLinkAndMleFrameCounterTlvs()` to `Mle::TxMessage` for appending both Link and MLE Frame Counter TLVs. This mirrors the existing `RxMessage` method for reading these counters. --- src/core/thread/mle.cpp | 14 ++++++++++++-- src/core/thread/mle.hpp | 1 + src/core/thread/mle_router.cpp | 6 ++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 76a397fdd..34cfaf904 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1791,8 +1791,7 @@ Error Mle::SendChildIdRequest(void) VerifyOrExit((message = NewMleMessage(kCommandChildIdRequest)) != nullptr, error = kErrorNoBufs); SuccessOrExit(error = message->AppendResponseTlv(mParentCandidate.mRxChallenge)); - SuccessOrExit(error = message->AppendLinkFrameCounterTlv()); - SuccessOrExit(error = message->AppendMleFrameCounterTlv()); + SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs()); SuccessOrExit(error = message->AppendModeTlv(mDeviceMode)); SuccessOrExit(error = message->AppendTimeoutTlv(mTimeout)); SuccessOrExit(error = message->AppendVersionTlv()); @@ -4513,6 +4512,17 @@ Error Mle::TxMessage::AppendMleFrameCounterTlv(void) return Tlv::Append(*this, Get().GetMleFrameCounter()); } +Error Mle::TxMessage::AppendLinkAndMleFrameCounterTlvs(void) +{ + Error error; + + SuccessOrExit(error = AppendLinkFrameCounterTlv()); + error = AppendMleFrameCounterTlv(); + +exit: + return error; +} + Error Mle::TxMessage::AppendAddress16Tlv(uint16_t aRloc16) { return Tlv::Append(*this, aRloc16); } Error Mle::TxMessage::AppendLeaderDataTlv(void) diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index a13c5f594..ad1b5b448 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1011,6 +1011,7 @@ class Mle : public InstanceLocator, private NonCopyable Error AppendResponseTlv(const RxChallenge &aResponse); Error AppendLinkFrameCounterTlv(void); Error AppendMleFrameCounterTlv(void); + Error AppendLinkAndMleFrameCounterTlvs(void); Error AppendAddress16Tlv(uint16_t aRloc16); Error AppendNetworkDataTlv(NetworkData::Type aType); Error AppendTlvRequestTlv(const uint8_t *aTlvs, uint8_t aTlvsLength); diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 7c12d8133..73e5e1563 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -786,8 +786,7 @@ Error MleRouter::SendLinkAccept(const RxInfo &aRxInfo, SuccessOrExit(error = message->AppendVersionTlv()); SuccessOrExit(error = message->AppendSourceAddressTlv()); SuccessOrExit(error = message->AppendResponseTlv(aChallenge)); - SuccessOrExit(error = message->AppendLinkFrameCounterTlv()); - SuccessOrExit(error = message->AppendMleFrameCounterTlv()); + SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs()); linkMargin = Get().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss()); SuccessOrExit(error = message->AppendLinkMarginTlv(linkMargin)); @@ -1698,8 +1697,7 @@ void MleRouter::SendParentResponse(Child *aChild, const RxChallenge &aChallenge, SuccessOrExit(error = message->AppendSourceAddressTlv()); SuccessOrExit(error = message->AppendLeaderDataTlv()); - SuccessOrExit(error = message->AppendLinkFrameCounterTlv()); - SuccessOrExit(error = message->AppendMleFrameCounterTlv()); + SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs()); SuccessOrExit(error = message->AppendResponseTlv(aChallenge)); #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE if (aChild->IsTimeSyncEnabled()) From 3b589b3e1f0b28a2e6c02cfb017b76ef583b58c2 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 14 Jun 2024 10:00:14 -0700 Subject: [PATCH 19/65] [routing-manager] add `RxRaTracker::Router::IsReachable()` (#10379) This commit adds the `IsReachable()` helper method to `Router` class, which checks whether a router is considered reachable. It replaces the previous comparisons of `mNsProbeCount` in the code, improving readability. Neighbor Solicitation (NS) messages are used to determine reachability if the router has not been heard from for some time. --- src/core/border_router/routing_manager.cpp | 21 +++++++++++---------- src/core/border_router/routing_manager.hpp | 7 ++++--- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index f4c9d9678..11c4a8692 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -1459,15 +1459,15 @@ void RoutingManager::RxRaTracker::RemoveOrDeprecateOldEntries(TimeMilli aTimeThr RemoveExpiredEntries(); } -void RoutingManager::RxRaTracker::RemoveOrDeprecateEntriesFromInactiveRouters(void) +void RoutingManager::RxRaTracker::RemoveOrDeprecateEntriesFromUnreachableRouters(void) { // Remove route prefix entries and deprecate on-link prefix entries // in the table for routers that have reached the max NS probe - // attempts and considered as inactive. + // attempts and considered unreachable. for (Router &router : mRouters) { - if (router.mNsProbeCount <= Router::kMaxNsProbes) + if (router.IsReachable()) { continue; } @@ -1522,7 +1522,7 @@ void RoutingManager::RxRaTracker::ScheduleAllTimers(void) for (const Router &router : mRouters) { - if ((router.mNsProbeCount <= Router::kMaxNsProbes) && !router.mIsLocalDevice) + if (router.IsReachable() && !router.mIsLocalDevice) { // Skip if router is this device or has failed all // earlier NS probes. @@ -1697,7 +1697,8 @@ void RoutingManager::RxRaTracker::UpdateRouterOnRx(Router &aRouter) aRouter.mNsProbeCount = 0; aRouter.mLastUpdateTime = TimerMilli::GetNow(); - aRouter.mTimeout = aRouter.mLastUpdateTime + Random::NonCrypto::AddJitter(Router::kActiveTimeout, Router::kJitter); + aRouter.mTimeout = + aRouter.mLastUpdateTime + Random::NonCrypto::AddJitter(Router::kReachableTimeout, Router::kJitter); mRouterTimer.FireAtIfEarlier(aRouter.mTimeout); } @@ -1707,7 +1708,7 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void) for (Router &router : mRouters) { - if (router.mNsProbeCount > Router::kMaxNsProbes) + if (!router.IsReachable()) { continue; } @@ -1725,7 +1726,7 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void) { router.mNsProbeCount++; - if (router.mNsProbeCount > Router::kMaxNsProbes) + if (!router.IsReachable()) { LogInfo("No response to all Neighbor Solicitations attempts from router %s", router.mAddress.ToString().AsCString()); @@ -1739,7 +1740,7 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void) } } - RemoveOrDeprecateEntriesFromInactiveRouters(); + RemoveOrDeprecateEntriesFromUnreachableRouters(); ScheduleAllTimers(); } @@ -1782,7 +1783,7 @@ void RoutingManager::RxRaTracker::DetermineAndSetFlags(RouterAdvert::Header &aHe continue; } - if (router.mNsProbeCount > Router::kMaxNsProbes) + if (!router.IsReachable()) { continue; } @@ -1952,7 +1953,7 @@ bool RoutingManager::RxRaTracker::Router::Matches(EmptyChecker aChecker) const bool hasFlags = false; - if (mNsProbeCount <= kMaxNsProbes) + if (IsReachable()) { hasFlags = (mManagedAddressConfigFlag || mOtherConfigFlag); } diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 1c5be7928..41160638f 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -811,9 +811,9 @@ class RoutingManager : public InstanceLocator struct Router : public Clearable { - // The timeout (in msec) for router staying in active state + // The timeout (in msec) for router to be considered reachable // before starting the Neighbor Solicitation (NS) probes. - static constexpr uint32_t kActiveTimeout = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT; + static constexpr uint32_t kReachableTimeout = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT; static constexpr uint8_t kMaxNsProbes = 5; // Max number of NS probe attempts. static constexpr uint32_t kNsProbeRetryInterval = 1000; // In msec. Time between NS probe attempts. @@ -827,6 +827,7 @@ class RoutingManager : public InstanceLocator kContainsNoEntriesOrFlags }; + bool IsReachable(void) const { return mNsProbeCount <= kMaxNsProbes; } bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; } bool Matches(EmptyChecker aChecker) const; void CopyInfoTo(RouterEntry &aEntry, TimeMilli aNow) const; @@ -914,7 +915,7 @@ class RoutingManager : public InstanceLocator void ProcessRouteInfoOption(const RouteInfoOption &aRio, Router &aRouter); void ProcessRaFlagsExtOption(const RaFlagsExtOption &aFlagsOption, Router &aRouter); bool ContainsOnLinkPrefix(OnLinkPrefix::UlaChecker aUlaChecker) const; - void RemoveOrDeprecateEntriesFromInactiveRouters(void); + void RemoveOrDeprecateEntriesFromUnreachableRouters(void); void RemoveRoutersWithNoEntriesOrFlags(void); void RemoveExpiredEntries(void); void SignalTableChanged(void); From a98b60ef2ed025ee4c0da06495b2d40e3926eb78 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 14 Jun 2024 10:00:58 -0700 Subject: [PATCH 20/65] [udp] clear all properties in `SocketHandle` from `Udp::Open()` (#10380) This commit modifies `Udp::Open()` to clear all properties of the passed-in `aSocket` using the `Clear()` method. This replaces the existing code, which only cleared the socket and peer address and port numbers. This change ensures that `void *mHandle` member variable in `otUdpSocket` is also set to `nullptr` before invoking platform UDP `otPlatUdpSocket()`. --- src/core/net/udp6.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp index bb24e5030..05ba27bc9 100644 --- a/src/core/net/udp6.cpp +++ b/src/core/net/udp6.cpp @@ -175,8 +175,7 @@ Error Udp::Open(SocketHandle &aSocket, otUdpReceive aHandler, void *aContext) OT_ASSERT(!IsOpen(aSocket)); - aSocket.GetSockName().Clear(); - aSocket.GetPeerName().Clear(); + aSocket.Clear(); aSocket.mHandler = aHandler; aSocket.mContext = aContext; From 18e635d2ee0ea3a670a9225fb9e7c951db2c3f09 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 14 Jun 2024 10:03:15 -0700 Subject: [PATCH 21/65] [dataset] move secure storage methods to `DatasetManager` (#10381) This commit refactors methods that save or read a specified Dataset TLV in/from secure storage under `PLATFORM_KEY_REFERENCES`. These methods are moved from the `Dataset` class to the `DatasetManager` class, consolidating related functionality and aligning with the responsibilities of each class. The `Dataset` class is focused on appending/parsing TLVs, while the `DatasetManager` class is responsible for managing and saving the Active and Pending Datasets. --- src/core/meshcop/dataset.cpp | 40 ---------------------------- src/core/meshcop/dataset.hpp | 29 -------------------- src/core/meshcop/dataset_manager.cpp | 40 ++++++++++++++++++++++++++-- src/core/meshcop/dataset_manager.hpp | 18 ++++++++----- 4 files changed, 49 insertions(+), 78 deletions(-) diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index 8f2202323..cb0c53e9a 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -576,45 +576,5 @@ bool Dataset::IsSubsetOf(const Dataset &aOther) const const char *Dataset::TypeToString(Type aType) { return (aType == kActive) ? "Active" : "Pending"; } -#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - -void Dataset::SaveTlvInSecureStorageAndClearValue(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef) -{ - using namespace ot::Crypto::Storage; - - Tlv *tlv = FindTlv(aTlvType); - - VerifyOrExit(tlv != nullptr); - VerifyOrExit(tlv->GetLength() > 0); - - SuccessOrAssert(ImportKey(aKeyRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent, tlv->GetValue(), - tlv->GetLength())); - - memset(tlv->GetValue(), 0, tlv->GetLength()); - -exit: - return; -} - -Error Dataset::ReadTlvFromSecureStorage(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef) -{ - using namespace ot::Crypto::Storage; - - Error error = kErrorNone; - Tlv *tlv = FindTlv(aTlvType); - size_t readLength; - - VerifyOrExit(tlv != nullptr); - VerifyOrExit(tlv->GetLength() > 0); - - SuccessOrExit(error = ExportKey(aKeyRef, tlv->GetValue(), tlv->GetLength(), readLength)); - VerifyOrExit(readLength == tlv->GetLength(), error = OT_ERROR_FAILED); - -exit: - return error; -} - -#endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - } // namespace MeshCoP } // namespace ot diff --git a/src/core/meshcop/dataset.hpp b/src/core/meshcop/dataset.hpp index 165999d93..d458b2c78 100644 --- a/src/core/meshcop/dataset.hpp +++ b/src/core/meshcop/dataset.hpp @@ -702,35 +702,6 @@ class Dataset */ static const char *TypeToString(Type aType); -#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - - /** - * Saves a given TLV value in secure storage and clears the TLV value by setting all value bytes to zero. - * - * If the Dataset does not contain the @p aTlvType, no action is performed. - * - * @param[in] aTlvType The TLV type. - * @param[in] aKeyRef The `KeyRef` to use with secure storage. - * - */ - void SaveTlvInSecureStorageAndClearValue(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef); - - /** - * Reads and updates a given TLV value in Dataset from secure storage. - * - * If the Dataset does not contain the @p aTlvType, no action is performed and `kErrorNone` is returned. - * - * @param[in] aTlvType The TLV type. - * @param[in] aKeyRef The `KeyRef` to use with secure storage. - * - * @retval kErrorNone Successfully read the TLV value from secure storage and updated the Dataset. - * @retval KErrorFailed Could not read the @aKeyRef from secure storage. - * - */ - Error ReadTlvFromSecureStorage(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef); - -#endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - private: void RemoveTlv(Tlv *aTlv); diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index 87fddbaf7..c55e03c39 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -760,7 +760,7 @@ void DatasetManager::MoveKeysToSecureStorage(Dataset &aDataset) const { for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs) { - aDataset.SaveTlvInSecureStorageAndClearValue(entry.mTlvType, entry.GetKeyRef(mType)); + SaveTlvInSecureStorageAndClearValue(aDataset, entry.mTlvType, entry.GetKeyRef(mType)); } } @@ -775,7 +775,7 @@ void DatasetManager::EmplaceSecurelyStoredKeys(Dataset &aDataset) const for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs) { - if (aDataset.ReadTlvFromSecureStorage(entry.mTlvType, entry.GetKeyRef(mType)) != kErrorNone) + if (ReadTlvFromSecureStorage(aDataset, entry.mTlvType, entry.GetKeyRef(mType)) != kErrorNone) { moveKeys = true; } @@ -791,6 +791,42 @@ void DatasetManager::EmplaceSecurelyStoredKeys(Dataset &aDataset) const } } +void DatasetManager::SaveTlvInSecureStorageAndClearValue(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const +{ + using namespace ot::Crypto::Storage; + + Tlv *tlv = aDataset.FindTlv(aTlvType); + + VerifyOrExit(tlv != nullptr); + VerifyOrExit(tlv->GetLength() > 0); + + SuccessOrAssert(ImportKey(aKeyRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent, tlv->GetValue(), + tlv->GetLength())); + + memset(tlv->GetValue(), 0, tlv->GetLength()); + +exit: + return; +} + +Error DatasetManager::ReadTlvFromSecureStorage(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const +{ + using namespace ot::Crypto::Storage; + + Error error = kErrorNone; + Tlv *tlv = aDataset.FindTlv(aTlvType); + size_t readLength; + + VerifyOrExit(tlv != nullptr); + VerifyOrExit(tlv->GetLength() > 0); + + SuccessOrExit(error = ExportKey(aKeyRef, tlv->GetValue(), tlv->GetLength(), readLength)); + VerifyOrExit(readLength == tlv->GetLength(), error = OT_ERROR_FAILED); + +exit: + return error; +} + #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/core/meshcop/dataset_manager.hpp b/src/core/meshcop/dataset_manager.hpp index edb63f5c0..270903b8d 100644 --- a/src/core/meshcop/dataset_manager.hpp +++ b/src/core/meshcop/dataset_manager.hpp @@ -233,16 +233,18 @@ class DatasetManager : public InstanceLocator }; #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + using KeyRef = Crypto::Storage::KeyRef; + struct SecurelyStoredTlv { - Crypto::Storage::KeyRef GetKeyRef(Dataset::Type aType) const + KeyRef GetKeyRef(Dataset::Type aType) const { return (aType == Dataset::kActive) ? mActiveKeyRef : mPendingKeyRef; } - Tlv::Type mTlvType; - Crypto::Storage::KeyRef mActiveKeyRef; - Crypto::Storage::KeyRef mPendingKeyRef; + Tlv::Type mTlvType; + KeyRef mActiveKeyRef; + KeyRef mPendingKeyRef; }; static const SecurelyStoredTlv kSecurelyStoredTlvs[]; @@ -288,9 +290,11 @@ class DatasetManager : public InstanceLocator Error aError); #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - void MoveKeysToSecureStorage(Dataset &aDataset) const; - void DestroySecurelyStoredKeys(void) const; - void EmplaceSecurelyStoredKeys(Dataset &aDataset) const; + void MoveKeysToSecureStorage(Dataset &aDataset) const; + void DestroySecurelyStoredKeys(void) const; + void EmplaceSecurelyStoredKeys(Dataset &aDataset) const; + void SaveTlvInSecureStorageAndClearValue(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const; + Error ReadTlvFromSecureStorage(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const; #endif #if OPENTHREAD_FTD From 503bca022e9ff27628c0ea7eac4c160428dcf3e3 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 14 Jun 2024 10:04:45 -0700 Subject: [PATCH 22/65] [mle] add `GetLeaderRloc16()` helper method (#10383) This commit adds the `Mle::GetLeaderRloc16()` method, which returns the RLOC16 of the Leader. This simplifies code that previously used `GetLeaderId()` followed by a conversion to RLOC16. --- src/core/thread/mesh_forwarder_ftd.cpp | 2 +- src/core/thread/mle.cpp | 2 +- src/core/thread/mle.hpp | 8 ++++++++ src/core/thread/mle_router.cpp | 2 +- src/core/thread/network_data_service.cpp | 2 +- src/core/thread/router_table.cpp | 5 +---- 6 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index d4911b9a8..e69f200a9 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -522,7 +522,7 @@ Error MeshForwarder::UpdateIp6RouteFtd(const Ip6::Header &aIp6Header, Message &a if (aloc16 == Mle::kAloc16Leader) { - mMeshDest = Mle::Rloc16FromRouterId(mle.GetLeaderId()); + mMeshDest = mle.GetLeaderRloc16(); } else if (aloc16 <= Mle::kAloc16DhcpAgentEnd) { diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 34cfaf904..b3ba28076 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1004,7 +1004,7 @@ Error Mle::GetLeaderAddress(Ip6::Address &aAddress) const VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); - aAddress.SetToRoutingLocator(mMeshLocalPrefix, Rloc16FromRouterId(mLeaderData.GetLeaderRouterId())); + aAddress.SetToRoutingLocator(mMeshLocalPrefix, GetLeaderRloc16()); exit: return error; diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index ad1b5b448..6c407cbed 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -547,6 +547,14 @@ class Mle : public InstanceLocator, private NonCopyable */ uint8_t GetLeaderId(void) const { return mLeaderData.GetLeaderRouterId(); } + /** + * Returns the RLOC16 of the Leader. + * + * @returns The RLOC16 of the Leader. + * + */ + uint16_t GetLeaderRloc16(void) const { return Rloc16FromRouterId(GetLeaderId()); } + /** * Retrieves the Leader's RLOC. * diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 73e5e1563..df6c28903 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -958,7 +958,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) router = mRouterTable.FindRouterById(routerId); VerifyOrExit(router != nullptr); - if (mLeaderData.GetLeaderRouterId() == RouterIdFromRloc16(GetRloc16())) + if (GetLeaderRloc16() == GetRloc16()) { SetStateLeader(GetRloc16(), kRestoringLeaderRoleAfterReset); } diff --git a/src/core/thread/network_data_service.cpp b/src/core/thread/network_data_service.cpp index 77ff48597..dbd8be7b0 100644 --- a/src/core/thread/network_data_service.cpp +++ b/src/core/thread/network_data_service.cpp @@ -152,7 +152,7 @@ bool Manager::IsBackboneRouterPreferredTo(const ServerTlv &aSer const BackboneRouter::ServerData &aOtherServerData) const { bool isPreferred; - uint16_t leaderRloc16 = Mle::Rloc16FromRouterId(Get().GetLeaderId()); + uint16_t leaderRloc16 = Get().GetLeaderRloc16(); VerifyOrExit(aServerTlv.GetServer16() != leaderRloc16, isPreferred = true); VerifyOrExit(aOtherServerTlv.GetServer16() != leaderRloc16, isPreferred = false); diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index 1302ce788..7117e5c94 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -396,10 +396,7 @@ uint8_t RouterTable::GetPathCost(uint16_t aDestRloc16) const return pathCost; } -uint8_t RouterTable::GetPathCostToLeader(void) const -{ - return GetPathCost(Mle::Rloc16FromRouterId(Get().GetLeaderId())); -} +uint8_t RouterTable::GetPathCostToLeader(void) const { return GetPathCost(Get().GetLeaderRloc16()); } void RouterTable::GetNextHopAndPathCost(uint16_t aDestRloc16, uint16_t &aNextHopRloc16, uint8_t &aPathCost) const { From cba0f5ca2bc7bad04a06ae6ac66084699123cfe2 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 14 Jun 2024 10:05:40 -0700 Subject: [PATCH 23/65] [mle] use `RouterIdMatch()` to compare Router IDs of two RLOC16 values (#10384) This commit updates the code to use `RouterIdMatch()` for comparing the Router IDs of two given RLOC16 values. Additionally, it simplifies the `IsMinimalChild()` method. --- src/core/thread/mle.cpp | 2 +- src/core/thread/mle_router.cpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index b3ba28076..2fea5db79 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -3582,7 +3582,7 @@ void Mle::HandleChildUpdateResponse(RxInfo &aRxInfo) case kRoleChild: SuccessOrExit(error = Tlv::Find(aRxInfo.mMessage, sourceAddress)); - if (RouterIdFromRloc16(sourceAddress) != RouterIdFromRloc16(GetRloc16())) + if (!RouterIdMatch(sourceAddress, GetRloc16())) { IgnoreError(BecomeDetached()); ExitNow(); diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index df6c28903..bfef47222 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3109,18 +3109,18 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination, bool MleRouter::IsMinimalChild(uint16_t aRloc16) { - bool rval = false; + bool isMinimalChild = false; + Neighbor *neighbor; - if (RouterIdFromRloc16(aRloc16) == RouterIdFromRloc16(Get().GetShortAddress())) - { - Neighbor *neighbor; + VerifyOrExit(RouterIdMatch(aRloc16, GetRloc16())); - neighbor = mNeighborTable.FindNeighbor(aRloc16); + neighbor = mNeighborTable.FindNeighbor(aRloc16); + VerifyOrExit(neighbor != nullptr); - rval = (neighbor != nullptr) && (!neighbor->IsFullThreadDevice()); - } + isMinimalChild = !neighbor->IsFullThreadDevice(); - return rval; +exit: + return isMinimalChild; } void MleRouter::RemoveRouterLink(Router &aRouter) From 3315c44bb3b031708a0f88deef862db9bf28ad28 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 14 Jun 2024 10:06:25 -0700 Subject: [PATCH 24/65] [mle] rename mesh local address methods to use `Rloc` and `Eid` (#10385) This commit renames the methods for retrieving mesh local addresses to `GetMeshLocalRloc()` and `GetMeshLocalEid()` (from `GetMeshLocal16()` and `GetMeshLocal64()`, respectively) to align with the terminology used in the Thread specification. Member and local variables are also renamed accordingly. --- src/core/api/thread_api.cpp | 4 +- src/core/api/udp_api.cpp | 2 +- src/core/meshcop/commissioner.cpp | 4 +- src/core/net/dhcp6_client.cpp | 2 +- src/core/net/ip6_mpl.cpp | 2 +- src/core/net/srp_client.cpp | 16 ++--- src/core/thread/address_resolver.cpp | 4 +- src/core/thread/anycast_locator.cpp | 2 +- src/core/thread/dua_manager.cpp | 2 +- src/core/thread/mesh_forwarder_ftd.cpp | 2 +- src/core/thread/mle.cpp | 74 +++++++++++----------- src/core/thread/mle.hpp | 22 +++---- src/core/thread/network_data_publisher.cpp | 4 +- src/core/thread/tmf.cpp | 4 +- src/core/utils/mesh_diag.cpp | 4 +- tests/unit/test_child.cpp | 2 +- tests/unit/test_srp_server.cpp | 2 +- 17 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/core/api/thread_api.cpp b/src/core/api/thread_api.cpp index b5661df64..5d41308d6 100644 --- a/src/core/api/thread_api.cpp +++ b/src/core/api/thread_api.cpp @@ -145,12 +145,12 @@ otError otThreadSetNetworkKeyRef(otInstance *aInstance, otNetworkKeyRef aKeyRef) const otIp6Address *otThreadGetRloc(otInstance *aInstance) { - return &AsCoreType(aInstance).Get().GetMeshLocal16(); + return &AsCoreType(aInstance).Get().GetMeshLocalRloc(); } const otIp6Address *otThreadGetMeshLocalEid(otInstance *aInstance) { - return &AsCoreType(aInstance).Get().GetMeshLocal64(); + return &AsCoreType(aInstance).Get().GetMeshLocalEid(); } const otMeshLocalPrefix *otThreadGetMeshLocalPrefix(otInstance *aInstance) diff --git a/src/core/api/udp_api.cpp b/src/core/api/udp_api.cpp index 5141a50b6..01c5a3408 100644 --- a/src/core/api/udp_api.cpp +++ b/src/core/api/udp_api.cpp @@ -98,7 +98,7 @@ void otUdpForwardReceive(otInstance *aInstance, { Ip6::MessageInfo messageInfo; - messageInfo.SetSockAddr(AsCoreType(aInstance).Get().GetMeshLocal16()); + messageInfo.SetSockAddr(AsCoreType(aInstance).Get().GetMeshLocalRloc()); messageInfo.SetSockPort(aSockPort); messageInfo.SetPeerAddr(AsCoreType(aPeerAddr)); messageInfo.SetPeerPort(aPeerPort); diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index bb09ebb24..0068e32c8 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -954,7 +954,7 @@ template <> void Commissioner::HandleTmf(Coap::Message &aMessage, c aMessage.SetOffset(startOffset); SuccessOrExit(error = aMessage.SetLength(endOffset)); - joinerMessageInfo.SetPeerAddr(Get().GetMeshLocal64()); + joinerMessageInfo.SetPeerAddr(Get().GetMeshLocalEid()); joinerMessageInfo.GetPeerAddr().SetIid(mJoinerIid); joinerMessageInfo.SetPeerPort(mJoinerPort); @@ -1048,7 +1048,7 @@ void Commissioner::SendJoinFinalizeResponse(const Coap::Message &aRequest, State SuccessOrExit(error = Tlv::Append(*message, aState)); - joinerMessageInfo.SetPeerAddr(Get().GetMeshLocal64()); + joinerMessageInfo.SetPeerAddr(Get().GetMeshLocalEid()); joinerMessageInfo.GetPeerAddr().SetIid(mJoinerIid); joinerMessageInfo.SetPeerPort(mJoinerPort); diff --git a/src/core/net/dhcp6_client.cpp b/src/core/net/dhcp6_client.cpp index 56654fb47..11a88fd99 100644 --- a/src/core/net/dhcp6_client.cpp +++ b/src/core/net/dhcp6_client.cpp @@ -278,7 +278,7 @@ void Client::Solicit(uint16_t aRloc16) #else messageInfo.GetPeerAddr().SetToRoutingLocator(Get().GetMeshLocalPrefix(), aRloc16); #endif - messageInfo.SetSockAddr(Get().GetMeshLocal16()); + messageInfo.SetSockAddr(Get().GetMeshLocalRloc()); messageInfo.mPeerPort = kDhcpServerPort; SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); diff --git a/src/core/net/ip6_mpl.cpp b/src/core/net/ip6_mpl.cpp index 7e18b39c6..4f3964d7b 100644 --- a/src/core/net/ip6_mpl.cpp +++ b/src/core/net/ip6_mpl.cpp @@ -76,7 +76,7 @@ void MplOption::Init(SeedIdLength aSeedIdLength) void Mpl::InitOption(MplOption &aOption, const Address &aAddress) { - if (aAddress == Get().GetMeshLocal16()) + if (aAddress == Get().GetMeshLocalRloc()) { // Seed ID can be elided when `aAddress` is RLOC. aOption.Init(MplOption::kSeedIdLength0); diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index 96b647ed3..6b6a15250 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -528,15 +528,15 @@ bool Client::ShouldUpdateHostAutoAddresses(void) const { bool shouldUpdate = false; uint16_t registeredCount = 0; - Ip6::Netif::UnicastAddress &ml64 = Get().GetMeshLocal64UnicastAddress(); + Ip6::Netif::UnicastAddress &mlEid = Get().GetMeshLocalEidUnicastAddress(); VerifyOrExit(mHostInfo.IsAutoAddressEnabled()); // Check all addresses on `ThreadNetif` excluding the mesh local - // EID (`ml64`). If any address should be registered but is not, + // EID (`mlEid`). If any address should be registered but is not, // or if any address was registered earlier but no longer should // be, the host information needs to be re-registered to update - // the addresses. If there is no eligible address, then `ml64` + // the addresses. If there is no eligible address, then `mlEid` // should be registered, so its status is checked. Finally, the // number of addresses that should be registered is verified // against the previous value `mAutoHostAddressCount` to handle @@ -544,7 +544,7 @@ bool Client::ShouldUpdateHostAutoAddresses(void) const for (const Ip6::Netif::UnicastAddress &unicastAddress : Get().GetUnicastAddresses()) { - if (&unicastAddress == &ml64) + if (&unicastAddress == &mlEid) { continue; } @@ -562,7 +562,7 @@ bool Client::ShouldUpdateHostAutoAddresses(void) const if (registeredCount == 0) { - ExitNow(shouldUpdate = !ml64.mSrpRegistered); + ExitNow(shouldUpdate = !mlEid.mSrpRegistered); } shouldUpdate = (registeredCount != mAutoHostAddressCount); @@ -1350,10 +1350,10 @@ Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) if (mAutoHostAddressCount == 0) { - Ip6::Netif::UnicastAddress &ml64 = Get().GetMeshLocal64UnicastAddress(); + Ip6::Netif::UnicastAddress &mlEid = Get().GetMeshLocalEidUnicastAddress(); - SuccessOrExit(error = AppendAaaaRecord(ml64.GetAddress(), aMessage, aInfo)); - ml64.mSrpRegistered = true; + SuccessOrExit(error = AppendAaaaRecord(mlEid.GetAddress(), aMessage, aInfo)); + mlEid.mSrpRegistered = true; mAutoHostAddressCount++; } } diff --git a/src/core/thread/address_resolver.cpp b/src/core/thread/address_resolver.cpp index 28f6483cd..6fedd1568 100644 --- a/src/core/thread/address_resolver.cpp +++ b/src/core/thread/address_resolver.cpp @@ -787,7 +787,7 @@ void AddressResolver::HandleTmf(Coap::Message &aMessage, const for (Ip6::Netif::UnicastAddress &address : Get().GetUnicastAddresses()) { - if (address.GetAddress() == target && Get().GetMeshLocal64().GetIid() != meshLocalIid) + if (address.GetAddress() == target && Get().GetMeshLocalEid().GetIid() != meshLocalIid) { // Target EID matches address and Mesh Local EID differs #if OPENTHREAD_CONFIG_DUA_ENABLE @@ -856,7 +856,7 @@ void AddressResolver::HandleTmf(Coap::Message &aMessage, const if (Get().HasUnicastAddress(target)) { - SendAddressQueryResponse(target, Get().GetMeshLocal64().GetIid(), nullptr, + SendAddressQueryResponse(target, Get().GetMeshLocalEid().GetIid(), nullptr, aMessageInfo.GetPeerAddr()); ExitNow(); } diff --git a/src/core/thread/anycast_locator.cpp b/src/core/thread/anycast_locator.cpp index f3fd31e90..ed926a4c4 100644 --- a/src/core/thread/anycast_locator.cpp +++ b/src/core/thread/anycast_locator.cpp @@ -124,7 +124,7 @@ void AnycastLocator::HandleTmf(Coap::Message &aMessage, const message = Get().NewResponseMessage(aMessage); VerifyOrExit(message != nullptr); - SuccessOrExit(Tlv::Append(*message, Get().GetMeshLocal64().GetIid())); + SuccessOrExit(Tlv::Append(*message, Get().GetMeshLocalEid().GetIid())); SuccessOrExit(Tlv::Append(*message, Get().GetRloc16())); SuccessOrExit(Get().SendMessage(*message, aMessageInfo)); diff --git a/src/core/thread/dua_manager.cpp b/src/core/thread/dua_manager.cpp index 7e3ccc771..3f1ce2de1 100644 --- a/src/core/thread/dua_manager.cpp +++ b/src/core/thread/dua_manager.cpp @@ -472,7 +472,7 @@ void DuaManager::PerformNextRegistration(void) { dua = GetDomainUnicastAddress(); SuccessOrExit(error = Tlv::Append(*message, dua)); - SuccessOrExit(error = Tlv::Append(*message, mle.GetMeshLocal64().GetIid())); + SuccessOrExit(error = Tlv::Append(*message, mle.GetMeshLocalEid().GetIid())); mDuaState = kRegistering; mLastRegistrationTime = TimerMilli::GetNow(); } diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index e69f200a9..387fe2426 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -654,7 +654,7 @@ void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Ip6:: { Ip6::MessageInfo messageInfo; - messageInfo.GetPeerAddr() = Get().GetMeshLocal16(); + messageInfo.GetPeerAddr() = Get().GetMeshLocalRloc(); messageInfo.GetPeerAddr().GetIid().SetLocator(aMeshSource); IgnoreError(Get().SendError(Ip6::Icmp::Header::kTypeDstUnreach, diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 2fea5db79..a5d136b78 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -123,15 +123,15 @@ Mle::Mle(Instance &aInstance) mParentCandidate.Clear(); ResetCounters(); - mLinkLocal64.InitAsThreadOrigin(); - mLinkLocal64.GetAddress().SetToLinkLocalAddress(Get().GetExtAddress()); + mLinkLocalAddress.InitAsThreadOrigin(); + mLinkLocalAddress.GetAddress().SetToLinkLocalAddress(Get().GetExtAddress()); - mMeshLocal64.InitAsThreadOriginMeshLocal(); - mMeshLocal64.GetAddress().GetIid().GenerateRandom(); + mMeshLocalEid.InitAsThreadOriginMeshLocal(); + mMeshLocalEid.GetAddress().GetIid().GenerateRandom(); - mMeshLocal16.InitAsThreadOriginMeshLocal(); - mMeshLocal16.GetAddress().GetIid().SetToLocator(0); - mMeshLocal16.mRloc = true; + mMeshLocalRloc.InitAsThreadOriginMeshLocal(); + mMeshLocalRloc.GetAddress().GetIid().SetToLocator(0); + mMeshLocalRloc.mRloc = true; mLinkLocalAllThreadNodes.Clear(); mLinkLocalAllThreadNodes.GetAddress().mFields.m16[0] = BigEndian::HostSwap16(0xff32); @@ -172,7 +172,7 @@ Error Mle::Disable(void) Stop(kKeepNetworkDatasets); SuccessOrExit(error = mSocket.Close()); - Get().RemoveUnicastAddress(mLinkLocal64); + Get().RemoveUnicastAddress(mLinkLocalAddress); exit: return error; @@ -193,7 +193,7 @@ Error Mle::Start(StartMode aMode) SetStateDetached(); - Get().AddUnicastAddress(mMeshLocal64); + Get().AddUnicastAddress(mMeshLocalEid); Get().SubscribeMulticast(mLinkLocalAllThreadNodes); Get().SubscribeMulticast(mRealmLocalAllThreadNodes); @@ -246,8 +246,8 @@ void Mle::Stop(StopMode aMode) SetStateDetached(); Get().UnsubscribeMulticast(mRealmLocalAllThreadNodes); Get().UnsubscribeMulticast(mLinkLocalAllThreadNodes); - Get().RemoveUnicastAddress(mMeshLocal16); - Get().RemoveUnicastAddress(mMeshLocal64); + Get().RemoveUnicastAddress(mMeshLocalRloc); + Get().RemoveUnicastAddress(mMeshLocalEid); SetRole(kRoleDisabled); @@ -405,7 +405,7 @@ void Mle::Restore(void) } Get().SetExtAddress(networkInfo.GetExtAddress()); - mMeshLocal64.GetAddress().SetIid(networkInfo.GetMeshLocalIid()); + mMeshLocalEid.GetAddress().SetIid(networkInfo.GetMeshLocalIid()); if (networkInfo.GetRloc16() == Mac::kShortAddrInvalid) { @@ -473,7 +473,7 @@ Error Mle::Store(void) networkInfo.SetRloc16(GetRloc16()); networkInfo.SetPreviousPartitionId(mLeaderData.GetPartitionId()); networkInfo.SetExtAddress(Get().GetExtAddress()); - networkInfo.SetMeshLocalIid(mMeshLocal64.GetAddress().GetIid()); + networkInfo.SetMeshLocalIid(mMeshLocalEid.GetAddress().GetIid()); networkInfo.SetVersion(kThreadVersion); if (IsChild()) @@ -880,9 +880,9 @@ Error Mle::SetDeviceMode(DeviceMode aDeviceMode) void Mle::UpdateLinkLocalAddress(void) { - Get().RemoveUnicastAddress(mLinkLocal64); - mLinkLocal64.GetAddress().GetIid().SetFromExtAddress(Get().GetExtAddress()); - Get().AddUnicastAddress(mLinkLocal64); + Get().RemoveUnicastAddress(mLinkLocalAddress); + mLinkLocalAddress.GetAddress().GetIid().SetFromExtAddress(Get().GetExtAddress()); + Get().AddUnicastAddress(mLinkLocalAddress); Get().Signal(kEventThreadLinkLocalAddrChanged); } @@ -909,12 +909,12 @@ void Mle::SetMeshLocalPrefix(const Ip6::NetworkPrefix &aMeshLocalPrefix) // `ApplyNewMeshLocalPrefix()` call, but we apply the new prefix to // them in case they are not yet added to the `Netif`. This ensures // that addresses are always updated and other modules can retrieve - // them using methods such as `GetMeshLocal16()`, `GetMeshLocal64()` + // them using methods such as `GetMeshLocalRloc()`, `GetMeshLocalEid()` // or `GetLinkLocalAllThreadNodesAddress()`, even if they have not // yet been added to the `Netif`. - mMeshLocal64.GetAddress().SetPrefix(mMeshLocalPrefix); - mMeshLocal16.GetAddress().SetPrefix(mMeshLocalPrefix); + mMeshLocalEid.GetAddress().SetPrefix(mMeshLocalPrefix); + mMeshLocalRloc.GetAddress().SetPrefix(mMeshLocalPrefix); mLinkLocalAllThreadNodes.GetAddress().SetMulticastNetworkPrefix(mMeshLocalPrefix); mRealmLocalAllThreadNodes.GetAddress().SetMulticastNetworkPrefix(mMeshLocalPrefix); @@ -933,9 +933,9 @@ Error Mle::SetMeshLocalIid(const Ip6::InterfaceIdentifier &aMlIid) { Error error = kErrorNone; - VerifyOrExit(!Get().HasUnicastAddress(mMeshLocal64), error = kErrorInvalidState); + VerifyOrExit(!Get().HasUnicastAddress(mMeshLocalEid), error = kErrorInvalidState); - mMeshLocal64.GetAddress().SetIid(aMlIid); + mMeshLocalEid.GetAddress().SetIid(aMlIid); exit: return error; } @@ -950,11 +950,11 @@ void Mle::SetRloc16(uint16_t aRloc16) LogNote("RLOC16 %04x -> %04x", oldRloc16, aRloc16); } - if (Get().HasUnicastAddress(mMeshLocal16) && - (mMeshLocal16.GetAddress().GetIid().GetLocator() != aRloc16)) + if (Get().HasUnicastAddress(mMeshLocalRloc) && + (mMeshLocalRloc.GetAddress().GetIid().GetLocator() != aRloc16)) { - Get().RemoveUnicastAddress(mMeshLocal16); - Get().ClearRequests(mMeshLocal16.GetAddress()); + Get().RemoveUnicastAddress(mMeshLocalRloc); + Get().ClearRequests(mMeshLocalRloc.GetAddress()); } Get().SetShortAddress(aRloc16); @@ -965,8 +965,8 @@ void Mle::SetRloc16(uint16_t aRloc16) // We can always call `AddUnicastAddress(mMeshLocat16)` and if // the address is already added, it will perform no action. - mMeshLocal16.GetAddress().GetIid().SetLocator(aRloc16); - Get().AddUnicastAddress(mMeshLocal16); + mMeshLocalRloc.GetAddress().GetIid().SetLocator(aRloc16); + Get().AddUnicastAddress(mMeshLocalRloc); #if OPENTHREAD_FTD Get().RestartAddressQueries(); #endif @@ -1016,7 +1016,7 @@ Error Mle::GetLocatorAddress(Ip6::Address &aAddress, uint16_t aLocator) const VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); - memcpy(&aAddress, &mMeshLocal16.GetAddress(), 14); + memcpy(&aAddress, &mMeshLocalRloc.GetAddress(), 14); aAddress.GetIid().SetLocator(aLocator); exit: @@ -1052,7 +1052,7 @@ bool Mle::HasUnregisteredAddress(void) for (const Ip6::Netif::UnicastAddress &addr : Get().GetUnicastAddresses()) { if (!addr.GetAddress().IsLinkLocal() && !IsRoutingLocator(addr.GetAddress()) && - !IsAnycastLocator(addr.GetAddress()) && addr.GetAddress() != GetMeshLocal64()) + !IsAnycastLocator(addr.GetAddress()) && addr.GetAddress() != GetMeshLocalEid()) { ExitNow(retval = true); } @@ -1118,11 +1118,11 @@ void Mle::HandleNotifierEvents(Events aEvents) if (aEvents.ContainsAny(kEventIp6AddressAdded | kEventIp6AddressRemoved)) { - if (!Get().HasUnicastAddress(mMeshLocal64.GetAddress())) + if (!Get().HasUnicastAddress(mMeshLocalEid.GetAddress())) { - mMeshLocal64.GetAddress().GetIid().GenerateRandom(); + mMeshLocalEid.GetAddress().GetIid().GenerateRandom(); - Get().AddUnicastAddress(mMeshLocal64); + Get().AddUnicastAddress(mMeshLocalEid); Get().Signal(kEventThreadMeshLocalAddrChanged); } @@ -3883,8 +3883,8 @@ void Mle::InformPreviousParent(void) VerifyOrExit((message = Get().NewMessage(0)) != nullptr, error = kErrorNoBufs); SuccessOrExit(error = message->SetLength(0)); - messageInfo.SetSockAddr(GetMeshLocal64()); - messageInfo.SetPeerAddr(GetMeshLocal16()); + messageInfo.SetSockAddr(GetMeshLocalEid()); + messageInfo.SetPeerAddr(GetMeshLocalRloc()); messageInfo.GetPeerAddr().GetIid().SetLocator(mPreviousParentRloc); SuccessOrExit(error = Get().SendDatagram(*message, messageInfo, Ip6::kProtoNone)); @@ -4581,7 +4581,7 @@ Error Mle::TxMessage::AppendAddressRegistrationTlv(AddressRegistrationMode aMode SuccessOrExit(error = Append(tlv)); // Prioritize ML-EID - SuccessOrExit(error = AppendCompressedAddressEntry(kMeshLocalPrefixContextId, Get().GetMeshLocal64())); + SuccessOrExit(error = AppendCompressedAddressEntry(kMeshLocalPrefixContextId, Get().GetMeshLocalEid())); // Continue to append the other addresses if not `kAppendMeshLocalOnly` mode VerifyOrExit(aMode != kAppendMeshLocalOnly); @@ -4601,7 +4601,7 @@ Error Mle::TxMessage::AppendAddressRegistrationTlv(AddressRegistrationMode aMode for (const Ip6::Netif::UnicastAddress &addr : Get().GetUnicastAddresses()) { if (addr.GetAddress().IsLinkLocal() || Get().IsRoutingLocator(addr.GetAddress()) || - Get().IsAnycastLocator(addr.GetAddress()) || addr.GetAddress() == Get().GetMeshLocal64()) + Get().IsAnycastLocator(addr.GetAddress()) || addr.GetAddress() == Get().GetMeshLocalEid()) { continue; } @@ -4803,7 +4803,7 @@ Error Mle::TxMessage::SendTo(const Ip6::Address &aDestination) Ip6::MessageInfo messageInfo; messageInfo.SetPeerAddr(aDestination); - messageInfo.SetSockAddr(Get().mLinkLocal64.GetAddress()); + messageInfo.SetSockAddr(Get().mLinkLocalAddress.GetAddress()); messageInfo.SetPeerPort(kUdpPort); messageInfo.SetHopLimit(kMleHopLimit); diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 6c407cbed..e2ba6159b 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -390,7 +390,7 @@ class Mle : public InstanceLocator, private NonCopyable * @returns A reference to the Thread link local address. * */ - const Ip6::Address &GetLinkLocalAddress(void) const { return mLinkLocal64.GetAddress(); } + const Ip6::Address &GetLinkLocalAddress(void) const { return mLinkLocalAddress.GetAddress(); } /** * Updates the link local address. @@ -516,20 +516,20 @@ class Mle : public InstanceLocator, private NonCopyable uint16_t GetRloc16(void) const { return mRloc16; } /** - * Returns a reference to the RLOC assigned to the Thread interface. + * Returns the mesh local RLOC IPv6 address assigned to the Thread interface. * - * @returns A reference to the RLOC assigned to the Thread interface. + * @returns The mesh local RLOC IPv6 address. * */ - const Ip6::Address &GetMeshLocal16(void) const { return mMeshLocal16.GetAddress(); } + const Ip6::Address &GetMeshLocalRloc(void) const { return mMeshLocalRloc.GetAddress(); } /** - * Returns a reference to the ML-EID assigned to the Thread interface. + * Returns the mesh local endpoint identifier (ML-EID) IPv6 address assigned to the Thread interface. * - * @returns A reference to the ML-EID assigned to the Thread interface. + * @returns The ML-EID address. * */ - const Ip6::Address &GetMeshLocal64(void) const { return mMeshLocal64.GetAddress(); } + const Ip6::Address &GetMeshLocalEid(void) const { return mMeshLocalEid.GetAddress(); } /** * Returns a reference to the ML-EID as a `Netif::UnicastAddress`. @@ -537,7 +537,7 @@ class Mle : public InstanceLocator, private NonCopyable * @returns A reference to the ML-EID. * */ - Ip6::Netif::UnicastAddress &GetMeshLocal64UnicastAddress(void) { return mMeshLocal64; } + Ip6::Netif::UnicastAddress &GetMeshLocalEidUnicastAddress(void) { return mMeshLocalEid; } /** * Returns the Router ID of the Leader. @@ -1457,9 +1457,9 @@ class Mle : public InstanceLocator, private NonCopyable MsgTxTimer mMessageTransmissionTimer; DetachGracefullyTimer mDetachGracefullyTimer; Ip6::NetworkPrefix mMeshLocalPrefix; - Ip6::Netif::UnicastAddress mLinkLocal64; - Ip6::Netif::UnicastAddress mMeshLocal64; - Ip6::Netif::UnicastAddress mMeshLocal16; + Ip6::Netif::UnicastAddress mLinkLocalAddress; + Ip6::Netif::UnicastAddress mMeshLocalEid; + Ip6::Netif::UnicastAddress mMeshLocalRloc; Ip6::Netif::MulticastAddress mLinkLocalAllThreadNodes; Ip6::Netif::MulticastAddress mRealmLocalAllThreadNodes; }; diff --git a/src/core/thread/network_data_publisher.cpp b/src/core/thread/network_data_publisher.cpp index a64f0c39e..3ad23a330 100644 --- a/src/core/thread/network_data_publisher.cpp +++ b/src/core/thread/network_data_publisher.cpp @@ -510,7 +510,7 @@ void Publisher::DnsSrpServiceEntry::PublishUnicast(const Ip6::Address &aAddress, void Publisher::DnsSrpServiceEntry::PublishUnicast(uint16_t aPort) { LogInfo("Publishing DNS/SRP service unicast (ml-eid, port:%d)", aPort); - Publish(Info::InfoUnicast(kTypeUnicastMeshLocalEid, Get().GetMeshLocal64(), aPort)); + Publish(Info::InfoUnicast(kTypeUnicastMeshLocalEid, Get().GetMeshLocalEid(), aPort)); } void Publisher::DnsSrpServiceEntry::Publish(const Info &aInfo) @@ -546,7 +546,7 @@ void Publisher::DnsSrpServiceEntry::HandleNotifierEvents(Events aEvents) { if ((GetType() == kTypeUnicastMeshLocalEid) && aEvents.Contains(kEventThreadMeshLocalAddrChanged)) { - mInfo.SetAddress(Get().GetMeshLocal64()); + mInfo.SetAddress(Get().GetMeshLocalEid()); if (GetState() == kAdded) { diff --git a/src/core/thread/tmf.cpp b/src/core/thread/tmf.cpp index dec43943d..c695ed682 100644 --- a/src/core/thread/tmf.cpp +++ b/src/core/thread/tmf.cpp @@ -42,7 +42,7 @@ namespace Tmf { //---------------------------------------------------------------------------------------------------------------------- // MessageInfo -void MessageInfo::SetSockAddrToRloc(void) { SetSockAddr(Get().GetMeshLocal16()); } +void MessageInfo::SetSockAddrToRloc(void) { SetSockAddr(Get().GetMeshLocalRloc()); } Error MessageInfo::SetSockAddrToRlocPeerAddrToLeaderAloc(void) { @@ -65,7 +65,7 @@ void MessageInfo::SetSockAddrToRlocPeerAddrToRealmLocalAllRoutersMulticast(void) void MessageInfo::SetSockAddrToRlocPeerAddrTo(uint16_t aRloc16) { SetSockAddrToRloc(); - SetPeerAddr(Get().GetMeshLocal16()); + SetPeerAddr(Get().GetMeshLocalRloc()); GetPeerAddr().GetIid().SetLocator(aRloc16); } diff --git a/src/core/utils/mesh_diag.cpp b/src/core/utils/mesh_diag.cpp index 07566b6aa..4d5745498 100644 --- a/src/core/utils/mesh_diag.cpp +++ b/src/core/utils/mesh_diag.cpp @@ -98,7 +98,7 @@ Error MeshDiag::DiscoverTopology(const DiscoverConfig &aConfig, DiscoverCallback continue; } - destination = Get().GetMeshLocal16(); + destination = Get().GetMeshLocalRloc(); destination.GetIid().SetLocator(Mle::Rloc16FromRouterId(routerId)); SuccessOrExit(error = Get().SendCommand(kUriDiagnosticGetRequest, Message::kPriorityLow, destination, @@ -176,7 +176,7 @@ Error MeshDiag::SendQuery(uint16_t aRloc16, const uint8_t *aTlvs, uint8_t aTlvsL VerifyOrExit(Mle::IsActiveRouter(aRloc16), error = kErrorInvalidArgs); VerifyOrExit(Get().IsAllocated(Mle::RouterIdFromRloc16(aRloc16)), error = kErrorNotFound); - destination = Get().GetMeshLocal16(); + destination = Get().GetMeshLocalRloc(); destination.GetIid().SetLocator(aRloc16); SuccessOrExit(error = Get().SendCommand(kUriDiagnosticGetQuery, Message::kPriorityNormal, destination, diff --git a/tests/unit/test_child.cpp b/tests/unit/test_child.cpp index eb239f085..feec4b573 100644 --- a/tests/unit/test_child.cpp +++ b/tests/unit/test_child.cpp @@ -214,7 +214,7 @@ void TestChildIp6Address(void) numAddresses = 0; // First addresses uses the mesh local prefix (mesh-local address). - addresses[numAddresses] = sInstance->Get().GetMeshLocal64(); + addresses[numAddresses] = sInstance->Get().GetMeshLocalEid(); addresses[numAddresses].SetIid(meshLocalIid); numAddresses++; diff --git a/tests/unit/test_srp_server.cpp b/tests/unit/test_srp_server.cpp index d381ee250..15bcdc104 100644 --- a/tests/unit/test_srp_server.cpp +++ b/tests/unit/test_srp_server.cpp @@ -1097,7 +1097,7 @@ void TestSrpClientDelayedResponse(void) break; } - serverSockAddr.SetAddress(sInstance->Get().GetMeshLocal16()); + serverSockAddr.SetAddress(sInstance->Get().GetMeshLocalRloc()); serverSockAddr.SetPort(kServerPort); SuccessOrQuit(srpClient->Start(serverSockAddr)); From 282f54c2a63957181352fb3596db9ee7da6d67a3 Mon Sep 17 00:00:00 2001 From: brian-level <98054876+brian-level@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:07:24 -0400 Subject: [PATCH 25/65] [ip6] fix warning when logging enabled (#10375) --- src/core/net/ip6.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 0740e11a3..fe9c2c7b1 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -654,8 +654,8 @@ Error Ip6::HandleFragment(Message &aMessage) offset = FragmentHeader::FragmentOffsetToBytes(fragmentHeader.GetOffset()); payloadFragment = aMessage.GetLength() - aMessage.GetOffset() - sizeof(fragmentHeader); - LogInfo("Fragment with id %d received > %d bytes, offset %d", fragmentHeader.GetIdentification(), payloadFragment, - offset); + LogInfo("Fragment with id %lu received > %u bytes, offset %u", ToUlong(fragmentHeader.GetIdentification()), + payloadFragment, offset); if (offset + payloadFragment + aMessage.GetOffset() > kMaxAssembledDatagramLength) { From 8a8a4d8e315ea32526f47bba80bb5c6062d227d3 Mon Sep 17 00:00:00 2001 From: Konrad Derda Date: Fri, 14 Jun 2024 19:08:44 +0200 Subject: [PATCH 26/65] [netif] remove multicast promiscuous mode configuration (#10338) Since 74c833b6236ac1dab3673fb8ebd705eca662d2b4 was introduced all IPv6 multicast packets are passed to the host. Previously used promiscuous mode configuration is now unused. This commit removes the dead code and corresponding elements as there is no use case for them at the moment (and they can confuse a user). Signed-off-by: Konrad Derda --- include/openthread/instance.h | 2 +- include/openthread/ip6.h | 21 -------------------- src/cli/README.md | 28 --------------------------- src/cli/cli.cpp | 29 ---------------------------- src/core/api/ip6_api.cpp | 10 ---------- src/core/net/ip6.cpp | 4 ---- src/core/net/netif.cpp | 1 - src/core/net/netif.hpp | 18 ----------------- tests/scripts/expect/cli-ipmaddr.exp | 10 ---------- tools/otci/otci/otci.py | 12 ------------ tools/otci/tests/test_otci.py | 6 ------ 11 files changed, 1 insertion(+), 140 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 5c69dfe8a..6c88dfab2 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (420) +#define OPENTHREAD_API_VERSION (421) /** * @addtogroup api-instance diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index 2636702b4..4d1f3ce60 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -381,27 +381,6 @@ otError otIp6UnsubscribeMulticastAddress(otInstance *aInstance, const otIp6Addre */ const otNetifMulticastAddress *otIp6GetMulticastAddresses(otInstance *aInstance); -/** - * Checks if multicast promiscuous mode is enabled on the Thread interface. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - * @sa otIp6SetMulticastPromiscuousEnabled - * - */ -bool otIp6IsMulticastPromiscuousEnabled(otInstance *aInstance); - -/** - * Enables or disables multicast promiscuous mode on the Thread interface. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aEnabled TRUE to enable Multicast Promiscuous mode, FALSE otherwise. - * - * @sa otIp6IsMulticastPromiscuousEnabled - * - */ -void otIp6SetMulticastPromiscuousEnabled(otInstance *aInstance, bool aEnabled); - /** * Allocate a new message buffer for sending an IPv6 message. * diff --git a/src/cli/README.md b/src/cli/README.md index e93c91bfd..4dac6266c 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -1767,34 +1767,6 @@ ff32:40:fdde:ad00:beef:0:0:1 Done ``` -### ipmaddr promiscuous - -Get multicast promiscuous mode. - -```bash -> ipmaddr promiscuous -Disabled -Done -``` - -### ipmaddr promiscuous enable - -Enable multicast promiscuous mode. - -```bash -> ipmaddr promiscuous enable -Done -``` - -### ipmaddr promiscuous disable - -Disable multicast promiscuous mode. - -```bash -> ipmaddr promiscuous disable -Done -``` - ### ipmaddr rlatn Get the Realm-Local All Thread Nodes multicast address. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index e50326011..89bb9c8e5 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -3365,35 +3365,6 @@ template <> otError Interpreter::Process(Arg aArgs[]) SuccessOrExit(error = aArgs[1].ParseAsIp6Address(address)); error = otIp6UnsubscribeMulticastAddress(GetInstancePtr(), &address); } - /** - * @cli ipmaddr promiscuous - * @code - * ipmaddr promiscuous - * Disabled - * Done - * @endcode - * @par api_copy - * #otIp6IsMulticastPromiscuousEnabled - */ - else if (aArgs[0] == "promiscuous") - { - /** - * @cli ipmaddr promiscuous (enable,disable) - * @code - * ipmaddr promiscuous enable - * Done - * @endcode - * @code - * ipmaddr promiscuous disable - * Done - * @endcode - * @cparam ipmaddr promiscuous @ca{enable|disable} - * @par api_copy - * #otIp6SetMulticastPromiscuousEnabled - */ - error = - ProcessEnableDisable(aArgs + 1, otIp6IsMulticastPromiscuousEnabled, otIp6SetMulticastPromiscuousEnabled); - } /** * @cli ipmaddr llatn * @code diff --git a/src/core/api/ip6_api.cpp b/src/core/api/ip6_api.cpp index 5ca4f50d9..29fee9da3 100644 --- a/src/core/api/ip6_api.cpp +++ b/src/core/api/ip6_api.cpp @@ -105,16 +105,6 @@ otError otIp6UnsubscribeMulticastAddress(otInstance *aInstance, const otIp6Addre return AsCoreType(aInstance).Get().UnsubscribeExternalMulticast(AsCoreType(aAddress)); } -bool otIp6IsMulticastPromiscuousEnabled(otInstance *aInstance) -{ - return AsCoreType(aInstance).Get().IsMulticastPromiscuousEnabled(); -} - -void otIp6SetMulticastPromiscuousEnabled(otInstance *aInstance, bool aEnabled) -{ - AsCoreType(aInstance).Get().SetMulticastPromiscuous(aEnabled); -} - void otIp6SetReceiveCallback(otInstance *aInstance, otIp6ReceiveCallback aCallback, void *aCallbackContext) { AsCoreType(aInstance).Get().SetReceiveDatagramCallback(aCallback, aCallbackContext); diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index fe9c2c7b1..5c0aee0ad 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -1122,10 +1122,6 @@ Error Ip6::HandleDatagram(OwnedPtr aMessagePtr, bool aIsReassembled) { receive = true; } - else if (Get().IsMulticastPromiscuousEnabled()) - { - forwardHost = true; - } } else { diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index 3e103312b..27d6f2365 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -85,7 +85,6 @@ const otNetifMulticastAddress Netif::kLinkLocalAllRoutersMulticastAddress = { Netif::Netif(Instance &aInstance) : InstanceLocator(aInstance) - , mMulticastPromiscuous(false) { } diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp index a736df8e4..4428a4776 100644 --- a/src/core/net/netif.hpp +++ b/src/core/net/netif.hpp @@ -612,23 +612,6 @@ class Netif : public InstanceLocator, private NonCopyable */ void UnsubscribeAllExternalMulticastAddresses(void); - /** - * Checks if multicast promiscuous mode is enabled on the network interface. - * - * @retval TRUE If the multicast promiscuous mode is enabled. - * @retval FALSE If the multicast promiscuous mode is disabled. - * - */ - bool IsMulticastPromiscuousEnabled(void) const { return mMulticastPromiscuous; } - - /** - * Enables multicast promiscuous mode on the network interface. - * - * @param[in] aEnabled TRUE if Multicast Promiscuous mode is enabled, FALSE otherwise. - * - */ - void SetMulticastPromiscuous(bool aEnabled) { mMulticastPromiscuous = aEnabled; } - /** * Enables range-based `for` loop iteration over external multicast addresses on the Netif that matches * a given IPv6 address type filter. @@ -702,7 +685,6 @@ class Netif : public InstanceLocator, private NonCopyable LinkedList mUnicastAddresses; LinkedList mMulticastAddresses; - bool mMulticastPromiscuous; Callback mAddressCallback; diff --git a/tests/scripts/expect/cli-ipmaddr.exp b/tests/scripts/expect/cli-ipmaddr.exp index 0c9babd6d..5ab10f986 100755 --- a/tests/scripts/expect/cli-ipmaddr.exp +++ b/tests/scripts/expect/cli-ipmaddr.exp @@ -59,16 +59,6 @@ send "ipmaddr del ff0e::1\n" expect_line "Done" send "ipmaddr del ff0e::1\n" expect "Error 23: NotFound" -send "ipmaddr promiscuous enable\n" -expect_line "Done" -send "ipmaddr promiscuous\n" -expect "Enabled" -expect_line "Done" -send "ipmaddr promiscuous disable\n" -expect_line "Done" -send "ipmaddr promiscuous\n" -expect "Disabled" -expect_line "Done" send "ipmaddr something_invalid\n" expect "Error 35: InvalidCommand" diff --git a/tools/otci/otci/otci.py b/tools/otci/otci/otci.py index e60acf8ee..46a73734d 100644 --- a/tools/otci/otci/otci.py +++ b/tools/otci/otci/otci.py @@ -1946,18 +1946,6 @@ def has_ipmaddr(self, ip: Union[str, ipaddress.IPv6Address]): """Check if a IPv6 multicast address was subscribed by the Thread interface.""" return ip in self.get_ipmaddrs() - def get_ipmaddr_promiscuous(self) -> bool: - """Get multicast promiscuous mode.""" - return self.__parse_Enabled_or_Disabled(self.execute_command("ipmaddr promiscuous")) - - def enable_ipmaddr_promiscuous(self): - """Enable multicast promiscuous mode.""" - self.execute_command('ipmaddr promiscuous enable') - - def disable_ipmaddr_promiscuous(self): - """Disable multicast promiscuous mode.""" - self.execute_command('ipmaddr promiscuous disable') - def get_ipmaddr_llatn(self) -> Ip6Addr: """Get Link Local All Thread Nodes Multicast Address""" return self.__parse_ip6addr(self.execute_command('ipmaddr llatn')) diff --git a/tools/otci/tests/test_otci.py b/tools/otci/tests/test_otci.py index 011c8a379..d065867aa 100644 --- a/tools/otci/tests/test_otci.py +++ b/tools/otci/tests/test_otci.py @@ -257,12 +257,6 @@ def _test_otci_single_node(self, leader): logging.info("EID-to-RLOC cache: %r", leader.get_eidcache()) - logging.info("ipmaddr promiscuous: %r", leader.get_ipmaddr_promiscuous()) - leader.enable_ipmaddr_promiscuous() - self.assertTrue(leader.get_ipmaddr_promiscuous()) - leader.disable_ipmaddr_promiscuous() - self.assertFalse(leader.get_ipmaddr_promiscuous()) - logging.info("leader data: %r", leader.get_leader_data()) logging.info("leader neighbor list: %r", leader.get_neighbor_list()) logging.info("leader neighbor table: %r", leader.get_neighbor_table()) From 5127e7e5c0fc1918f062baa5b869e9c99e013636 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 17 Jun 2024 09:23:43 -0700 Subject: [PATCH 27/65] [mle] enhance RLOC and ALOC address generation (#10391) This commit enhances the generation of RLOC and ALOC addresses in the `Mle` class. Methods retrieving RLOC/ALOC addresses no longer return an `Error` and are now `void`. The previous check for a valid `GetRloc16()` value, which returned `kErrorDetach` if unset, is removed because this scenario only occurred before the device's initial attachment. Post-attachment, the RLOC16 remains valid even if the device is detached. This change simplifies the code since RLOC/ALOC address retrieval happens after the initial attachment. Additional enhancements include: - Changing the input parameter order in `GetCommissionerAloc()` to match `GetServiceAloc()`. - Using `Ip6::Address::SetToRoutingLocator()` to construct RLOC addresses, harmonizing address generation and improving code readability. --- src/core/api/thread_api.cpp | 16 +++++++- src/core/meshcop/border_agent.cpp | 4 +- src/core/meshcop/commissioner.cpp | 10 ++--- src/core/meshcop/dataset_manager.cpp | 4 +- src/core/meshcop/dataset_manager_ftd.cpp | 2 +- src/core/net/nd_agent.cpp | 4 +- src/core/thread/address_resolver.cpp | 2 +- src/core/thread/dua_manager.cpp | 2 +- src/core/thread/mesh_forwarder_ftd.cpp | 3 +- src/core/thread/mle.cpp | 34 ++++------------- src/core/thread/mle.hpp | 45 +++++------------------ src/core/thread/mle_router.cpp | 6 +-- src/core/thread/mlr_manager.cpp | 2 +- src/core/thread/network_data_notifier.cpp | 2 +- src/core/thread/network_data_service.cpp | 5 ++- src/core/thread/tmf.cpp | 11 +++--- src/core/thread/tmf.hpp | 12 ++---- src/core/utils/mesh_diag.cpp | 6 +-- 18 files changed, 63 insertions(+), 107 deletions(-) diff --git a/src/core/api/thread_api.cpp b/src/core/api/thread_api.cpp index 5d41308d6..91ac5f318 100644 --- a/src/core/api/thread_api.cpp +++ b/src/core/api/thread_api.cpp @@ -79,7 +79,13 @@ otError otThreadSetExtendedPanId(otInstance *aInstance, const otExtendedPanId *a otError otThreadGetLeaderRloc(otInstance *aInstance, otIp6Address *aLeaderRloc) { - return AsCoreType(aInstance).Get().GetLeaderAddress(AsCoreType(aLeaderRloc)); + Error error = kErrorNone; + + VerifyOrExit(AsCoreType(aInstance).Get().GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); + AsCoreType(aInstance).Get().GetLeaderRloc(AsCoreType(aLeaderRloc)); + +exit: + return error; } otLinkModeConfig otThreadGetLinkMode(otInstance *aInstance) @@ -189,7 +195,13 @@ const otIp6Address *otThreadGetRealmLocalAllThreadNodesMulticastAddress(otInstan otError otThreadGetServiceAloc(otInstance *aInstance, uint8_t aServiceId, otIp6Address *aServiceAloc) { - return AsCoreType(aInstance).Get().GetServiceAloc(aServiceId, AsCoreType(aServiceAloc)); + Error error = kErrorNone; + + VerifyOrExit(AsCoreType(aInstance).Get().GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); + AsCoreType(aInstance).Get().GetServiceAloc(aServiceId, AsCoreType(aServiceAloc)); + +exit: + return error; } const char *otThreadGetNetworkName(otInstance *aInstance) diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index 24e7331d8..ef82c3965 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -200,7 +200,7 @@ void BorderAgent::HandleCoapResponse(const ForwardContext &aForwardContext, SuccessOrExit(error = Tlv::Find(*aResponse, sessionId)); - IgnoreError(Get().GetCommissionerAloc(mCommissionerAloc.GetAddress(), sessionId)); + Get().GetCommissionerAloc(sessionId, mCommissionerAloc.GetAddress()); Get().AddUnicastAddress(mCommissionerAloc); IgnoreError(Get().AddReceiver(mUdpReceiver)); @@ -561,7 +561,7 @@ Error BorderAgent::ForwardToLeader(const Coap::Message &aMessage, const Ip6::Mes SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset())); - SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); messageInfo.SetSockPortToTmf(); SuccessOrExit(error = diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 0068e32c8..c3987e82c 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -639,7 +639,7 @@ Error Commissioner::SendMgmtCommissionerGetRequest(const uint8_t *aTlvs, uint8_t SuccessOrExit(error = message->AppendBytes(aTlvs, aLength)); } - SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); SuccessOrExit(error = Get().SendMessage(*message, messageInfo, Commissioner::HandleMgmtCommissionerGetResponse, this)); @@ -710,7 +710,7 @@ Error Commissioner::SendMgmtCommissionerSetRequest(const CommissioningDataset &a SuccessOrExit(error = message->AppendBytes(aTlvs, aLength)); } - SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); SuccessOrExit(error = Get().SendMessage(*message, messageInfo, Commissioner::HandleMgmtCommissionerSetResponse, this)); @@ -763,7 +763,7 @@ Error Commissioner::SendPetition(void) SuccessOrExit(error = Tlv::Append(*message, mCommissionerId)); - SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); SuccessOrExit( error = Get().SendMessage(*message, messageInfo, Commissioner::HandleLeaderPetitionResponse, this)); @@ -811,7 +811,7 @@ void Commissioner::HandleLeaderPetitionResponse(Coap::Message *aMessage ExitNow(); } - IgnoreError(Get().GetCommissionerAloc(mCommissionerAloc.GetAddress(), mSessionId)); + Get().GetCommissionerAloc(mSessionId, mCommissionerAloc.GetAddress()); Get().AddUnicastAddress(mCommissionerAloc); SetState(kStateActive); @@ -850,7 +850,7 @@ void Commissioner::SendKeepAlive(uint16_t aSessionId) SuccessOrExit(error = Tlv::Append(*message, aSessionId)); - SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); SuccessOrExit(error = Get().SendMessage(*message, messageInfo, Commissioner::HandleLeaderKeepAliveResponse, this)); diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index c55e03c39..8038af1fb 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -483,7 +483,7 @@ Error DatasetManager::SendSetRequest(const Dataset &aDataset) VerifyOrExit(message != nullptr, error = kErrorNoBufs); SuccessOrExit(error = message->AppendBytes(aDataset.GetBytes(), aDataset.GetLength())); - IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); SuccessOrExit(error = Get().SendMessage(*message, messageInfo, HandleMgmtSetResponse, this)); mMgmtPending = true; @@ -708,7 +708,7 @@ Error DatasetManager::SendGetRequest(const Dataset::Components &aDatasetComponen SuccessOrExit(error = Tlv::AppendTlv(*message, Tlv::kGet, tlvList.GetArrayBuffer(), tlvList.GetLength())); } - IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); if (aAddress != nullptr) { diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp index 927d24543..956a5fa58 100644 --- a/src/core/meshcop/dataset_manager_ftd.cpp +++ b/src/core/meshcop/dataset_manager_ftd.cpp @@ -241,7 +241,7 @@ Error DatasetManager::HandleSetOrReplace(MgmtCommand aCommand, Ip6::Address destination; SuccessOrExit(Get().FindCommissioningSessionId(localSessionId)); - SuccessOrExit(Get().GetCommissionerAloc(destination, localSessionId)); + Get().GetCommissionerAloc(localSessionId, destination); Get().SendDatasetChanged(destination); } diff --git a/src/core/net/nd_agent.cpp b/src/core/net/nd_agent.cpp index e05dd283f..1af8b58c5 100644 --- a/src/core/net/nd_agent.cpp +++ b/src/core/net/nd_agent.cpp @@ -101,10 +101,10 @@ void Agent::UpdateService(void) if (error == kErrorNone) { - uint16_t rloc = Mle::kAloc16NeighborDiscoveryAgentStart + lowpanContext.mContextId - 1; + uint16_t aloc16 = Mle::kAloc16NeighborDiscoveryAgentStart + lowpanContext.mContextId - 1; mAloc.InitAsThreadOrigin(); - mAloc.GetAddress().SetToAnycastLocator(Get().GetMeshLocalPrefix(), rloc); + mAloc.GetAddress().SetToAnycastLocator(Get().GetMeshLocalPrefix(), aloc16); mAloc.mMeshLocal = true; Get().AddUnicastAddress(mAloc); ExitNow(); diff --git a/src/core/thread/address_resolver.cpp b/src/core/thread/address_resolver.cpp index 6fedd1568..db0390386 100644 --- a/src/core/thread/address_resolver.cpp +++ b/src/core/thread/address_resolver.cpp @@ -822,7 +822,7 @@ void AddressResolver::HandleTmf(Coap::Message &aMessage, const if (child.RemoveIp6Address(target) == kErrorNone) { - SuccessOrExit(error = Get().GetLocatorAddress(destination, child.GetRloc16())); + destination.SetToRoutingLocator(Get().GetMeshLocalPrefix(), child.GetRloc16()); SendAddressError(target, meshLocalIid, &destination); ExitNow(); diff --git a/src/core/thread/dua_manager.cpp b/src/core/thread/dua_manager.cpp index 3f1ce2de1..808ed9250 100644 --- a/src/core/thread/dua_manager.cpp +++ b/src/core/thread/dua_manager.cpp @@ -512,7 +512,7 @@ void DuaManager::PerformNextRegistration(void) uint8_t pbbrServiceId; SuccessOrExit(error = Get().GetServiceId(pbbrServiceId)); - SuccessOrExit(error = mle.GetServiceAloc(pbbrServiceId, messageInfo.GetPeerAddr())); + mle.GetServiceAloc(pbbrServiceId, messageInfo.GetPeerAddr()); } else { diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 387fe2426..2daae86b5 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -654,8 +654,7 @@ void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Ip6:: { Ip6::MessageInfo messageInfo; - messageInfo.GetPeerAddr() = Get().GetMeshLocalRloc(); - messageInfo.GetPeerAddr().GetIid().SetLocator(aMeshSource); + messageInfo.GetPeerAddr().SetToRoutingLocator(Get().GetMeshLocalPrefix(), aMeshSource); IgnoreError(Get().SendError(Ip6::Icmp::Header::kTypeDstUnreach, Ip6::Icmp::Header::kCodeDstUnreachNoRoute, messageInfo, aIp6Headers)); diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index a5d136b78..57b1beff9 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -998,40 +998,21 @@ void Mle::SetLeaderData(uint32_t aPartitionId, uint8_t aWeighting, uint8_t aLead mLeaderData.SetLeaderRouterId(aLeaderRouterId); } -Error Mle::GetLeaderAddress(Ip6::Address &aAddress) const +void Mle::GetLeaderRloc(Ip6::Address &aAddress) const { - Error error = kErrorNone; - - VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); - aAddress.SetToRoutingLocator(mMeshLocalPrefix, GetLeaderRloc16()); - -exit: - return error; } -Error Mle::GetLocatorAddress(Ip6::Address &aAddress, uint16_t aLocator) const -{ - Error error = kErrorNone; - - VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); +void Mle::GetLeaderAloc(Ip6::Address &aAddress) const { aAddress.SetToAnycastLocator(mMeshLocalPrefix, kAloc16Leader); } - memcpy(&aAddress, &mMeshLocalRloc.GetAddress(), 14); - aAddress.GetIid().SetLocator(aLocator); - -exit: - return error; +void Mle::GetCommissionerAloc(uint16_t aSessionId, Ip6::Address &aAddress) const +{ + aAddress.SetToAnycastLocator(mMeshLocalPrefix, CommissionerAloc16FromId(aSessionId)); } -Error Mle::GetServiceAloc(uint8_t aServiceId, Ip6::Address &aAddress) const +void Mle::GetServiceAloc(uint8_t aServiceId, Ip6::Address &aAddress) const { - Error error = kErrorNone; - - VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); aAddress.SetToAnycastLocator(mMeshLocalPrefix, ServiceAlocFromId(aServiceId)); - -exit: - return error; } const LeaderData &Mle::GetLeaderData(void) @@ -3884,8 +3865,7 @@ void Mle::InformPreviousParent(void) SuccessOrExit(error = message->SetLength(0)); messageInfo.SetSockAddr(GetMeshLocalEid()); - messageInfo.SetPeerAddr(GetMeshLocalRloc()); - messageInfo.GetPeerAddr().GetIid().SetLocator(mPreviousParentRloc); + messageInfo.GetPeerAddr().SetToRoutingLocator(mMeshLocalPrefix, mPreviousParentRloc); SuccessOrExit(error = Get().SendDatagram(*message, messageInfo, Ip6::kProtoNone)); diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index e2ba6159b..d920e95fa 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -558,51 +558,36 @@ class Mle : public InstanceLocator, private NonCopyable /** * Retrieves the Leader's RLOC. * - * @param[out] aAddress A reference to the Leader's RLOC. - * - * @retval kErrorNone Successfully retrieved the Leader's RLOC. - * @retval kErrorDetached The Thread interface is not currently attached to a Thread Partition. + * @param[out] aAddress A reference to an address to return the Leader's RLOC. * */ - Error GetLeaderAddress(Ip6::Address &aAddress) const; + void GetLeaderRloc(Ip6::Address &aAddress) const; /** * Retrieves the Leader's ALOC. * - * @param[out] aAddress A reference to the Leader's ALOC. - * - * @retval kErrorNone Successfully retrieved the Leader's ALOC. - * @retval kErrorDetached The Thread interface is not currently attached to a Thread Partition. + * @param[out] aAddress A reference to an address to return the Leader's ALOC. * */ - Error GetLeaderAloc(Ip6::Address &aAddress) const { return GetLocatorAddress(aAddress, kAloc16Leader); } + void GetLeaderAloc(Ip6::Address &aAddress) const; /** - * Computes the Commissioner's ALOC. + * Retrieves the Commissioner's ALOC for a given session ID. * - * @param[out] aAddress A reference to the Commissioner's ALOC. * @param[in] aSessionId Commissioner session id. - * - * @retval kErrorNone Successfully retrieved the Commissioner's ALOC. - * @retval kErrorDetached The Thread interface is not currently attached to a Thread Partition. + * @param[out] aAddress A reference to an address to return the Commissioner's ALOC. * */ - Error GetCommissionerAloc(Ip6::Address &aAddress, uint16_t aSessionId) const - { - return GetLocatorAddress(aAddress, CommissionerAloc16FromId(aSessionId)); - } + void GetCommissionerAloc(uint16_t aSessionId, Ip6::Address &aAddress) const; /** * Retrieves the Service ALOC for given Service ID. * * @param[in] aServiceId Service ID to get ALOC for. - * @param[out] aAddress A reference to the Service ALOC. - * - * @retval kErrorNone Successfully retrieved the Service ALOC. - * @retval kErrorDetached The Thread interface is not currently attached to a Thread Partition. + * @param[out] aAddress A reference to an address to return the Service ALOC. * */ - Error GetServiceAloc(uint8_t aServiceId, Ip6::Address &aAddress) const; + void GetServiceAloc(uint8_t aServiceId, Ip6::Address &aAddress) const; /** * Returns the most recently received Leader Data. @@ -677,18 +662,6 @@ class Mle : public InstanceLocator, private NonCopyable */ void RequestShorterChildIdRequest(void); - /** - * Gets the RLOC or ALOC of a given RLOC16 or ALOC16. - * - * @param[out] aAddress A reference to the RLOC or ALOC. - * @param[in] aLocator RLOC16 or ALOC16. - * - * @retval kErrorNone If got the RLOC or ALOC successfully. - * @retval kErrorDetached If device is detached. - * - */ - Error GetLocatorAddress(Ip6::Address &aAddress, uint16_t aLocator) const; - /** * Schedules a Child Update Request. * diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index bfef47222..615b6a308 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -450,7 +450,7 @@ void MleRouter::SetStateRouterOrLeader(DeviceRole aRole, uint16_t aRloc16, Leade if (aRole == kRoleLeader) { - IgnoreError(GetLeaderAloc(mLeaderAloc.GetAddress())); + GetLeaderAloc(mLeaderAloc.GetAddress()); Get().AddUnicastAddress(mLeaderAloc); Get().RegisterReceiver(TimeTicker::kMleRouter); Get().Start(aStartMode); @@ -3293,7 +3293,7 @@ Error MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus) SuccessOrExit(error = Tlv::Append(*message, otPlatTimeGetXtalAccuracy())); #endif - SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc(); SuccessOrExit(error = Get().SendMessage(*message, messageInfo, &HandleAddressSolicitResponse, this)); mAddressSolicitPending = true; @@ -3317,7 +3317,7 @@ void MleRouter::SendAddressRelease(void) SuccessOrExit(error = Tlv::Append(*message, Rloc16FromRouterId(mRouterId))); SuccessOrExit(error = Tlv::Append(*message, Get().GetExtAddress())); - SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc(); SuccessOrExit(error = Get().SendMessage(*message, messageInfo)); diff --git a/src/core/thread/mlr_manager.cpp b/src/core/thread/mlr_manager.cpp index df770fe4f..76d7378c3 100644 --- a/src/core/thread/mlr_manager.cpp +++ b/src/core/thread/mlr_manager.cpp @@ -401,7 +401,7 @@ Error MlrManager::SendMlrMessage(const Ip6::Address *aAddresses, uint8_t pbbrServiceId; SuccessOrExit(error = Get().GetServiceId(pbbrServiceId)); - SuccessOrExit(error = mle.GetServiceAloc(pbbrServiceId, messageInfo.GetPeerAddr())); + mle.GetServiceAloc(pbbrServiceId, messageInfo.GetPeerAddr()); } else { diff --git a/src/core/thread/network_data_notifier.cpp b/src/core/thread/network_data_notifier.cpp index e451a73e4..e5eebe62c 100644 --- a/src/core/thread/network_data_notifier.cpp +++ b/src/core/thread/network_data_notifier.cpp @@ -216,7 +216,7 @@ Error Notifier::SendServerDataNotification(uint16_t aOldRloc16, const NetworkDat SuccessOrExit(error = Tlv::Append(*message, aOldRloc16)); } - IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc()); + messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); SuccessOrExit(error = Get().SendMessage(*message, messageInfo, HandleCoapResponse, this)); LogInfo("Sent %s", UriToString()); diff --git a/src/core/thread/network_data_service.cpp b/src/core/thread/network_data_service.cpp index dbd8be7b0..2eb0edf21 100644 --- a/src/core/thread/network_data_service.cpp +++ b/src/core/thread/network_data_service.cpp @@ -182,8 +182,9 @@ Error Manager::GetNextDnsSrpAnycastInfo(Iterator &aIterator, DnsSrpAnycast::Info } while (tlv->GetServiceDataLength() < sizeof(DnsSrpAnycast::ServiceData)); tlv->GetServiceData(serviceData); - aInfo.mAnycastAddress.SetToAnycastLocator(Get().GetMeshLocalPrefix(), - Mle::ServiceAlocFromId(tlv->GetServiceId())); + + Get().GetServiceAloc(tlv->GetServiceId(), aInfo.mAnycastAddress); + aInfo.mSequenceNumber = reinterpret_cast(serviceData.GetBytes())->GetSequenceNumber(); diff --git a/src/core/thread/tmf.cpp b/src/core/thread/tmf.cpp index c695ed682..8585ae114 100644 --- a/src/core/thread/tmf.cpp +++ b/src/core/thread/tmf.cpp @@ -44,16 +44,16 @@ namespace Tmf { void MessageInfo::SetSockAddrToRloc(void) { SetSockAddr(Get().GetMeshLocalRloc()); } -Error MessageInfo::SetSockAddrToRlocPeerAddrToLeaderAloc(void) +void MessageInfo::SetSockAddrToRlocPeerAddrToLeaderAloc(void) { SetSockAddrToRloc(); - return Get().GetLeaderAloc(GetPeerAddr()); + Get().GetLeaderAloc(GetPeerAddr()); } -Error MessageInfo::SetSockAddrToRlocPeerAddrToLeaderRloc(void) +void MessageInfo::SetSockAddrToRlocPeerAddrToLeaderRloc(void) { SetSockAddrToRloc(); - return Get().GetLeaderAddress(GetPeerAddr()); + Get().GetLeaderRloc(GetPeerAddr()); } void MessageInfo::SetSockAddrToRlocPeerAddrToRealmLocalAllRoutersMulticast(void) @@ -65,8 +65,7 @@ void MessageInfo::SetSockAddrToRlocPeerAddrToRealmLocalAllRoutersMulticast(void) void MessageInfo::SetSockAddrToRlocPeerAddrTo(uint16_t aRloc16) { SetSockAddrToRloc(); - SetPeerAddr(Get().GetMeshLocalRloc()); - GetPeerAddr().GetIid().SetLocator(aRloc16); + GetPeerAddr().SetToRoutingLocator(Get().GetMeshLocalPrefix(), aRloc16); } void MessageInfo::SetSockAddrToRlocPeerAddrTo(const Ip6::Address &aPeerAddress) diff --git a/src/core/thread/tmf.hpp b/src/core/thread/tmf.hpp index c90e24257..27518705a 100644 --- a/src/core/thread/tmf.hpp +++ b/src/core/thread/tmf.hpp @@ -99,20 +99,14 @@ class MessageInfo : public InstanceLocator, public Ip6::MessageInfo /** * Sets the local socket address to RLOC address and the peer socket address to leader ALOC. * - * @retval kErrorNone Successfully set the addresses. - * @retval kErrorDetached Cannot set leader ALOC since device is currently detached. - * */ - Error SetSockAddrToRlocPeerAddrToLeaderAloc(void); + void SetSockAddrToRlocPeerAddrToLeaderAloc(void); /** * Sets the local socket address to RLOC address and the peer socket address to leader RLOC. - * - * @retval kErrorNone Successfully set the addresses. - * @retval kErrorDetached Cannot set leader RLOC since device is currently detached. - * +q * */ - Error SetSockAddrToRlocPeerAddrToLeaderRloc(void); + void SetSockAddrToRlocPeerAddrToLeaderRloc(void); /** * Sets the local socket address to RLOC address and the peer socket address to realm-local all diff --git a/src/core/utils/mesh_diag.cpp b/src/core/utils/mesh_diag.cpp index 4d5745498..e8092eb25 100644 --- a/src/core/utils/mesh_diag.cpp +++ b/src/core/utils/mesh_diag.cpp @@ -98,8 +98,7 @@ Error MeshDiag::DiscoverTopology(const DiscoverConfig &aConfig, DiscoverCallback continue; } - destination = Get().GetMeshLocalRloc(); - destination.GetIid().SetLocator(Mle::Rloc16FromRouterId(routerId)); + destination.SetToRoutingLocator(Get().GetMeshLocalPrefix(), Mle::Rloc16FromRouterId(routerId)); SuccessOrExit(error = Get().SendCommand(kUriDiagnosticGetRequest, Message::kPriorityLow, destination, tlvs, tlvsLength, HandleDiagGetResponse, this)); @@ -176,8 +175,7 @@ Error MeshDiag::SendQuery(uint16_t aRloc16, const uint8_t *aTlvs, uint8_t aTlvsL VerifyOrExit(Mle::IsActiveRouter(aRloc16), error = kErrorInvalidArgs); VerifyOrExit(Get().IsAllocated(Mle::RouterIdFromRloc16(aRloc16)), error = kErrorNotFound); - destination = Get().GetMeshLocalRloc(); - destination.GetIid().SetLocator(aRloc16); + destination.SetToRoutingLocator(Get().GetMeshLocalPrefix(), aRloc16); SuccessOrExit(error = Get().SendCommand(kUriDiagnosticGetQuery, Message::kPriorityNormal, destination, aTlvs, aTlvsLength)); From 1837b64c21ce7e752c9fa362738ae573a49e4254 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:31:54 -0700 Subject: [PATCH 28/65] github-actions: bump codecov/codecov-action from 4.3.1 to 4.5.0 (#10395) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4.3.1 to 4.5.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/5ecb98a3c6b747ed38dc09f787459979aebb39be...e28ff129e5465c2c0dcc6f003fc735cb6ae0c673) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/otbr.yml | 2 +- .github/workflows/posix.yml | 2 +- .github/workflows/simulation-1.1.yml | 2 +- .github/workflows/simulation-1.2.yml | 2 +- .github/workflows/toranj.yml | 2 +- .github/workflows/unit.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/otbr.yml b/.github/workflows/otbr.yml index e73387d53..0d4d5c46f 100644 --- a/.github/workflows/otbr.yml +++ b/.github/workflows/otbr.yml @@ -255,7 +255,7 @@ jobs: script/test combine_coverage - name: Upload Coverage continue-on-error: true - uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # v4.3.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index 840ae5ad3..a2d56b561 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -315,7 +315,7 @@ jobs: run: | script/test combine_coverage - name: Upload Coverage - uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # v4.3.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: diff --git a/.github/workflows/simulation-1.1.yml b/.github/workflows/simulation-1.1.yml index 2058a9641..0623d2781 100644 --- a/.github/workflows/simulation-1.1.yml +++ b/.github/workflows/simulation-1.1.yml @@ -423,7 +423,7 @@ jobs: run: | script/test combine_coverage - name: Upload Coverage - uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # v4.3.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: diff --git a/.github/workflows/simulation-1.2.yml b/.github/workflows/simulation-1.2.yml index 809c8fcf1..48677c2f6 100644 --- a/.github/workflows/simulation-1.2.yml +++ b/.github/workflows/simulation-1.2.yml @@ -424,7 +424,7 @@ jobs: run: | script/test combine_coverage - name: Upload Coverage - uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # v4.3.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: diff --git a/.github/workflows/toranj.yml b/.github/workflows/toranj.yml index 6d0634276..046e9badb 100644 --- a/.github/workflows/toranj.yml +++ b/.github/workflows/toranj.yml @@ -206,7 +206,7 @@ jobs: run: | script/test combine_coverage - name: Upload Coverage - uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # v4.3.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index d255c76e0..d3f6dab9e 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -123,7 +123,7 @@ jobs: run: | script/test combine_coverage - name: Upload Coverage - uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # v4.3.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: From 0fac5dcf0b7a05dfb47b7c89ddbb778319fb1236 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Tue, 18 Jun 2024 02:09:22 +0800 Subject: [PATCH 29/65] [child-supervision] remove unused method declarations (#10394) --- src/core/thread/child_supervision.hpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/core/thread/child_supervision.hpp b/src/core/thread/child_supervision.hpp index ae72f55d1..508442495 100644 --- a/src/core/thread/child_supervision.hpp +++ b/src/core/thread/child_supervision.hpp @@ -102,18 +102,6 @@ class ChildSupervisor : public InstanceLocator, private NonCopyable */ explicit ChildSupervisor(Instance &aInstance); - /** - * Starts the child supervision process on parent. - * - */ - void Start(void); - - /** - * Stops the child supervision process on parent. - * - */ - void Stop(void); - /** * Returns the destination for a supervision message. * From 4749aa2ae0078ae9aff7f9a78abd93380b00a902 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 17 Jun 2024 11:31:30 -0700 Subject: [PATCH 30/65] [routing-manager] add `mIsReachable` to `otBorderRoutingRouterEntry` (#10388) This commit adds `mIsReachable` to the `otBorderRoutingRouterEntry` structure to indicate whether a router is reachable. A router is marked unreachable after it fails to respond to multiple Neighbor Solicitation (NS) probes. Additionally, the `br` CLI commands are updated to display this information. --- include/openthread/border_routing.h | 1 + include/openthread/instance.h | 2 +- src/cli/README_BR.md | 4 +++- src/cli/cli_br.cpp | 8 ++++++-- src/core/border_router/routing_manager.cpp | 1 + 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/openthread/border_routing.h b/include/openthread/border_routing.h index 403c9b600..55af0131a 100644 --- a/include/openthread/border_routing.h +++ b/include/openthread/border_routing.h @@ -102,6 +102,7 @@ typedef struct otBorderRoutingRouterEntry bool mOtherConfigFlag : 1; ///< The router's Other Config flag (`O` flag). bool mStubRouterFlag : 1; ///< The router's Stub Router flag. bool mIsLocalDevice : 1; ///< This router is the local device (this BR). + bool mIsReachable : 1; ///< This router is reachable. } otBorderRoutingRouterEntry; /** diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 6c88dfab2..d4325eff0 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (421) +#define OPENTHREAD_API_VERSION (422) /** * @addtogroup api-instance diff --git a/src/cli/README_BR.md b/src/cli/README_BR.md index e6eb264ea..ed704ee32 100644 --- a/src/cli/README_BR.md +++ b/src/cli/README_BR.md @@ -352,9 +352,11 @@ Info per router: - O: Other Config flag - Stub: Stub Router flag (indicates whether the router is a stub router) - Milliseconds since last received message from this router +- Reachability flag: A router is marked as unreachable if it fails to respond to multiple Neighbor Solicitation probes. +- `(this BR)` is appended when the router is the local device itself. ```bash > br routers -ff02:0:0:0:0:0:0:1 (M:0 O:0 Stub:1) ms-since-rx:1505 +ff02:0:0:0:0:0:0:1 (M:0 O:0 Stub:1) ms-since-rx:1505 reachable:yes Done ``` diff --git a/src/cli/cli_br.cpp b/src/cli/cli_br.cpp index b76e76716..cee063d01 100644 --- a/src/cli/cli_br.cpp +++ b/src/cli/cli_br.cpp @@ -518,7 +518,7 @@ template <> otError Br::Process(Arg aArgs[]) * @cli br routers * @code * br routers - * ff02:0:0:0:0:0:0:1 (M:0 O:0 Stub:1) ms-since-rx:1505 + * ff02:0:0:0:0:0:0:1 (M:0 O:0 Stub:1) ms-since-rx:1505 reachable:yes * Done * @endcode * @par @@ -530,6 +530,9 @@ template <> otError Br::Process(Arg aArgs[]) * - O: Other Config flag * - Stub: Stub Router flag (indicates whether the router is a stub router) * - Milliseconds since last received message from this router + * - Reachability flag: A router is marked as unreachable if it fails to respond to multiple Neighbor Solicitation + * probes. + * - `(this BR)` is appended when the router is the local device itself. * @sa otBorderRoutingGetNextRouterEntry */ template <> otError Br::Process(Arg aArgs[]) @@ -559,7 +562,8 @@ void Br::OutputRouterInfo(const otBorderRoutingRouterEntry &aEntry, RouterOutput if (aMode == kLongVersion) { - OutputFormat(" ms-since-rx:%lu", ToUlong(aEntry.mMsecSinceLastUpdate)); + OutputFormat(" ms-since-rx:%lu reachable:%s", ToUlong(aEntry.mMsecSinceLastUpdate), + aEntry.mIsReachable ? "yes" : "no"); if (aEntry.mIsLocalDevice) { diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index 11c4a8692..5e4dd2d08 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -1969,6 +1969,7 @@ void RoutingManager::RxRaTracker::Router::CopyInfoTo(RouterEntry &aEntry, TimeMi aEntry.mOtherConfigFlag = mOtherConfigFlag; aEntry.mStubRouterFlag = mStubRouterFlag; aEntry.mIsLocalDevice = mIsLocalDevice; + aEntry.mIsReachable = IsReachable(); } //--------------------------------------------------------------------------------------------------------------------- From 54afce92abacf177d2f67affd1b846d94a403770 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 17 Jun 2024 18:31:26 -0700 Subject: [PATCH 31/65] [udp] add template `SocketIn` class for easier socket usage (#10392) This commit adds a new template `Udp::SocketIn`, which defines a UDP socket for use within a specified `Owner` class. It includes a `HandleUdpReceive()` member method callback for processing received messages. This model, similar to `TimerMilliIn`, eliminates the need for each socket user to define boilerplate code for providing a static member function that simply casts and calls the member method. This is now handled by the template `SocketIn` class. The `Udp::Socket::Open()` method is also modified to no longer require the callback and context parameters. --- src/core/coap/coap.cpp | 8 ++--- src/core/coap/coap.hpp | 7 +++-- src/core/meshcop/joiner_router.cpp | 9 ++---- src/core/meshcop/joiner_router.hpp | 6 ++-- src/core/meshcop/secure_transport.cpp | 9 ++---- src/core/meshcop/secure_transport.hpp | 6 ++-- src/core/net/dhcp6_client.cpp | 9 ++---- src/core/net/dhcp6_client.hpp | 6 ++-- src/core/net/dhcp6_server.cpp | 9 ++---- src/core/net/dhcp6_server.hpp | 11 ++++--- src/core/net/dns_client.cpp | 9 +++--- src/core/net/dns_client.hpp | 7 +++-- src/core/net/dnssd_server.cpp | 9 ++---- src/core/net/dnssd_server.hpp | 13 ++++---- src/core/net/sntp_client.cpp | 9 ++---- src/core/net/sntp_client.hpp | 10 +++---- src/core/net/srp_client.cpp | 8 ++--- src/core/net/srp_client.hpp | 7 +++-- src/core/net/srp_server.cpp | 9 ++---- src/core/net/srp_server.hpp | 4 +-- src/core/net/udp6.cpp | 17 +++++++++-- src/core/net/udp6.hpp | 43 +++++++++++++++++++++++---- src/core/thread/mle.cpp | 9 ++---- src/core/thread/mle.hpp | 20 ++++++------- tests/unit/test_srp_server.cpp | 4 +-- 25 files changed, 129 insertions(+), 129 deletions(-) diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp index 941f6086b..38ba54e9b 100644 --- a/src/core/coap/coap.cpp +++ b/src/core/coap/coap.cpp @@ -1693,7 +1693,7 @@ Resource::Resource(Uri aUri, RequestHandler aHandler, void *aContext) Coap::Coap(Instance &aInstance) : CoapBase(aInstance, &Coap::Send) - , mSocket(aInstance) + , mSocket(aInstance, *this) { } @@ -1704,7 +1704,7 @@ Error Coap::Start(uint16_t aPort, Ip6::NetifIdentifier aNetifIdentifier) VerifyOrExit(!mSocket.IsBound()); - SuccessOrExit(error = mSocket.Open(&Coap::HandleUdpReceive, this)); + SuccessOrExit(error = mSocket.Open()); socketOpened = true; SuccessOrExit(error = mSocket.Bind(aPort, aNetifIdentifier)); @@ -1731,9 +1731,9 @@ Error Coap::Stop(void) return error; } -void Coap::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) +void Coap::HandleUdpReceive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - static_cast(aContext)->Receive(AsCoapMessage(aMessage), AsCoreType(aMessageInfo)); + Receive(AsCoapMessage(&aMessage), aMessageInfo); } Error Coap::Send(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp index 9a08916a1..aeae3bb74 100644 --- a/src/core/coap/coap.hpp +++ b/src/core/coap/coap.hpp @@ -997,11 +997,14 @@ class Coap : public CoapBase Error Stop(void); protected: - Ip6::Udp::Socket mSocket; + void HandleUdpReceive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + using CoapSocket = Ip6::Udp::SocketIn; + + CoapSocket mSocket; private: static Error Send(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); Error Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); }; diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp index a5df41367..b9f4a57c4 100644 --- a/src/core/meshcop/joiner_router.cpp +++ b/src/core/meshcop/joiner_router.cpp @@ -56,7 +56,7 @@ RegisterLogModule("JoinerRouter"); JoinerRouter::JoinerRouter(Instance &aInstance) : InstanceLocator(aInstance) - , mSocket(aInstance) + , mSocket(aInstance, *this) , mTimer(aInstance) , mJoinerUdpPort(0) , mIsJoinerPortConfigured(false) @@ -81,7 +81,7 @@ void JoinerRouter::Start(void) VerifyOrExit(!mSocket.IsBound()); - IgnoreError(mSocket.Open(&JoinerRouter::HandleUdpReceive, this)); + IgnoreError(mSocket.Open()); IgnoreError(mSocket.Bind(port)); IgnoreError(Get().AddUnsecurePort(port)); LogInfo("Joiner Router: start"); @@ -126,11 +126,6 @@ void JoinerRouter::SetJoinerUdpPort(uint16_t aJoinerUdpPort) Start(); } -void JoinerRouter::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); -} - void JoinerRouter::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { Error error; diff --git a/src/core/meshcop/joiner_router.hpp b/src/core/meshcop/joiner_router.hpp index bc76297ba..63672e2a5 100644 --- a/src/core/meshcop/joiner_router.hpp +++ b/src/core/meshcop/joiner_router.hpp @@ -100,8 +100,7 @@ class JoinerRouter : public InstanceLocator, private NonCopyable void HandleNotifierEvents(Events aEvents); - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); template void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); @@ -120,8 +119,9 @@ class JoinerRouter : public InstanceLocator, private NonCopyable Coap::Message *PrepareJoinerEntrustMessage(void); using JoinerRouterTimer = TimerMilliIn; + using JoinerSocket = Ip6::Udp::SocketIn; - Ip6::Udp::Socket mSocket; + JoinerSocket mSocket; JoinerRouterTimer mTimer; MessageQueue mDelayedJoinEnts; diff --git a/src/core/meshcop/secure_transport.cpp b/src/core/meshcop/secure_transport.cpp index e527c1f1e..bfb5db6d9 100644 --- a/src/core/meshcop/secure_transport.cpp +++ b/src/core/meshcop/secure_transport.cpp @@ -87,7 +87,7 @@ SecureTransport::SecureTransport(Instance &aInstance, bool aLayerTwoSecurity, bo , mMaxConnectionAttempts(0) , mRemainingConnectionAttempts(0) , mReceiveMessage(nullptr) - , mSocket(aInstance) + , mSocket(aInstance, *this) , mMessageSubType(Message::kSubTypeNone) , mMessageDefaultSubType(Message::kSubTypeNone) { @@ -158,7 +158,7 @@ Error SecureTransport::Open(ReceiveHandler aReceiveHandler, ConnectedHandler aCo VerifyOrExit(IsStateClosed(), error = kErrorAlready); - SuccessOrExit(error = mSocket.Open(&SecureTransport::HandleReceive, this)); + SuccessOrExit(error = mSocket.Open()); mConnectedCallback.Set(aConnectedHandler, aContext); mReceiveCallback.Set(aReceiveHandler, aContext); @@ -204,11 +204,6 @@ Error SecureTransport::Connect(const Ip6::SockAddr &aSockAddr) return error; } -void SecureTransport::HandleReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->HandleReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); -} - void SecureTransport::HandleReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { VerifyOrExit(!IsStateClosed()); diff --git a/src/core/meshcop/secure_transport.hpp b/src/core/meshcop/secure_transport.hpp index 4641ef537..b5749a951 100644 --- a/src/core/meshcop/secure_transport.hpp +++ b/src/core/meshcop/secure_transport.hpp @@ -584,8 +584,6 @@ class SecureTransport : public InstanceLocator static void HandleTimer(Timer &aTimer); void HandleTimer(void); - static void HandleReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void HandleReceive(const uint8_t *aBuf, uint16_t aLength); Error HandleSecureTransportSend(const uint8_t *aBuf, uint16_t aLength, Message::SubType aMessageSubType); @@ -595,6 +593,8 @@ class SecureTransport : public InstanceLocator static const char *StateToString(State aState); #endif + using TransportSocket = Ip6::Udp::SocketIn; + State mState; int mCipherSuites[2]; @@ -663,7 +663,7 @@ class SecureTransport : public InstanceLocator void *mContext; Ip6::MessageInfo mMessageInfo; - Ip6::Udp::Socket mSocket; + TransportSocket mSocket; Callback mTransportCallback; void *mTransportContext; diff --git a/src/core/net/dhcp6_client.cpp b/src/core/net/dhcp6_client.cpp index 11a88fd99..abf6e3265 100644 --- a/src/core/net/dhcp6_client.cpp +++ b/src/core/net/dhcp6_client.cpp @@ -52,7 +52,7 @@ RegisterLogModule("Dhcp6Client"); Client::Client(Instance &aInstance) : InstanceLocator(aInstance) - , mSocket(aInstance) + , mSocket(aInstance, *this) , mTrickleTimer(aInstance, Client::HandleTrickleTimer) , mStartTime(0) , mIdentityAssociationCurrent(nullptr) @@ -170,7 +170,7 @@ void Client::Start(void) { VerifyOrExit(!mSocket.IsBound()); - IgnoreError(mSocket.Open(&Client::HandleUdpReceive, this)); + IgnoreError(mSocket.Open()); IgnoreError(mSocket.Bind(kDhcpClientPort)); ProcessNextIdentityAssociation(); @@ -395,11 +395,6 @@ Error Client::AppendRapidCommit(Message &aMessage) return aMessage.Append(option); } -void Client::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); -} - void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { OT_UNUSED_VARIABLE(aMessageInfo); diff --git a/src/core/net/dhcp6_client.hpp b/src/core/net/dhcp6_client.hpp index c50b13889..2d9287db0 100644 --- a/src/core/net/dhcp6_client.hpp +++ b/src/core/net/dhcp6_client.hpp @@ -126,8 +126,7 @@ class Client : public InstanceLocator, private NonCopyable Error AppendElapsedTime(Message &aMessage); Error AppendRapidCommit(Message &aMessage); - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void ProcessReply(Message &aMessage); uint16_t FindOption(Message &aMessage, uint16_t aOffset, uint16_t aLength, Code aCode); @@ -140,8 +139,9 @@ class Client : public InstanceLocator, private NonCopyable static void HandleTrickleTimer(TrickleTimer &aTrickleTimer); void HandleTrickleTimer(void); - Ip6::Udp::Socket mSocket; + using ClientSocket = Ip6::Udp::SocketIn; + ClientSocket mSocket; TrickleTimer mTrickleTimer; TransactionId mTransactionId; diff --git a/src/core/net/dhcp6_server.cpp b/src/core/net/dhcp6_server.cpp index ea9570737..f25884e12 100644 --- a/src/core/net/dhcp6_server.cpp +++ b/src/core/net/dhcp6_server.cpp @@ -52,7 +52,7 @@ RegisterLogModule("Dhcp6Server"); Server::Server(Instance &aInstance) : InstanceLocator(aInstance) - , mSocket(aInstance) + , mSocket(aInstance, *this) , mPrefixAgentsCount(0) , mPrefixAgentsMask(0) { @@ -138,7 +138,7 @@ void Server::Start(void) { VerifyOrExit(!mSocket.IsOpen()); - IgnoreError(mSocket.Open(&Server::HandleUdpReceive, this)); + IgnoreError(mSocket.Open()); IgnoreError(mSocket.Bind(kDhcpServerPort)); exit: @@ -176,11 +176,6 @@ void Server::AddPrefixAgent(const Ip6::Prefix &aIp6Prefix, const Lowpan::Context OT_UNUSED_VARIABLE(error); } -void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); -} - void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { Header header; diff --git a/src/core/net/dhcp6_server.hpp b/src/core/net/dhcp6_server.hpp index eba2d6c96..8869f24e6 100644 --- a/src/core/net/dhcp6_server.hpp +++ b/src/core/net/dhcp6_server.hpp @@ -192,11 +192,8 @@ class Server : public InstanceLocator, private NonCopyable Error AppendVendorSpecificInformation(Message &aMessage); Error AddIaAddress(Message &aMessage, const Ip6::Address &aPrefix, ClientIdentifier &aClientId); - - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - - void ProcessSolicit(Message &aMessage, const Ip6::Address &aDst, const TransactionId &aTransactionId); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + void ProcessSolicit(Message &aMessage, const Ip6::Address &aDst, const TransactionId &aTransactionId); uint16_t FindOption(Message &aMessage, uint16_t aOffset, uint16_t aLength, Code aCode); Error ProcessClientIdentifier(Message &aMessage, uint16_t aOffset, ClientIdentifier &aClientId); @@ -209,7 +206,9 @@ class Server : public InstanceLocator, private NonCopyable ClientIdentifier &aClientId, IaNa &aIaNa); - Ip6::Udp::Socket mSocket; + using ServerSocket = Ip6::Udp::SocketIn; + + ServerSocket mSocket; PrefixAgent mPrefixAgents[kNumPrefixes]; uint8_t mPrefixAgentsCount; diff --git a/src/core/net/dns_client.cpp b/src/core/net/dns_client.cpp index 61bdb1714..1b1b77ee5 100644 --- a/src/core/net/dns_client.cpp +++ b/src/core/net/dns_client.cpp @@ -737,7 +737,7 @@ const uint16_t *const Client::kQuestionRecordTypes[] = { Client::Client(Instance &aInstance) : InstanceLocator(aInstance) - , mSocket(aInstance) + , mSocket(aInstance, *this) #if OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE , mTcpState(kTcpUninitialized) #endif @@ -768,7 +768,7 @@ Error Client::Start(void) { Error error; - SuccessOrExit(error = mSocket.Open(&Client::HandleUdpReceive, this)); + SuccessOrExit(error = mSocket.Open()); SuccessOrExit(error = mSocket.Bind(0, Ip6::kNetifUnspecified)); exit: @@ -1301,11 +1301,10 @@ Client::Query *Client::FindQueryById(uint16_t aMessageId) return matchedQuery; } -void Client::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMsgInfo) +void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMsgInfo) { OT_UNUSED_VARIABLE(aMsgInfo); - - static_cast(aContext)->ProcessResponse(AsCoreType(aMessage)); + ProcessResponse(aMessage); } void Client::ProcessResponse(const Message &aResponseMessage) diff --git a/src/core/net/dns_client.hpp b/src/core/net/dns_client.hpp index e086f746b..9ac6a3868 100644 --- a/src/core/net/dns_client.hpp +++ b/src/core/net/dns_client.hpp @@ -839,7 +839,7 @@ class Client : public InstanceLocator, private NonCopyable static void GetQueryTypeAndCallback(const Query &aQuery, QueryType &aType, Callback &aCallback, void *&aContext); Error AppendNameFromQuery(const Query &aQuery, Message &aMessage); Query *FindQueryById(uint16_t aMessageId); - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMsgInfo); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMsgInfo); void ProcessResponse(const Message &aResponseMessage); Error ParseResponse(const Message &aResponseMessage, Query *&aQuery, Error &aResponseError); bool CanFinalizeQuery(Query &aQuery); @@ -904,9 +904,10 @@ class Client : public InstanceLocator, private NonCopyable static constexpr uint16_t kUdpQueryMaxSize = 512; - using RetryTimer = TimerMilliIn; + using RetryTimer = TimerMilliIn; + using ClientSocket = Ip6::Udp::SocketIn; - Ip6::Udp::Socket mSocket; + ClientSocket mSocket; #if OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE Ip6::Tcp::Endpoint mEndpoint; diff --git a/src/core/net/dnssd_server.cpp b/src/core/net/dnssd_server.cpp index 9f177db4b..10fa87d9f 100644 --- a/src/core/net/dnssd_server.cpp +++ b/src/core/net/dnssd_server.cpp @@ -63,7 +63,7 @@ const char *Server::kBlockedDomains[] = {"ipv4only.arpa."}; Server::Server(Instance &aInstance) : InstanceLocator(aInstance) - , mSocket(aInstance) + , mSocket(aInstance, *this) #if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE , mDiscoveryProxy(aInstance) #endif @@ -82,7 +82,7 @@ Error Server::Start(void) VerifyOrExit(!IsRunning()); - SuccessOrExit(error = mSocket.Open(&Server::HandleUdpReceive, this)); + SuccessOrExit(error = mSocket.Open()); SuccessOrExit(error = mSocket.Bind(kPort, kBindUnspecifiedNetif ? Ip6::kNetifUnspecified : Ip6::kNetifThread)); #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE @@ -135,11 +135,6 @@ void Server::Stop(void) #endif } -void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); -} - void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { Request request; diff --git a/src/core/net/dnssd_server.hpp b/src/core/net/dnssd_server.hpp index 692239ecb..ea8f7e7d7 100644 --- a/src/core/net/dnssd_server.hpp +++ b/src/core/net/dnssd_server.hpp @@ -513,11 +513,9 @@ class Server : public InstanceLocator, private NonCopyable }; #endif - bool IsRunning(void) const { return mSocket.IsBound(); } - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - void ProcessQuery(Request &aRequest); - + bool IsRunning(void) const { return mSocket.IsBound(); } + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + void ProcessQuery(Request &aRequest); void ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessageInfo); void RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, ProxyQueryInfo &aInfo, Response &aResponse); void Finalize(ProxyQuery &aQuery, ResponseCode aResponseCode); @@ -560,7 +558,8 @@ class Server : public InstanceLocator, private NonCopyable void UpdateResponseCounters(ResponseCode aResponseCode); - using ServerTimer = TimerMilliIn; + using ServerTimer = TimerMilliIn; + using ServerSocket = Ip6::Udp::SocketIn; static const char kDefaultDomainName[]; static const char kSubLabel[]; @@ -568,7 +567,7 @@ class Server : public InstanceLocator, private NonCopyable static const char *kBlockedDomains[]; #endif - Ip6::Udp::Socket mSocket; + ServerSocket mSocket; ProxyQueryList mProxyQueries; Callback mQuerySubscribe; diff --git a/src/core/net/sntp_client.cpp b/src/core/net/sntp_client.cpp index 3950f49b1..7e28ad795 100644 --- a/src/core/net/sntp_client.cpp +++ b/src/core/net/sntp_client.cpp @@ -51,7 +51,7 @@ namespace Sntp { RegisterLogModule("SntpClnt"); Client::Client(Instance &aInstance) - : mSocket(aInstance) + : mSocket(aInstance, *this) , mRetransmissionTimer(aInstance) , mUnixEra(0) { @@ -61,7 +61,7 @@ Error Client::Start(void) { Error error; - SuccessOrExit(error = mSocket.Open(&Client::HandleUdpReceive, this)); + SuccessOrExit(error = mSocket.Open()); SuccessOrExit(error = mSocket.Bind(0, Ip6::kNetifUnspecified)); exit: @@ -263,11 +263,6 @@ void Client::HandleRetransmissionTimer(void) mRetransmissionTimer.FireAt(nextTime); } -void Client::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); -} - void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { OT_UNUSED_VARIABLE(aMessageInfo); diff --git a/src/core/net/sntp_client.hpp b/src/core/net/sntp_client.hpp index d6d4dad3c..dd4c4ab33 100644 --- a/src/core/net/sntp_client.hpp +++ b/src/core/net/sntp_client.hpp @@ -272,14 +272,12 @@ class Client : private NonCopyable void FinalizeSntpTransaction(Message &aQuery, const QueryMetadata &aQueryMetadata, uint64_t aTime, Error aResult); void HandleRetransmissionTimer(void); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - - using RetxTimer = TimerMilliIn; - - Ip6::Udp::Socket mSocket; + using RetxTimer = TimerMilliIn; + using ClientSocket = Ip6::Udp::SocketIn; + ClientSocket mSocket; MessageQueue mPendingQueries; RetxTimer mRetransmissionTimer; diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index 6b6a15250..9ac4e72db 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -267,7 +267,7 @@ Client::Client(Instance &aInstance) , mKeyLease(0) , mDefaultLease(kDefaultLease) , mDefaultKeyLease(kDefaultKeyLease) - , mSocket(aInstance) + , mSocket(aInstance, *this) , mDomainName(kDefaultDomainName) , mTimer(aInstance) { @@ -296,7 +296,7 @@ Error Client::Start(const Ip6::SockAddr &aServerSockAddr, Requester aRequester) VerifyOrExit(GetState() == kStateStopped, error = (aServerSockAddr == GetServerAddress()) ? kErrorNone : kErrorBusy); - SuccessOrExit(error = mSocket.Open(Client::HandleUdpReceive, this)); + SuccessOrExit(error = mSocket.Open()); SuccessOrExit(error = mSocket.Connect(aServerSockAddr)); LogInfo("%starting, server %s", (aRequester == kRequesterUser) ? "S" : "Auto-s", @@ -1583,11 +1583,11 @@ void Client::UpdateRecordLengthInMessage(Dns::ResourceRecord &aRecord, uint16_t aMessage.Write(aOffset, aRecord); } -void Client::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) +void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { OT_UNUSED_VARIABLE(aMessageInfo); - static_cast(aContext)->ProcessResponse(AsCoreType(aMessage)); + ProcessResponse(aMessage); } void Client::ProcessResponse(Message &aMessage) diff --git a/src/core/net/srp_client.hpp b/src/core/net/srp_client.hpp index 8c9cf7e3f..f45b95364 100644 --- a/src/core/net/srp_client.hpp +++ b/src/core/net/srp_client.hpp @@ -1040,7 +1040,7 @@ class Client : public InstanceLocator, private NonCopyable Error AppendUpdateLeaseOptRecord(Message &aMessage); Error AppendSignature(Message &aMessage, Info &aInfo); void UpdateRecordLengthInMessage(Dns::ResourceRecord &aRecord, uint16_t aOffset, Message &aMessage) const; - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void ProcessResponse(Message &aMessage); bool IsResponseMessageIdValid(uint16_t aId) const; void HandleUpdateDone(void); @@ -1074,7 +1074,8 @@ class Client : public InstanceLocator, private NonCopyable static_assert(kMaxTxFailureRetries < 16, "kMaxTxFailureRetries exceed the range of mTxFailureRetryCount (4-bit)"); - using DelayTimer = TimerMilliIn; + using DelayTimer = TimerMilliIn; + using ClientSocket = Ip6::Udp::SocketIn; State mState; uint8_t mTxFailureRetryCount : 4; @@ -1097,7 +1098,7 @@ class Client : public InstanceLocator, private NonCopyable uint32_t mDefaultLease; uint32_t mDefaultKeyLease; - Ip6::Udp::Socket mSocket; + ClientSocket mSocket; Callback mCallback; const char *mDomainName; diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index b3ea87b5d..7fafba1d9 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -86,7 +86,7 @@ static Dns::UpdateHeader::Response ErrorToDnsResponseCode(Error aError) Server::Server(Instance &aInstance) : InstanceLocator(aInstance) - , mSocket(aInstance) + , mSocket(aInstance, *this) , mLeaseTimer(aInstance) , mOutstandingUpdatesTimer(aInstance) , mCompletedUpdateTask(aInstance) @@ -668,7 +668,7 @@ Error Server::PrepareSocket(void) #endif VerifyOrExit(!mSocket.IsOpen()); - SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this)); + SuccessOrExit(error = mSocket.Open()); error = mSocket.Bind(mPort, Ip6::kNetifThread); exit: @@ -1561,11 +1561,6 @@ void Server::SendResponse(const Dns::UpdateHeader &aHeader, FreeMessageOnError(response, error); } -void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); -} - void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { Error error = ProcessMessage(aMessage, aMessageInfo); diff --git a/src/core/net/srp_server.hpp b/src/core/net/srp_server.hpp index ebe67d8fe..48c9780a3 100644 --- a/src/core/net/srp_server.hpp +++ b/src/core/net/srp_server.hpp @@ -1034,7 +1034,6 @@ class Server : public InstanceLocator, private NonCopyable uint32_t aKeyLease, bool mUseShortLeaseOption, const Ip6::MessageInfo &aMessageInfo); - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void HandleLeaseTimer(void); static void HandleOutstandingUpdatesTimer(Timer &aTimer); @@ -1050,8 +1049,9 @@ class Server : public InstanceLocator, private NonCopyable using LeaseTimer = TimerMilliIn; using UpdateTimer = TimerMilliIn; using CompletedUpdatesTask = TaskletIn; + using ServerSocket = Ip6::Udp::SocketIn; - Ip6::Udp::Socket mSocket; + ServerSocket mSocket; Callback mServiceUpdateHandler; diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp index 05ba27bc9..5fd34b266 100644 --- a/src/core/net/udp6.cpp +++ b/src/core/net/udp6.cpp @@ -47,6 +47,9 @@ namespace ot { namespace Ip6 { +//--------------------------------------------------------------------------------------------------------------------- +// Udp::SocketHandle + bool Udp::SocketHandle::Matches(const MessageInfo &aMessageInfo) const { bool matches = false; @@ -71,10 +74,15 @@ bool Udp::SocketHandle::Matches(const MessageInfo &aMessageInfo) const return matches; } -Udp::Socket::Socket(Instance &aInstance) +//--------------------------------------------------------------------------------------------------------------------- +// Udp::Socket + +Udp::Socket::Socket(Instance &aInstance, ReceiveHandler aHandler, void *aContext) : InstanceLocator(aInstance) { Clear(); + mHandler = aHandler; + mContext = aContext; } Message *Udp::Socket::NewMessage(void) { return NewMessage(0); } @@ -86,7 +94,7 @@ Message *Udp::Socket::NewMessage(uint16_t aReserved, const Message::Settings &aS return Get().NewMessage(aReserved, aSettings); } -Error Udp::Socket::Open(otUdpReceive aHandler, void *aContext) { return Get().Open(*this, aHandler, aContext); } +Error Udp::Socket::Open(void) { return Get().Open(*this, mHandler, mContext); } bool Udp::Socket::IsOpen(void) const { return Get().IsOpen(*this); } @@ -147,6 +155,9 @@ Error Udp::Socket::LeaveNetifMulticastGroup(NetifIdentifier aNetifIdentifier, co } #endif +//--------------------------------------------------------------------------------------------------------------------- +// Udp + Udp::Udp(Instance &aInstance) : InstanceLocator(aInstance) , mEphemeralPort(kDynamicPortMin) @@ -169,7 +180,7 @@ Error Udp::RemoveReceiver(Receiver &aReceiver) return error; } -Error Udp::Open(SocketHandle &aSocket, otUdpReceive aHandler, void *aContext) +Error Udp::Open(SocketHandle &aSocket, ReceiveHandler aHandler, void *aContext) { Error error = kErrorNone; diff --git a/src/core/net/udp6.hpp b/src/core/net/udp6.hpp index 24e706607..73d7429fc 100644 --- a/src/core/net/udp6.hpp +++ b/src/core/net/udp6.hpp @@ -84,6 +84,8 @@ enum NetifIdentifier : uint8_t class Udp : public InstanceLocator, private NonCopyable { public: + typedef otUdpReceive ReceiveHandler; ///< Receive handler callback. + /** * Implements a UDP/IPv6 socket. * @@ -157,9 +159,11 @@ class Udp : public InstanceLocator, private NonCopyable * Initializes the object. * * @param[in] aInstance A reference to OpenThread instance. + * @param[in] aHandler A pointer to a function that is called when receiving UDP messages. + * @param[in] aContext A pointer to arbitrary context information. * */ - explicit Socket(Instance &aInstance); + Socket(Instance &aInstance, ReceiveHandler aHandler, void *aContext); /** * Returns a new UDP message with default settings (link security enabled and `kPriorityNormal`) @@ -193,14 +197,11 @@ class Udp : public InstanceLocator, private NonCopyable /** * Opens the UDP socket. * - * @param[in] aHandler A pointer to a function that is called when receiving UDP messages. - * @param[in] aContext A pointer to arbitrary context information. - * * @retval kErrorNone Successfully opened the socket. * @retval kErrorFailed Failed to open the socket. * */ - Error Open(otUdpReceive aHandler, void *aContext); + Error Open(void); /** * Returns if the UDP socket is open. @@ -324,6 +325,36 @@ class Udp : public InstanceLocator, private NonCopyable #endif }; + /** + * A socket owned by a specific type with a given owner type as the callback. + * + * @tparam Owner The type of the owner of this socket. + * @tparam HandleUdpReceivePtr A pointer to a non-static member method of `Owner` to handle received messages. + * + */ + template + class SocketIn : public Socket + { + public: + /** + * Initializes the socket. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aOnwer The owner of the socket, providing the `HandleUdpReceivePtr` callback. + * + */ + explicit SocketIn(Instance &aInstance, Owner &aOwner) + : Socket(aInstance, HandleUdpReceive, &aOwner) + { + } + + private: + static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) + { + (reinterpret_cast(aContext)->*HandleUdpReceivePtr)(AsCoreType(aMessage), AsCoreType(aMessageInfo)); + } + }; + /** * Implements a UDP receiver. * @@ -480,7 +511,7 @@ class Udp : public InstanceLocator, private NonCopyable * @retval kErrorFailed Failed to open the socket. * */ - Error Open(SocketHandle &aSocket, otUdpReceive aHandler, void *aContext); + Error Open(SocketHandle &aSocket, ReceiveHandler aHandler, void *aContext); /** * Returns if a UDP socket is open. diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 57b1beff9..7b78baf74 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -106,7 +106,7 @@ Mle::Mle(Instance &aInstance) #endif , mAlternateTimestamp(0) , mNeighborTable(aInstance) - , mSocket(aInstance) + , mSocket(aInstance, *this) #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE , mParentSearch(aInstance) #endif @@ -150,7 +150,7 @@ Error Mle::Enable(void) Error error = kErrorNone; UpdateLinkLocalAddress(); - SuccessOrExit(error = mSocket.Open(&Mle::HandleUdpReceive, this)); + SuccessOrExit(error = mSocket.Open()); SuccessOrExit(error = mSocket.Bind(kUdpPort)); #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE @@ -2390,11 +2390,6 @@ Error Mle::ProcessMessageSecurity(Crypto::AesCcm::Mode aMode, return error; } -void Mle::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); -} - void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { Error error = kErrorNone; diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index d920e95fa..85d1207cc 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1222,9 +1222,6 @@ class Mle : public InstanceLocator, private NonCopyable //------------------------------------------------------------------------------------------------------------------ // Methods - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - static void HandleDetachGracefullyTimer(Timer &aTimer); - Error Start(StartMode aMode); void Stop(StopMode aMode); TxMessage *NewMleMessage(Command aCommand); @@ -1364,6 +1361,7 @@ class Mle : public InstanceLocator, private NonCopyable using AttachTimer = TimerMilliIn; using DelayTimer = TimerMilliIn; using MsgTxTimer = TimerMilliIn; + using MleSocket = Ip6::Udp::SocketIn; static const otMeshLocalPrefix kMeshLocalPrefixInit; @@ -1407,14 +1405,14 @@ class Mle : public InstanceLocator, private NonCopyable uint64_t mLastUpdatedTimestamp; #endif - LeaderData mLeaderData; - Parent mParent; - NeighborTable mNeighborTable; - MessageQueue mDelayedResponses; - TxChallenge mParentRequestChallenge; - ParentCandidate mParentCandidate; - Ip6::Udp::Socket mSocket; - Counters mCounters; + LeaderData mLeaderData; + Parent mParent; + NeighborTable mNeighborTable; + MessageQueue mDelayedResponses; + TxChallenge mParentRequestChallenge; + ParentCandidate mParentCandidate; + MleSocket mSocket; + Counters mCounters; #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE ParentSearch mParentSearch; #endif diff --git a/tests/unit/test_srp_server.cpp b/tests/unit/test_srp_server.cpp index 15bcdc104..f0218e004 100644 --- a/tests/unit/test_srp_server.cpp +++ b/tests/unit/test_srp_server.cpp @@ -1068,7 +1068,7 @@ void TestSrpClientDelayedResponse(void) //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Prepare a socket to act as SRP server. - Ip6::Udp::Socket udpSocket(*sInstance); + Ip6::Udp::Socket udpSocket(*sInstance, HandleServerUdpReceive, nullptr); Ip6::SockAddr serverSockAddr; uint16_t firstMsgId; Message *response; @@ -1076,7 +1076,7 @@ void TestSrpClientDelayedResponse(void) sServerRxCount = 0; - SuccessOrQuit(udpSocket.Open(HandleServerUdpReceive, nullptr)); + SuccessOrQuit(udpSocket.Open()); SuccessOrQuit(udpSocket.Bind(kServerPort, Ip6::kNetifThread)); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From fad66e272a92247d355c665afc3a40cef1977481 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Tue, 18 Jun 2024 23:30:35 +0800 Subject: [PATCH 32/65] [posix] add OT sys API to get the spinel driver (#10393) --- src/lib/spinel/spinel_driver.hpp | 10 +++++++++- .../include/openthread/openthread-system.h | 17 +++++++++++++++++ src/posix/platform/system.cpp | 3 +++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/lib/spinel/spinel_driver.hpp b/src/lib/spinel/spinel_driver.hpp index 1f45bc719..5a3090c83 100644 --- a/src/lib/spinel/spinel_driver.hpp +++ b/src/lib/spinel/spinel_driver.hpp @@ -36,6 +36,14 @@ #include "lib/spinel/spinel.h" #include "lib/spinel/spinel_interface.hpp" +/** + * Represents an opaque (and empty) type corresponding to a SpinelDriver object. + * + */ +struct otSpinelDriver +{ +}; + namespace ot { namespace Spinel { @@ -49,7 +57,7 @@ static constexpr uint8_t kSpinelHeaderMaxNumIid = 4; static constexpr uint8_t kSpinelHeaderMaxNumIid = 1; #endif -class SpinelDriver : public Logger +class SpinelDriver : public otSpinelDriver, public Logger { public: typedef void ( diff --git a/src/posix/platform/include/openthread/openthread-system.h b/src/posix/platform/include/openthread/openthread-system.h index 460016e45..3c72ad0b5 100644 --- a/src/posix/platform/include/openthread/openthread-system.h +++ b/src/posix/platform/include/openthread/openthread-system.h @@ -97,6 +97,23 @@ typedef struct otPlatformConfig ///< the type to the app layer. } otPlatformConfig; +/** + * Represents the platform spinel driver structure. + * + */ +typedef struct otSpinelDriver otSpinelDriver; + +/** + * Gets the instance of the spinel driver; + * + * @note This API is used for external projects to get the instance of `SpinelDriver` to customize + * different spinel handlings. + * + * @returns A pointer to the spinel driver instance. + * + */ +otSpinelDriver *otSysGetSpinelDriver(void); + /** * Initializes the co-processor and the spinel driver. * diff --git a/src/posix/platform/system.cpp b/src/posix/platform/system.cpp index 8de729c4a..89da6af13 100644 --- a/src/posix/platform/system.cpp +++ b/src/posix/platform/system.cpp @@ -57,6 +57,7 @@ #include "posix/platform/mainloop.hpp" #include "posix/platform/mdns_socket.hpp" #include "posix/platform/radio_url.hpp" +#include "posix/platform/spinel_driver_getter.hpp" #include "posix/platform/udp.hpp" otInstance *gInstance = nullptr; @@ -258,6 +259,8 @@ CoprocessorType otSysInitCoprocessor(otPlatformCoprocessorUrls *aUrls) return sCoprocessorType; } +otSpinelDriver *otSysGetSpinelDriver(void) { return &ot::Posix::GetSpinelDriver(); } + otInstance *otSysInit(otPlatformConfig *aPlatformConfig) { OT_ASSERT(gInstance == nullptr); From a46786b0e878173c72c3c52c358219c589c936fe Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Tue, 18 Jun 2024 18:17:11 +0200 Subject: [PATCH 33/65] [cli] `udp bind` doc update to clarify that multicast address cannot be used as argument (#10370) --- src/cli/README_UDP.md | 4 +++- src/cli/cli_udp.cpp | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cli/README_UDP.md b/src/cli/README_UDP.md index 720aa880f..7c365ee96 100644 --- a/src/cli/README_UDP.md +++ b/src/cli/README_UDP.md @@ -71,7 +71,7 @@ Assigns a name (i.e. IPv6 address and port) to the example socket. - not specified: Thread network interface. - `-u`: unspecified network interface. - `-b`: Backbone network interface. -- ip: the IPv6 address or the unspecified IPv6 address (`::`). +- ip: the unicast IPv6 address or the unspecified IPv6 address (`::`). - port: the UDP port ```bash @@ -83,6 +83,8 @@ Done Done ``` +> Note: to receive datagrams sent to a multicast IPv6 address, the unspecified IPv6 address must be used. Using a multicast address for the \ argument is not supported. Also, the node must subscribe to the multicast group using `ipmaddr add` before it can receive UDP multicast. + ### close Closes the example socket. diff --git a/src/cli/cli_udp.cpp b/src/cli/cli_udp.cpp index fba14f1c0..257b188ab 100644 --- a/src/cli/cli_udp.cpp +++ b/src/cli/cli_udp.cpp @@ -70,9 +70,9 @@ UdpExample::UdpExample(otInstance *aInstance, OutputImplementer &aOutputImplemen * - `-u`: Unspecified network interface, which means that the UDP/IPv6 stack determines which * network interface to bind the socket to. * - `-b`: Backbone network interface is used. - * - `ip`: IPv6 address to bind to. If you wish to have the UDP/IPv6 stack assign the binding - * IPv6 address, then you can use the following value to use the unspecified - * IPv6 address: `::`. Each example uses the unspecified IPv6 address. + * - `ip`: Unicast IPv6 address to bind to. If you wish to have the UDP/IPv6 stack assign the binding + * IPv6 address, or if you wish to bind to multicast IPv6 addresses, then you can use the following + * value to use the unspecified IPv6 address: `::`. Each example uses the unspecified IPv6 address. * - `port`: UDP port number to bind to. Each of the examples is using port number 1234. * @par * Assigns an IPv6 address and a port to an open socket, which binds the socket for communication. From fc0646c6ebba0a1420579ffaccdcf539f5bfa77c Mon Sep 17 00:00:00 2001 From: Li Cao Date: Wed, 19 Jun 2024 01:38:59 +0800 Subject: [PATCH 34/65] [simulation] fix tiny issue of infra if (#10402) --- examples/platforms/simulation/infra_if.c | 2 +- examples/platforms/simulation/system.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/platforms/simulation/infra_if.c b/examples/platforms/simulation/infra_if.c index ccb5e9be7..e8db5f84f 100644 --- a/examples/platforms/simulation/infra_if.c +++ b/examples/platforms/simulation/infra_if.c @@ -335,4 +335,4 @@ OT_TOOL_WEAK void otPlatInfraIfRecvIcmp6Nd(otInstance *aInstance, exit(1); } -#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE +#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && !OPENTHREAD_RADIO diff --git a/examples/platforms/simulation/system.c b/examples/platforms/simulation/system.c index 0b0033f8a..772681393 100644 --- a/examples/platforms/simulation/system.c +++ b/examples/platforms/simulation/system.c @@ -215,7 +215,7 @@ void otSysDeinit(void) platformTrelDeinit(); #endif #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE - // platformInfrIfDeinit(); + platformInfraIfDeinit(); #endif platformLoggingDeinit(); } From 4e8f3c06c1cce216070d821cca91b38be150d2c8 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Wed, 19 Jun 2024 01:47:14 +0800 Subject: [PATCH 35/65] [posix] check whether the RCP support specified Spinel properties (#10387) This commit calls RadioSpinel `Set()`, `Get()`, `Insert()` and `Remove()` functions to check if the RCP supports specified Spinel properties. --- src/posix/platform/rcp_caps_diag.cpp | 399 +++++++++++++++++++++++++-- src/posix/platform/rcp_caps_diag.hpp | 2 +- 2 files changed, 381 insertions(+), 20 deletions(-) diff --git a/src/posix/platform/rcp_caps_diag.cpp b/src/posix/platform/rcp_caps_diag.cpp index 79959b210..e9b9517c8 100644 --- a/src/posix/platform/rcp_caps_diag.cpp +++ b/src/posix/platform/rcp_caps_diag.cpp @@ -37,11 +37,44 @@ namespace Posix { aCategory, aCommand, aKey, &RcpCapsDiag::HandleSpinelCommand \ } -template <> otError RcpCapsDiag::HandleSpinelCommand(void) +template <> otError RcpCapsDiag::HandleSpinelCommand(void) { - int8_t ccaThreshold; + static constexpr uint8_t kCapsBufferSize = 100; + uint8_t capsBuffer[kCapsBufferSize]; + spinel_size_t capsLength = sizeof(capsBuffer); + + return mRadioSpinel.Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + unsigned int versionMajor; + unsigned int versionMinor; + + return mRadioSpinel.Get(SPINEL_PROP_PROTOCOL_VERSION, (SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S), + &versionMajor, &versionMinor); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + unsigned int radioCaps; + + return mRadioSpinel.Get(SPINEL_PROP_RADIO_CAPS, SPINEL_DATATYPE_UINT_PACKED_S, &radioCaps); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + unsigned int rcpApiVersion; + + return mRadioSpinel.Get(SPINEL_PROP_RCP_API_VERSION, SPINEL_DATATYPE_UINT_PACKED_S, &rcpApiVersion); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint16_t kVersionStringSize = 128; + char mVersion[kVersionStringSize]; - return mRadioSpinel.GetCcaEnergyDetectThreshold(ccaThreshold); + return mRadioSpinel.Get(SPINEL_PROP_NCP_VERSION, SPINEL_DATATYPE_UTF8_S, mVersion, sizeof(mVersion)); } template <> otError RcpCapsDiag::HandleSpinelCommand(void) @@ -51,39 +84,367 @@ template <> otError RcpCapsDiag::HandleSpinelCommand otError RcpCapsDiag::HandleSpinelCommand(void) +template <> otError RcpCapsDiag::HandleSpinelCommand(void) { - static constexpr uint8_t kCapsBufferSize = 100; - uint8_t capsBuffer[kCapsBufferSize]; - spinel_size_t capsLength = sizeof(capsBuffer); + return mRadioSpinel.Set(SPINEL_PROP_PHY_ENABLED, SPINEL_DATATYPE_BOOL_S, true /* aEnable*/); +} - return mRadioSpinel.Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength); +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint16_t kPanId = 0x1234; + + return mRadioSpinel.SetPanId(kPanId); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr otExtAddress kExtAddress = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}; + + return mRadioSpinel.Set(SPINEL_PROP_MAC_15_4_LADDR, SPINEL_DATATYPE_EUI64_S, kExtAddress.m8); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint16_t kShortAddress = 0x1100; + + return mRadioSpinel.Set(SPINEL_PROP_MAC_15_4_SADDR, SPINEL_DATATYPE_UINT16_S, kShortAddress); +} + +template <> +otError RcpCapsDiag::HandleSpinelCommand(void) +{ + return mRadioSpinel.Set(SPINEL_PROP_MAC_RAW_STREAM_ENABLED, SPINEL_DATATYPE_BOOL_S, true); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint8_t kScanChannel = 20; + + return mRadioSpinel.Set(SPINEL_PROP_MAC_SCAN_MASK, SPINEL_DATATYPE_DATA_S, &kScanChannel, sizeof(uint8_t)); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint16_t kScanDuration = 1; + + return mRadioSpinel.Set(SPINEL_PROP_MAC_SCAN_PERIOD, SPINEL_DATATYPE_UINT16_S, kScanDuration); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + return mRadioSpinel.Set(SPINEL_PROP_MAC_SCAN_STATE, SPINEL_DATATYPE_UINT8_S, SPINEL_SCAN_STATE_ENERGY); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + return mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_ENABLED, SPINEL_DATATYPE_BOOL_S, true); +} + +template <> +otError RcpCapsDiag::HandleSpinelCommand(void) +{ + return mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, nullptr); +} + +template <> +otError RcpCapsDiag::HandleSpinelCommand(void) +{ + return mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, nullptr); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + otExtAddress ieeeEui64; + + return mRadioSpinel.Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_EUI64_S, ieeeEui64.m8); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint8_t kChannelMaskBufferSize = 32; + uint8_t maskBuffer[kChannelMaskBufferSize]; + spinel_size_t maskLength = sizeof(maskBuffer); + + return mRadioSpinel.Get(SPINEL_PROP_PHY_CHAN_PREFERRED, SPINEL_DATATYPE_DATA_S, maskBuffer, &maskLength); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint8_t kChannelMaskBufferSize = 32; + uint8_t maskBuffer[kChannelMaskBufferSize]; + spinel_size_t maskLength = sizeof(maskBuffer); + + return mRadioSpinel.Get(SPINEL_PROP_PHY_CHAN_SUPPORTED, SPINEL_DATATYPE_DATA_S, maskBuffer, &maskLength); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + int8_t rssi; + + return mRadioSpinel.Get(SPINEL_PROP_PHY_RSSI, SPINEL_DATATYPE_INT8_S, &rssi); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + int8_t rxSensitivity; + + return mRadioSpinel.Get(SPINEL_PROP_PHY_RX_SENSITIVITY, SPINEL_DATATYPE_INT8_S, &rxSensitivity); +} + +template <> +otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint16_t kShortAddress = 0x1122; + + return mRadioSpinel.Insert(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, SPINEL_DATATYPE_UINT16_S, kShortAddress); +} + +template <> +otError RcpCapsDiag::HandleSpinelCommand( + void) +{ + static constexpr otExtAddress kExtAddress = {{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}}; + + return mRadioSpinel.Insert(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, SPINEL_DATATYPE_EUI64_S, kExtAddress.m8); +} + +template <> +otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint16_t kShortAddress = 0x1122; + + return mRadioSpinel.Remove(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, SPINEL_DATATYPE_UINT16_S, kShortAddress); +} + +template <> +otError RcpCapsDiag::HandleSpinelCommand( + void) +{ + static constexpr otExtAddress extAddress = {{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}}; + + return mRadioSpinel.Remove(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, SPINEL_DATATYPE_EUI64_S, extAddress.m8); } template <> otError RcpCapsDiag::HandleSpinelCommand(void) { - uint16_t shortAddress = 0x1122; - otExtAddress extAddress = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; - uint8_t flags = SPINEL_THREAD_LINK_METRIC_PDU_COUNT | SPINEL_THREAD_LINK_METRIC_LQI | - SPINEL_THREAD_LINK_METRIC_LINK_MARGIN | SPINEL_THREAD_LINK_METRIC_RSSI; + static constexpr uint16_t kShortAddress = 0x1122; + static constexpr otExtAddress kExtAddress = {{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}}; + static constexpr uint8_t kFlags = SPINEL_THREAD_LINK_METRIC_PDU_COUNT | SPINEL_THREAD_LINK_METRIC_LQI | + SPINEL_THREAD_LINK_METRIC_LINK_MARGIN | SPINEL_THREAD_LINK_METRIC_RSSI; return mRadioSpinel.Set(SPINEL_PROP_RCP_ENH_ACK_PROBING, - SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_UINT8_S, shortAddress, - extAddress.m8, flags); + SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_UINT8_S, kShortAddress, + kExtAddress.m8, kFlags); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint32_t kMacFrameCounter = 1; + + return mRadioSpinel.Set(SPINEL_PROP_RCP_MAC_FRAME_COUNTER, SPINEL_DATATYPE_UINT32_S SPINEL_DATATYPE_BOOL_S, + kMacFrameCounter, true /*aSetIfLarger*/); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint8_t keyIdMode1 = 1 << 3; + static constexpr uint8_t keyId = 100; + otMacKeyMaterial prevKey; + otMacKeyMaterial curKey; + otMacKeyMaterial nextKey; + + memset(prevKey.mKeyMaterial.mKey.m8, 0x11, OT_MAC_KEY_SIZE); + memset(curKey.mKeyMaterial.mKey.m8, 0x22, OT_MAC_KEY_SIZE); + memset(nextKey.mKeyMaterial.mKey.m8, 0x33, OT_MAC_KEY_SIZE); + return mRadioSpinel.SetMacKey(keyIdMode1, keyId, &prevKey, &curKey, &nextKey); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + uint8_t accuracy; + + return mRadioSpinel.Get(SPINEL_PROP_RCP_CSL_ACCURACY, SPINEL_DATATYPE_UINT8_S, &accuracy); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + uint8_t uncertainty; + + return mRadioSpinel.Get(SPINEL_PROP_RCP_CSL_UNCERTAINTY, SPINEL_DATATYPE_UINT8_S, &uncertainty); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + uint64_t remoteTimestamp = 0; + uint8_t buffer[sizeof(remoteTimestamp)]; + spinel_ssize_t packed; + + packed = spinel_datatype_pack(buffer, sizeof(buffer), SPINEL_DATATYPE_UINT64_S, remoteTimestamp); + return mRadioSpinel.GetWithParam(SPINEL_PROP_RCP_TIMESTAMP, buffer, static_cast(packed), + SPINEL_DATATYPE_UINT64_S, &remoteTimestamp); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + return mRadioSpinel.SetPromiscuous(false /* aEnable*/); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + int8_t ccaThreshold; + + return mRadioSpinel.Get(SPINEL_PROP_PHY_CCA_THRESHOLD, SPINEL_DATATYPE_INT8_S, &ccaThreshold); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + int8_t gain; + + return mRadioSpinel.Get(SPINEL_PROP_PHY_FEM_LNA_GAIN, SPINEL_DATATYPE_INT8_S, &gain); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + uint16_t regionCode; + + return mRadioSpinel.Get(SPINEL_PROP_PHY_REGION_CODE, SPINEL_DATATYPE_UINT16_S, ®ionCode); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + int8_t power; + + return mRadioSpinel.Get(SPINEL_PROP_PHY_TX_POWER, SPINEL_DATATYPE_INT8_S, &power); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + bool enabled; + + return mRadioSpinel.Get(SPINEL_PROP_RADIO_COEX_ENABLE, SPINEL_DATATYPE_BOOL_S, &enabled); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + otRadioCoexMetrics coexMetrics; + + return mRadioSpinel.GetCoexMetrics(coexMetrics); +} + +template <> +otError RcpCapsDiag::HandleSpinelCommand(void) +{ + unsigned int minHostRcpApiVersion; + + return mRadioSpinel.Get(SPINEL_PROP_RCP_MIN_HOST_API_VERSION, SPINEL_DATATYPE_UINT_PACKED_S, &minHostRcpApiVersion); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr int8_t kCcaThreshold = -75; + + return mRadioSpinel.Set(SPINEL_PROP_PHY_CCA_THRESHOLD, SPINEL_DATATYPE_INT8_S, kCcaThreshold); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint8_t kChannel = 20; + static constexpr uint8_t kMaxPower = 10; + + return mRadioSpinel.Set(SPINEL_PROP_PHY_CHAN_MAX_POWER, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT8_S, kChannel, + kMaxPower); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint8_t kChannel = 20; + static constexpr uint16_t kTargetPower = 1000; + + return mRadioSpinel.Set(SPINEL_PROP_PHY_CHAN_TARGET_POWER, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S, + kChannel, kTargetPower); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr int8_t kFemLnaGain = 0; + + return mRadioSpinel.Set(SPINEL_PROP_PHY_FEM_LNA_GAIN, SPINEL_DATATYPE_INT8_S, kFemLnaGain); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr uint16_t kRegionCode = 0x5757; + + return mRadioSpinel.Set(SPINEL_PROP_PHY_REGION_CODE, SPINEL_DATATYPE_UINT16_S, kRegionCode); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + static constexpr int8_t kTransmitPower = 10; + + return mRadioSpinel.Set(SPINEL_PROP_PHY_TX_POWER, SPINEL_DATATYPE_INT8_S, kTransmitPower); +} + +template <> otError RcpCapsDiag::HandleSpinelCommand(void) +{ + return mRadioSpinel.Set(SPINEL_PROP_RADIO_COEX_ENABLE, SPINEL_DATATYPE_BOOL_S, true /* aEnabled*/); } const struct RcpCapsDiag::SpinelEntry RcpCapsDiag::sSpinelEntries[] = { // Basic Spinel commands SPINEL_ENTRY(kCategoryBasic, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_CAPS), + SPINEL_ENTRY(kCategoryBasic, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PROTOCOL_VERSION), + SPINEL_ENTRY(kCategoryBasic, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_RADIO_CAPS), + SPINEL_ENTRY(kCategoryBasic, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_RCP_API_VERSION), + SPINEL_ENTRY(kCategoryBasic, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_NCP_VERSION), // Thread Version >= 1.1 SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_PHY_CHAN), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_PHY_ENABLED), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_15_4_PANID), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_15_4_LADDR), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_15_4_SADDR), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_RAW_STREAM_ENABLED), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_SCAN_MASK), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_SCAN_PERIOD), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_SCAN_STATE), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_SRC_MATCH_ENABLED), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_HWADDR), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_CHAN_PREFERRED), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_CHAN_SUPPORTED), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_RSSI), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_RX_SENSITIVITY), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_INSERT, SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_INSERT, SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_REMOVE, SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES), + SPINEL_ENTRY(kCategoryThread1_1, SPINEL_CMD_PROP_VALUE_REMOVE, SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES), // Thread Version >= 1.2 SPINEL_ENTRY(kCategoryThread1_2, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_RCP_ENH_ACK_PROBING), - - // Optional Spinel commands - SPINEL_ENTRY(kCategoryOptional, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_CCA_THRESHOLD), + SPINEL_ENTRY(kCategoryThread1_2, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_RCP_MAC_FRAME_COUNTER), + SPINEL_ENTRY(kCategoryThread1_2, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_RCP_MAC_KEY), + SPINEL_ENTRY(kCategoryThread1_2, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_RCP_CSL_ACCURACY), + SPINEL_ENTRY(kCategoryThread1_2, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_RCP_CSL_UNCERTAINTY), + SPINEL_ENTRY(kCategoryThread1_2, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_RCP_TIMESTAMP), + + // Utils + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_MAC_PROMISCUOUS_MODE), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_CCA_THRESHOLD), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_FEM_LNA_GAIN), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_REGION_CODE), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_TX_POWER), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_RADIO_COEX_ENABLE), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_RADIO_COEX_METRICS), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_RCP_MIN_HOST_API_VERSION), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_PHY_CCA_THRESHOLD), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_PHY_CHAN_MAX_POWER), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_PHY_CHAN_TARGET_POWER), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_PHY_FEM_LNA_GAIN), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_PHY_REGION_CODE), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_PHY_TX_POWER), + SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_RADIO_COEX_ENABLE), }; otError RcpCapsDiag::DiagProcess(char *aArgs[], uint8_t aArgsLength, char *aOutput, size_t aOutputMaxLen) @@ -175,13 +536,13 @@ const char *RcpCapsDiag::CategoryToString(Category aCategory) "Basic", // (0) kCategoryBasic "Thread Version >= 1.1", // (1) kCategoryThread1_1 "Thread Version >= 1.2", // (2) kCategoryThread1_2 - "Optional", // (3) kCategoryOptional + "Utils", // (3) kCategoryUtils }; static_assert(kCategoryBasic == 0, "kCategoryBasic value is incorrect"); static_assert(kCategoryThread1_1 == 1, "kCategoryThread1_1 value is incorrect"); static_assert(kCategoryThread1_2 == 2, "kCategoryThread1_2 value is incorrect"); - static_assert(kCategoryOptional == 3, "kCategoryOptional value is incorrect"); + static_assert(kCategoryUtils == 3, "kCategoryUtils value is incorrect"); return (aCategory < OT_ARRAY_LENGTH(kCategoryStrings)) ? kCategoryStrings[aCategory] : "invalid"; } diff --git a/src/posix/platform/rcp_caps_diag.hpp b/src/posix/platform/rcp_caps_diag.hpp index 401c0e72f..1b01f098e 100644 --- a/src/posix/platform/rcp_caps_diag.hpp +++ b/src/posix/platform/rcp_caps_diag.hpp @@ -87,7 +87,7 @@ class RcpCapsDiag kCategoryBasic, kCategoryThread1_1, kCategoryThread1_2, - kCategoryOptional, + kCategoryUtils, kNumCategories, }; From 4978e58e5c4fe3495aa23184f5ffedb8dd3da648 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Thu, 20 Jun 2024 07:40:17 +0800 Subject: [PATCH 36/65] [otci] add ADB USB connection support for OTCI (#10406) --- tools/otci/otci/__init__.py | 6 +++-- tools/otci/otci/command_handlers.py | 41 ++++++++++++++++++++++------- tools/otci/otci/otci.py | 11 +++++--- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/tools/otci/otci/__init__.py b/tools/otci/otci/__init__.py index 7cb0aa45b..eed56c615 100644 --- a/tools/otci/otci/__init__.py +++ b/tools/otci/otci/__init__.py @@ -37,7 +37,8 @@ connect_ncp_sim, \ connect_cmd_handler, \ connect_otbr_ssh, \ - connect_otbr_adb + connect_otbr_adb_tcp, \ + connect_otbr_adb_usb from .types import Rloc16, ChildId, NetifIdentifier @@ -46,7 +47,8 @@ 'connect_cli_serial', 'connect_ncp_sim', 'connect_otbr_ssh', - 'connect_otbr_adb', + 'connect_otbr_adb_tcp', + 'connect_otbr_adb_usb', 'connect_cmd_handler', ] diff --git a/tools/otci/otci/command_handlers.py b/tools/otci/otci/command_handlers.py index 7c790e6d8..f5f264c9d 100644 --- a/tools/otci/otci/command_handlers.py +++ b/tools/otci/otci/command_handlers.py @@ -285,19 +285,13 @@ def set_line_read_callback(self, callback: Optional[Callable[[str], Any]]): class OtbrAdbCommandRunner(OTCommandHandler): - def __init__(self, host, port): - from adb_shell.adb_device import AdbDeviceTcp - - self.__host = host - self.__port = port - self.__adb = AdbDeviceTcp(host, port, default_transport_timeout_s=9.0) + from adb_shell.adb_device import AdbDevice + def __init__(self, adb: AdbDevice): + self.__adb = adb self.__line_read_callback = None self.__adb.connect(rsa_keys=None, auth_timeout_s=0.1) - def __repr__(self): - return f'{self.__host}:{self.__port}' - def execute_command(self, cmd: str, timeout: float) -> List[str]: sh_cmd = f'ot-ctl {cmd}' @@ -324,3 +318,32 @@ def wait(self, duration: float) -> List[str]: def set_line_read_callback(self, callback: Optional[Callable[[str], Any]]): self.__line_read_callback = callback + + +class OtbrAdbTcpCommandRunner(OtbrAdbCommandRunner): + + def __init__(self, host: str, port: int): + from adb_shell.adb_device import AdbDeviceTcp + + self.__host = host + self.__port = port + + adb = AdbDeviceTcp(host, port, default_transport_timeout_s=9.0) + super(OtbrAdbTcpCommandRunner, self).__init__(adb) + + def __repr__(self): + return f'{self.__host}:{self.__port}' + + +class OtbrAdbUsbCommandRunner(OtbrAdbCommandRunner): + + def __init__(self, serial: str): + from adb_shell.adb_device import AdbDeviceUsb + + self.__serial = serial + + adb = AdbDeviceUsb(serial, port_path=None, default_transport_timeout_s=9.0) + super(OtbrAdbUsbCommandRunner, self).__init__(adb) + + def __repr__(self): + return f'USB:{self.__serial}' diff --git a/tools/otci/otci/otci.py b/tools/otci/otci/otci.py index 46a73734d..93bb56a67 100644 --- a/tools/otci/otci/otci.py +++ b/tools/otci/otci/otci.py @@ -33,7 +33,7 @@ from typing import Callable, List, Collection, Union, Tuple, Optional, Dict, Pattern, Any from . import connectors -from .command_handlers import OTCommandHandler, OtCliCommandRunner, OtbrSshCommandRunner, OtbrAdbCommandRunner +from .command_handlers import OTCommandHandler, OtCliCommandRunner, OtbrSshCommandRunner, OtbrAdbTcpCommandRunner, OtbrAdbUsbCommandRunner from .connectors import Simulator from .errors import UnexpectedCommandOutput, ExpectLineTimeoutError, CommandError, InvalidArgumentsError from .types import ChildId, Rloc16, Ip6Addr, ThreadState, PartitionId, DeviceMode, RouterId, SecurityPolicy, Ip6Prefix, \ @@ -2503,8 +2503,13 @@ def connect_otbr_ssh(host: str, port: int = 22, username='pi', password='raspber return OTCI(cmd_handler) -def connect_otbr_adb(host: str, port: int = 5555): - cmd_handler = OtbrAdbCommandRunner(host, port) +def connect_otbr_adb_tcp(host: str, port: int = 5555): + cmd_handler = OtbrAdbTcpCommandRunner(host, port) + return OTCI(cmd_handler) + + +def connect_otbr_adb_usb(serial: str): + cmd_handler = OtbrAdbUsbCommandRunner(serial) return OTCI(cmd_handler) From 3345af078040ae6c74693efb3e4b2966eb739bc2 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Thu, 20 Jun 2024 07:41:09 +0800 Subject: [PATCH 37/65] [otci] fix the `setDaemon() is deprecated` warning (#10409) The otci reports warning `DeprecationWarning: setDaemon() is deprecated, set the daemon attribute instead`. This commit updates the otci to fix this warning. --- tools/otci/otci/command_handlers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/otci/otci/command_handlers.py b/tools/otci/otci/command_handlers.py index f5f264c9d..ed08584c6 100644 --- a/tools/otci/otci/command_handlers.py +++ b/tools/otci/otci/command_handlers.py @@ -105,8 +105,7 @@ def __init__(self, otcli: OtCliHandler, is_spinel_cli=False): self.__pending_lines = queue.Queue() self.__should_close = threading.Event() - self.__otcli_reader = threading.Thread(target=self.__otcli_read_routine) - self.__otcli_reader.setDaemon(True) + self.__otcli_reader = threading.Thread(target=self.__otcli_read_routine, daemon=True) self.__otcli_reader.start() def __repr__(self): From e581f074142ea71faa8580b996ce196754ac2a53 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 19 Jun 2024 16:53:29 -0700 Subject: [PATCH 38/65] [ip6] add `Ip6::Address::IsLinkLocalUnicastOrMulticast()` (#10405) This commit adds `IsLinkLocalUnicastOrMulticast()` to `Ip6::Address` to indicate whether the address is either a link-local unicast or a link-local multicast address. The existing `IsLinkLocal()` is renamed to `IsLinkLocalUnicast()` to clarify its purpose and align its name with `IsLinkLocalMulticast()` and the new method. --- src/core/backbone_router/backbone_tmf.cpp | 4 ++-- src/core/net/dnssd_server.cpp | 3 ++- src/core/net/ip6.cpp | 11 ++++++----- src/core/net/ip6_address.cpp | 6 ++++-- src/core/net/ip6_address.hpp | 17 +++++++++++++---- src/core/net/ip6_filter.cpp | 4 +--- src/core/net/netif.cpp | 2 +- src/core/net/srp_advertising_proxy.cpp | 2 +- src/core/net/srp_client.cpp | 2 +- src/core/thread/indirect_sender.cpp | 2 +- src/core/thread/link_metrics.cpp | 2 +- src/core/thread/lowpan.cpp | 4 ++-- src/core/thread/mesh_forwarder.cpp | 4 ++-- src/core/thread/mle.cpp | 4 ++-- src/core/thread/neighbor_table.cpp | 2 +- src/core/thread/network_diagnostic.cpp | 2 +- src/core/thread/tmf.cpp | 4 ++-- src/posix/platform/multicast_routing.cpp | 2 +- 18 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/core/backbone_router/backbone_tmf.cpp b/src/core/backbone_router/backbone_tmf.cpp index d49e31c62..63abcf2e0 100644 --- a/src/core/backbone_router/backbone_tmf.cpp +++ b/src/core/backbone_router/backbone_tmf.cpp @@ -120,8 +120,8 @@ bool BackboneTmfAgent::IsBackboneTmfMessage(const Ip6::MessageInfo &aMessageInfo // 2. All Domain BBRs (Link-Local scope) // 3. A Backbone Link-Local address // The source must be a Backbone Link-local address. - return (Get().IsEnabled() && src.IsLinkLocal() && - (dst.IsLinkLocal() || dst == Get().GetAllNetworkBackboneRoutersAddress() || + return (Get().IsEnabled() && src.IsLinkLocalUnicast() && + (dst.IsLinkLocalUnicast() || dst == Get().GetAllNetworkBackboneRoutersAddress() || dst == Get().GetAllDomainBackboneRoutersAddress())); } diff --git a/src/core/net/dnssd_server.cpp b/src/core/net/dnssd_server.cpp index 10fa87d9f..7d512efc8 100644 --- a/src/core/net/dnssd_server.cpp +++ b/src/core/net/dnssd_server.cpp @@ -2103,7 +2103,8 @@ Error Server::Response::AppendHostAddresses(const ProxyResult &aResult) bool Server::IsProxyAddressValid(const Ip6::Address &aAddress) { - return !aAddress.IsLinkLocal() && !aAddress.IsMulticast() && !aAddress.IsUnspecified() && !aAddress.IsLoopback(); + return !aAddress.IsLinkLocalUnicast() && !aAddress.IsMulticast() && !aAddress.IsUnspecified() && + !aAddress.IsLoopback(); } #endif // OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 5c0aee0ad..a8ce030e4 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -1025,7 +1025,8 @@ Error Ip6::PassToHost(OwnedPtr &aMessagePtr, // than realm-local, set the hop limit to 1 before sending to host, so this packet // will not be forwarded by host. if (aMessageInfo.GetSockAddr().IsMulticastLargerThanRealmLocal() && - (aMessageInfo.GetPeerAddr().IsLinkLocal() || (Get().IsMeshLocalAddress(aMessageInfo.GetPeerAddr())))) + (aMessageInfo.GetPeerAddr().IsLinkLocalUnicast() || + (Get().IsMeshLocalAddress(aMessageInfo.GetPeerAddr())))) { messagePtr->Write(Header::kHopLimitFieldOffset, 1); } @@ -1131,9 +1132,9 @@ Error Ip6::HandleDatagram(OwnedPtr aMessagePtr, bool aIsReassembled) { receive = true; } - else if (!aMessagePtr->IsOriginThreadNetif() || !header.GetDestination().IsLinkLocal()) + else if (!aMessagePtr->IsOriginThreadNetif() || !header.GetDestination().IsLinkLocalUnicast()) { - if (header.GetDestination().IsLinkLocal()) + if (header.GetDestination().IsLinkLocalUnicast()) { forwardThread = true; } @@ -1430,8 +1431,8 @@ void Ip6::UpdateBorderRoutingCounters(const Header &aHeader, uint16_t aMessageLe otPacketsAndBytes *counter = nullptr; otPacketsAndBytes *internetCounter = nullptr; - VerifyOrExit(!aHeader.GetSource().IsLinkLocal()); - VerifyOrExit(!aHeader.GetDestination().IsLinkLocal()); + VerifyOrExit(!aHeader.GetSource().IsLinkLocalUnicast()); + VerifyOrExit(!aHeader.GetDestination().IsLinkLocalUnicast()); VerifyOrExit(aHeader.GetSource().GetPrefix() != Get().GetMeshLocalPrefix()); VerifyOrExit(aHeader.GetDestination().GetPrefix() != Get().GetMeshLocalPrefix()); diff --git a/src/core/net/ip6_address.cpp b/src/core/net/ip6_address.cpp index d82dfb4f1..acd443dae 100644 --- a/src/core/net/ip6_address.cpp +++ b/src/core/net/ip6_address.cpp @@ -343,7 +343,7 @@ bool Address::IsLoopback(void) const mFields.m32[3] == BigEndian::HostSwap32(1)); } -bool Address::IsLinkLocal(void) const +bool Address::IsLinkLocalUnicast(void) const { return (mFields.m16[0] & BigEndian::HostSwap16(0xffc0)) == BigEndian::HostSwap16(0xfe80); } @@ -364,6 +364,8 @@ void Address::SetToLinkLocalAddress(const InterfaceIdentifier &aIid) bool Address::IsLinkLocalMulticast(void) const { return IsMulticast() && (GetScope() == kLinkLocalScope); } +bool Address::IsLinkLocalUnicastOrMulticast(void) const { return IsLinkLocalUnicast() || IsLinkLocalMulticast(); } + bool Address::IsLinkLocalAllNodesMulticast(void) const { return (*this == GetLinkLocalAllNodesMulticast()); } void Address::SetToLinkLocalAllNodesMulticast(void) { *this = GetLinkLocalAllNodesMulticast(); } @@ -458,7 +460,7 @@ uint8_t Address::GetScope(void) const { rval = mFields.m8[1] & 0xf; } - else if (IsLinkLocal()) + else if (IsLinkLocalUnicast()) { rval = kLinkLocalScope; } diff --git a/src/core/net/ip6_address.hpp b/src/core/net/ip6_address.hpp index d7dfe4969..5f06cd66f 100644 --- a/src/core/net/ip6_address.hpp +++ b/src/core/net/ip6_address.hpp @@ -646,13 +646,13 @@ class Address : public otIp6Address, public Equatable
, public Clearable bool IsLoopback(void) const; /** - * Indicates whether or not the IPv6 address scope is Link-Local. + * Indicates whether or not the IPv6 address is a Link-Local unicast address. * - * @retval TRUE If the IPv6 address scope is Link-Local. - * @retval FALSE If the IPv6 address scope is not Link-Local. + * @retval TRUE If the IPv6 address is a Link-Local unicast address. + * @retval FALSE If the IPv6 address is not a Link-Local unicast address. * */ - bool IsLinkLocal(void) const; + bool IsLinkLocalUnicast(void) const; /** * Sets the IPv6 address to a Link-Local address with Interface Identifier generated from a given @@ -689,6 +689,15 @@ class Address : public otIp6Address, public Equatable
, public Clearable */ bool IsLinkLocalMulticast(void) const; + /** + * Indicates whether or not the IPv6 address is a link-local unicast or a link-local multicast address. + * + * @retval TRUE If the IPv6 address is a link-local unicast or multicast address. + * @retval FALSE If the IPv6 address is not a link-local unicast and not a link-local multicast address. + * + */ + bool IsLinkLocalUnicastOrMulticast(void) const; + /** * Indicates whether or not the IPv6 address is a link-local all nodes multicast address (ff02::01). * diff --git a/src/core/net/ip6_filter.cpp b/src/core/net/ip6_filter.cpp index 1dae10c71..81e9c2178 100644 --- a/src/core/net/ip6_filter.cpp +++ b/src/core/net/ip6_filter.cpp @@ -64,9 +64,7 @@ bool Filter::Accept(Message &aMessage) const SuccessOrExit(headers.ParseFrom(aMessage)); - // Allow only link-local unicast or multicast - VerifyOrExit(headers.GetDestinationAddress().IsLinkLocal() || - headers.GetDestinationAddress().IsLinkLocalMulticast()); + VerifyOrExit(headers.GetDestinationAddress().IsLinkLocalUnicastOrMulticast()); // Allow all link-local IPv6 datagrams when Thread is not enabled if (Get().GetRole() == Mle::kRoleDisabled) diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index 27d6f2365..0701436c1 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -453,7 +453,7 @@ Error Netif::AddExternalUnicastAddress(const UnicastAddress &aAddress) ExitNow(); } - VerifyOrExit(!aAddress.GetAddress().IsLinkLocal(), error = kErrorInvalidArgs); + VerifyOrExit(!aAddress.GetAddress().IsLinkLocalUnicast(), error = kErrorInvalidArgs); entry = mExtUnicastAddressPool.Allocate(); VerifyOrExit(entry != nullptr, error = kErrorNoBufs); diff --git a/src/core/net/srp_advertising_proxy.cpp b/src/core/net/srp_advertising_proxy.cpp index c8acc6f70..e8b086cbd 100644 --- a/src/core/net/srp_advertising_proxy.cpp +++ b/src/core/net/srp_advertising_proxy.cpp @@ -944,7 +944,7 @@ void AdvertisingProxy::RegisterHost(Host &aHost) for (const Ip6::Address &address : aHost.mAddresses) { - if (!address.IsLinkLocal() && !Get().IsMeshLocalAddress(address)) + if (!address.IsLinkLocalUnicast() && !Get().IsMeshLocalAddress(address)) { IgnoreError(hostAddresses.PushBack(address)); } diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index 9ac4e72db..ebc28ce51 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -577,7 +577,7 @@ bool Client::ShouldHostAutoAddressRegister(const Ip6::Netif::UnicastAddress &aUn VerifyOrExit(aUnicastAddress.mValid); VerifyOrExit(aUnicastAddress.mPreferred); - VerifyOrExit(!aUnicastAddress.GetAddress().IsLinkLocal()); + VerifyOrExit(!aUnicastAddress.GetAddress().IsLinkLocalUnicast()); VerifyOrExit(!Get().IsMeshLocalAddress(aUnicastAddress.GetAddress())); shouldRegister = true; diff --git a/src/core/thread/indirect_sender.cpp b/src/core/thread/indirect_sender.cpp index 89e886917..4fc4d07c5 100644 --- a/src/core/thread/indirect_sender.cpp +++ b/src/core/thread/indirect_sender.cpp @@ -370,7 +370,7 @@ uint16_t IndirectSender::PrepareDataFrame(Mac::TxFrame &aFrame, Child &aChild, M Get().GetMacSourceAddress(ip6Header.GetSource(), macAddrs.mSource); - if (ip6Header.GetDestination().IsLinkLocal()) + if (ip6Header.GetDestination().IsLinkLocalUnicast()) { Get().GetMacDestinationAddress(ip6Header.GetDestination(), macAddrs.mDestination); } diff --git a/src/core/thread/link_metrics.cpp b/src/core/thread/link_metrics.cpp index 9bf6e9a18..a8936f371 100644 --- a/src/core/thread/link_metrics.cpp +++ b/src/core/thread/link_metrics.cpp @@ -395,7 +395,7 @@ Error Initiator::FindNeighbor(const Ip6::Address &aDestination, Neighbor *&aNeig aNeighbor = nullptr; - VerifyOrExit(aDestination.IsLinkLocal()); + VerifyOrExit(aDestination.IsLinkLocalUnicast()); aDestination.GetIid().ConvertToMacAddress(macAddress); aNeighbor = Get().FindNeighbor(macAddress); diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp index a3d0ef048..3860f7ba0 100644 --- a/src/core/thread/lowpan.cpp +++ b/src/core/thread/lowpan.cpp @@ -345,7 +345,7 @@ Error Lowpan::Compress(Message &aMessage, { hcCtl |= kHcSrcAddrContext; } - else if (ip6Header.GetSource().IsLinkLocal()) + else if (ip6Header.GetSource().IsLinkLocalUnicast()) { SuccessOrExit( error = CompressSourceIid(aMacAddrs.mSource, ip6Header.GetSource(), srcContext, hcCtl, aFrameBuilder)); @@ -366,7 +366,7 @@ Error Lowpan::Compress(Message &aMessage, { SuccessOrExit(error = CompressMulticast(ip6Header.GetDestination(), hcCtl, aFrameBuilder)); } - else if (ip6Header.GetDestination().IsLinkLocal()) + else if (ip6Header.GetDestination().IsLinkLocalUnicast()) { SuccessOrExit(error = CompressDestinationIid(aMacAddrs.mDestination, ip6Header.GetDestination(), dstContext, hcCtl, aFrameBuilder)); diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 4b5b4b20a..932e6d2f0 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -670,7 +670,7 @@ Error MeshForwarder::UpdateIp6Route(Message &aMessage) if (mle.IsDisabled() || mle.IsDetached()) { - if (ip6Header.GetDestination().IsLinkLocal() || ip6Header.GetDestination().IsLinkLocalMulticast()) + if (ip6Header.GetDestination().IsLinkLocalUnicastOrMulticast()) { GetMacDestinationAddress(ip6Header.GetDestination(), mMacAddrs.mDestination); } @@ -697,7 +697,7 @@ Error MeshForwarder::UpdateIp6Route(Message &aMessage) mMacAddrs.mDestination.SetShort(Mac::kShortAddrBroadcast); } } - else if (ip6Header.GetDestination().IsLinkLocal()) + else if (ip6Header.GetDestination().IsLinkLocalUnicast()) { GetMacDestinationAddress(ip6Header.GetDestination(), mMacAddrs.mDestination); } diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 7b78baf74..157dac149 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1032,7 +1032,7 @@ bool Mle::HasUnregisteredAddress(void) for (const Ip6::Netif::UnicastAddress &addr : Get().GetUnicastAddresses()) { - if (!addr.GetAddress().IsLinkLocal() && !IsRoutingLocator(addr.GetAddress()) && + if (!addr.GetAddress().IsLinkLocalUnicast() && !IsRoutingLocator(addr.GetAddress()) && !IsAnycastLocator(addr.GetAddress()) && addr.GetAddress() != GetMeshLocalEid()) { ExitNow(retval = true); @@ -4575,7 +4575,7 @@ Error Mle::TxMessage::AppendAddressRegistrationTlv(AddressRegistrationMode aMode for (const Ip6::Netif::UnicastAddress &addr : Get().GetUnicastAddresses()) { - if (addr.GetAddress().IsLinkLocal() || Get().IsRoutingLocator(addr.GetAddress()) || + if (addr.GetAddress().IsLinkLocalUnicast() || Get().IsRoutingLocator(addr.GetAddress()) || Get().IsAnycastLocator(addr.GetAddress()) || addr.GetAddress() == Get().GetMeshLocalEid()) { continue; diff --git a/src/core/thread/neighbor_table.cpp b/src/core/thread/neighbor_table.cpp index 217414121..f7a2a7920 100644 --- a/src/core/thread/neighbor_table.cpp +++ b/src/core/thread/neighbor_table.cpp @@ -139,7 +139,7 @@ Neighbor *NeighborTable::FindNeighbor(const Ip6::Address &aIp6Address, Neighbor: Neighbor *neighbor = nullptr; Mac::Address macAddress; - if (aIp6Address.IsLinkLocal()) + if (aIp6Address.IsLinkLocalUnicast()) { aIp6Address.GetIid().ConvertToMacAddress(macAddress); } diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index f32e7813e..af92d417a 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -113,7 +113,7 @@ void Server::PrepareMessageInfoForDest(const Ip6::Address &aDestination, Tmf::Me aMessageInfo.SetMulticastLoop(true); } - if (aDestination.IsLinkLocal() || aDestination.IsLinkLocalMulticast()) + if (aDestination.IsLinkLocalUnicastOrMulticast()) { aMessageInfo.SetSockAddr(Get().GetLinkLocalAddress()); } diff --git a/src/core/thread/tmf.cpp b/src/core/thread/tmf.cpp index 8585ae114..a0bb80f34 100644 --- a/src/core/thread/tmf.cpp +++ b/src/core/thread/tmf.cpp @@ -208,9 +208,9 @@ bool Agent::IsTmfMessage(const Ip6::Address &aSourceAddress, const Ip6::Address VerifyOrExit(aDestPort == kUdpPort); - if (aSourceAddress.IsLinkLocal()) + if (aSourceAddress.IsLinkLocalUnicast()) { - isTmf = aDestAddress.IsLinkLocal() || aDestAddress.IsLinkLocalMulticast(); + isTmf = aDestAddress.IsLinkLocalUnicastOrMulticast(); ExitNow(); } diff --git a/src/posix/platform/multicast_routing.cpp b/src/posix/platform/multicast_routing.cpp index 864f984d4..ffac62157 100644 --- a/src/posix/platform/multicast_routing.cpp +++ b/src/posix/platform/multicast_routing.cpp @@ -310,7 +310,7 @@ otError MulticastRoutingManager::AddMulticastForwardingCache(const Ip6::Address } else { - VerifyOrExit(!aSrcAddr.IsLinkLocal(), error = OT_ERROR_NONE); + VerifyOrExit(!aSrcAddr.IsLinkLocalUnicast(), error = OT_ERROR_NONE); VerifyOrExit(aSrcAddr.GetPrefix() != AsCoreType(otThreadGetMeshLocalPrefix(gInstance)), error = OT_ERROR_NONE); // Forward multicast traffic from Thread to Backbone if multicast scope > kRealmLocalScope // TODO: (MLR) allow scope configuration of outbound multicast routing From 31e512ac7bc2c3d60b50d5cf8130657b28dc2c9f Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 19 Jun 2024 16:57:34 -0700 Subject: [PATCH 39/65] [mle] replace `Mle::GetNextHop()` with `GetParentRloc16()` (#10407) This commit removes the `Mle::GetNextHop()` method, which returned the parent RLOC16 (when the parent state was valid) irrespective of a given destination. The `Mle::GetNextHop()` method was only used on MTD builds and from `MeshForwarder::UpdateIp6Route()` method, where `mle.GetNextHop(Mac::kShortAddrBroadcast)` served as an indirect way to get the parent RLOC16. This is now replaced with a direct `GetParentRloc16()` call, clarifying the intended purpose. On FTD builds, the `MleRouter::GetNextHop()` is used instead of `Mle::GetNextHop()`. The `MleRouter` method remains unchanged. Since it would also return the parent's RLOC16 when the device is acting as a child, using `GetParentRloc16()` covers this case as well. --- src/core/thread/mesh_forwarder.cpp | 4 ++-- src/core/thread/mle.cpp | 6 +----- src/core/thread/mle.hpp | 18 ++++++++---------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 932e6d2f0..8a6b8611f 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -690,7 +690,7 @@ Error MeshForwarder::UpdateIp6Route(Message &aMessage) if (mle.IsChild() && aMessage.IsLinkSecurityEnabled() && !aMessage.IsSubTypeMle()) { - mMacAddrs.mDestination.SetShort(mle.GetNextHop(Mac::kShortAddrBroadcast)); + mMacAddrs.mDestination.SetShort(mle.GetParentRloc16()); } else { @@ -703,7 +703,7 @@ Error MeshForwarder::UpdateIp6Route(Message &aMessage) } else if (mle.IsMinimalEndDevice()) { - mMacAddrs.mDestination.SetShort(mle.GetNextHop(Mac::kShortAddrBroadcast)); + mMacAddrs.mDestination.SetShort(mle.GetParentRloc16()); } else { diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 157dac149..246d73f2c 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -3813,11 +3813,7 @@ void Mle::ProcessAnnounce(void) IgnoreError(Start(kAnnounceAttach)); } -uint16_t Mle::GetNextHop(uint16_t aDestination) const -{ - OT_UNUSED_VARIABLE(aDestination); - return (mParent.IsStateValid()) ? mParent.GetRloc16() : static_cast(Mac::kShortAddrInvalid); -} +uint16_t Mle::GetParentRloc16(void) const { return (mParent.IsStateValid() ? mParent.GetRloc16() : kInvalidRloc16); } Error Mle::GetParentInfo(Router::Info &aParentInfo) const { diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 85d1207cc..466f799ec 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -419,6 +419,14 @@ class Mle : public InstanceLocator, private NonCopyable return mRealmLocalAllThreadNodes.GetAddress(); } + /** + * Gets the parent's RLOC16. + * + * @returns The parent's RLOC16, or `kInvalidRloc16` if parent's state is not valid. + * + */ + uint16_t GetParentRloc16(void) const; + /** * Gets the parent when operating in End Device mode. * @@ -693,16 +701,6 @@ class Mle : public InstanceLocator, private NonCopyable return (&aAddress == &mLinkLocalAllThreadNodes) || (&aAddress == &mRealmLocalAllThreadNodes); } - /** - * Determines the next hop towards an RLOC16 destination. - * - * @param[in] aDestination The RLOC16 of the destination. - * - * @returns A RLOC16 of the next hop if a route is known, kInvalidRloc16 otherwise. - * - */ - uint16_t GetNextHop(uint16_t aDestination) const; - #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE /** * Gets the CSL timeout. From 215c23f2a647953f6aafd84d7473040e5fc1b042 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Thu, 20 Jun 2024 11:27:35 +0800 Subject: [PATCH 40/65] [diag] add diag output callback (#10354) The length of diag output messages is limited by the diag buffer size. Developers have to change the diag buffer size to allow diag module to output long messages. If diag output messages become longer and longer, developers have to keep changing the diag buffer size. This commit adds an output callback to diag module to output diag messages. Then the length of diag output messages won't be limited by the diag buffer size. --- examples/platforms/simulation/diag.c | 7 + include/openthread/diag.h | 32 ++-- include/openthread/instance.h | 2 +- include/openthread/platform/diag.h | 31 ++-- script/check-size | 4 +- script/git-tool | 13 +- src/cli/cli.cpp | 19 +- src/cli/cli.hpp | 5 + src/core/api/diags_api.cpp | 12 +- src/core/diags/factory_diags.cpp | 259 ++++++++++++++------------- src/core/diags/factory_diags.hpp | 56 +++--- src/lib/spinel/radio_spinel.cpp | 49 +++-- src/lib/spinel/radio_spinel.hpp | 24 ++- src/ncp/ncp_base.cpp | 56 +++++- src/ncp/ncp_base.hpp | 10 ++ src/posix/platform/radio.cpp | 100 ++++++++--- src/posix/platform/rcp_caps_diag.cpp | 18 +- src/posix/platform/rcp_caps_diag.hpp | 25 ++- tests/fuzz/fuzzer_platform.cpp | 15 +- tests/unit/test_platform.cpp | 28 ++- tests/unit/test_platform.h | 1 + 21 files changed, 501 insertions(+), 265 deletions(-) diff --git a/examples/platforms/simulation/diag.c b/examples/platforms/simulation/diag.c index dcd9f1d9f..8ce6efcfd 100644 --- a/examples/platforms/simulation/diag.c +++ b/examples/platforms/simulation/diag.c @@ -58,6 +58,13 @@ static bool sGpioValue = false; static uint8_t sRawPowerSetting[OPENTHREAD_CONFIG_POWER_CALIBRATION_RAW_POWER_SETTING_SIZE]; static uint16_t sRawPowerSettingLength = 0; +void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aCallback); + OT_UNUSED_VARIABLE(aContext); +} + void otPlatDiagModeSet(bool aMode) { sDiagMode = aMode; } bool otPlatDiagModeGet(void) { return sDiagMode; } diff --git a/include/openthread/diag.h b/include/openthread/diag.h index 217abf6cb..9362ef378 100644 --- a/include/openthread/diag.h +++ b/include/openthread/diag.h @@ -36,6 +36,7 @@ #define OPENTHREAD_DIAG_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -51,39 +52,38 @@ extern "C" { * */ +/* Represents the pointer to callback to output diag messages. */ +typedef otPlatDiagOutputCallback otDiagOutputCallback; + /** - * Processes a factory diagnostics command line. + * Sets the diag output callback. * - * The output of this function (the content written to @p aOutput) MUST terminate with `\0` and the `\0` is within the - * output buffer. + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aCallback A pointer to a function that is called on outputting diag messages. + * @param[in] aContext A pointer to the user context. + * + */ +void otDiagSetOutputCallback(otInstance *aInstance, otDiagOutputCallback aCallback, void *aContext); + +/** + * Processes a factory diagnostics command line. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aArgsLength The number of elements in @p aArgs. * @param[in] aArgs An array of arguments. - * @param[out] aOutput The diagnostics execution result. - * @param[in] aOutputMaxLen The output buffer size. * * @retval OT_ERROR_INVALID_ARGS The command is supported but invalid arguments provided. * @retval OT_ERROR_NONE The command is successfully process. * @retval OT_ERROR_NOT_IMPLEMENTED The command is not supported. * */ -otError otDiagProcessCmd(otInstance *aInstance, - uint8_t aArgsLength, - char *aArgs[], - char *aOutput, - size_t aOutputMaxLen); +otError otDiagProcessCmd(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]); /** * Processes a factory diagnostics command line. * - * The output of this function (the content written to @p aOutput) MUST terminate with `\0` and the `\0` is within the - * output buffer. - * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aString A NULL-terminated input string. - * @param[out] aOutput The diagnostics execution result. - * @param[in] aOutputMaxLen The output buffer size. * * @retval OT_ERROR_NONE The command is successfully process. * @retval OT_ERROR_INVALID_ARGS The command is supported but invalid arguments provided. @@ -91,7 +91,7 @@ otError otDiagProcessCmd(otInstance *aInstance, * @retval OT_ERROR_NO_BUFS The command string is too long. * */ -otError otDiagProcessCmdLine(otInstance *aInstance, const char *aString, char *aOutput, size_t aOutputMaxLen); +otError otDiagProcessCmdLine(otInstance *aInstance, const char *aString); /** * Indicates whether or not the factory diagnostics mode is enabled. diff --git a/include/openthread/instance.h b/include/openthread/instance.h index d4325eff0..887c58cb6 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (422) +#define OPENTHREAD_API_VERSION (423) /** * @addtogroup api-instance diff --git a/include/openthread/platform/diag.h b/include/openthread/platform/diag.h index 7bc229946..888ef448c 100644 --- a/include/openthread/platform/diag.h +++ b/include/openthread/platform/diag.h @@ -67,27 +67,38 @@ typedef enum } otGpioMode; /** - * Processes a factory diagnostics command line. + * Pointer to callback to output platform diag messages. + * + * @param[in] aFormat The format string. + * @param[in] aArguments The format string arguments. + * @param[out] aContext A pointer to the user context. + * + */ +typedef void (*otPlatDiagOutputCallback)(const char *aFormat, va_list aArguments, void *aContext); + +/** + * Sets the platform diag output callback. * - * The output of this function (the content written to @p aOutput) MUST terminate with `\0` and the `\0` is within the - * output buffer. + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aCallback A pointer to a function that is called on outputting diag messages. + * @param[in] aContext A pointer to the user context. + * + */ +void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext); + +/** + * Processes a factory diagnostics command line. * * @param[in] aInstance The OpenThread instance for current request. * @param[in] aArgsLength The number of arguments in @p aArgs. * @param[in] aArgs The arguments of diagnostics command line. - * @param[out] aOutput The diagnostics execution result. - * @param[in] aOutputMaxLen The output buffer size. * * @retval OT_ERROR_INVALID_ARGS The command is supported but invalid arguments provided. * @retval OT_ERROR_NONE The command is successfully process. * @retval OT_ERROR_INVALID_COMMAND The command is not valid or not supported. * */ -otError otPlatDiagProcess(otInstance *aInstance, - uint8_t aArgsLength, - char *aArgs[], - char *aOutput, - size_t aOutputMaxLen); +otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]); /** * Enables/disables the factory diagnostics mode. diff --git a/script/check-size b/script/check-size index c50ade344..7317b6c37 100755 --- a/script/check-size +++ b/script/check-size @@ -105,9 +105,11 @@ build_nrf52840() case "$2" in new) local sha=${OT_SHA_NEW} + local clone_options=("clone") ;; old) local sha=${OT_SHA_OLD} + local clone_options=("clone" "no-depend") ;; *) exit 128 @@ -119,7 +121,7 @@ build_nrf52840() local config_file="../examples/config/${config_name}" mkdir -p "${OT_TMP_DIR}/${folder}" - script/git-tool clone https://github.com/openthread/ot-nrf528xx.git "${OT_TMP_DIR}/${folder}" + script/git-tool "${clone_options[@]}" https://github.com/openthread/ot-nrf528xx.git "${OT_TMP_DIR}/${folder}" rm -rf "${OT_TMP_DIR}/${folder}/openthread/*" # replace openthread submodule with latest commit git archive "${sha}" | tar x -C "${OT_TMP_DIR}/${folder}/openthread" diff --git a/script/git-tool b/script/git-tool index 4bcdae8e4..c6fb695f0 100755 --- a/script/git-tool +++ b/script/git-tool @@ -80,10 +80,15 @@ try_clone() { local dest_dir - dest_dir="$(git clone "$@" 2>&1 | tee | cut -d\' -f2)" - - cd "${dest_dir}" - get_pr_body | apply_dependencies + if [[ $1 == no-depend ]]; then + shift + git clone "$@" 2>&1 + else + dest_dir="$(git clone "$@" 2>&1 | tee | cut -d\' -f2)" + + cd "${dest_dir}" + get_pr_body | apply_dependencies + fi } print_help() diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 89bb9c8e5..7680a4f58 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -169,6 +169,10 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi #if (OPENTHREAD_FTD || OPENTHREAD_MTD) && OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK otIp6SetReceiveCallback(GetInstancePtr(), &Interpreter::HandleIp6Receive, this); #endif +#if OPENTHREAD_CONFIG_DIAG_ENABLE + otDiagSetOutputCallback(GetInstancePtr(), &Interpreter::HandleDiagOutput, this); +#endif + ClearAllBytes(mUserCommands); OutputPrompt(); @@ -210,19 +214,20 @@ void Interpreter::OutputResult(otError aError) #if OPENTHREAD_CONFIG_DIAG_ENABLE template <> otError Interpreter::Process(Arg aArgs[]) { - otError error; - char *args[kMaxArgs]; - char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE]; + char *args[kMaxArgs]; // all diagnostics related features are processed within diagnostics module Arg::CopyArgsToStringArray(aArgs, args); - error = otDiagProcessCmd(GetInstancePtr(), Arg::GetArgsLength(aArgs), args, output, sizeof(output)); - - OutputFormat("%s", output); + return otDiagProcessCmd(GetInstancePtr(), Arg::GetArgsLength(aArgs), args); +} - return error; +void Interpreter::HandleDiagOutput(const char *aFormat, va_list aArguments, void *aContext) +{ + static_cast(aContext)->HandleDiagOutput(aFormat, aArguments); } + +void Interpreter::HandleDiagOutput(const char *aFormat, va_list aArguments) { OutputFormatV(aFormat, aArguments); } #endif template <> otError Interpreter::Process(Arg aArgs[]) diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index d5fe30ad9..65af2e839 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -339,6 +339,11 @@ class Interpreter : public OutputImplementer, public Utils #endif // OPENTHREAD_FTD || OPENTHREAD_MTD +#if OPENTHREAD_CONFIG_DIAG_ENABLE + static void HandleDiagOutput(const char *aFormat, va_list aArguments, void *aContext); + void HandleDiagOutput(const char *aFormat, va_list aArguments); +#endif + void SetCommandTimeout(uint32_t aTimeoutMilli); static void HandleTimer(Timer &aTimer); diff --git a/src/core/api/diags_api.cpp b/src/core/api/diags_api.cpp index a87bde581..cb8488ddc 100644 --- a/src/core/api/diags_api.cpp +++ b/src/core/api/diags_api.cpp @@ -42,18 +42,22 @@ using namespace ot; -otError otDiagProcessCmdLine(otInstance *aInstance, const char *aString, char *aOutput, size_t aOutputMaxLen) +otError otDiagProcessCmdLine(otInstance *aInstance, const char *aString) { AssertPointerIsNotNull(aString); - return AsCoreType(aInstance).Get().ProcessLine(aString, aOutput, aOutputMaxLen); + return AsCoreType(aInstance).Get().ProcessLine(aString); } -otError otDiagProcessCmd(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +otError otDiagProcessCmd(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { - return AsCoreType(aInstance).Get().ProcessCmd(aArgsLength, aArgs, aOutput, aOutputMaxLen); + return AsCoreType(aInstance).Get().ProcessCmd(aArgsLength, aArgs); } bool otDiagIsEnabled(otInstance *aInstance) { return AsCoreType(aInstance).Get().IsEnabled(); } +void otDiagSetOutputCallback(otInstance *aInstance, otDiagOutputCallback aCallback, void *aContext) +{ + AsCoreType(aInstance).Get().SetOutputCallback(aCallback, aContext); +} #endif // OPENTHREAD_CONFIG_DIAG_ENABLE diff --git a/src/core/diags/factory_diags.cpp b/src/core/diags/factory_diags.cpp index 03ce33d72..d5a0ee288 100644 --- a/src/core/diags/factory_diags.cpp +++ b/src/core/diags/factory_diags.cpp @@ -50,17 +50,11 @@ #include "utils/parse_cmdline.hpp" OT_TOOL_WEAK -otError otPlatDiagProcess(otInstance *aInstance, - uint8_t aArgsLength, - char *aArgs[], - char *aOutput, - size_t aOutputMaxLen) +otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { OT_UNUSED_VARIABLE(aArgsLength); OT_UNUSED_VARIABLE(aArgs); OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aOutput); - OT_UNUSED_VARIABLE(aOutputMaxLen); return ot::kErrorInvalidCommand; } @@ -85,10 +79,12 @@ const struct Diags::Command Diags::sCommands[] = { Diags::Diags(Instance &aInstance) : InstanceLocator(aInstance) + , mOutputCallback(nullptr) + , mOutputContext(nullptr) { } -Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; long value; @@ -101,11 +97,11 @@ Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[], char *aOutput, s otPlatDiagChannelSet(static_cast(value)); exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessPower(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessPower(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; long value; @@ -117,35 +113,39 @@ Error Diags::ProcessPower(uint8_t aArgsLength, char *aArgs[], char *aOutput, siz otPlatDiagTxPowerSet(static_cast(value)); exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessEcho(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessEcho(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; if (aArgsLength == 1) { - snprintf(aOutput, aOutputMaxLen, "%s\r\n", aArgs[0]); + Output("%s\r\n", aArgs[0]); } else if ((aArgsLength == 2) && (strcmp(aArgs[0], "-n") == 0)) { - const uint8_t kReservedLen = 3; // 1 byte '\r', 1 byte '\n' and 1 byte '\0' - uint32_t outputMaxLen = static_cast(aOutputMaxLen) - kReservedLen; - long value; - uint32_t i; - uint32_t number; + static constexpr uint8_t kReservedLen = 1; // 1 byte '\0' + static constexpr uint16_t kOutputLen = OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE; + static constexpr uint16_t kOutputMaxLen = kOutputLen - kReservedLen; + char output[kOutputLen]; + long value; + uint32_t i; + uint32_t number; SuccessOrExit(error = ParseLong(aArgs[1], value)); - number = Min(static_cast(value), outputMaxLen); + number = Min(static_cast(value), static_cast(kOutputMaxLen)); for (i = 0; i < number; i++) { - aOutput[i] = '0' + i % 10; + output[i] = '0' + i % 10; } - snprintf(&aOutput[i], aOutputMaxLen - i, "\r\n"); + output[number] = '\0'; + + Output("%s\r\n", output); } else { @@ -153,28 +153,24 @@ Error Diags::ProcessEcho(uint8_t aArgsLength, char *aArgs[], char *aOutput, size } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessStart(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessStart(uint8_t aArgsLength, char *aArgs[]) { OT_UNUSED_VARIABLE(aArgsLength); OT_UNUSED_VARIABLE(aArgs); - OT_UNUSED_VARIABLE(aOutput); - OT_UNUSED_VARIABLE(aOutputMaxLen); otPlatDiagModeSet(true); return kErrorNone; } -Error Diags::ProcessStop(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessStop(uint8_t aArgsLength, char *aArgs[]) { OT_UNUSED_VARIABLE(aArgsLength); OT_UNUSED_VARIABLE(aArgs); - OT_UNUSED_VARIABLE(aOutput); - OT_UNUSED_VARIABLE(aOutputMaxLen); otPlatDiagModeSet(false); @@ -213,11 +209,13 @@ Diags::Diags(Instance &aInstance) , mIsTxPacketSet(false) , mRepeatActive(false) , mDiagSendOn(false) + , mOutputCallback(nullptr) + , mOutputContext(nullptr) { mStats.Clear(); } -Error Diags::ProcessFrame(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessFrame(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; uint16_t size = OT_RADIO_FRAME_MAX_SIZE; @@ -231,11 +229,11 @@ Error Diags::ProcessFrame(uint8_t aArgsLength, char *aArgs[], char *aOutput, siz mIsTxPacketSet = true; exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; @@ -243,7 +241,7 @@ Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[], char *aOutput, s if (aArgsLength == 0) { - snprintf(aOutput, aOutputMaxLen, "channel: %d\r\n", mChannel); + Output("channel: %d\r\n", mChannel); } else { @@ -256,15 +254,15 @@ Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[], char *aOutput, s IgnoreError(Get().Receive(mChannel)); otPlatDiagChannelSet(mChannel); - snprintf(aOutput, aOutputMaxLen, "set channel to %d\r\nstatus 0x%02x\r\n", mChannel, error); + Output("set channel to %d\r\nstatus 0x%02x\r\n", mChannel, error); } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessPower(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessPower(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; @@ -272,7 +270,7 @@ Error Diags::ProcessPower(uint8_t aArgsLength, char *aArgs[], char *aOutput, siz if (aArgsLength == 0) { - snprintf(aOutput, aOutputMaxLen, "tx power: %d dBm\r\n", mTxPower); + Output("tx power: %d dBm\r\n", mTxPower); } else { @@ -284,15 +282,15 @@ Error Diags::ProcessPower(uint8_t aArgsLength, char *aArgs[], char *aOutput, siz SuccessOrExit(error = Get().SetTransmitPower(mTxPower)); otPlatDiagTxPowerSet(mTxPower); - snprintf(aOutput, aOutputMaxLen, "set tx power to %d dBm\r\nstatus 0x%02x\r\n", mTxPower, error); + Output("set tx power to %d dBm\r\nstatus 0x%02x\r\n", mTxPower, error); } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessRepeat(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessRepeat(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; @@ -303,7 +301,7 @@ Error Diags::ProcessRepeat(uint8_t aArgsLength, char *aArgs[], char *aOutput, si { otPlatAlarmMilliStop(&GetInstance()); mRepeatActive = false; - snprintf(aOutput, aOutputMaxLen, "repeated packet transmission is stopped\r\nstatus 0x%02x\r\n", error); + Output("repeated packet transmission is stopped\r\nstatus 0x%02x\r\n", error); } else { @@ -335,16 +333,16 @@ Error Diags::ProcessRepeat(uint8_t aArgsLength, char *aArgs[], char *aOutput, si mRepeatActive = true; uint32_t now = otPlatAlarmMilliGetNow(); otPlatAlarmMilliStartAt(&GetInstance(), now, mTxPeriod); - snprintf(aOutput, aOutputMaxLen, "sending packets of length %#x at the delay of %#x ms\r\nstatus 0x%02x\r\n", - static_cast(mTxLen), static_cast(mTxPeriod), error); + Output("sending packets of length %#x at the delay of %#x ms\r\nstatus 0x%02x\r\n", static_cast(mTxLen), + static_cast(mTxPeriod), error); } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessSend(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessSend(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; long value; @@ -373,16 +371,16 @@ Error Diags::ProcessSend(uint8_t aArgsLength, char *aArgs[], char *aOutput, size VerifyOrExit(value >= OT_RADIO_FRAME_MIN_SIZE, error = kErrorInvalidArgs); mTxLen = static_cast(value); - snprintf(aOutput, aOutputMaxLen, "sending %#x packet(s), length %#x\r\nstatus 0x%02x\r\n", - static_cast(mTxPackets), static_cast(mTxLen), error); + Output("sending %#x packet(s), length %#x\r\nstatus 0x%02x\r\n", static_cast(mTxPackets), + static_cast(mTxLen), error); TransmitPacket(); exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessStart(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessStart(uint8_t aArgsLength, char *aArgs[]) { OT_UNUSED_VARIABLE(aArgsLength); OT_UNUSED_VARIABLE(aArgs); @@ -403,14 +401,14 @@ Error Diags::ProcessStart(uint8_t aArgsLength, char *aArgs[], char *aOutput, siz SuccessOrExit(error = Get().SetTransmitPower(mTxPower)); otPlatDiagModeSet(true); mStats.Clear(); - snprintf(aOutput, aOutputMaxLen, "start diagnostics mode\r\nstatus 0x%02x\r\n", error); + Output("start diagnostics mode\r\nstatus 0x%02x\r\n", error); exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessStats(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessStats(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; @@ -419,26 +417,25 @@ Error Diags::ProcessStats(uint8_t aArgsLength, char *aArgs[], char *aOutput, siz if ((aArgsLength == 1) && (strcmp(aArgs[0], "clear") == 0)) { mStats.Clear(); - snprintf(aOutput, aOutputMaxLen, "stats cleared\r\n"); + Output("stats cleared\r\n"); } else { VerifyOrExit(aArgsLength == 0, error = kErrorInvalidArgs); - snprintf(aOutput, aOutputMaxLen, - "received packets: %d\r\nsent packets: %d\r\n" - "first received packet: rssi=%d, lqi=%d\r\n" - "last received packet: rssi=%d, lqi=%d\r\n", - static_cast(mStats.mReceivedPackets), static_cast(mStats.mSentPackets), - static_cast(mStats.mFirstRssi), static_cast(mStats.mFirstLqi), - static_cast(mStats.mLastRssi), static_cast(mStats.mLastLqi)); + Output("received packets: %d\r\nsent packets: %d\r\n" + "first received packet: rssi=%d, lqi=%d\r\n" + "last received packet: rssi=%d, lqi=%d\r\n", + static_cast(mStats.mReceivedPackets), static_cast(mStats.mSentPackets), + static_cast(mStats.mFirstRssi), static_cast(mStats.mFirstLqi), + static_cast(mStats.mLastRssi), static_cast(mStats.mLastLqi)); } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessStop(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessStop(uint8_t aArgsLength, char *aArgs[]) { OT_UNUSED_VARIABLE(aArgsLength); OT_UNUSED_VARIABLE(aArgs); @@ -451,17 +448,16 @@ Error Diags::ProcessStop(uint8_t aArgsLength, char *aArgs[], char *aOutput, size otPlatDiagModeSet(false); Get().SetPromiscuous(false); - snprintf(aOutput, aOutputMaxLen, - "received packets: %d\r\nsent packets: %d\r\n" - "first received packet: rssi=%d, lqi=%d\r\n" - "last received packet: rssi=%d, lqi=%d\r\n" - "\nstop diagnostics mode\r\nstatus 0x%02x\r\n", - static_cast(mStats.mReceivedPackets), static_cast(mStats.mSentPackets), - static_cast(mStats.mFirstRssi), static_cast(mStats.mFirstLqi), - static_cast(mStats.mLastRssi), static_cast(mStats.mLastLqi), error); + Output("received packets: %d\r\nsent packets: %d\r\n" + "first received packet: rssi=%d, lqi=%d\r\n" + "last received packet: rssi=%d, lqi=%d\r\n" + "\nstop diagnostics mode\r\nstatus 0x%02x\r\n", + static_cast(mStats.mReceivedPackets), static_cast(mStats.mSentPackets), + static_cast(mStats.mFirstRssi), static_cast(mStats.mFirstLqi), static_cast(mStats.mLastRssi), + static_cast(mStats.mLastLqi), error); exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } @@ -483,7 +479,7 @@ void Diags::TransmitPacket(void) IgnoreError(Get().Transmit(*static_cast(mTxPacket))); } -Error Diags::ProcessRadio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessRadio(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorInvalidArgs; @@ -493,7 +489,7 @@ Error Diags::ProcessRadio(uint8_t aArgsLength, char *aArgs[], char *aOutput, siz if (strcmp(aArgs[0], "sleep") == 0) { SuccessOrExit(error = Get().Sleep()); - snprintf(aOutput, aOutputMaxLen, "set radio from receive to sleep \r\nstatus 0x%02x\r\n", error); + Output("set radio from receive to sleep \r\nstatus 0x%02x\r\n", error); } else if (strcmp(aArgs[0], "receive") == 0) { @@ -502,8 +498,7 @@ Error Diags::ProcessRadio(uint8_t aArgsLength, char *aArgs[], char *aOutput, siz otPlatDiagChannelSet(mChannel); otPlatDiagTxPowerSet(mTxPower); - snprintf(aOutput, aOutputMaxLen, "set radio from sleep to receive on channel %d\r\nstatus 0x%02x\r\n", mChannel, - error); + Output("set radio from sleep to receive on channel %d\r\nstatus 0x%02x\r\n", mChannel, error); } else if (strcmp(aArgs[0], "state") == 0) { @@ -514,29 +509,29 @@ Error Diags::ProcessRadio(uint8_t aArgsLength, char *aArgs[], char *aOutput, siz switch (state) { case OT_RADIO_STATE_DISABLED: - snprintf(aOutput, aOutputMaxLen, "disabled\r\n"); + Output("disabled\r\n"); break; case OT_RADIO_STATE_SLEEP: - snprintf(aOutput, aOutputMaxLen, "sleep\r\n"); + Output("sleep\r\n"); break; case OT_RADIO_STATE_RECEIVE: - snprintf(aOutput, aOutputMaxLen, "receive\r\n"); + Output("receive\r\n"); break; case OT_RADIO_STATE_TRANSMIT: - snprintf(aOutput, aOutputMaxLen, "transmit\r\n"); + Output("transmit\r\n"); break; default: - snprintf(aOutput, aOutputMaxLen, "invalid\r\n"); + Output("invalid\r\n"); break; } } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } @@ -605,7 +600,7 @@ void Diags::TransmitDone(Error aError) #endif // OPENTHREAD_RADIO -Error Diags::ProcessContinuousWave(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessContinuousWave(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorInvalidArgs; @@ -622,11 +617,11 @@ Error Diags::ProcessContinuousWave(uint8_t aArgsLength, char *aArgs[], char *aOu } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessStream(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessStream(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorInvalidArgs; @@ -643,7 +638,7 @@ Error Diags::ProcessStream(uint8_t aArgsLength, char *aArgs[], char *aOutput, si } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } @@ -655,7 +650,7 @@ Error Diags::GetPowerSettings(uint8_t aChannel, PowerSettings &aPowerSettings) &aPowerSettings.mRawPowerSetting.mLength); } -Error Diags::ProcessPowerSettings(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessPowerSettings(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorInvalidArgs; uint8_t channel; @@ -668,14 +663,9 @@ Error Diags::ProcessPowerSettings(uint8_t aArgsLength, char *aArgs[], char *aOut bool isPrePowerSettingsValid = false; uint8_t preChannel = 0; PowerSettings prePowerSettings; - int n; - n = snprintf(aOutput, aOutputMaxLen, - "| StartCh | EndCh | TargetPower | ActualPower | RawPowerSetting |\r\n" - "+---------+-------+-------------+-------------+-----------------+\r\n"); - VerifyOrExit((n > 0) && (n < static_cast(aOutputMaxLen)), error = kErrorNoBufs); - aOutput += n; - aOutputMaxLen -= static_cast(n); + Output("| StartCh | EndCh | TargetPower | ActualPower | RawPowerSetting |\r\n" + "+---------+-------+-------------+-------------+-----------------+\r\n"); for (channel = Radio::kChannelMin; channel <= Radio::kChannelMax + 1; channel++) { @@ -683,12 +673,8 @@ Error Diags::ProcessPowerSettings(uint8_t aArgsLength, char *aArgs[], char *aOut if (isPrePowerSettingsValid && ((powerSettings != prePowerSettings) || (error != kErrorNone))) { - n = snprintf(aOutput, aOutputMaxLen, "| %7u | %5u | %11d | %11d | %15s |\r\n", preChannel, channel - 1, - prePowerSettings.mTargetPower, prePowerSettings.mActualPower, - prePowerSettings.mRawPowerSetting.ToString().AsCString()); - VerifyOrExit((n > 0) && (n < static_cast(aOutputMaxLen)), error = kErrorNoBufs); - aOutput += n; - aOutputMaxLen -= static_cast(n); + Output("| %7u | %5u | %11d | %11d | %15s |\r\n", preChannel, channel - 1, prePowerSettings.mTargetPower, + prePowerSettings.mActualPower, prePowerSettings.mRawPowerSetting.ToString().AsCString()); isPrePowerSettingsValid = false; } @@ -708,14 +694,13 @@ Error Diags::ProcessPowerSettings(uint8_t aArgsLength, char *aArgs[], char *aOut VerifyOrExit(channel >= Radio::kChannelMin && channel <= Radio::kChannelMax, error = kErrorInvalidArgs); SuccessOrExit(error = GetPowerSettings(channel, powerSettings)); - snprintf(aOutput, aOutputMaxLen, - "TargetPower(0.01dBm): %d\r\nActualPower(0.01dBm): %d\r\nRawPowerSetting: %s\r\n", - powerSettings.mTargetPower, powerSettings.mActualPower, - powerSettings.mRawPowerSetting.ToString().AsCString()); + Output("TargetPower(0.01dBm): %d\r\nActualPower(0.01dBm): %d\r\nRawPowerSetting: %s\r\n", + powerSettings.mTargetPower, powerSettings.mActualPower, + powerSettings.mRawPowerSetting.ToString().AsCString()); } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } @@ -725,7 +710,7 @@ Error Diags::GetRawPowerSetting(RawPowerSetting &aRawPowerSetting) return otPlatDiagRadioGetRawPowerSetting(&GetInstance(), aRawPowerSetting.mData, &aRawPowerSetting.mLength); } -Error Diags::ProcessRawPowerSetting(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessRawPowerSetting(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorInvalidArgs; RawPowerSetting setting; @@ -735,7 +720,7 @@ Error Diags::ProcessRawPowerSetting(uint8_t aArgsLength, char *aArgs[], char *aO if (aArgsLength == 0) { SuccessOrExit(error = GetRawPowerSetting(setting)); - snprintf(aOutput, aOutputMaxLen, "%s\r\n", setting.ToString().AsCString()); + Output("%s\r\n", setting.ToString().AsCString()); } else if (strcmp(aArgs[0], "enable") == 0) { @@ -753,11 +738,11 @@ Error Diags::ProcessRawPowerSetting(uint8_t aArgsLength, char *aArgs[], char *aO } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorInvalidArgs; long value; @@ -770,7 +755,7 @@ Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size SuccessOrExit(error = ParseLong(aArgs[1], value)); gpio = static_cast(value); SuccessOrExit(error = otPlatDiagGpioGet(gpio, &level)); - snprintf(aOutput, aOutputMaxLen, "%d\r\n", level); + Output("%d\r\n", level); } else if ((aArgsLength == 3) && (strcmp(aArgs[0], "set") == 0)) { @@ -789,11 +774,11 @@ Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size SuccessOrExit(error = otPlatDiagGpioGetMode(gpio, &mode)); if (mode == OT_GPIO_MODE_INPUT) { - snprintf(aOutput, aOutputMaxLen, "in\r\n"); + Output("in\r\n"); } else if (mode == OT_GPIO_MODE_OUTPUT) { - snprintf(aOutput, aOutputMaxLen, "out\r\n"); + Output("out\r\n"); } } else if ((aArgsLength == 3) && (strcmp(aArgs[2], "in") == 0)) @@ -807,15 +792,15 @@ Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size } exit: - AppendErrorResult(error, aOutput, aOutputMaxLen); + AppendErrorResult(error); return error; } -void Diags::AppendErrorResult(Error aError, char *aOutput, size_t aOutputMaxLen) +void Diags::AppendErrorResult(Error aError) { if (aError != kErrorNone) { - snprintf(aOutput, aOutputMaxLen, "failed\r\nstatus %#x\r\n", aError); + Output("failed\r\nstatus %#x\r\n", aError); } } @@ -852,7 +837,7 @@ Error Diags::ParseCmd(char *aString, uint8_t &aArgsLength, char *aArgs[]) return error; } -Error Diags::ProcessLine(const char *aString, char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessLine(const char *aString) { constexpr uint16_t kMaxCommandBuffer = OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE; @@ -871,27 +856,26 @@ Error Diags::ProcessLine(const char *aString, char *aOutput, size_t aOutputMaxLe switch (error) { case kErrorNone: - aOutput[0] = '\0'; // In case there is no output. - error = ProcessCmd(argCount, &args[0], aOutput, aOutputMaxLen); + error = ProcessCmd(argCount, &args[0]); break; case kErrorNoBufs: - snprintf(aOutput, aOutputMaxLen, "failed: command string too long\r\n"); + Output("failed: command string too long\r\n"); break; case kErrorInvalidArgs: - snprintf(aOutput, aOutputMaxLen, "failed: command string contains too many arguments\r\n"); + Output("failed: command string contains too many arguments\r\n"); break; default: - snprintf(aOutput, aOutputMaxLen, "failed to parse command string\r\n"); + Output("failed to parse command string\r\n"); break; } return error; } -Error Diags::ProcessCmd(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +Error Diags::ProcessCmd(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorNone; @@ -907,37 +891,54 @@ Error Diags::ProcessCmd(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_ if (aArgsLength == 0) { - snprintf(aOutput, aOutputMaxLen, "diagnostics mode is %s\r\n", otPlatDiagModeGet() ? "enabled" : "disabled"); + Output("diagnostics mode is %s\r\n", otPlatDiagModeGet() ? "enabled" : "disabled"); ExitNow(); } - else - { - aOutput[0] = '\0'; - } for (const Command &command : sCommands) { if (strcmp(aArgs[0], command.mName) == 0) { - error = (this->*command.mCommand)(aArgsLength - 1, (aArgsLength > 1) ? &aArgs[1] : nullptr, aOutput, - aOutputMaxLen); + error = (this->*command.mCommand)(aArgsLength - 1, (aArgsLength > 1) ? &aArgs[1] : nullptr); ExitNow(); } } // more platform specific features will be processed under platform layer - error = otPlatDiagProcess(&GetInstance(), aArgsLength, aArgs, aOutput, aOutputMaxLen); + error = otPlatDiagProcess(&GetInstance(), aArgsLength, aArgs); exit: // Add more platform specific diagnostics features here. if (error == kErrorInvalidCommand && aArgsLength > 1) { - snprintf(aOutput, aOutputMaxLen, "diag feature '%s' is not supported\r\n", aArgs[0]); + Output("diag feature '%s' is not supported\r\n", aArgs[0]); } return error; } +void Diags::SetOutputCallback(otDiagOutputCallback aCallback, void *aContext) +{ + mOutputCallback = aCallback; + mOutputContext = aContext; + + otPlatDiagSetOutputCallback(&GetInstance(), aCallback, aContext); +} + +void Diags::Output(const char *aFormat, ...) +{ + va_list args; + + va_start(args, aFormat); + + if (mOutputCallback != nullptr) + { + mOutputCallback(aFormat, args, mOutputContext); + } + + va_end(args); +} + bool Diags::IsEnabled(void) { return otPlatDiagModeGet(); } } // namespace FactoryDiags diff --git a/src/core/diags/factory_diags.hpp b/src/core/diags/factory_diags.hpp index cb1c7b95b..01864786d 100644 --- a/src/core/diags/factory_diags.hpp +++ b/src/core/diags/factory_diags.hpp @@ -40,6 +40,7 @@ #include +#include #include #include "common/clearable.hpp" @@ -66,26 +67,22 @@ class Diags : public InstanceLocator, private NonCopyable * Processes a factory diagnostics command line. * * @param[in] aString A null-terminated input string. - * @param[out] aOutput The diagnostics execution result. - * @param[in] aOutputMaxLen The output buffer size. * */ - Error ProcessLine(const char *aString, char *aOutput, size_t aOutputMaxLen); + Error ProcessLine(const char *aString); /** * Processes a factory diagnostics command line. * * @param[in] aArgsLength The number of args in @p aArgs. * @param[in] aArgs The arguments of diagnostics command line. - * @param[out] aOutput The diagnostics execution result. - * @param[in] aOutputMaxLen The output buffer size. * * @retval kErrorInvalidArgs The command is supported but invalid arguments provided. * @retval kErrorNone The command is successfully process. * @retval kErrorNotImplemented The command is not supported. * */ - Error ProcessCmd(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); + Error ProcessCmd(uint8_t aArgsLength, char *aArgs[]); /** * Indicates whether or not the factory diagnostics mode is enabled. @@ -123,13 +120,22 @@ class Diags : public InstanceLocator, private NonCopyable */ void TransmitDone(Error aError); + /** + * Sets the diag output callback. + * + * @param[in] aCallback A callback method called to output diag messages. + * @param[in] aContext A user context pointer. + * + */ + void SetOutputCallback(otDiagOutputCallback aCallback, void *aContext); + private: static constexpr uint8_t kMaxArgs = OPENTHREAD_CONFIG_DIAG_CMD_LINE_ARGS_MAX; struct Command { const char *mName; - Error (Diags::*mCommand)(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); + Error (Diags::*mCommand)(uint8_t aArgsLength, char *aArgs[]); }; struct Stats : public Clearable @@ -180,30 +186,31 @@ class Diags : public InstanceLocator, private NonCopyable }; Error ParseCmd(char *aString, uint8_t &aArgsLength, char *aArgs[]); - Error ProcessChannel(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessFrame(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessContinuousWave(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessGpio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessPower(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessRadio(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessRepeat(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessPowerSettings(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessRawPowerSetting(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessSend(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessStart(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessStats(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessStop(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); - Error ProcessStream(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); + Error ProcessChannel(uint8_t aArgsLength, char *aArgs[]); + Error ProcessFrame(uint8_t aArgsLength, char *aArgs[]); + Error ProcessContinuousWave(uint8_t aArgsLength, char *aArgs[]); + Error ProcessGpio(uint8_t aArgsLength, char *aArgs[]); + Error ProcessPower(uint8_t aArgsLength, char *aArgs[]); + Error ProcessRadio(uint8_t aArgsLength, char *aArgs[]); + Error ProcessRepeat(uint8_t aArgsLength, char *aArgs[]); + Error ProcessPowerSettings(uint8_t aArgsLength, char *aArgs[]); + Error ProcessRawPowerSetting(uint8_t aArgsLength, char *aArgs[]); + Error ProcessSend(uint8_t aArgsLength, char *aArgs[]); + Error ProcessStart(uint8_t aArgsLength, char *aArgs[]); + Error ProcessStats(uint8_t aArgsLength, char *aArgs[]); + Error ProcessStop(uint8_t aArgsLength, char *aArgs[]); + Error ProcessStream(uint8_t aArgsLength, char *aArgs[]); #if OPENTHREAD_RADIO && !OPENTHREAD_RADIO_CLI - Error ProcessEcho(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); + Error ProcessEcho(uint8_t aArgsLength, char *aArgs[]); #endif Error GetRawPowerSetting(RawPowerSetting &aRawPowerSetting); Error GetPowerSettings(uint8_t aChannel, PowerSettings &aPowerSettings); void TransmitPacket(void); + void Output(const char *aFormat, ...); + void AppendErrorResult(Error aError); - static void AppendErrorResult(Error aError, char *aOutput, size_t aOutputMaxLen); static Error ParseLong(char *aString, long &aLong); static Error ParseBool(char *aString, bool &aBool); @@ -222,6 +229,9 @@ class Diags : public InstanceLocator, private NonCopyable bool mRepeatActive; bool mDiagSendOn; #endif + + otDiagOutputCallback mOutputCallback; + void *mOutputContext; }; } // namespace FactoryDiags diff --git a/src/lib/spinel/radio_spinel.cpp b/src/lib/spinel/radio_spinel.cpp index 6cef38565..605d1deba 100644 --- a/src/lib/spinel/radio_spinel.cpp +++ b/src/lib/spinel/radio_spinel.cpp @@ -99,8 +99,8 @@ RadioSpinel::RadioSpinel(void) #endif #if OPENTHREAD_CONFIG_DIAG_ENABLE , mDiagMode(false) - , mDiagOutput(nullptr) - , mDiagOutputMaxLen(0) + , mOutputCallback(nullptr) + , mOutputContext(nullptr) #endif , mTxRadioEndUs(UINT64_MAX) , mRadioTimeRecalcStart(UINT64_MAX) @@ -431,12 +431,13 @@ void RadioSpinel::HandleWaitingResponse(uint32_t aCommand, else if (aKey == SPINEL_PROP_NEST_STREAM_MFG) { spinel_ssize_t unpacked; + const char *diagOutput; mError = OT_ERROR_NONE; - EXPECT(mDiagOutput != nullptr, NO_ACTION); - unpacked = - spinel_datatype_unpack_in_place(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, mDiagOutput, &mDiagOutputMaxLen); + EXPECT(mOutputCallback != nullptr, NO_ACTION); + unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, &diagOutput); EXPECT(unpacked > 0, mError = OT_ERROR_PARSE); + PlatDiagOutput("%s", diagOutput); } #endif else if (aKey == mWaitingKey) @@ -591,6 +592,17 @@ void RadioSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, break; } } +#if OPENTHREAD_CONFIG_DIAG_ENABLE + else if (aKey == SPINEL_PROP_NEST_STREAM_MFG) + { + const char *diagOutput; + + EXPECT(mOutputCallback != nullptr, NO_ACTION); + unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, &diagOutput); + EXPECT(unpacked > 0, error = OT_ERROR_PARSE); + PlatDiagOutput("%s", diagOutput); + } +#endif #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE else if (aKey >= SPINEL_PROP_VENDOR__BEGIN && aKey < SPINEL_PROP_VENDOR__END) { @@ -1753,20 +1765,31 @@ otError RadioSpinel::Disable(void) } #if OPENTHREAD_CONFIG_DIAG_ENABLE -otError RadioSpinel::PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen) +void RadioSpinel::SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void *aContext) { - otError error; + mOutputCallback = aCallback; + mOutputContext = aContext; +} - mDiagOutput = aOutput; - mDiagOutputMaxLen = aOutputMaxLen; +otError RadioSpinel::PlatDiagProcess(const char *aString) +{ + return Set(SPINEL_PROP_NEST_STREAM_MFG, SPINEL_DATATYPE_UTF8_S, aString); +} - error = Set(SPINEL_PROP_NEST_STREAM_MFG, SPINEL_DATATYPE_UTF8_S, aString); +void RadioSpinel::PlatDiagOutput(const char *aFormat, ...) +{ + va_list args; - mDiagOutput = nullptr; - mDiagOutputMaxLen = 0; + va_start(args, aFormat); - return error; + if (mOutputCallback != nullptr) + { + mOutputCallback(aFormat, args, mOutputContext); + } + + va_end(args); } + #endif uint32_t RadioSpinel::GetRadioChannelMask(bool aPreferred) diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index 8fdca562e..4d30ff893 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -34,6 +34,7 @@ #ifndef RADIO_SPINEL_HPP_ #define RADIO_SPINEL_HPP_ +#include #include #include "openthread-spinel-config.h" @@ -678,15 +679,22 @@ class RadioSpinel : private Logger * Processes platform diagnostics commands. * * @param[in] aString A null-terminated input string. - * @param[out] aOutput The diagnostics execution result. - * @param[in] aOutputMaxLen The output buffer size. * * @retval OT_ERROR_NONE Succeeded. * @retval OT_ERROR_BUSY Failed due to another operation is on going. * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. * */ - otError PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen); + otError PlatDiagProcess(const char *aString); + + /** + * Sets the diag output callback. + * + * @param[in] aCallback A pointer to a function that is called on outputting diag messages. + * @param[in] aContext A pointer to the user context. + * + */ + void SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void *aContext); #endif /** @@ -1194,6 +1202,10 @@ class RadioSpinel : private Logger static otError ReadMacKey(const otMacKeyMaterial &aKeyMaterial, otMacKey &aKey); #endif +#if OPENTHREAD_CONFIG_DIAG_ENABLE + void PlatDiagOutput(const char *aFormat, ...); +#endif + otInstance *mInstance; RadioSpinelCallbacks mCallbacks; ///< Callbacks for notifications of higher layer. @@ -1281,9 +1293,9 @@ class RadioSpinel : private Logger #endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 #if OPENTHREAD_CONFIG_DIAG_ENABLE - bool mDiagMode; - char *mDiagOutput; - size_t mDiagOutputMaxLen; + bool mDiagMode; + otPlatDiagOutputCallback mOutputCallback; + void *mOutputContext; #endif uint64_t mTxRadioEndUs; diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 6b99b4d4a..fc6b56529 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -313,6 +313,10 @@ NcpBase::NcpBase(Instance *aInstance) , mTxSpinelFrameCounter(0) , mDidInitialUpdates(false) , mLogTimestampBase(0) +#if OPENTHREAD_CONFIG_DIAG_ENABLE + , mDiagOutput(nullptr) + , mDiagOutputLen(0) +#endif { OT_ASSERT(mInstance != nullptr); @@ -354,6 +358,9 @@ NcpBase::NcpBase(Instance *aInstance) otSrpClientSetCallback(mInstance, HandleSrpClientCallback, this); #endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD +#if OPENTHREAD_CONFIG_DIAG_ENABLE + otDiagSetOutputCallback(mInstance, &NcpBase::HandleDiagOutput_Jump, this); +#endif mChangedPropsSet.AddLastStatus(SPINEL_STATUS_RESET_UNKNOWN); mUpdateChangedPropsTask.Post(); @@ -1418,12 +1425,11 @@ otError NcpBase::CommandHandler_POKE(uint8_t aHeader) // ---------------------------------------------------------------------------- #if OPENTHREAD_CONFIG_DIAG_ENABLE - otError NcpBase::HandlePropertySet_SPINEL_PROP_NEST_STREAM_MFG(uint8_t aHeader) { - const char *string = nullptr; - char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE]; - otError error = OT_ERROR_NONE; + const char *string = nullptr; + char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE] = {0}; + otError error = OT_ERROR_NONE; error = mDecoder.ReadUtf8(string); @@ -1438,7 +1444,10 @@ otError NcpBase::HandlePropertySet_SPINEL_PROP_NEST_STREAM_MFG(uint8_t aHeader) } #endif - SuccessOrExit(error = otDiagProcessCmdLine(mInstance, string, output, sizeof(output))); + mDiagOutput = output; + mDiagOutputLen = sizeof(output); + + SuccessOrExit(error = otDiagProcessCmdLine(mInstance, string)); // Prepare the response SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_NEST_STREAM_MFG)); @@ -1446,9 +1455,46 @@ otError NcpBase::HandlePropertySet_SPINEL_PROP_NEST_STREAM_MFG(uint8_t aHeader) SuccessOrExit(error = mEncoder.EndFrame()); exit: + mDiagOutput = nullptr; + mDiagOutputLen = 0; + return error; } +void NcpBase::HandleDiagOutput_Jump(const char *aFormat, va_list aArguments, void *aContext) +{ + static_cast(aContext)->HandleDiagOutput(aFormat, aArguments); +} + +void NcpBase::HandleDiagOutput(const char *aFormat, va_list aArguments) +{ + int charsWritten; + + if (mDiagOutput != nullptr) + { + charsWritten = vsnprintf(mDiagOutput, mDiagOutputLen, aFormat, aArguments); + VerifyOrExit(charsWritten > 0); + charsWritten = (mDiagOutputLen <= charsWritten) ? mDiagOutputLen : charsWritten; + mDiagOutput += charsWritten; + mDiagOutputLen -= charsWritten; + } + else + { + uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0; + char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE]; + + charsWritten = vsnprintf(output, sizeof(output), aFormat, aArguments); + VerifyOrExit(charsWritten >= 0); + + SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_NEST_STREAM_MFG)); + SuccessOrExit(mEncoder.WriteUtf8(output)); + SuccessOrExit(mEncoder.EndFrame()); + } + +exit: + return; +} + #endif // OPENTHREAD_CONFIG_DIAG_ENABLE template <> otError NcpBase::HandlePropertyGet(void) diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 676b7b3ba..831705791 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -549,6 +549,11 @@ class NcpBase static uint8_t ConvertLogLevel(otLogLevel aLogLevel); static unsigned int ConvertLogRegion(otLogRegion aLogRegion); +#if OPENTHREAD_CONFIG_DIAG_ENABLE + static void HandleDiagOutput_Jump(const char *aFormat, va_list aArguments, void *aContext); + void HandleDiagOutput(const char *aFormat, va_list aArguments); +#endif + #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK /** * Defines a vendor "command handler" hook to process vendor-specific spinel commands. @@ -734,6 +739,11 @@ class NcpBase bool mDidInitialUpdates; uint64_t mLogTimestampBase; // Timestamp base used for logging + +#if OPENTHREAD_CONFIG_DIAG_ENABLE + char *mDiagOutput; + uint16_t mDiagOutputLen; +#endif }; } // namespace Ncp diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index eabeaf6bb..ba63d1b8d 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -498,11 +498,55 @@ otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCo #endif #if OPENTHREAD_CONFIG_DIAG_ENABLE -otError otPlatDiagProcess(otInstance *aInstance, - uint8_t aArgsLength, - char *aArgs[], - char *aOutput, - size_t aOutputMaxLen) +static otPlatDiagOutputCallback sDiagOutputCallback = nullptr; +static void *sDiagCallbackContext = nullptr; +static char *sDiagOutput = nullptr; +static uint16_t sDiagOutputLen = 0; + +static void handleDiagOutput(const char *aFormat, va_list aArguments, void *aContext) +{ + OT_UNUSED_VARIABLE(aContext); + int charsWritten; + + VerifyOrExit((sDiagOutput != nullptr) && (sDiagOutputLen > 0)); + charsWritten = vsnprintf(sDiagOutput, sDiagOutputLen, aFormat, aArguments); + VerifyOrExit(charsWritten > 0); + charsWritten = (sDiagOutputLen <= charsWritten) ? sDiagOutputLen : charsWritten; + sDiagOutput += charsWritten; + sDiagOutputLen -= charsWritten; + +exit: + return; +} + +static void setDiagOutput(char *aOutput, size_t aSize) +{ + sDiagOutput = aOutput; + sDiagOutputLen = static_cast(aSize); + GetRadioSpinel().SetDiagOutputCallback(handleDiagOutput, nullptr); +} + +static void freeDiagOutput(void) +{ + sDiagOutput = nullptr; + sDiagOutputLen = 0; + GetRadioSpinel().SetDiagOutputCallback(sDiagOutputCallback, sDiagCallbackContext); +} + +void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext) +{ + OT_UNUSED_VARIABLE(aInstance); + + sDiagOutputCallback = aCallback; + sDiagCallbackContext = aContext; + + GetRadioSpinel().SetDiagOutputCallback(aCallback, aContext); +#if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE + GetRcpCapsDiag().SetDiagOutputCallback(aCallback, aContext); +#endif +} + +otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { // deliver the platform specific diags commands to radio only ncp. OT_UNUSED_VARIABLE(aInstance); @@ -513,7 +557,7 @@ otError otPlatDiagProcess(otInstance *aInstance, #if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE if (strcmp(aArgs[0], "rcpcaps") == 0) { - return GetRcpCapsDiag().DiagProcess(aArgs, aArgsLength, aOutput, aOutputMaxLen); + return GetRcpCapsDiag().DiagProcess(aArgs, aArgsLength); } #endif @@ -522,12 +566,12 @@ otError otPlatDiagProcess(otInstance *aInstance, cur += snprintf(cur, static_cast(end - cur), "%s ", aArgs[index]); } - return GetRadioSpinel().PlatDiagProcess(cmd, aOutput, aOutputMaxLen); + return GetRadioSpinel().PlatDiagProcess(cmd); } void otPlatDiagModeSet(bool aMode) { - SuccessOrExit(GetRadioSpinel().PlatDiagProcess(aMode ? "start" : "stop", nullptr, 0)); + SuccessOrExit(GetRadioSpinel().PlatDiagProcess(aMode ? "start" : "stop")); GetRadioSpinel().SetDiagEnabled(aMode); exit: @@ -541,7 +585,7 @@ void otPlatDiagTxPowerSet(int8_t aTxPower) char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; snprintf(cmd, sizeof(cmd), "power %d", aTxPower); - SuccessOrExit(GetRadioSpinel().PlatDiagProcess(cmd, nullptr, 0)); + SuccessOrExit(GetRadioSpinel().PlatDiagProcess(cmd)); exit: return; @@ -552,7 +596,7 @@ void otPlatDiagChannelSet(uint8_t aChannel) char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; snprintf(cmd, sizeof(cmd), "channel %d", aChannel); - SuccessOrExit(GetRadioSpinel().PlatDiagProcess(cmd, nullptr, 0)); + SuccessOrExit(GetRadioSpinel().PlatDiagProcess(cmd)); exit: return; @@ -564,7 +608,7 @@ otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue) char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; snprintf(cmd, sizeof(cmd), "gpio set %d %d", aGpio, aValue); - SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd, nullptr, 0)); + SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd)); exit: return error; @@ -577,12 +621,16 @@ otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue) char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE]; char *str; + setDiagOutput(output, sizeof(output)); + snprintf(cmd, sizeof(cmd), "gpio get %d", aGpio); - SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd, output, sizeof(output))); + SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd)); VerifyOrExit((str = strtok(output, "\r")) != nullptr, error = OT_ERROR_FAILED); *aValue = static_cast(atoi(str)); exit: + freeDiagOutput(); + return error; } @@ -592,7 +640,7 @@ otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode) char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; snprintf(cmd, sizeof(cmd), "gpio mode %d %s", aGpio, aMode == OT_GPIO_MODE_INPUT ? "in" : "out"); - SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd, nullptr, 0)); + SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd)); exit: return error; @@ -605,8 +653,10 @@ otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode) char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE]; char *str; + setDiagOutput(output, sizeof(output)); + snprintf(cmd, sizeof(cmd), "gpio mode %d", aGpio); - SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd, output, sizeof(output))); + SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd)); VerifyOrExit((str = strtok(output, "\r")) != nullptr, error = OT_ERROR_FAILED); if (strcmp(str, "in") == 0) @@ -623,6 +673,8 @@ otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode) } exit: + freeDiagOutput(); + return error; } @@ -648,8 +700,10 @@ otError otPlatDiagRadioGetPowerSettings(otInstance *aInstance, assert((aTargetPower != nullptr) && (aActualPower != nullptr) && (aRawPowerSetting != nullptr) && (aRawPowerSettingLength != nullptr)); + setDiagOutput(output, sizeof(output)); + snprintf(cmd, sizeof(cmd), "powersettings %d", aChannel); - SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd, output, sizeof(output))); + SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd)); snprintf(fmt, sizeof(fmt), "TargetPower(0.01dBm): %%d\r\nActualPower(0.01dBm): %%d\r\nRawPowerSetting: %%%us\r\n", kRawPowerStringSize); VerifyOrExit(sscanf(output, fmt, &targetPower, &actualPower, rawPowerSetting) == 3, error = OT_ERROR_FAILED); @@ -659,6 +713,8 @@ otError otPlatDiagRadioGetPowerSettings(otInstance *aInstance, *aActualPower = static_cast(actualPower); exit: + freeDiagOutput(); + return error; } @@ -682,7 +738,7 @@ otError otPlatDiagRadioSetRawPowerSetting(otInstance *aInstance, VerifyOrExit(nbytes < static_cast(sizeof(cmd)), error = OT_ERROR_INVALID_ARGS); } - SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd, nullptr, 0)); + SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd)); exit: return error; @@ -700,12 +756,16 @@ otError otPlatDiagRadioGetRawPowerSetting(otInstance *aInstance, assert((aRawPowerSetting != nullptr) && (aRawPowerSettingLength != nullptr)); + setDiagOutput(output, sizeof(output)); + snprintf(cmd, sizeof(cmd), "rawpowersetting"); - SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd, output, sizeof(output))); + SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd)); VerifyOrExit((str = strtok(output, "\r")) != nullptr, error = OT_ERROR_FAILED); SuccessOrExit(error = ot::Utils::CmdLineParser::ParseAsHexString(str, *aRawPowerSettingLength, aRawPowerSetting)); exit: + freeDiagOutput(); + return error; } @@ -717,7 +777,7 @@ otError otPlatDiagRadioRawPowerSettingEnable(otInstance *aInstance, bool aEnable char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; snprintf(cmd, sizeof(cmd), "rawpowersetting %s", aEnable ? "enable" : "disable"); - SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd, nullptr, 0)); + SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd)); exit: return error; @@ -731,7 +791,7 @@ otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable) char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; snprintf(cmd, sizeof(cmd), "cw %s", aEnable ? "start" : "stop"); - SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd, nullptr, 0)); + SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd)); exit: return error; @@ -744,7 +804,7 @@ otError otPlatDiagRadioTransmitStream(otInstance *aInstance, bool aEnable) char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; snprintf(cmd, sizeof(cmd), "stream %s", aEnable ? "start" : "stop"); - return GetRadioSpinel().PlatDiagProcess(cmd, nullptr, 0); + return GetRadioSpinel().PlatDiagProcess(cmd); } void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError) diff --git a/src/posix/platform/rcp_caps_diag.cpp b/src/posix/platform/rcp_caps_diag.cpp index e9b9517c8..b0f15e494 100644 --- a/src/posix/platform/rcp_caps_diag.cpp +++ b/src/posix/platform/rcp_caps_diag.cpp @@ -447,15 +447,12 @@ const struct RcpCapsDiag::SpinelEntry RcpCapsDiag::sSpinelEntries[] = { SPINEL_ENTRY(kCategoryUtils, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_RADIO_COEX_ENABLE), }; -otError RcpCapsDiag::DiagProcess(char *aArgs[], uint8_t aArgsLength, char *aOutput, size_t aOutputMaxLen) +otError RcpCapsDiag::DiagProcess(char *aArgs[], uint8_t aArgsLength) { otError error = OT_ERROR_NONE; VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS); - mOutputStart = aOutput; - mOutputEnd = aOutput + aOutputMaxLen; - if (strcmp(aArgs[1], "spinel") == 0) { ProcessSpinel(); @@ -465,9 +462,6 @@ otError RcpCapsDiag::DiagProcess(char *aArgs[], uint8_t aArgsLength, char *aOutp error = OT_ERROR_INVALID_COMMAND; } - mOutputStart = nullptr; - mOutputEnd = nullptr; - exit: return error; } @@ -498,6 +492,12 @@ void RcpCapsDiag::TestSpinelCommands(Category aCategory) } } +void RcpCapsDiag::SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void *aContext) +{ + mOutputCallback = aCallback; + mOutputContext = aContext; +} + void RcpCapsDiag::OutputResult(const SpinelEntry &aEntry, otError error) { static constexpr uint8_t kSpaceLength = 1; @@ -522,9 +522,9 @@ void RcpCapsDiag::Output(const char *aFormat, ...) va_start(args, aFormat); - if ((mOutputStart != nullptr) && (mOutputEnd != nullptr) && (mOutputStart < mOutputEnd)) + if (mOutputCallback != nullptr) { - mOutputStart += vsnprintf(mOutputStart, static_cast(mOutputEnd - mOutputStart), aFormat, args); + mOutputCallback(aFormat, args, mOutputContext); } va_end(args); diff --git a/src/posix/platform/rcp_caps_diag.hpp b/src/posix/platform/rcp_caps_diag.hpp index 1b01f098e..f799f8187 100644 --- a/src/posix/platform/rcp_caps_diag.hpp +++ b/src/posix/platform/rcp_caps_diag.hpp @@ -37,6 +37,8 @@ #include "platform-posix.h" #if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE +#include + #include "lib/spinel/radio_spinel.hpp" #include "lib/spinel/spinel.h" @@ -58,8 +60,8 @@ class RcpCapsDiag */ explicit RcpCapsDiag(Spinel::RadioSpinel &aRadioSpinel) : mRadioSpinel(aRadioSpinel) - , mOutputStart(nullptr) - , mOutputEnd(nullptr) + , mOutputCallback(nullptr) + , mOutputContext(nullptr) { } @@ -68,15 +70,22 @@ class RcpCapsDiag * * @param[in] aArgs The arguments of diagnostics command line. * @param[in] aArgsLength The number of arguments in @p aArgs. - * @param[out] aOutput The diagnostics execution result. - * @param[in] aOutputMaxLen The output buffer size. * * @retval OT_ERROR_INVALID_ARGS The command is supported but invalid arguments provided. * @retval OT_ERROR_NONE The command is successfully processed. * @retval OT_ERROR_INVALID_COMMAND The command is not valid or not supported. * */ - otError DiagProcess(char *aArgs[], uint8_t aArgsLength, char *aOutput, size_t aOutputMaxLen); + otError DiagProcess(char *aArgs[], uint8_t aArgsLength); + + /** + * Sets the diag output callback. + * + * @param[in] aCallback A pointer to a function that is called on outputting diag messages. + * @param[in] aContext A user context pointer. + * + */ + void SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void *aContext); private: template otError HandleSpinelCommand(void); @@ -108,9 +117,9 @@ class RcpCapsDiag static const struct SpinelEntry sSpinelEntries[]; - Spinel::RadioSpinel &mRadioSpinel; - char *mOutputStart; - char *mOutputEnd; + Spinel::RadioSpinel &mRadioSpinel; + otPlatDiagOutputCallback mOutputCallback; + void *mOutputContext; }; } // namespace Posix diff --git a/tests/fuzz/fuzzer_platform.cpp b/tests/fuzz/fuzzer_platform.cpp index abc8baae3..524760954 100644 --- a/tests/fuzz/fuzzer_platform.cpp +++ b/tests/fuzz/fuzzer_platform.cpp @@ -488,17 +488,18 @@ otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex) void otPlatSettingsWipe(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); } -otError otPlatDiagProcess(otInstance *aInstance, - uint8_t aArgsLength, - char *aArgs[], - char *aOutput, - size_t aOutputMaxLen) +void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aCallback); + OT_UNUSED_VARIABLE(aContext); +} + +otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { OT_UNUSED_VARIABLE(aInstance); OT_UNUSED_VARIABLE(aArgsLength); OT_UNUSED_VARIABLE(aArgs); - OT_UNUSED_VARIABLE(aOutput); - OT_UNUSED_VARIABLE(aOutputMaxLen); return OT_ERROR_INVALID_COMMAND; } diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp index 0cef5796e..89dfda775 100644 --- a/tests/unit/test_platform.cpp +++ b/tests/unit/test_platform.cpp @@ -99,6 +99,9 @@ void testFreeInstance(otInstance *aInstance) bool sDiagMode = false; +static otPlatDiagOutputCallback sOutputCallback = nullptr; +static void *sOutputCallbackContext = nullptr; + extern "C" { #if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE @@ -225,9 +228,30 @@ OT_TOOL_WEAK otError otPlatEntropyGet(uint8_t *aOutput, uint16_t aOutputLength) return error; } -OT_TOOL_WEAK void otPlatDiagProcess(otInstance *, uint8_t, char *aArgs[], char *aOutput, size_t aOutputMaxLen) +static void DiagOutput(const char *aFormat, ...) { - snprintf(aOutput, aOutputMaxLen, "diag feature '%s' is not supported\r\n", aArgs[0]); + va_list args; + + va_start(args, aFormat); + + if (sOutputCallback != nullptr) + { + sOutputCallback(aFormat, args, sOutputCallbackContext); + } + + va_end(args); +} + +OT_TOOL_WEAK void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext) +{ + sOutputCallback = aCallback; + sOutputCallbackContext = aContext; +} + +OT_TOOL_WEAK otError otPlatDiagProcess(otInstance *, uint8_t, char *aArgs[]) +{ + DiagOutput("diag feature '%s' is not supported\r\n", aArgs[0]); + return OT_ERROR_NONE; } OT_TOOL_WEAK void otPlatDiagModeSet(bool aMode) { sDiagMode = aMode; } diff --git a/tests/unit/test_platform.h b/tests/unit/test_platform.h index 8f9d2917a..66df45a5b 100644 --- a/tests/unit/test_platform.h +++ b/tests/unit/test_platform.h @@ -33,6 +33,7 @@ #include #include +#include #include #include #include From 387831b697097ba71b982fffc26655761c1b07e9 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 20 Jun 2024 20:11:27 -0700 Subject: [PATCH 41/65] [routing-manager] simplify `RxRaTracker::HandleRouterTimer()` (#10382) This commit simplifies `RxRaTracker::HandleRouterTimer()`. When all NS probes to a router fail and it is marked as unreachable, `HandleRouterTimer()` now directly removes/deprecates its route/on-link prefixes, replacing a separate method previously used for this purpose. Additionally, a new helper method, `ShouldCheckReachability()`, is added to check if a reachability check (sending NS probes) is needed. This check is performed only if the router is not already marked as unreachable and is not the local device itself. --- src/core/border_router/routing_manager.cpp | 87 +++++++++------------- src/core/border_router/routing_manager.hpp | 2 +- 2 files changed, 36 insertions(+), 53 deletions(-) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index 5e4dd2d08..b3ec00fe4 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -1459,37 +1459,6 @@ void RoutingManager::RxRaTracker::RemoveOrDeprecateOldEntries(TimeMilli aTimeThr RemoveExpiredEntries(); } -void RoutingManager::RxRaTracker::RemoveOrDeprecateEntriesFromUnreachableRouters(void) -{ - // Remove route prefix entries and deprecate on-link prefix entries - // in the table for routers that have reached the max NS probe - // attempts and considered unreachable. - - for (Router &router : mRouters) - { - if (router.IsReachable()) - { - continue; - } - - for (OnLinkPrefix &entry : router.mOnLinkPrefixes) - { - if (!entry.IsDeprecated()) - { - entry.ClearPreferredLifetime(); - SignalTableChanged(); - } - } - - for (RoutePrefix &entry : router.mRoutePrefixes) - { - entry.ClearValidLifetime(); - } - } - - RemoveExpiredEntries(); -} - void RoutingManager::RxRaTracker::ScheduleAllTimers(void) { TimeMilli now = TimerMilli::GetNow(); @@ -1522,10 +1491,8 @@ void RoutingManager::RxRaTracker::ScheduleAllTimers(void) for (const Router &router : mRouters) { - if (router.IsReachable() && !router.mIsLocalDevice) + if (router.ShouldCheckReachability()) { - // Skip if router is this device or has failed all - // earlier NS probes. routerTimeout.UpdateIfEarlier(router.mTimeout); } @@ -1708,39 +1675,45 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void) for (Router &router : mRouters) { - if (!router.IsReachable()) + if (!router.ShouldCheckReachability() || (router.mTimeout > now)) { continue; } - // Skip NS probes if the router is this device. This prevents - // issues where the platform might not be able to receive and - // process the NA messages from the local device itself. + router.mNsProbeCount++; - if (router.mIsLocalDevice) + if (router.IsReachable()) { - continue; + router.mTimeout = now + ((router.mNsProbeCount < Router::kMaxNsProbes) ? Router::kNsProbeRetryInterval + : Router::kNsProbeTimeout); + SendNeighborSolicitToRouter(router); } - - if (router.mTimeout <= now) + else { - router.mNsProbeCount++; + LogInfo("No response to all Neighbor Solicitations attempts from router %s - marking it unreachable", + router.mAddress.ToString().AsCString()); - if (!router.IsReachable()) + // Remove route prefix entries and deprecate on-link prefix entries + // of the unreachable router. + + for (OnLinkPrefix &entry : router.mOnLinkPrefixes) { - LogInfo("No response to all Neighbor Solicitations attempts from router %s", - router.mAddress.ToString().AsCString()); - continue; + if (!entry.IsDeprecated()) + { + entry.ClearPreferredLifetime(); + SignalTableChanged(); + } } - router.mTimeout = now + ((router.mNsProbeCount < Router::kMaxNsProbes) ? Router::kNsProbeRetryInterval - : Router::kNsProbeTimeout); - - SendNeighborSolicitToRouter(router); + for (RoutePrefix &entry : router.mRoutePrefixes) + { + entry.ClearValidLifetime(); + SignalTableChanged(); + } } } - RemoveOrDeprecateEntriesFromUnreachableRouters(); + RemoveExpiredEntries(); ScheduleAllTimers(); } @@ -1940,6 +1913,16 @@ Error RoutingManager::RxRaTracker::Iterator::AdvanceToNextEntry(void) //--------------------------------------------------------------------------------------------------------------------- // RxRaTracker::Router +bool RoutingManager::RxRaTracker::Router::ShouldCheckReachability(void) const +{ + // Perform reachability check (send NS probes) only if the router: + // - Is not already marked as unreachable (due to failed NS probes) + // - Is not the local device itself (to avoid potential issues with + // the platform receiving/processing NAs from itself). + + return IsReachable() && !mIsLocalDevice; +} + bool RoutingManager::RxRaTracker::Router::Matches(EmptyChecker aChecker) const { // Checks whether or not a `Router` instance has any useful info. An diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 41160638f..16286658b 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -828,6 +828,7 @@ class RoutingManager : public InstanceLocator }; bool IsReachable(void) const { return mNsProbeCount <= kMaxNsProbes; } + bool ShouldCheckReachability(void) const; bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; } bool Matches(EmptyChecker aChecker) const; void CopyInfoTo(RouterEntry &aEntry, TimeMilli aNow) const; @@ -915,7 +916,6 @@ class RoutingManager : public InstanceLocator void ProcessRouteInfoOption(const RouteInfoOption &aRio, Router &aRouter); void ProcessRaFlagsExtOption(const RaFlagsExtOption &aFlagsOption, Router &aRouter); bool ContainsOnLinkPrefix(OnLinkPrefix::UlaChecker aUlaChecker) const; - void RemoveOrDeprecateEntriesFromUnreachableRouters(void); void RemoveRoutersWithNoEntriesOrFlags(void); void RemoveExpiredEntries(void); void SignalTableChanged(void); From 1b871905093ab0b9e806c8f8ee3e5173a4c0c509 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 20 Jun 2024 20:12:16 -0700 Subject: [PATCH 42/65] [cli] output service ID when listing services in network data (#10408) --- src/cli/README_NETDATA.md | 5 +++-- src/cli/cli_network_data.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cli/README_NETDATA.md b/src/cli/README_NETDATA.md index 940288596..5deeb7762 100644 --- a/src/cli/README_NETDATA.md +++ b/src/cli/README_NETDATA.md @@ -374,6 +374,7 @@ Service entries are listed under `Services` header: - Flags - s: Stable flag - RLOC16 of devices which added the service entry +- Service ID 6LoWPAN Context IDs are listed under `Contexts` header: @@ -400,7 +401,7 @@ Routes: fd00:1234:0:0::/64 s med a000 fd00:4567:0:0::/64 s med 8000 Services: -44970 5d fddead00beef00007bad0069ce45948504d2 s a000 +44970 5d fddead00beef00007bad0069ce45948504d2 s a000 0 Contexts: fd00:dead:beef:cafe::/64 1 c Commissioning: @@ -417,7 +418,7 @@ fd00:dead:beef:cafe::/64 paros med a000 Routes: fd00:1234:0:0::/64 s med a000 Services: -44970 5d fddead00beef00007bad0069ce45948504d2 s a000 +44970 5d fddead00beef00007bad0069ce45948504d2 s a000 0 Done ``` diff --git a/src/cli/cli_network_data.cpp b/src/cli/cli_network_data.cpp index 5d1d769c0..629b59f20 100644 --- a/src/cli/cli_network_data.cpp +++ b/src/cli/cli_network_data.cpp @@ -170,7 +170,7 @@ void NetworkData::OutputService(const otServiceConfig &aConfig) OutputFormat(" s"); } - OutputLine(" %04x", aConfig.mServerConfig.mRloc16); + OutputLine(" %04x %u", aConfig.mServerConfig.mRloc16, aConfig.mServiceId); } /** @@ -713,8 +713,8 @@ otError NetworkData::OutputBinary(bool aLocal) * Routes: * fd49:7770:7fc5:0::/64 s med 4000 * Services: - * 44970 5d c000 s 4000 - * 44970 01 9a04b000000e10 s 4000 + * 44970 5d c000 s 4000 0 + * 44970 01 9a04b000000e10 s 4000 1 * Contexts: * fd00:dead:beef:cafe::/64 1 c * Commissioning: @@ -771,6 +771,7 @@ otError NetworkData::OutputBinary(bool aLocal) * * Flags * * s: Stable flag * * RLOC16 of devices which added the service entry + * * Service ID * @par * 6LoWPAN Context IDs are listed under `Contexts` header: * * The prefix From 89b54dca2b4b7f5da0f203eaac8a9e048738403f Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 20 Jun 2024 20:41:49 -0700 Subject: [PATCH 43/65] [mle] remove `GetNextHop()` and directly use `RouterTable` method (#10417) This commit removes the `MleRouter::GetNextHop()` method and instead directly uses `RouterTable::GetNextHop()`. This improves consistency across all modules. --- src/core/thread/mesh_forwarder_ftd.cpp | 4 ++-- src/core/thread/mle_router.cpp | 4 ++-- src/core/thread/mle_router.hpp | 10 ---------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 2daae86b5..78020bc9d 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -374,7 +374,7 @@ Error MeshForwarder::UpdateMeshRoute(Message &aMessage) IgnoreError(meshHeader.ParseFrom(aMessage)); - nextHop = Get().GetNextHop(meshHeader.GetDestination()); + nextHop = Get().GetNextHop(meshHeader.GetDestination()); if (nextHop != Mac::kShortAddrInvalid) { @@ -577,7 +577,7 @@ Error MeshForwarder::UpdateIp6RouteFtd(const Ip6::Header &aIp6Header, Message &a SuccessOrExit(error = mle.CheckReachability(mMeshDest, aIp6Header)); aMessage.SetMeshDest(mMeshDest); - mMacAddrs.mDestination.SetShort(mle.GetNextHop(mMeshDest)); + mMacAddrs.mDestination.SetShort(Get().GetNextHop(mMeshDest)); if (mMacAddrs.mDestination.GetShort() != mMeshDest) { diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 615b6a308..8374accaa 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3217,7 +3217,7 @@ void MleRouter::ResolveRoutingLoops(uint16_t aSourceMac, uint16_t aDestRloc16) { Router *router; - if (aSourceMac != GetNextHop(aDestRloc16)) + if (aSourceMac != mRouterTable.GetNextHop(aDestRloc16)) { ExitNow(); } @@ -3263,7 +3263,7 @@ Error MleRouter::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6He ExitNow(); } - isReachable = (GetNextHop(aMeshDest) != Mac::kShortAddrInvalid); + isReachable = (mRouterTable.GetNextHop(aMeshDest) != Mac::kShortAddrInvalid); exit: return isReachable ? kErrorNone : kErrorNoRoute; diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index e7d7b47c0..2b4d0fb79 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -236,16 +236,6 @@ class MleRouter : public Mle */ void SetRouterId(uint8_t aRouterId); - /** - * Returns the next hop towards an RLOC16 destination. - * - * @param[in] aDestination The RLOC16 of the destination. - * - * @returns A RLOC16 of the next hop if a route is known, kInvalidRloc16 otherwise. - * - */ - uint16_t GetNextHop(uint16_t aDestination) { return mRouterTable.GetNextHop(aDestination); } - /** * Returns the NETWORK_ID_TIMEOUT value. * From 473fbcaba93972b62d94c5e0492044bdda340e1f Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 21 Jun 2024 11:26:13 -0700 Subject: [PATCH 44/65] [child-table] add `HasMinimalChild()` and move logic from `MleRouter` (#10418) This commit adds the `HasMinimalChild()` method to the `ChildTable` class and moves the logic for checking if a device has an MTD child with a given RLOC16 from the `MleRouter` class to `ChildTable`. This aligns better with the `ChildTable` class's responsibility of managing all children and providing methods to search and find child entries in the table. --- src/core/thread/address_resolver.cpp | 4 ++-- src/core/thread/child_table.cpp | 16 ++++++++++++++++ src/core/thread/child_table.hpp | 13 +++++++++++++ src/core/thread/mesh_forwarder_ftd.cpp | 2 +- src/core/thread/mle_router.cpp | 16 ---------------- src/core/thread/mle_router.hpp | 11 ----------- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/core/thread/address_resolver.cpp b/src/core/thread/address_resolver.cpp index db0390386..5acb9c7fe 100644 --- a/src/core/thread/address_resolver.cpp +++ b/src/core/thread/address_resolver.cpp @@ -397,12 +397,12 @@ void AddressResolver::UpdateSnoopedCacheEntry(const Ip6::Address &aEid, // is this device or an MTD (minimal) child of the device itself. macAddress = Get().GetShortAddress(); - VerifyOrExit((aRloc16 != macAddress) && !Get().IsMinimalChild(aRloc16)); + VerifyOrExit((aRloc16 != macAddress) && !Get().HasMinimalChild(aRloc16)); // Ensure that the destination of the snooped message is this device // or a minimal child of this device. - VerifyOrExit((aDest == macAddress) || Get().IsMinimalChild(aDest)); + VerifyOrExit((aDest == macAddress) || Get().HasMinimalChild(aDest)); entry = NewCacheEntry(/* aSnoopedEntry */ true); VerifyOrExit(entry != nullptr); diff --git a/src/core/thread/child_table.cpp b/src/core/thread/child_table.cpp index 7fb557dbd..1f9b3b6d3 100644 --- a/src/core/thread/child_table.cpp +++ b/src/core/thread/child_table.cpp @@ -315,6 +315,22 @@ void ChildTable::RefreshStoredChildren(void) return; } +bool ChildTable::HasMinimalChild(uint16_t aRloc16) const +{ + bool hasMinimalChild = false; + const Child *child; + + VerifyOrExit(Mle::RouterIdMatch(aRloc16, Get().GetRloc16())); + + child = FindChild(Child::AddressMatcher(aRloc16, Child::kInStateValidOrRestoring)); + VerifyOrExit(child != nullptr); + + hasMinimalChild = !child->IsFullThreadDevice(); + +exit: + return hasMinimalChild; +} + bool ChildTable::HasSleepyChildWithAddress(const Ip6::Address &aIp6Address) const { bool hasChild = false; diff --git a/src/core/thread/child_table.hpp b/src/core/thread/child_table.hpp index 61d930742..510db7ef5 100644 --- a/src/core/thread/child_table.hpp +++ b/src/core/thread/child_table.hpp @@ -292,6 +292,19 @@ class ChildTable : public InstanceLocator, private NonCopyable */ Error StoreChild(const Child &aChild); + /** + * Indicates whether or not the child table contains an MTD child with a given @p aRloc16. + * + * Only children in `kInStateValidOrRestoring` are considered. + * + * @param[in] aRloc16 The RLOC16 to check. + * + * @retval TRUE If the child table contains an MTD child with @p aRloc16. + * @retval FALSE If the child table does not contain an MTD child with @p aRloc16. + * + */ + bool HasMinimalChild(uint16_t aRloc16) const; + /** * Indicates whether the child table contains any sleepy child (in states valid or restoring) with a * given IPv6 address. diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 78020bc9d..4b29627d5 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -677,7 +677,7 @@ void MeshForwarder::HandleMesh(FrameData &aFrameData, const Mac::Address &aMacSo UpdateRoutes(aFrameData, meshAddrs); if (meshAddrs.mDestination.GetShort() == Get().GetShortAddress() || - Get().IsMinimalChild(meshAddrs.mDestination.GetShort())) + Get().HasMinimalChild(meshAddrs.mDestination.GetShort())) { if (Lowpan::FragmentHeader::IsFragmentHeader(aFrameData)) { diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 8374accaa..9642aaef1 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3107,22 +3107,6 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination, LogSendError(kTypeDataResponse, error); } -bool MleRouter::IsMinimalChild(uint16_t aRloc16) -{ - bool isMinimalChild = false; - Neighbor *neighbor; - - VerifyOrExit(RouterIdMatch(aRloc16, GetRloc16())); - - neighbor = mNeighborTable.FindNeighbor(aRloc16); - VerifyOrExit(neighbor != nullptr); - - isMinimalChild = !neighbor->IsFullThreadDevice(); - -exit: - return isMinimalChild; -} - void MleRouter::RemoveRouterLink(Router &aRouter) { switch (mRole) diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 2b4d0fb79..8dbcb0807 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -361,17 +361,6 @@ class MleRouter : public Mle */ void RemoveRouterLink(Router &aRouter); - /** - * Indicates whether or not the RLOC16 is an MTD child of this device. - * - * @param[in] aRloc16 The RLOC16. - * - * @retval TRUE if @p aRloc16 is an MTD child of this device. - * @retval FALSE if @p aRloc16 is not an MTD child of this device. - * - */ - bool IsMinimalChild(uint16_t aRloc16); - /** * Indicates whether or not the given Thread partition attributes are preferred. * From 8370a827a9bd9d8fbd97315cd863ff233827c23f Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 24 Jun 2024 05:00:09 -0700 Subject: [PATCH 45/65] [mesh-forwarder] remove unused `SetDiscoverParameters()` method (#10420) --- src/core/thread/mesh_forwarder.hpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 1ccd0d0ba..459481b83 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -240,15 +240,6 @@ class MeshForwarder : public InstanceLocator, private NonCopyable */ void SetRxOnWhenIdle(bool aRxOnWhenIdle); - /** - * Sets the scan parameters for MLE Discovery Request messages. - * - * @param[in] aScanChannels A reference to channel mask indicating which channels to scan. - * If @p aScanChannels is empty, then all channels are used instead. - * - */ - void SetDiscoverParameters(const Mac::ChannelMask &aScanChannels); - #if OPENTHREAD_FTD /** * Frees any messages queued for an existing child. From a9f34d944c497bff1321121e8300d51b215a5610 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 24 Jun 2024 05:25:55 -0700 Subject: [PATCH 46/65] [child] use `Array` to track registered addresses (#10422) This commit updates the `Child` class to use `Array` to track the list of IPv6 addresses registered by an MTD child, simplifying the code. --- src/core/thread/child.cpp | 86 ++++++++++++++------------------------- src/core/thread/child.hpp | 19 +++++---- 2 files changed, 41 insertions(+), 64 deletions(-) diff --git a/src/core/thread/child.cpp b/src/core/thread/child.cpp index d627e175b..17cf3075e 100644 --- a/src/core/thread/child.cpp +++ b/src/core/thread/child.cpp @@ -82,7 +82,19 @@ const Ip6::Address *Child::AddressIterator::GetAddress(void) const // from one for first element (i.e, `mIndex - 1` gives the array // index). - return (mIndex == 0) ? &mMeshLocalAddress : ((mIndex < kMaxIndex) ? &mChild.mIp6Address[mIndex - 1] : nullptr); + const Ip6::Address *address = nullptr; + + if (mIndex == 0) + { + address = &mMeshLocalAddress; + ExitNow(); + } + + VerifyOrExit(mIndex - 1 < mChild.mIp6Addresses.GetLength()); + address = &mChild.mIp6Addresses[static_cast(mIndex - 1)]; + +exit: + return address; } void Child::AddressIterator::Update(void) @@ -119,7 +131,7 @@ void Child::Clear(void) void Child::ClearIp6Addresses(void) { mMeshLocalIid.Clear(); - ClearAllBytes(mIp6Address); + mIp6Addresses.Clear(); #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE mMlrToRegisterMask.Clear(); mMlrRegisteredMask.Clear(); @@ -165,18 +177,8 @@ Error Child::AddIp6Address(const Ip6::Address &aAddress) ExitNow(); } - for (Ip6::Address &ip6Address : mIp6Address) - { - if (ip6Address.IsUnspecified()) - { - ip6Address = aAddress; - ExitNow(); - } - - VerifyOrExit(ip6Address != aAddress, error = kErrorAlready); - } - - error = kErrorNoBufs; + VerifyOrExit(!mIp6Addresses.Contains(aAddress), error = kErrorAlready); + error = mIp6Addresses.PushBack(aAddress); exit: return error; @@ -184,10 +186,8 @@ Error Child::AddIp6Address(const Ip6::Address &aAddress) Error Child::RemoveIp6Address(const Ip6::Address &aAddress) { - Error error = kErrorNotFound; - uint16_t index; - - VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs); + Error error = kErrorNotFound; + Ip6::Address *entry; if (Get().IsMeshLocalAddress(aAddress)) { @@ -200,25 +200,11 @@ Error Child::RemoveIp6Address(const Ip6::Address &aAddress) ExitNow(); } - for (index = 0; index < kNumIp6Addresses; index++) - { - VerifyOrExit(!mIp6Address[index].IsUnspecified()); - - if (mIp6Address[index] == aAddress) - { - error = kErrorNone; - break; - } - } - - SuccessOrExit(error); - - for (; index < kNumIp6Addresses - 1; index++) - { - mIp6Address[index] = mIp6Address[index + 1]; - } + entry = mIp6Addresses.Find(aAddress); + VerifyOrExit(entry != nullptr); - mIp6Address[kNumIp6Addresses - 1].Clear(); + mIp6Addresses.Remove(*entry); + error = kErrorNone; exit: return error; @@ -226,28 +212,20 @@ Error Child::RemoveIp6Address(const Ip6::Address &aAddress) bool Child::HasIp6Address(const Ip6::Address &aAddress) const { - bool retval = false; + bool hasAddress = false; VerifyOrExit(!aAddress.IsUnspecified()); if (Get().IsMeshLocalAddress(aAddress)) { - retval = (aAddress.GetIid() == mMeshLocalIid); + hasAddress = (aAddress.GetIid() == mMeshLocalIid); ExitNow(); } - for (const Ip6::Address &ip6Address : mIp6Address) - { - VerifyOrExit(!ip6Address.IsUnspecified()); - - if (ip6Address == aAddress) - { - ExitNow(retval = true); - } - } + hasAddress = mIp6Addresses.Contains(aAddress); exit: - return retval; + return hasAddress; } #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE @@ -255,10 +233,8 @@ Error Child::GetDomainUnicastAddress(Ip6::Address &aAddress) const { Error error = kErrorNotFound; - for (const Ip6::Address &ip6Address : mIp6Address) + for (const Ip6::Address &ip6Address : mIp6Addresses) { - VerifyOrExit(!ip6Address.IsUnspecified()); - if (Get().IsDomainUnicast(ip6Address)) { aAddress = ip6Address; @@ -295,9 +271,9 @@ MlrState Child::GetAddressMlrState(const Ip6::Address &aAddress) const { uint16_t addressIndex; - OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address)); + OT_ASSERT(mIp6Addresses.IsInArrayBuffer(&aAddress)); - addressIndex = static_cast(&aAddress - mIp6Address); + addressIndex = mIp6Addresses.IndexOf(aAddress); return mMlrToRegisterMask.Get(addressIndex) ? kMlrStateToRegister @@ -308,9 +284,9 @@ void Child::SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState) { uint16_t addressIndex; - OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address)); + OT_ASSERT(mIp6Addresses.IsInArrayBuffer(&aAddress)); - addressIndex = static_cast(&aAddress - mIp6Address); + addressIndex = mIp6Addresses.IndexOf(aAddress); mMlrToRegisterMask.Set(addressIndex, aState == kMlrStateToRegister); mMlrRegisteredMask.Set(addressIndex, aState == kMlrStateRegistered); diff --git a/src/core/thread/child.hpp b/src/core/thread/child.hpp index d05fd094a..d2f707f72 100644 --- a/src/core/thread/child.hpp +++ b/src/core/thread/child.hpp @@ -502,7 +502,8 @@ class Child : public Neighbor, static constexpr uint16_t kNumIp6Addresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1; - typedef BitVector ChildIp6AddressMask; + typedef BitVector ChildIp6AddressMask; + typedef Array Ip6AddressArray; class AddressIteratorBuilder { @@ -521,25 +522,25 @@ class Child : public Neighbor, Ip6::Address::TypeFilter mFilter; }; - Ip6::InterfaceIdentifier mMeshLocalIid; ///< IPv6 address IID for mesh-local address - Ip6::Address mIp6Address[kNumIp6Addresses]; ///< Registered IPv6 addresses - uint32_t mTimeout; ///< Child timeout + uint32_t mTimeout; + Ip6::InterfaceIdentifier mMeshLocalIid; + Ip6AddressArray mIp6Addresses; #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE ChildIp6AddressMask mMlrToRegisterMask; ChildIp6AddressMask mMlrRegisteredMask; #endif - uint8_t mNetworkDataVersion; ///< Current Network Data version + uint8_t mNetworkDataVersion; union { - uint8_t mRequestTlvs[kMaxRequestTlvs]; ///< Requested MLE TLVs - Mle::TxChallenge mAttachChallenge; ///< The challenge value + uint8_t mRequestTlvs[kMaxRequestTlvs]; + Mle::TxChallenge mAttachChallenge; }; - uint16_t mSupervisionInterval; // Supervision interval for the child (in sec). - uint16_t mSecondsSinceSupervision; // Number of seconds since last supervision of the child. + uint16_t mSupervisionInterval; + uint16_t mSecondsSinceSupervision; static_assert(OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS < 8192, "mQueuedMessageCount cannot fit max required!"); }; From 336984b25a3953509157906a9806a03259c5ce90 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 24 Jun 2024 05:29:53 -0700 Subject: [PATCH 47/65] [mle] add `IsRouterRloc16()` and `IsChildRloc16()` (#10423) This commit adds `IsRouterRloc16()` (replacing `IsActiveRouter()`), which checks whether a given RLOC16 refers to a router and not a child. The new name clarifies that it is only a check on the RLOC16 value and does not verify if the corresponding router ID is allocated and active. This commit also adds `IsChildRloc16()`, which is similar to `IsRouterRloc16()` and checks if the given RLOC16 is for a child. This simplifies the code and improves readability. --- src/core/thread/mesh_forwarder.cpp | 2 +- src/core/thread/mesh_forwarder_ftd.cpp | 2 +- src/core/thread/mle.cpp | 10 +++++----- src/core/thread/mle_router.cpp | 14 +++++++------- src/core/thread/mle_types.hpp | 19 +++++++++++++++---- src/core/thread/network_data.cpp | 4 ++-- src/core/thread/network_data_leader.cpp | 2 +- src/core/thread/network_data_notifier.cpp | 2 +- src/core/thread/network_data_publisher.cpp | 2 +- src/core/thread/router_table.cpp | 6 +++--- src/core/utils/mesh_diag.cpp | 2 +- 11 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 8a6b8611f..5ff167ed0 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -1157,7 +1157,7 @@ void MeshForwarder::UpdateNeighborLinkFailures(Neighbor &aNeighbor, { aNeighbor.IncrementLinkFailures(); - if (aAllowNeighborRemove && (Mle::IsActiveRouter(aNeighbor.GetRloc16())) && + if (aAllowNeighborRemove && (Mle::IsRouterRloc16(aNeighbor.GetRloc16())) && (aNeighbor.GetLinkFailures() >= aFailLimit)) { #if OPENTHREAD_FTD diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 4b29627d5..810d2c62f 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -487,7 +487,7 @@ Error MeshForwarder::AnycastRouteLookup(uint8_t aServiceId, AnycastType aType, u routerId = Mle::RouterIdFromRloc16(bestDest); - if (!(Mle::IsActiveRouter(bestDest) || Mle::Rloc16FromRouterId(routerId) == Get().GetRloc16())) + if (!(Mle::IsRouterRloc16(bestDest) || Mle::Rloc16FromRouterId(routerId) == Get().GetRloc16())) { // if agent is neither active router nor child of this device // use the parent of the ED Agent as Dest diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 246d73f2c..00d754c50 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -214,7 +214,7 @@ Error Mle::Start(StartMode aMode) Attach(kAnyPartition); } #if OPENTHREAD_FTD - else if (IsActiveRouter(GetRloc16())) + else if (IsRouterRloc16(GetRloc16())) { if (Get().BecomeRouter(ThreadStatusTlv::kTooFewRouters) != kErrorNone) { @@ -397,7 +397,7 @@ void Mle::Restore(void) } #if OPENTHREAD_MTD - if (!IsActiveRouter(networkInfo.GetRloc16())) + if (IsChildRloc16(networkInfo.GetRloc16())) #endif { Get().SetShortAddress(networkInfo.GetRloc16()); @@ -412,7 +412,7 @@ void Mle::Restore(void) ExitNow(); } - if (!IsActiveRouter(networkInfo.GetRloc16())) + if (IsChildRloc16(networkInfo.GetRloc16())) { if (Get().Read(parentInfo) != kErrorNone) { @@ -2751,7 +2751,7 @@ void Mle::ReestablishLinkWithNeighbor(Neighbor &aNeighbor) #if OPENTHREAD_FTD VerifyOrExit(IsFullThreadDevice()); - if (IsActiveRouter(aNeighbor.GetRloc16())) + if (IsRouterRloc16(aNeighbor.GetRloc16())) { IgnoreError(Get().SendLinkRequest(&aNeighbor)); } @@ -3045,7 +3045,7 @@ bool Mle::IsBetterParent(uint16_t aRloc16, rval = ThreeWayCompare(LinkQualityForLinkMargin(aTwoWayLinkMargin), mParentCandidate.GetTwoWayLinkQuality()); VerifyOrExit(rval == 0); - rval = ThreeWayCompare(IsActiveRouter(aRloc16), IsActiveRouter(mParentCandidate.GetRloc16())); + rval = ThreeWayCompare(IsRouterRloc16(aRloc16), IsRouterRloc16(mParentCandidate.GetRloc16())); VerifyOrExit(rval == 0); rval = ThreeWayCompare(aConnectivityTlv.GetParentPriority(), mParentCandidate.mPriority); diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 9642aaef1..2edd75f44 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -702,7 +702,7 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) switch (Tlv::Find(aRxInfo.mMessage, sourceAddress)) { case kErrorNone: - if (IsActiveRouter(sourceAddress)) + if (IsRouterRloc16(sourceAddress)) { neighbor = mRouterTable.FindRouterByRloc16(sourceAddress); VerifyOrExit(neighbor != nullptr, error = kErrorParse); @@ -727,7 +727,7 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) case kErrorNotFound: // A missing source address indicates that the router was // recently reset. - VerifyOrExit(aRxInfo.IsNeighborStateValid() && IsActiveRouter(aRxInfo.mNeighbor->GetRloc16()), + VerifyOrExit(aRxInfo.IsNeighborStateValid() && IsRouterRloc16(aRxInfo.mNeighbor->GetRloc16()), error = kErrorDrop); neighbor = aRxInfo.mNeighbor; break; @@ -791,7 +791,7 @@ Error MleRouter::SendLinkAccept(const RxInfo &aRxInfo, linkMargin = Get().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss()); SuccessOrExit(error = message->AppendLinkMarginTlv(linkMargin)); - if (aNeighbor != nullptr && IsActiveRouter(aNeighbor->GetRloc16())) + if (aNeighbor != nullptr && IsRouterRloc16(aNeighbor->GetRloc16())) { SuccessOrExit(error = message->AppendLeaderDataTlv()); } @@ -891,7 +891,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) Log(kMessageReceive, aRequest ? kTypeLinkAcceptAndRequest : kTypeLinkAccept, aRxInfo.mMessageInfo.GetPeerAddr(), sourceAddress); - VerifyOrExit(IsActiveRouter(sourceAddress), error = kErrorParse); + VerifyOrExit(IsRouterRloc16(sourceAddress), error = kErrorParse); routerId = RouterIdFromRloc16(sourceAddress); router = mRouterTable.FindRouterById(routerId); @@ -1249,7 +1249,7 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, c ExitNow(); } - VerifyOrExit(IsActiveRouter(aSourceAddress) && routeTlv.IsValid()); + VerifyOrExit(IsRouterRloc16(aSourceAddress) && routeTlv.IsValid()); routerId = RouterIdFromRloc16(aSourceAddress); #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE @@ -2353,7 +2353,7 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo) LeaderData leaderData; Child *child; - if ((aRxInfo.mNeighbor == nullptr) || IsActiveRouter(aRxInfo.mNeighbor->GetRloc16()) || + if ((aRxInfo.mNeighbor == nullptr) || IsRouterRloc16(aRxInfo.mNeighbor->GetRloc16()) || !Get().Contains(*aRxInfo.mNeighbor)) { Log(kMessageReceive, kTypeChildUpdateResponseOfUnknownChild, aRxInfo.mMessageInfo.GetPeerAddr()); @@ -3143,7 +3143,7 @@ void MleRouter::RemoveNeighbor(Neighbor &aNeighbor) { ClearParentCandidate(); } - else if (!IsActiveRouter(aNeighbor.GetRloc16())) + else if (IsChildRloc16(aNeighbor.GetRloc16())) { OT_ASSERT(mChildTable.Contains(aNeighbor)); diff --git a/src/core/thread/mle_types.hpp b/src/core/thread/mle_types.hpp index fd08cdccd..a228d06ee 100644 --- a/src/core/thread/mle_types.hpp +++ b/src/core/thread/mle_types.hpp @@ -682,15 +682,26 @@ inline uint16_t CommissionerAloc16FromId(uint16_t aSessionId) inline uint16_t Rloc16FromRouterId(uint8_t aRouterId) { return static_cast(aRouterId << kRouterIdOffset); } /** - * Indicates whether or not @p aRloc16 refers to an active router. + * Indicates whether or not @p aRloc16 refers to a router. * * @param[in] aRloc16 The RLOC16 value. * - * @retval TRUE If @p aRloc16 refers to an active router. - * @retval FALSE If @p aRloc16 does not refer to an active router. + * @retval TRUE If @p aRloc16 refers to a router. + * @retval FALSE If @p aRloc16 does not refer to a router. * */ -inline bool IsActiveRouter(uint16_t aRloc16) { return ChildIdFromRloc16(aRloc16) == 0; } +inline bool IsRouterRloc16(uint16_t aRloc16) { return ChildIdFromRloc16(aRloc16) == 0; } + +/** + * Indicates whether or not @p aRloc16 refers to a child. + * + * @param[in] aRloc16 The RLOC16 value. + * + * @retval TRUE If @p aRloc16 refers to a child. + * @retval FALSE If @p aRloc16 does not refer to a child. + * + */ +inline bool IsChildRloc16(uint16_t aRloc16) { return ChildIdFromRloc16(aRloc16) != 0; } /** * Converts a device role into a human-readable string. diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp index 28675ad6f..9ced6a310 100644 --- a/src/core/thread/network_data.cpp +++ b/src/core/thread/network_data.cpp @@ -579,11 +579,11 @@ void NetworkData::AddRloc16ToRlocs(uint16_t aRloc16, Rlocs &aRlocs, RoleFilter a break; case kRouterRoleOnly: - VerifyOrExit(Mle::IsActiveRouter(aRloc16)); + VerifyOrExit(Mle::IsRouterRloc16(aRloc16)); break; case kChildRoleOnly: - VerifyOrExit(!Mle::IsActiveRouter(aRloc16)); + VerifyOrExit(Mle::IsChildRloc16(aRloc16)); break; } diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index 187e431c2..95b978907 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -339,7 +339,7 @@ int Leader::CompareRouteEntries(int8_t aFirstPreference, // If all the same, prefer the BR acting as a router over an // end device. - result = ThreeWayCompare(Mle::IsActiveRouter(aFirstRloc), Mle::IsActiveRouter(aSecondRloc)); + result = ThreeWayCompare(Mle::IsRouterRloc16(aFirstRloc), Mle::IsRouterRloc16(aSecondRloc)); #endif exit: diff --git a/src/core/thread/network_data_notifier.cpp b/src/core/thread/network_data_notifier.cpp index e5eebe62c..8d086baa2 100644 --- a/src/core/thread/network_data_notifier.cpp +++ b/src/core/thread/network_data_notifier.cpp @@ -138,7 +138,7 @@ Error Notifier::RemoveStaleChildEntries(void) for (uint16_t rloc16 : rlocs) { - if (!Mle::IsActiveRouter(rloc16) && Mle::RouterIdMatch(Get().GetRloc16(), rloc16) && + if (Mle::IsChildRloc16(rloc16) && Mle::RouterIdMatch(Get().GetRloc16(), rloc16) && Get().FindChild(rloc16, Child::kInStateValid) == nullptr) { error = SendServerDataNotification(rloc16); diff --git a/src/core/thread/network_data_publisher.cpp b/src/core/thread/network_data_publisher.cpp index 3ad23a330..5bf16d30e 100644 --- a/src/core/thread/network_data_publisher.cpp +++ b/src/core/thread/network_data_publisher.cpp @@ -275,7 +275,7 @@ bool Publisher::Entry::IsPreferred(uint16_t aRloc16) const // router over an entry from an end-device (e.g., a REED). If both // are the same type, then the one with smaller RLOC16 is preferred. - bool isOtherRouter = Mle::IsActiveRouter(aRloc16); + bool isOtherRouter = Mle::IsRouterRloc16(aRloc16); return (Get().IsRouterOrLeader() == isOtherRouter) ? (aRloc16 < Get().GetRloc16()) : isOtherRouter; diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index 7117e5c94..16a4d98c5 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -322,7 +322,7 @@ Error RouterTable::GetRouterInfo(uint16_t aRouterId, Router::Info &aRouterInfo) } else { - VerifyOrExit(Mle::IsActiveRouter(aRouterId), error = kErrorInvalidArgs); + VerifyOrExit(Mle::IsRouterRloc16(aRouterId), error = kErrorInvalidArgs); routerId = Mle::RouterIdFromRloc16(aRouterId); VerifyOrExit(routerId <= Mle::kMaxRouterId, error = kErrorInvalidArgs); } @@ -486,7 +486,7 @@ void RouterTable::GetNextHopAndPathCost(uint16_t aDestRloc16, uint16_t &aNextHop } } - if (!Mle::IsActiveRouter(aDestRloc16)) + if (Mle::IsChildRloc16(aDestRloc16)) { // Destination is a child. we assume best link quality // between destination and its parent router. @@ -721,7 +721,7 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighb mRouterIdMap.GetAsRouterIdSet(routerIdSet); - if ((aNeighbor != nullptr) && Mle::IsActiveRouter(aNeighbor->GetRloc16())) + if ((aNeighbor != nullptr) && Mle::IsRouterRloc16(aNeighbor->GetRloc16())) { // Sending a Link Accept message that may require truncation // of Route64 TLV. diff --git a/src/core/utils/mesh_diag.cpp b/src/core/utils/mesh_diag.cpp index e8092eb25..5e470b3f4 100644 --- a/src/core/utils/mesh_diag.cpp +++ b/src/core/utils/mesh_diag.cpp @@ -172,7 +172,7 @@ Error MeshDiag::SendQuery(uint16_t aRloc16, const uint8_t *aTlvs, uint8_t aTlvsL VerifyOrExit(Get().IsAttached(), error = kErrorInvalidState); VerifyOrExit(mState == kStateIdle, error = kErrorBusy); - VerifyOrExit(Mle::IsActiveRouter(aRloc16), error = kErrorInvalidArgs); + VerifyOrExit(Mle::IsRouterRloc16(aRloc16), error = kErrorInvalidArgs); VerifyOrExit(Get().IsAllocated(Mle::RouterIdFromRloc16(aRloc16)), error = kErrorNotFound); destination.SetToRoutingLocator(Get().GetMeshLocalPrefix(), aRloc16); From 5d3764d1ea1280f8dd6bd31dc8355fb8e3c69ed8 Mon Sep 17 00:00:00 2001 From: Handa Wang <7058128+superwhd@users.noreply.github.com> Date: Mon, 24 Jun 2024 20:31:14 +0800 Subject: [PATCH 48/65] [doc] fix the broken link of `meshdiag topology` in CLI README (#10430) --- src/cli/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/README.md b/src/cli/README.md index 4dac6266c..deb90c3d7 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -72,7 +72,7 @@ Done - [log](#log-filename-filename) - [mac](#mac-retries-direct) - [macfilter](#macfilter) -- [meshdiag](#meshdiag-topology) +- [meshdiag](#meshdiag-topology-ip6-addrs-children) - [mliid](#mliid-iid) - [mlr](#mlr-reg-ipaddr--timeout) - [mode](#mode) @@ -2089,7 +2089,7 @@ Set the log level. Done ``` -### meshdiag topology [ip6-addrs][children] +### meshdiag topology \[ip6-addrs\] \[children\] Discover network topology (list of routers and their connections). From 35847e19af0523cb28399c128cab6d5442ba5b4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 08:38:20 -0400 Subject: [PATCH 49/65] github-actions: bump step-security/harden-runner from 2.7.0 to 2.8.1 (#10432) Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.7.0 to 2.8.1. - [Release notes](https://github.com/step-security/harden-runner/releases) - [Commits](https://github.com/step-security/harden-runner/compare/63c24ba6bd7ba022e95695ff85de572c04a18142...17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6) --- updated-dependencies: - dependency-name: step-security/harden-runner dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 28 ++++++++++++++-------------- .github/workflows/codeql.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/fuzz.yml | 2 +- .github/workflows/makefile-check.yml | 2 +- .github/workflows/otci.yml | 2 +- .github/workflows/otns.yml | 6 +++--- .github/workflows/posix.yml | 12 ++++++------ .github/workflows/simulation-1.1.yml | 18 +++++++++--------- .github/workflows/simulation-1.2.yml | 14 +++++++------- .github/workflows/size.yml | 2 +- .github/workflows/toranj.yml | 10 +++++----- .github/workflows/unit.yml | 6 +++--- .github/workflows/version.yml | 2 +- 14 files changed, 54 insertions(+), 54 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74353173f..acfdd5d52 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -71,7 +71,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -85,7 +85,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -104,7 +104,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -144,7 +144,7 @@ jobs: CXX: ${{ matrix.compiler_cpp }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -163,7 +163,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -182,7 +182,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -238,7 +238,7 @@ jobs: gcc_extract_dir: arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -279,7 +279,7 @@ jobs: CXX: g++-${{ matrix.gcc_ver }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -312,7 +312,7 @@ jobs: CXX: clang++-${{ matrix.clang_ver }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -350,7 +350,7 @@ jobs: LDFLAGS: -m32 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -378,7 +378,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -414,7 +414,7 @@ jobs: CXX: ${{ matrix.CXX }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -438,7 +438,7 @@ jobs: image: openthread/environment steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9c1159c69..d1a4a3c4e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -54,7 +54,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 45bc98021..c8d37141e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -55,7 +55,7 @@ jobs: - docker_name: environment steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index da612bb36..2a5dbc33c 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/makefile-check.yml b/.github/workflows/makefile-check.yml index 1e38d85be..e264d5fd8 100644 --- a/.github/workflows/makefile-check.yml +++ b/.github/workflows/makefile-check.yml @@ -48,7 +48,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/otci.yml b/.github/workflows/otci.yml index 87187ad5a..dea78b709 100644 --- a/.github/workflows/otci.yml +++ b/.github/workflows/otci.yml @@ -57,7 +57,7 @@ jobs: REAL_DEVICE: 0 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/otns.yml b/.github/workflows/otns.yml index 8412b8cd9..23ddc0f90 100644 --- a/.github/workflows/otns.yml +++ b/.github/workflows/otns.yml @@ -58,7 +58,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -160,7 +160,7 @@ jobs: STRESS_LEVEL: ${{ matrix.stress_level }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -208,7 +208,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index a2d56b561..7f3e3cb65 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -52,7 +52,7 @@ jobs: CXXFLAGS: -DCLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER=1 -DOPENTHREAD_CONFIG_MLE_MAX_CHILDREN=15 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -138,7 +138,7 @@ jobs: VIRTUAL_TIME: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -182,7 +182,7 @@ jobs: OT_READLINE: 'readline' steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -232,7 +232,7 @@ jobs: OT_READLINE: 'off' steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -262,7 +262,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -296,7 +296,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/simulation-1.1.yml b/.github/workflows/simulation-1.1.yml index 0623d2781..f7a8eed31 100644 --- a/.github/workflows/simulation-1.1.yml +++ b/.github/workflows/simulation-1.1.yml @@ -55,7 +55,7 @@ jobs: MULTIPLY: 3 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -104,7 +104,7 @@ jobs: VIRTUAL_TIME: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -155,7 +155,7 @@ jobs: MESSAGE_USE_HEAP: ${{ matrix.message_use_heap }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -199,7 +199,7 @@ jobs: VIRTUAL_TIME: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -239,7 +239,7 @@ jobs: THREAD_VERSION: 1.1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -280,7 +280,7 @@ jobs: THREAD_VERSION: 1.1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -333,7 +333,7 @@ jobs: CXXFLAGS: "-DOPENTHREAD_CONFIG_LOG_PREPEND_UPTIME=0" steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -370,7 +370,7 @@ jobs: COVERAGE: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -404,7 +404,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/simulation-1.2.yml b/.github/workflows/simulation-1.2.yml index 48677c2f6..1941300f7 100644 --- a/.github/workflows/simulation-1.2.yml +++ b/.github/workflows/simulation-1.2.yml @@ -66,7 +66,7 @@ jobs: arch: ["m32", "m64"] steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -128,7 +128,7 @@ jobs: INTER_OP_BBR: 0 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -199,7 +199,7 @@ jobs: MULTIPLY: 3 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -250,7 +250,7 @@ jobs: ADDON_FEAT_1_2: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -294,7 +294,7 @@ jobs: VIRTUAL_TIME: 0 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -344,7 +344,7 @@ jobs: INTER_OP: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -405,7 +405,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/size.yml b/.github/workflows/size.yml index b113c4fe3..5ba9f3d37 100644 --- a/.github/workflows/size.yml +++ b/.github/workflows/size.yml @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/toranj.yml b/.github/workflows/toranj.yml index 046e9badb..9b3983af6 100644 --- a/.github/workflows/toranj.yml +++ b/.github/workflows/toranj.yml @@ -59,7 +59,7 @@ jobs: TORANJ_EVENT_NAME: ${{ github.event_name }} steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -90,7 +90,7 @@ jobs: TORANJ_CLI: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -123,7 +123,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -164,7 +164,7 @@ jobs: runs-on: macos-14 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -187,7 +187,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index d3f6dab9e..9a8a66f71 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -67,7 +67,7 @@ jobs: COVERAGE: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -104,7 +104,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index 0bfebd5f4..054c887fa 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs From ea25f0954b9d01bb6cd24bd9b2479750e848b7e0 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 24 Jun 2024 05:43:17 -0700 Subject: [PATCH 50/65] [mesh-forwarder] move `CheckReachability()` to `MeshForwarder` (#10421) This commit moves the `CheckReachability()` & `ResolveRoutingLoops()` methods from the `MleRouter` class to the `MeshForwarder` class now as `private` methods. This consolidates all `CheckReachability()` overloads within the `MeshForwarder` class. --- src/core/thread/mesh_forwarder.hpp | 2 + src/core/thread/mesh_forwarder_ftd.cpp | 67 ++++++++++++++++++++++++-- src/core/thread/mle_router.cpp | 56 --------------------- src/core/thread/mle_router.hpp | 21 -------- 4 files changed, 65 insertions(+), 81 deletions(-) diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 459481b83..eba8e74ba 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -492,6 +492,7 @@ class MeshForwarder : public InstanceLocator, private NonCopyable void SendIcmpErrorIfDstUnreach(const Message &aMessage, const Mac::Addresses &aMacAddrs); Error CheckReachability(const FrameData &aFrameData, const Mac::Addresses &aMeshAddrs); + Error CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header); void UpdateRoutes(const FrameData &aFrameData, const Mac::Addresses &aMeshAddrs); Error FrameToMessage(const FrameData &aFrameData, uint16_t aDatagramSize, @@ -501,6 +502,7 @@ class MeshForwarder : public InstanceLocator, private NonCopyable void GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr); Message *PrepareNextDirectTransmission(void); void HandleMesh(FrameData &aFrameData, const Mac::Address &aMacSource, const ThreadLinkInfo &aLinkInfo); + void ResolveRoutingLoops(uint16_t aSourceRloc16, uint16_t aDestRloc16); void HandleFragment(FrameData &aFrameData, const Mac::Addresses &aMacAddrs, const ThreadLinkInfo &aLinkInfo); void HandleLowpanHC(const FrameData &aFrameData, const Mac::Addresses &aMacAddrs, const ThreadLinkInfo &aLinkInfo); diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 810d2c62f..bd36abf9f 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -575,7 +575,7 @@ Error MeshForwarder::UpdateIp6RouteFtd(const Ip6::Header &aIp6Header, Message &a mMeshSource = Get().GetShortAddress(); - SuccessOrExit(error = mle.CheckReachability(mMeshDest, aIp6Header)); + SuccessOrExit(error = CheckReachability(mMeshDest, aIp6Header)); aMessage.SetMeshDest(mMeshDest); mMacAddrs.mDestination.SetShort(Get().GetNextHop(mMeshDest)); @@ -609,7 +609,7 @@ void MeshForwarder::SendIcmpErrorIfDstUnreach(const Message &aMessage, const Mac VerifyOrExit(!ip6Headers.GetDestinationAddress().IsMulticast() && Get().IsOnMesh(ip6Headers.GetDestinationAddress())); - error = Get().CheckReachability(aMacAddrs.mDestination.GetShort(), ip6Headers.GetIp6Header()); + error = CheckReachability(aMacAddrs.mDestination.GetShort(), ip6Headers.GetIp6Header()); if (error == kErrorNoRoute) { @@ -639,7 +639,7 @@ Error MeshForwarder::CheckReachability(const FrameData &aFrameData, const Mac::A ExitNow(); } - error = Get().CheckReachability(aMeshAddrs.mDestination.GetShort(), ip6Headers.GetIp6Header()); + error = CheckReachability(aMeshAddrs.mDestination.GetShort(), ip6Headers.GetIp6Header()); if (error == kErrorNoRoute) { @@ -650,6 +650,44 @@ Error MeshForwarder::CheckReachability(const FrameData &aFrameData, const Mac::A return error; } +Error MeshForwarder::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header) +{ + bool isReachable = false; + uint16_t deviceRloc16 = Get().GetRloc16(); + + if (Get().IsChild()) + { + if (aMeshDest == deviceRloc16) + { + isReachable = Get().HasUnicastAddress(aIp6Header.GetDestination()); + } + else + { + isReachable = true; + } + + ExitNow(); + } + + if (aMeshDest == deviceRloc16) + { + isReachable = Get().HasUnicastAddress(aIp6Header.GetDestination()) || + (Get().FindNeighbor(aIp6Header.GetDestination()) != nullptr); + ExitNow(); + } + + if (Mle::RouterIdMatch(aMeshDest, deviceRloc16)) + { + isReachable = (Get().FindChild(aMeshDest, Child::kInStateValidOrRestoring) != nullptr); + ExitNow(); + } + + isReachable = (Get().GetNextHop(aMeshDest) != Mac::kShortAddrInvalid); + +exit: + return isReachable ? kErrorNone : kErrorNoRoute; +} + void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Ip6::Headers &aIp6Headers) { Ip6::MessageInfo messageInfo; @@ -697,7 +735,7 @@ void MeshForwarder::HandleMesh(FrameData &aFrameData, const Mac::Address &aMacSo OwnedPtr messagePtr; Message::Priority priority = Message::kPriorityNormal; - Get().ResolveRoutingLoops(aMacSource.GetShort(), meshAddrs.mDestination.GetShort()); + ResolveRoutingLoops(aMacSource.GetShort(), meshAddrs.mDestination.GetShort()); SuccessOrExit(error = CheckReachability(aFrameData, meshAddrs)); @@ -735,6 +773,27 @@ void MeshForwarder::HandleMesh(FrameData &aFrameData, const Mac::Address &aMacSo } } +void MeshForwarder::ResolveRoutingLoops(uint16_t aSourceRloc16, uint16_t aDestRloc16) +{ + // Resolves 2-hop routing loops. + + Router *router; + + if (aSourceRloc16 != Get().GetNextHop(aDestRloc16)) + { + ExitNow(); + } + + router = Get().FindRouterByRloc16(aDestRloc16); + VerifyOrExit(router != nullptr); + + router->SetNextHopToInvalid(); + Get().ResetAdvertiseInterval(); + +exit: + return; +} + void MeshForwarder::UpdateRoutes(const FrameData &aFrameData, const Mac::Addresses &aMeshAddrs) { Ip6::Headers ip6Headers; diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 2edd75f44..ca3476fe5 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3197,62 +3197,6 @@ void MleRouter::SetRouterId(uint8_t aRouterId) mPreviousRouterId = mRouterId; } -void MleRouter::ResolveRoutingLoops(uint16_t aSourceMac, uint16_t aDestRloc16) -{ - Router *router; - - if (aSourceMac != mRouterTable.GetNextHop(aDestRloc16)) - { - ExitNow(); - } - - router = mRouterTable.FindRouterByRloc16(aDestRloc16); - VerifyOrExit(router != nullptr); - - router->SetNextHopToInvalid(); - ResetAdvertiseInterval(); - -exit: - return; -} - -Error MleRouter::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header) -{ - bool isReachable = false; - - if (IsChild()) - { - if (aMeshDest == GetRloc16()) - { - isReachable = Get().HasUnicastAddress(aIp6Header.GetDestination()); - } - else - { - isReachable = true; - } - - ExitNow(); - } - - if (aMeshDest == GetRloc16()) - { - isReachable = Get().HasUnicastAddress(aIp6Header.GetDestination()) || - (mNeighborTable.FindNeighbor(aIp6Header.GetDestination()) != nullptr); - ExitNow(); - } - - if (RouterIdFromRloc16(aMeshDest) == mRouterId) - { - isReachable = (mChildTable.FindChild(aMeshDest, Child::kInStateValidOrRestoring) != nullptr); - ExitNow(); - } - - isReachable = (mRouterTable.GetNextHop(aMeshDest) != Mac::kShortAddrInvalid); - -exit: - return isReachable ? kErrorNone : kErrorNoRoute; -} - Error MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus) { Error error = kErrorNone; diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 8dbcb0807..3cf3f406b 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -379,27 +379,6 @@ class MleRouter : public Mle bool aSingletonB, const LeaderData &aLeaderDataB); - /** - * Checks if the destination is reachable. - * - * @param[in] aMeshDest The RLOC16 of the destination. - * @param[in] aIp6Header A reference to the IPv6 header of the message. - * - * @retval kErrorNone The destination is reachable. - * @retval kErrorNoRoute The destination is not reachable and the message should be dropped. - * - */ - Error CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header); - - /** - * Resolves 2-hop routing loops. - * - * @param[in] aSourceMac The RLOC16 of the previous hop. - * @param[in] aDestRloc16 The RLOC16 of the final destination. - * - */ - void ResolveRoutingLoops(uint16_t aSourceMac, uint16_t aDestRloc16); - /** * Fills an ConnectivityTlv. * From 9232ead5625f5534fafac6be5edc245e4ffd13b8 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 24 Jun 2024 15:05:53 +0200 Subject: [PATCH 51/65] [posix] fix build with custom netif prefix route set (#10431) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a build error when the pre-processor define OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC is set: ``` /usr/src/ot-br-posix/third_party/openthread/repo/src/posix/platform/netif.cpp:486:26: error: ‘kLinkLocalScope’ does not name a type 486 | static constexpr kLinkLocalScope = 2; | ^~~~~~~~~~~~~~~ compilation terminated due to -Wfatal-errors. ``` --- src/posix/platform/netif.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix/platform/netif.cpp b/src/posix/platform/netif.cpp index ebb0e79a1..12bee4256 100644 --- a/src/posix/platform/netif.cpp +++ b/src/posix/platform/netif.cpp @@ -483,7 +483,7 @@ static void UpdateUnicastLinux(otInstance *aInstance, const otIp6AddressInfo &aA #endif { #if OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC > 0 - static constexpr kLinkLocalScope = 2; + static constexpr uint8_t kLinkLocalScope = 2; if (aAddressInfo.mScope > kLinkLocalScope) { From 8bd427b9c3b249b67108715edcdd3850492d0d02 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Tue, 25 Jun 2024 01:07:47 +0800 Subject: [PATCH 52/65] [spinel] log sent Spinel frames (#10429) --- src/lib/spinel/spinel_driver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/spinel/spinel_driver.cpp b/src/lib/spinel/spinel_driver.cpp index e802b29b4..421ac47ed 100644 --- a/src/lib/spinel/spinel_driver.cpp +++ b/src/lib/spinel/spinel_driver.cpp @@ -192,6 +192,7 @@ otError SpinelDriver::SendCommand(uint32_t aCommand, spinel_prop_key_t aKey, spi offset = static_cast(packed); EXPECT_NO_ERROR(error = mSpinelInterface->SendFrame(buffer, offset)); + LogSpinelFrame(buffer, offset, true /* aTx */); exit: return error; @@ -226,6 +227,7 @@ otError SpinelDriver::SendCommand(uint32_t aCommand, } EXPECT_NO_ERROR(error = mSpinelInterface->SendFrame(buffer, offset)); + LogSpinelFrame(buffer, offset, true /* aTx */); exit: return error; From 7d619875d2f4593ae72d1ac8567bf263f3b96038 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 24 Jun 2024 12:00:15 -0700 Subject: [PATCH 53/65] [mesh-forwarder] update forwarding messages to ALOC destination (#10419) This commit updates how messages with an ALOC destination are forwarded. If the chosen ALOC destination is a child, its parent is used as the mesh destination unless the device itself is the parent. Additionally, if the selected ALOC destination is a sleepy child of the device, the parent node ensures to prepare the message for indirect transmission. These changes ensure correct forwarding to ED or SED devices when they register a service and want to receive messages on their service ALOC. This commit also adds a new test, `test-030-anycast-forwarding.py`, which validates the forwarding to ALOC addresses on both ED and SED devices. --- src/core/thread/mesh_forwarder.cpp | 9 ++ src/core/thread/mesh_forwarder_ftd.cpp | 35 +++- .../toranj/cli/test-030-anycast-forwarding.py | 151 ++++++++++++++++++ tests/toranj/start.sh | 1 + 4 files changed, 189 insertions(+), 7 deletions(-) create mode 100755 tests/toranj/cli/test-030-anycast-forwarding.py diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 5ff167ed0..14e239b7f 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -628,6 +628,15 @@ Message *MeshForwarder::PrepareNextDirectTransmission(void) switch (error) { case kErrorNone: + if (!curMessage->IsDirectTransmission()) + { + // Skip if message is no longer marked for direct transmission. + // For example, `UpdateIp6Route()` may determine the destination + // is an ALOC associated with an SED child of this device and + // mark it for indirect tx to the SED child. + continue; + } + #if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE mTxQueueStats.UpdateFor(*curMessage); #endif diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index bd36abf9f..38b70a045 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -424,7 +424,6 @@ Error MeshForwarder::AnycastRouteLookup(uint8_t aServiceId, AnycastType aType, u NetworkData::Iterator iterator = NetworkData::kIteratorInit; uint8_t bestCost = Mle::kMaxRouteCost; uint16_t bestDest = Mac::kShortAddrInvalid; - uint8_t routerId; switch (aType) { @@ -485,13 +484,18 @@ Error MeshForwarder::AnycastRouteLookup(uint8_t aServiceId, AnycastType aType, u } } - routerId = Mle::RouterIdFromRloc16(bestDest); - - if (!(Mle::IsRouterRloc16(bestDest) || Mle::Rloc16FromRouterId(routerId) == Get().GetRloc16())) + if (Mle::IsChildRloc16(bestDest)) { - // if agent is neither active router nor child of this device - // use the parent of the ED Agent as Dest - bestDest = Mle::Rloc16FromRouterId(routerId); + // If the selected destination is a child, we use its parent + // as the destination unless the device itself is the + // parent of the `bestDest`. + + uint16_t bestDestParent = Mle::Rloc16FromRouterId(Mle::RouterIdFromRloc16(bestDest)); + + if (Get().GetRloc16() != bestDestParent) + { + bestDest = bestDestParent; + } } aMeshDest = bestDest; @@ -556,6 +560,23 @@ Error MeshForwarder::UpdateIp6RouteFtd(const Ip6::Header &aIp6Header, Message &a { ExitNow(error = kErrorDrop); } + + // If the selected ALOC destination, `mMeshDest`, is a sleepy + // child of this device, prepare the message for indirect tx + // to the sleepy child and un-mark message for direct tx. + + if (mle.IsRouterOrLeader() && Mle::IsChildRloc16(mMeshDest) && Mle::RouterIdMatch(mMeshDest, mle.GetRloc16())) + { + Child *child = Get().FindChild(mMeshDest, Child::kInStateValid); + + VerifyOrExit(child != nullptr, error = kErrorDrop); + + if (!child->IsRxOnWhenIdle()) + { + mIndirectSender.AddMessageForSleepyChild(aMessage, *child); + aMessage.ClearDirectTransmission(); + } + } } else if ((neighbor = Get().FindNeighbor(aIp6Header.GetDestination())) != nullptr) { diff --git a/tests/toranj/cli/test-030-anycast-forwarding.py b/tests/toranj/cli/test-030-anycast-forwarding.py new file mode 100755 index 000000000..d4b1c5c3d --- /dev/null +++ b/tests/toranj/cli/test-030-anycast-forwarding.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2024, 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. + +from cli import verify +from cli import verify_within +import cli +import time + +# ----------------------------------------------------------------------------------------------------------------------- +# Test description: ALOC address forwarding to ED and SED devices. +# +# Network topology +# +# r1 ---- r2 ---- r3 +# /|\ +# / | \ +# ed sed sed2 +# + +test_name = __file__[:-3] if __file__.endswith('.py') else __file__ +print('-' * 120) +print('Starting \'{}\''.format(test_name)) + +# ----------------------------------------------------------------------------------------------------------------------- +# Creating `cli.Node` instances + +speedup = 40 +cli.Node.set_time_speedup_factor(speedup) + +r1 = cli.Node() +r2 = cli.Node() +r3 = cli.Node() +ed = cli.Node() +sed = cli.Node() +sed2 = cli.Node() + +nodes = [r1, r2, r3, ed, sed, sed2] + +# ----------------------------------------------------------------------------------------------------------------------- +# Form topology + +r1.allowlist_node(r2) + +r2.allowlist_node(r1) +r2.allowlist_node(r3) + +r3.allowlist_node(r2) +r3.allowlist_node(ed) +r3.allowlist_node(sed) +r3.allowlist_node(sed2) + +ed.allowlist_node(r3) +sed.allowlist_node(r3) +sed2.allowlist_node(r3) + +r1.form('aloc') +r2.join(r1) +r3.join(r2) +ed.join(r2, cli.JOIN_TYPE_END_DEVICE) +sed.join(r3, cli.JOIN_TYPE_SLEEPY_END_DEVICE) +sed2.join(r3, cli.JOIN_TYPE_SLEEPY_END_DEVICE) + +sed.set_pollperiod(400) +sed2.set_pollperiod(500) + +verify(r1.get_state() == 'leader') +verify(r2.get_state() == 'router') +verify(r3.get_state() == 'router') +verify(ed.get_state() == 'child') +verify(sed.get_state() == 'child') +verify(sed.get_state() == 'child') + +sed.set_mode('n') + +for child in [ed, sed, sed2]: + verify(int(child.get_parent_info()['Rloc'], 16) == int(r3.get_rloc16(), 16)) + +# ----------------------------------------------------------------------------------------------------------------------- +# Test Implementation + + +def check_netdata_services(expected_num_services): + # Check that all nodes see the `expected_num_services` service + # entries in network data. + for node in nodes: + verify(len(node.get_netdata_services()) == expected_num_services) + + +wait_time = 5 + +# Add a service on ed which is non-sleepy child. + +ed.cli('service add 44970 11 00') +ed.register_netdata() + +verify_within(check_netdata_services, wait_time, 1) + +# Verify that the ALOC associated with a non-sleepy child's service is +# pingable from all nodes. + +aloc1 = r1.get_mesh_local_prefix().split('/')[0] + 'ff:fe00:fc10' + +for node in nodes: + node.ping(aloc1) + +# Add a service now from `sed` which is a sleepy child and again make sure +# its ALOC can be pinged from all other nodes. + +sed.cli('service add 44970 22 00') +sed.register_netdata() + +verify_within(check_netdata_services, wait_time, 2) + +aloc2 = r1.get_mesh_local_prefix().split('/')[0] + 'ff:fe00:fc11' + +r1.ping(aloc2) + +for node in nodes: + node.ping(aloc2) + +# ----------------------------------------------------------------------------------------------------------------------- +# Test finished + +cli.Node.finalize_all_nodes() + +print('\'{}\' passed.'.format(test_name)) diff --git a/tests/toranj/start.sh b/tests/toranj/start.sh index ebbbdd700..ef471b00e 100755 --- a/tests/toranj/start.sh +++ b/tests/toranj/start.sh @@ -194,6 +194,7 @@ if [ "$TORANJ_CLI" = 1 ]; then run cli/test-027-slaac-address.py run cli/test-028-border-agent-ephemeral-key.py run cli/test-029-pending-dataset-key-change.py + run cli/test-030-anycast-forwarding.py run cli/test-400-srp-client-server.py run cli/test-401-srp-server-address-cache-snoop.py run cli/test-500-two-brs-two-networks.py From ec69ad31f9005e447056f8b5d6a4ac75a343b77a Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Tue, 25 Jun 2024 21:26:15 +0800 Subject: [PATCH 54/65] [posix] add rcp diag command to check RCP's radio and spinel capability flags (#10400) --- src/posix/platform/README_RCP_CAPS_DIAG.md | 84 ++++++++- src/posix/platform/rcp_caps_diag.cpp | 189 +++++++++++++++++++-- src/posix/platform/rcp_caps_diag.hpp | 15 +- 3 files changed, 275 insertions(+), 13 deletions(-) diff --git a/src/posix/platform/README_RCP_CAPS_DIAG.md b/src/posix/platform/README_RCP_CAPS_DIAG.md index 73322ad24..c4f675f6e 100644 --- a/src/posix/platform/README_RCP_CAPS_DIAG.md +++ b/src/posix/platform/README_RCP_CAPS_DIAG.md @@ -6,10 +6,49 @@ This module provides diag commands for checking RCP capabilities. ## Command List +- [capflags](#capflags) - [spinel](#spinel) ## Command Details +### capflags + +Check RCP's radio and spinel capbility flags. + +```bash +> diag rcpcaps capflags + +Radio Capbility Flags : + +Thread Version >= 1.1 : +RADIO_CAPS_ACK_TIMEOUT ------------------------------------ OK +RADIO_CAPS_TRANSMIT_RETRIES ------------------------------- OK +RADIO_CAPS_CSMA_BACKOFF ----------------------------------- OK + +Thread Version >= 1.2 : +RADIO_CAPS_TRANSMIT_SEC ----------------------------------- OK +RADIO_CAPS_TRANSMIT_TIMING -------------------------------- OK + +Utils : +RADIO_CAPS_ENERGY_SCAN ------------------------------------ OK +RADIO_CAPS_SLEEP_TO_TX ------------------------------------ NotSupported +RADIO_CAPS_RECEIVE_TIMING --------------------------------- NotSupported +RADIO_CAPS_RX_ON_WHEN_IDLE -------------------------------- NotSupported + +Spinel Capbility Flags : + +Basic : +SPINEL_CAPS_CONFIG_RADIO ---------------------------------- OK +SPINEL_CAPS_MAC_RAW --------------------------------------- OK +SPINEL_CAPS_RCP_API_VERSION ------------------------------- OK + +Utils : +SPINEL_CAPS_OPENTHREAD_LOG_METADATA ----------------------- NotSupported +SPINEL_CAPS_RCP_MIN_HOST_API_VERSION ---------------------- OK +SPINEL_CAPS_RCP_RESET_TO_BOOTLOADER ----------------------- NotSupported +Done +``` + ### spinel Check which Spinel commands RCP supports. @@ -19,14 +58,57 @@ Check which Spinel commands RCP supports. Basic : PROP_VALUE_GET CAPS --------------------------------------- OK +PROP_VALUE_GET PROTOCOL_VERSION --------------------------- OK +PROP_VALUE_GET RADIO_CAPS --------------------------------- OK +PROP_VALUE_GET RCP_API_VERSION ---------------------------- OK +PROP_VALUE_GET NCP_VERSION -------------------------------- OK Thread Version >= 1.1 : PROP_VALUE_SET PHY_CHAN ----------------------------------- OK +PROP_VALUE_SET PHY_ENABLED -------------------------------- OK +PROP_VALUE_SET MAC_15_4_PANID ----------------------------- OK +PROP_VALUE_SET MAC_15_4_LADDR ----------------------------- OK +PROP_VALUE_SET MAC_15_4_SADDR ----------------------------- OK +PROP_VALUE_SET MAC_RAW_STREAM_ENABLED --------------------- OK +PROP_VALUE_SET MAC_SCAN_MASK ------------------------------ OK +PROP_VALUE_SET MAC_SCAN_PERIOD ---------------------------- OK +PROP_VALUE_SET MAC_SCAN_STATE ----------------------------- OK +PROP_VALUE_SET MAC_SRC_MATCH_ENABLED ---------------------- OK +PROP_VALUE_SET MAC_SRC_MATCH_SHORT_ADDRESSES -------------- OK +PROP_VALUE_SET MAC_SRC_MATCH_EXTENDED_ADDRESSES ----------- OK +PROP_VALUE_GET HWADDR ------------------------------------- OK +PROP_VALUE_GET PHY_CHAN_PREFERRED ------------------------- OK +PROP_VALUE_GET PHY_CHAN_SUPPORTED ------------------------- OK +PROP_VALUE_GET PHY_RSSI ----------------------------------- OK +PROP_VALUE_GET PHY_RX_SENSITIVITY ------------------------- OK +PROP_VALUE_INSERT MAC_SRC_MATCH_SHORT_ADDRESSES ----------- OK +PROP_VALUE_INSERT MAC_SRC_MATCH_EXTENDED_ADDRESSES -------- OK +PROP_VALUE_REMOVE MAC_SRC_MATCH_SHORT_ADDRESSES ----------- OK +PROP_VALUE_REMOVE MAC_SRC_MATCH_EXTENDED_ADDRESSES -------- OK Thread Version >= 1.2 : PROP_VALUE_SET ENH_ACK_PROBING ---------------------------- NotImplemented +PROP_VALUE_SET RCP_MAC_FRAME_COUNTER ---------------------- OK +PROP_VALUE_SET RCP_MAC_KEY -------------------------------- OK +PROP_VALUE_GET CSL_ACCURACY ------------------------------- OK +PROP_VALUE_GET CSL_UNCERTAINTY ---------------------------- OK +PROP_VALUE_GET TIMESTAMP ---------------------------------- OK -Optional : +Utils : +PROP_VALUE_SET MAC_PROMISCUOUS_MODE ----------------------- OK PROP_VALUE_GET PHY_CCA_THRESHOLD -------------------------- OK +PROP_VALUE_GET PHY_FEM_LNA_GAIN --------------------------- OK +PROP_VALUE_GET PHY_REGION_CODE ---------------------------- OK +PROP_VALUE_GET PHY_TX_POWER ------------------------------- OK +PROP_VALUE_GET RADIO_COEX_ENABLE -------------------------- OK +PROP_VALUE_GET RADIO_COEX_METRICS ------------------------- OK +PROP_VALUE_GET RCP_MIN_HOST_API_VERSION ------------------- OK +PROP_VALUE_SET PHY_CCA_THRESHOLD -------------------------- OK +PROP_VALUE_SET PHY_CHAN_MAX_POWER ------------------------- OK +PROP_VALUE_SET PHY_CHAN_TARGET_POWER ---------------------- OK +PROP_VALUE_SET PHY_FEM_LNA_GAIN --------------------------- OK +PROP_VALUE_SET PHY_REGION_CODE ---------------------------- OK +PROP_VALUE_SET PHY_TX_POWER ------------------------------- OK +PROP_VALUE_SET RADIO_COEX_ENABLE -------------------------- OK Done ``` diff --git a/src/posix/platform/rcp_caps_diag.cpp b/src/posix/platform/rcp_caps_diag.cpp index b0f15e494..7a2242e38 100644 --- a/src/posix/platform/rcp_caps_diag.cpp +++ b/src/posix/platform/rcp_caps_diag.cpp @@ -453,7 +453,11 @@ otError RcpCapsDiag::DiagProcess(char *aArgs[], uint8_t aArgsLength) VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS); - if (strcmp(aArgs[1], "spinel") == 0) + if (strcmp(aArgs[1], "capflags") == 0) + { + ProcessCapabilityFlags(); + } + else if (strcmp(aArgs[1], "spinel") == 0) { ProcessSpinel(); } @@ -498,22 +502,146 @@ void RcpCapsDiag::SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void mOutputContext = aContext; } +void RcpCapsDiag::ProcessCapabilityFlags(void) +{ + TestRadioCapbilityFlags(); + TestSpinelCapbilityFlags(); +} + +void RcpCapsDiag::TestRadioCapbilityFlags(void) +{ + static constexpr uint32_t kRadioThread11Flags[] = {OT_RADIO_CAPS_ACK_TIMEOUT, OT_RADIO_CAPS_TRANSMIT_RETRIES, + OT_RADIO_CAPS_CSMA_BACKOFF}; + static constexpr uint32_t kRadioThread12Flags[] = {OT_RADIO_CAPS_TRANSMIT_SEC, OT_RADIO_CAPS_TRANSMIT_TIMING}; + static constexpr uint32_t kRadioUtilsFlags[] = {OT_RADIO_CAPS_ENERGY_SCAN, OT_RADIO_CAPS_SLEEP_TO_TX, + OT_RADIO_CAPS_RECEIVE_TIMING, OT_RADIO_CAPS_RX_ON_WHEN_IDLE}; + otError error; + unsigned int radioCaps; + + SuccessOrExit(error = mRadioSpinel.Get(SPINEL_PROP_RADIO_CAPS, SPINEL_DATATYPE_UINT_PACKED_S, &radioCaps)); + + Output("\r\nRadio Capbility Flags :\r\n"); + + OutputRadioCapFlags(kCategoryThread1_1, static_cast(radioCaps), kRadioThread11Flags, + OT_ARRAY_LENGTH(kRadioThread11Flags)); + OutputRadioCapFlags(kCategoryThread1_2, static_cast(radioCaps), kRadioThread12Flags, + OT_ARRAY_LENGTH(kRadioThread12Flags)); + OutputRadioCapFlags(kCategoryUtils, static_cast(radioCaps), kRadioUtilsFlags, + OT_ARRAY_LENGTH(kRadioUtilsFlags)); + +exit: + if (error != OT_ERROR_NONE) + { + Output("Failed to get radio capability flags: %s", otThreadErrorToString(error)); + } + + return; +} + +void RcpCapsDiag::OutputRadioCapFlags(Category aCategory, + uint32_t aRadioCaps, + const uint32_t *aFlags, + uint16_t aNumbFlags) +{ + Output("\r\n%s :\r\n", CategoryToString(aCategory)); + for (uint16_t i = 0; i < aNumbFlags; i++) + { + OutputFormat(RadioCapbilityToString(aFlags[i]), SupportToString((aRadioCaps & aFlags[i]) > 0)); + } +} + +void RcpCapsDiag::TestSpinelCapbilityFlags(void) +{ + static constexpr uint8_t kCapsBufferSize = 100; + static constexpr uint32_t kSpinelBasicFlags[] = {SPINEL_CAP_CONFIG_RADIO, SPINEL_CAP_MAC_RAW, + SPINEL_CAP_RCP_API_VERSION}; + static constexpr uint32_t kSpinelUtilsFlags[] = { + SPINEL_CAP_OPENTHREAD_LOG_METADATA, SPINEL_CAP_RCP_MIN_HOST_API_VERSION, SPINEL_CAP_RCP_RESET_TO_BOOTLOADER}; + otError error; + uint8_t capsBuffer[kCapsBufferSize]; + spinel_size_t capsLength = sizeof(capsBuffer); + + SuccessOrExit(error = mRadioSpinel.Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength)); + + Output("\r\nSpinel Capbility Flags :\r\n"); + + OutputSpinelCapFlags(kCategoryBasic, capsBuffer, capsLength, kSpinelBasicFlags, OT_ARRAY_LENGTH(kSpinelBasicFlags)); + OutputSpinelCapFlags(kCategoryUtils, capsBuffer, capsLength, kSpinelUtilsFlags, OT_ARRAY_LENGTH(kSpinelUtilsFlags)); + +exit: + if (error != OT_ERROR_NONE) + { + Output("Failed to get Spinel capbility flags: %s", otThreadErrorToString(error)); + } + + return; +} + +void RcpCapsDiag::OutputSpinelCapFlags(Category aCategory, + const uint8_t *aCapsData, + spinel_size_t aCapsLength, + const uint32_t *aFlags, + uint16_t aNumbFlags) +{ + static constexpr uint8_t kCapsNameSize = 40; + char capName[kCapsNameSize]; + + Output("\r\n%s :\r\n", CategoryToString(aCategory)); + + for (uint16_t i = 0; i < aNumbFlags; i++) + { + snprintf(capName, sizeof(capName), "SPINEL_CAPS_%s", spinel_capability_to_cstr(aFlags[i])); + OutputFormat(capName, SupportToString(IsSpinelCapabilitySupported(aCapsData, aCapsLength, aFlags[i]))); + } +} + +bool RcpCapsDiag::IsSpinelCapabilitySupported(const uint8_t *aCapsData, spinel_size_t aCapsLength, uint32_t aCapability) +{ + bool ret = false; + + while (aCapsLength > 0) + { + unsigned int capability; + spinel_ssize_t unpacked; + + unpacked = spinel_datatype_unpack(aCapsData, aCapsLength, SPINEL_DATATYPE_UINT_PACKED_S, &capability); + VerifyOrExit(unpacked > 0); + VerifyOrExit(capability != aCapability, ret = true); + + aCapsData += unpacked; + aCapsLength -= static_cast(unpacked); + } + +exit: + return ret; +} + +void RcpCapsDiag::OutputFormat(const char *aName, const char *aValue) +{ + static constexpr uint8_t kMaxNameLength = 56; + static const char kPadding[] = "----------------------------------------------------------"; + uint16_t actualLength = static_cast(strlen(aName)); + uint16_t paddingOffset = (actualLength > kMaxNameLength) ? kMaxNameLength : actualLength; + + static_assert(kMaxNameLength < sizeof(kPadding), "Padding bytes are too short"); + + Output("%.*s %s %s\r\n", kMaxNameLength, aName, &kPadding[paddingOffset], aValue); +} + void RcpCapsDiag::OutputResult(const SpinelEntry &aEntry, otError error) { static constexpr uint8_t kSpaceLength = 1; static constexpr uint8_t kMaxCommandStringLength = 20; static constexpr uint8_t kMaxKeyStringLength = 35; - static constexpr uint16_t kMaxLength = kMaxCommandStringLength + kMaxKeyStringLength + kSpaceLength; - static const char kPadding[] = "----------------------------------------------------------"; - const char *commandString = spinel_command_to_cstr(aEntry.mCommand); - const char *keyString = spinel_prop_key_to_cstr(aEntry.mKey); - uint16_t actualLength = static_cast(strlen(commandString) + strlen(keyString) + kSpaceLength); - uint16_t paddingOffset = (actualLength > kMaxLength) ? kMaxLength : actualLength; - - static_assert(kMaxLength < sizeof(kPadding), "Padding bytes are too short"); + static constexpr uint16_t kMaxBufferLength = + kMaxCommandStringLength + kMaxKeyStringLength + kSpaceLength + 1 /* size of '\0' */; + char buffer[kMaxBufferLength] = {0}; + const char *commandString = spinel_command_to_cstr(aEntry.mCommand); + const char *keyString = spinel_prop_key_to_cstr(aEntry.mKey); - Output("%.*s %.*s %s %s\r\n", kMaxCommandStringLength, commandString, kMaxKeyStringLength, keyString, - &kPadding[paddingOffset], otThreadErrorToString(error)); + snprintf(buffer, sizeof(buffer), "%.*s %.*s", kMaxCommandStringLength, commandString, kMaxKeyStringLength, + keyString); + OutputFormat(buffer, otThreadErrorToString(error)); } void RcpCapsDiag::Output(const char *aFormat, ...) @@ -547,6 +675,45 @@ const char *RcpCapsDiag::CategoryToString(Category aCategory) return (aCategory < OT_ARRAY_LENGTH(kCategoryStrings)) ? kCategoryStrings[aCategory] : "invalid"; } +const char *RcpCapsDiag::SupportToString(bool aSupport) { return aSupport ? "OK" : "NotSupported"; } + +const char *RcpCapsDiag::RadioCapbilityToString(uint32_t aCapability) +{ + static const char *const kCapbilityStrings[] = { + "RADIO_CAPS_ACK_TIMEOUT", // (1 << 0) OT_RADIO_CAPS_ACK_TIMEOUT + "RADIO_CAPS_ENERGY_SCAN", // (1 << 1) OT_RADIO_CAPS_ENERGY_SCAN + "RADIO_CAPS_TRANSMIT_RETRIES", // (1 << 2) OT_RADIO_CAPS_TRANSMIT_RETRIES + "RADIO_CAPS_CSMA_BACKOFF", // (1 << 3) OT_RADIO_CAPS_CSMA_BACKOFF + "RADIO_CAPS_SLEEP_TO_TX", // (1 << 4) OT_RADIO_CAPS_SLEEP_TO_TX + "RADIO_CAPS_TRANSMIT_SEC", // (1 << 5) OT_RADIO_CAPS_TRANSMIT_SEC + "RADIO_CAPS_TRANSMIT_TIMING", // (1 << 6) OT_RADIO_CAPS_TRANSMIT_TIMING + "RADIO_CAPS_RECEIVE_TIMING", // (1 << 7) OT_RADIO_CAPS_RECEIVE_TIMING + "RADIO_CAPS_RX_ON_WHEN_IDLE", // (1 << 8) OT_RADIO_CAPS_RX_ON_WHEN_IDLE + }; + const char *string = "invalid"; + uint16_t index = 0; + + static_assert(OT_RADIO_CAPS_ACK_TIMEOUT == 1 << 0, "OT_RADIO_CAPS_ACK_TIMEOUT value is incorrect"); + static_assert(OT_RADIO_CAPS_ENERGY_SCAN == 1 << 1, "OT_RADIO_CAPS_ENERGY_SCAN value is incorrect"); + static_assert(OT_RADIO_CAPS_TRANSMIT_RETRIES == 1 << 2, "OT_RADIO_CAPS_TRANSMIT_RETRIES value is incorrect"); + static_assert(OT_RADIO_CAPS_CSMA_BACKOFF == 1 << 3, "OT_RADIO_CAPS_CSMA_BACKOFF value is incorrect"); + static_assert(OT_RADIO_CAPS_SLEEP_TO_TX == 1 << 4, "OT_RADIO_CAPS_SLEEP_TO_TX value is incorrect"); + static_assert(OT_RADIO_CAPS_TRANSMIT_SEC == 1 << 5, "OT_RADIO_CAPS_TRANSMIT_SEC value is incorrect"); + static_assert(OT_RADIO_CAPS_TRANSMIT_TIMING == 1 << 6, "OT_RADIO_CAPS_TRANSMIT_TIMING value is incorrect"); + static_assert(OT_RADIO_CAPS_RECEIVE_TIMING == 1 << 7, "OT_RADIO_CAPS_RECEIVE_TIMING value is incorrect"); + static_assert(OT_RADIO_CAPS_RX_ON_WHEN_IDLE == 1 << 8, "OT_RADIO_CAPS_RX_ON_WHEN_IDLE value is incorrect"); + + for (; !(aCapability & 0x1); (aCapability >>= 1), index++) + { + VerifyOrExit(index < OT_ARRAY_LENGTH(kCapbilityStrings)); + } + + string = kCapbilityStrings[index]; + +exit: + return string; +} + } // namespace Posix } // namespace ot #endif // OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE diff --git a/src/posix/platform/rcp_caps_diag.hpp b/src/posix/platform/rcp_caps_diag.hpp index f799f8187..05e06498b 100644 --- a/src/posix/platform/rcp_caps_diag.hpp +++ b/src/posix/platform/rcp_caps_diag.hpp @@ -109,11 +109,24 @@ class RcpCapsDiag }; void ProcessSpinel(void); + void ProcessCapabilityFlags(void); void TestSpinelCommands(Category aCategory); + void TestRadioCapbilityFlags(void); + void OutputRadioCapFlags(Category aCategory, uint32_t aRadioCaps, const uint32_t *aFlags, uint16_t aNumbFlags); + void TestSpinelCapbilityFlags(void); + void OutputSpinelCapFlags(Category aCategory, + const uint8_t *aCapsData, + spinel_size_t aCapsLength, + const uint32_t *aFlags, + uint16_t aNumbFlags); + bool IsSpinelCapabilitySupported(const uint8_t *aCapsData, spinel_size_t aCapsLength, uint32_t aCapability); + void OutputFormat(const char *aName, const char *aValue); void OutputResult(const SpinelEntry &aEntry, otError error); void Output(const char *aFormat, ...); - const char *CategoryToString(Category aCategory); + static const char *SupportToString(bool aSupport); + static const char *RadioCapbilityToString(uint32_t aCapability); + static const char *CategoryToString(Category aCategory); static const struct SpinelEntry sSpinelEntries[]; From 7b779a3db1cb2f97b520623494c24b54a56d8744 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 25 Jun 2024 13:08:16 -0700 Subject: [PATCH 55/65] [child] update MLR masks when removing registered IPv6 addresses (#10425) This commit modifies `Child::RemoveIp6Address()` to update the `mMlrToRegisterMask` and `mMlrToUnregisterMask` when a registered child IPv6 address entry is removed from the list. These bit-vector masks track the MLR state associated with the entry using its index in the array. Since `Array::Remove()` replaces the deleted entry with the last one in the array, the MLR masks are also updated to reflect this change. --- src/core/thread/child.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/core/thread/child.cpp b/src/core/thread/child.cpp index 17cf3075e..a91512587 100644 --- a/src/core/thread/child.cpp +++ b/src/core/thread/child.cpp @@ -203,6 +203,23 @@ Error Child::RemoveIp6Address(const Ip6::Address &aAddress) entry = mIp6Addresses.Find(aAddress); VerifyOrExit(entry != nullptr); +#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE + { + // `Array::Remove()` will replace the removed entry with the + // last one in the array. We also update the MLR bit vectors + // to reflect this change. + + uint16_t entryIndex = mIp6Addresses.IndexOf(*entry); + uint16_t lastIndex = mIp6Addresses.GetLength() - 1; + + mMlrToRegisterMask.Set(entryIndex, mMlrToRegisterMask.Get(lastIndex)); + mMlrToRegisterMask.Set(lastIndex, false); + + mMlrRegisteredMask.Set(entryIndex, mMlrRegisteredMask.Get(lastIndex)); + mMlrRegisteredMask.Set(lastIndex, false); + } +#endif + mIp6Addresses.Remove(*entry); error = kErrorNone; From dc69fb1aceab72e0b0d1550ec3ba8200bae0424a Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 25 Jun 2024 13:08:31 -0700 Subject: [PATCH 56/65] [tcat-agent] use `Dataset` directly when setting Active Dataset (#10433) This commit updates `HandleSetActiveOperationalDataset()` by removing the extra conversion from `Dataset` to `Dataset::Tlvs` and directly using the `Dataset` when saving the Active Operational Dataset. --- src/core/meshcop/tcat_agent.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/core/meshcop/tcat_agent.cpp b/src/core/meshcop/tcat_agent.cpp index 29ae911b0..48dcba714 100644 --- a/src/core/meshcop/tcat_agent.cpp +++ b/src/core/meshcop/tcat_agent.cpp @@ -460,9 +460,8 @@ Error TcatAgent::HandleSingleTlv(const Message &aIncommingMessage, Message &aOut Error TcatAgent::HandleSetActiveOperationalDataset(const Message &aIncommingMessage, uint16_t aOffset, uint16_t aLength) { - Dataset dataset; - Dataset::Tlvs datasetTlvs; - Error error; + Dataset dataset; + Error error; SuccessOrExit(error = dataset.SetFrom(aIncommingMessage, aOffset, aLength)); SuccessOrExit(error = dataset.ValidateTlvs()); @@ -474,8 +473,7 @@ Error TcatAgent::HandleSetActiveOperationalDataset(const Message &aIncommingMess ExitNow(); } - dataset.ConvertTo(datasetTlvs); - error = Get().SaveLocal(datasetTlvs); + Get().SaveLocal(dataset); exit: return error; From cc8f66c56f9675648c3d2c47cd6aa7f4e92102b1 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 25 Jun 2024 13:09:35 -0700 Subject: [PATCH 57/65] [core] use RLOC16-related constants and methods consistently across modules (#10434) This commit aims to make the use of RLOC16-related constants and methods consistent across different modules. - It replaces `Mac::kShortAddrInvalid` with `Mle::kInvalidRloc16` to refer to an invalid RLOC16 value (note that these constants use the same value `0xfffe`). - It uses `Get().GetRloc16()` to retrieve the device's RLOC16 instead of `Get().GetShortAddress()`. - It updates `AddressResolver` to consistently use `uint16_t` for RLOC16 (instead of the `Mac::ShortAddress` typedef). --- src/core/api/thread_api.cpp | 4 +-- src/core/backbone_router/bbr_leader.cpp | 10 +++---- src/core/backbone_router/bbr_leader.hpp | 4 +-- src/core/backbone_router/bbr_local.cpp | 2 +- src/core/backbone_router/bbr_manager.cpp | 12 ++++---- src/core/backbone_router/bbr_manager.hpp | 4 +-- src/core/net/srp_server.cpp | 2 +- src/core/thread/address_resolver.cpp | 32 ++++++++++----------- src/core/thread/address_resolver.hpp | 28 +++++++++--------- src/core/thread/anycast_locator.cpp | 2 +- src/core/thread/child_table.cpp | 2 +- src/core/thread/mesh_forwarder_ftd.cpp | 20 ++++++------- src/core/thread/mle.cpp | 20 ++++++------- src/core/thread/mle.hpp | 2 +- src/core/thread/mle_router.cpp | 8 +++--- src/core/thread/neighbor.hpp | 3 +- src/core/thread/network_data_leader_ftd.cpp | 2 +- src/core/thread/network_data_notifier.cpp | 6 ++-- src/core/thread/network_data_service.cpp | 2 +- src/core/thread/network_data_tlvs.hpp | 5 ++-- src/core/utils/history_tracker.hpp | 2 +- 21 files changed, 85 insertions(+), 87 deletions(-) diff --git a/src/core/api/thread_api.cpp b/src/core/api/thread_api.cpp index 91ac5f318..eb55386f6 100644 --- a/src/core/api/thread_api.cpp +++ b/src/core/api/thread_api.cpp @@ -81,7 +81,7 @@ otError otThreadGetLeaderRloc(otInstance *aInstance, otIp6Address *aLeaderRloc) { Error error = kErrorNone; - VerifyOrExit(AsCoreType(aInstance).Get().GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); + VerifyOrExit(AsCoreType(aInstance).Get().GetRloc16() != Mle::kInvalidRloc16, error = kErrorDetached); AsCoreType(aInstance).Get().GetLeaderRloc(AsCoreType(aLeaderRloc)); exit: @@ -197,7 +197,7 @@ otError otThreadGetServiceAloc(otInstance *aInstance, uint8_t aServiceId, otIp6A { Error error = kErrorNone; - VerifyOrExit(AsCoreType(aInstance).Get().GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); + VerifyOrExit(AsCoreType(aInstance).Get().GetRloc16() != Mle::kInvalidRloc16, error = kErrorDetached); AsCoreType(aInstance).Get().GetServiceAloc(aServiceId, AsCoreType(aServiceAloc)); exit: diff --git a/src/core/backbone_router/bbr_leader.cpp b/src/core/backbone_router/bbr_leader.cpp index 5b605ac5e..85cb08be1 100644 --- a/src/core/backbone_router/bbr_leader.cpp +++ b/src/core/backbone_router/bbr_leader.cpp @@ -52,7 +52,7 @@ Leader::Leader(Instance &aInstance) void Leader::Reset(void) { // Invalid server short address indicates no available Backbone Router service in the Thread Network. - mConfig.mServer16 = Mac::kShortAddrInvalid; + mConfig.mServer16 = Mle::kInvalidRloc16; // Domain Prefix Length 0 indicates no available Domain Prefix in the Thread network. mDomainPrefix.SetLength(0); @@ -152,11 +152,11 @@ void Leader::UpdateBackboneRouterPrimary(void) if (config.mServer16 != mConfig.mServer16) { - if (config.mServer16 == Mac::kShortAddrInvalid) + if (config.mServer16 == Mle::kInvalidRloc16) { state = kStateRemoved; } - else if (mConfig.mServer16 == Mac::kShortAddrInvalid) + else if (mConfig.mServer16 == Mle::kInvalidRloc16) { state = kStateAdded; } @@ -166,7 +166,7 @@ void Leader::UpdateBackboneRouterPrimary(void) state = kStateToTriggerRereg; } } - else if (config.mServer16 == Mac::kShortAddrInvalid) + else if (config.mServer16 == Mle::kInvalidRloc16) { // If no Primary all the time. state = kStateNone; @@ -185,7 +185,7 @@ void Leader::UpdateBackboneRouterPrimary(void) } // Restrain the range of MLR timeout to be always valid - if (config.mServer16 != Mac::kShortAddrInvalid) + if (config.mServer16 != Mle::kInvalidRloc16) { uint32_t origTimeout = config.mMlrTimeout; diff --git a/src/core/backbone_router/bbr_leader.hpp b/src/core/backbone_router/bbr_leader.hpp index 4102651f2..2822bd8de 100644 --- a/src/core/backbone_router/bbr_leader.hpp +++ b/src/core/backbone_router/bbr_leader.hpp @@ -143,7 +143,7 @@ class Leader : public InstanceLocator, private NonCopyable /** * Gets the short address of the Primary Backbone Router. * - * @returns short address of Primary Backbone Router, or Mac::kShortAddrInvalid if no Primary Backbone Router. + * @returns short address of Primary Backbone Router, or Mle::kInvalidRloc16 if no Primary Backbone Router. * */ uint16_t GetServer16(void) const { return mConfig.mServer16; } @@ -155,7 +155,7 @@ class Leader : public InstanceLocator, private NonCopyable * @retval FALSE If there is no Primary Backbone Router. * */ - bool HasPrimary(void) const { return mConfig.mServer16 != Mac::kShortAddrInvalid; } + bool HasPrimary(void) const { return mConfig.mServer16 != Mle::kInvalidRloc16; } /** * Gets the Domain Prefix in the Thread Network. diff --git a/src/core/backbone_router/bbr_local.cpp b/src/core/backbone_router/bbr_local.cpp index 66cb8f519..2b4ab5f02 100644 --- a/src/core/backbone_router/bbr_local.cpp +++ b/src/core/backbone_router/bbr_local.cpp @@ -254,7 +254,7 @@ void Local::HandleBackboneRouterPrimaryUpdate(Leader::State aState, const Config VerifyOrExit(IsEnabled() && Get().IsAttached()); // Wait some jitter before trying to Register. - if (aConfig.mServer16 == Mac::kShortAddrInvalid) + if (aConfig.mServer16 == Mle::kInvalidRloc16) { mRegistrationTimeout = 1; diff --git a/src/core/backbone_router/bbr_manager.cpp b/src/core/backbone_router/bbr_manager.cpp index 4fb15e4bc..7a90d1c71 100644 --- a/src/core/backbone_router/bbr_manager.cpp +++ b/src/core/backbone_router/bbr_manager.cpp @@ -527,7 +527,7 @@ Error Manager::SendBackboneQuery(const Ip6::Address &aDua, uint16_t aRloc16) SuccessOrExit(error = Tlv::Append(*message, aDua)); - if (aRloc16 != Mac::kShortAddrInvalid) + if (aRloc16 != Mle::kInvalidRloc16) { SuccessOrExit(error = Tlv::Append(*message, aRloc16)); } @@ -550,7 +550,7 @@ template <> void Manager::HandleTmf(Coap::Message &aMessage, { Error error = kErrorNone; Ip6::Address dua; - uint16_t rloc16 = Mac::kShortAddrInvalid; + uint16_t rloc16 = Mle::kInvalidRloc16; NdProxyTable::NdProxy *ndProxy; VerifyOrExit(aMessageInfo.IsHostInterface(), error = kErrorDrop); @@ -583,7 +583,7 @@ template <> void Manager::HandleTmf(Coap::Message &aMessage, Ip6::InterfaceIdentifier meshLocalIid; uint16_t networkNameOffset, networkNameLength; uint32_t timeSinceLastTransaction; - uint16_t srcRloc16 = Mac::kShortAddrInvalid; + uint16_t srcRloc16 = Mle::kInvalidRloc16; VerifyOrExit(aMessageInfo.IsHostInterface(), error = kErrorDrop); @@ -606,7 +606,7 @@ template <> void Manager::HandleTmf(Coap::Message &aMessage, { HandleProactiveBackboneNotification(dua, meshLocalIid, timeSinceLastTransaction); } - else if (srcRloc16 == Mac::kShortAddrInvalid) + else if (srcRloc16 == Mle::kInvalidRloc16) { HandleDadBackboneAnswer(dua, meshLocalIid); } @@ -626,7 +626,7 @@ Error Manager::SendProactiveBackboneNotification(const Ip6::Address uint32_t aTimeSinceLastTransaction) { return SendBackboneAnswer(Get().GetAllDomainBackboneRoutersAddress(), aDua, aMeshLocalIid, - aTimeSinceLastTransaction, Mac::kShortAddrInvalid); + aTimeSinceLastTransaction, Mle::kInvalidRloc16); } Error Manager::SendBackboneAnswer(const Ip6::MessageInfo &aQueryMessageInfo, @@ -664,7 +664,7 @@ Error Manager::SendBackboneAnswer(const Ip6::Address &aDstAddr, SuccessOrExit(error = Tlv::Append( *message, Get().GetNetworkName().GetAsCString())); - if (aSrcRloc16 != Mac::kShortAddrInvalid) + if (aSrcRloc16 != Mle::kInvalidRloc16) { SuccessOrExit(Tlv::Append(*message, aSrcRloc16)); } diff --git a/src/core/backbone_router/bbr_manager.hpp b/src/core/backbone_router/bbr_manager.hpp index 87d8021bc..6a6d19d12 100644 --- a/src/core/backbone_router/bbr_manager.hpp +++ b/src/core/backbone_router/bbr_manager.hpp @@ -146,7 +146,7 @@ class Manager : public InstanceLocator, private NonCopyable * Sends BB.qry on the Backbone link. * * @param[in] aDua The Domain Unicast Address to query. - * @param[in] aRloc16 The short address of the address resolution initiator or `Mac::kShortAddrInvalid` for + * @param[in] aRloc16 The short address of the address resolution initiator or `Mle::kInvalidRloc16` for * DUA DAD. * * @retval kErrorNone Successfully sent BB.qry on backbone link. @@ -154,7 +154,7 @@ class Manager : public InstanceLocator, private NonCopyable * @retval kErrorNoBufs If insufficient message buffers available. * */ - Error SendBackboneQuery(const Ip6::Address &aDua, uint16_t aRloc16 = Mac::kShortAddrInvalid); + Error SendBackboneQuery(const Ip6::Address &aDua, uint16_t aRloc16 = Mle::kInvalidRloc16); /** * Send a Proactive Backbone Notification (PRO_BB.ntf) on the Backbone link. diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index 7fafba1d9..c6ffe222a 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -1783,7 +1783,7 @@ void Server::UpdateAddrResolverCacheTable(const Ip6::MessageInfo &aMessageInfo, rloc16 = Get().LookUp(aMessageInfo.GetPeerAddr()); - VerifyOrExit(rloc16 != Mac::kShortAddrInvalid); + VerifyOrExit(rloc16 != Mle::kInvalidRloc16); for (const Ip6::Address &address : aHost.mAddresses) { diff --git a/src/core/thread/address_resolver.cpp b/src/core/thread/address_resolver.cpp index 5acb9c7fe..913b184a0 100644 --- a/src/core/thread/address_resolver.cpp +++ b/src/core/thread/address_resolver.cpp @@ -176,7 +176,7 @@ AddressResolver::CacheEntry *AddressResolver::GetEntryAfter(CacheEntry *aPrev, C return (aPrev == nullptr) ? aList.GetHead() : aPrev->GetNext(); } -void AddressResolver::Remove(Mac::ShortAddress aRloc16, bool aMatchRouterId) +void AddressResolver::Remove(uint16_t aRloc16, bool aMatchRouterId) { CacheEntryList *lists[] = {&mCachedList, &mSnoopedList}; @@ -337,7 +337,7 @@ void AddressResolver::RemoveCacheEntry(CacheEntry &aEntry, LogCacheEntryChange(kEntryRemoved, aReason, aEntry, &aList); } -Error AddressResolver::UpdateCacheEntry(const Ip6::Address &aEid, Mac::ShortAddress aRloc16) +Error AddressResolver::UpdateCacheEntry(const Ip6::Address &aEid, uint16_t aRloc16) { // This method updates an existing cache entry for the EID (if any). // Returns `kErrorNone` if entry is found and successfully updated, @@ -377,18 +377,16 @@ Error AddressResolver::UpdateCacheEntry(const Ip6::Address &aEid, Mac::ShortAddr return error; } -void AddressResolver::UpdateSnoopedCacheEntry(const Ip6::Address &aEid, - Mac::ShortAddress aRloc16, - Mac::ShortAddress aDest) +void AddressResolver::UpdateSnoopedCacheEntry(const Ip6::Address &aEid, uint16_t aRloc16, uint16_t aDest) { - uint16_t numNonEvictable = 0; - CacheEntry *entry; - Mac::ShortAddress macAddress; + uint16_t numNonEvictable = 0; + CacheEntry *entry; + uint16_t deviceRloc16; VerifyOrExit(Get().IsFullThreadDevice()); #if OPENTHREAD_CONFIG_TMF_ALLOW_ADDRESS_RESOLUTION_USING_NET_DATA_SERVICES - VerifyOrExit(ResolveUsingNetDataServices(aEid, macAddress) != kErrorNone); + VerifyOrExit(ResolveUsingNetDataServices(aEid, deviceRloc16) != kErrorNone); #endif VerifyOrExit(UpdateCacheEntry(aEid, aRloc16) != kErrorNone); @@ -396,13 +394,13 @@ void AddressResolver::UpdateSnoopedCacheEntry(const Ip6::Address &aEid, // Skip if the `aRloc16` (i.e., the source of the snooped message) // is this device or an MTD (minimal) child of the device itself. - macAddress = Get().GetShortAddress(); - VerifyOrExit((aRloc16 != macAddress) && !Get().HasMinimalChild(aRloc16)); + deviceRloc16 = Get().GetRloc16(); + VerifyOrExit((aRloc16 != deviceRloc16) && !Get().HasMinimalChild(aRloc16)); // Ensure that the destination of the snooped message is this device // or a minimal child of this device. - VerifyOrExit((aDest == macAddress) || Get().HasMinimalChild(aDest)); + VerifyOrExit((aDest == deviceRloc16) || Get().HasMinimalChild(aDest)); entry = NewCacheEntry(/* aSnoopedEntry */ true); VerifyOrExit(entry != nullptr); @@ -470,15 +468,15 @@ void AddressResolver::RestartAddressQueries(void) } } -Mac::ShortAddress AddressResolver::LookUp(const Ip6::Address &aEid) +uint16_t AddressResolver::LookUp(const Ip6::Address &aEid) { - Mac::ShortAddress rloc16 = Mac::kShortAddrInvalid; + uint16_t rloc16 = Mle::kInvalidRloc16; IgnoreError(Resolve(aEid, rloc16, /* aAllowAddressQuery */ false)); return rloc16; } -Error AddressResolver::Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16, bool aAllowAddressQuery) +Error AddressResolver::Resolve(const Ip6::Address &aEid, uint16_t &aRloc16, bool aAllowAddressQuery) { Error error = kErrorNone; CacheEntry *entry; @@ -532,7 +530,7 @@ Error AddressResolver::Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRlo VerifyOrExit(entry != nullptr, error = kErrorNoBufs); entry->SetTarget(aEid); - entry->SetRloc16(Mac::kShortAddrInvalid); + entry->SetRloc16(Mle::kInvalidRloc16); entry->SetRetryDelay(kAddressQueryInitialRetryDelay); entry->SetCanEvict(false); list = nullptr; @@ -580,7 +578,7 @@ Error AddressResolver::Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRlo #if OPENTHREAD_CONFIG_TMF_ALLOW_ADDRESS_RESOLUTION_USING_NET_DATA_SERVICES -Error AddressResolver::ResolveUsingNetDataServices(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16) +Error AddressResolver::ResolveUsingNetDataServices(const Ip6::Address &aEid, uint16_t &aRloc16) { // Tries to resolve `aEid` Network Data DNS/SRP Unicast address // service entries. Returns `kErrorNone` and updates `aRloc16` diff --git a/src/core/thread/address_resolver.hpp b/src/core/thread/address_resolver.hpp index 8b5d0a422..9e9799f19 100644 --- a/src/core/thread/address_resolver.hpp +++ b/src/core/thread/address_resolver.hpp @@ -139,7 +139,7 @@ class AddressResolver : public InstanceLocator, private NonCopyable * @param[in] aRloc16 The RLOC16 address. * */ - void RemoveEntriesForRloc16(Mac::ShortAddress aRloc16); + void RemoveEntriesForRloc16(uint16_t aRloc16); /** * Removes all EID-to-RLOC cache entries associated with a Router ID. @@ -177,7 +177,7 @@ class AddressResolver : public InstanceLocator, private NonCopyable * @param[in] aDest The short MAC address destination of the received snooped message. * */ - void UpdateSnoopedCacheEntry(const Ip6::Address &aEid, Mac::ShortAddress aRloc16, Mac::ShortAddress aDest); + void UpdateSnoopedCacheEntry(const Ip6::Address &aEid, uint16_t aRloc16, uint16_t aDest); /** * Returns the RLOC16 for a given EID, initiates an Address Query if the mapping is not known. @@ -191,7 +191,7 @@ class AddressResolver : public InstanceLocator, private NonCopyable * @retval kErrorNoBufs Insufficient buffer space available to send Address Query. * */ - Error Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16) + Error Resolve(const Ip6::Address &aEid, uint16_t &aRloc16) { return Resolve(aEid, aRloc16, /* aAllowAddressQuery */ true); } @@ -204,10 +204,10 @@ class AddressResolver : public InstanceLocator, private NonCopyable * * @param[in] aEid A reference to the EID to lookup. * - * @returns The RLOC16 mapping to @p aEid or `Mac::kShortAddrInvalid` if it is not found in the address cache. + * @returns The RLOC16 mapping to @p aEid or `Mle::kInvalidRloc16` if it is not found in the address cache. * */ - Mac::ShortAddress LookUp(const Ip6::Address &aEid); + uint16_t LookUp(const Ip6::Address &aEid); /** * Restarts any ongoing address queries. @@ -267,8 +267,8 @@ class AddressResolver : public InstanceLocator, private NonCopyable const Ip6::Address &GetTarget(void) const { return mTarget; } void SetTarget(const Ip6::Address &aTarget) { mTarget = aTarget; } - Mac::ShortAddress GetRloc16(void) const { return mRloc16; } - void SetRloc16(Mac::ShortAddress aRloc16) { mRloc16 = aRloc16; } + uint16_t GetRloc16(void) const { return mRloc16; } + void SetRloc16(uint16_t aRloc16) { mRloc16 = aRloc16; } const Ip6::InterfaceIdentifier &GetMeshLocalIid(void) const { return mInfo.mCached.mMeshLocalIid; } void SetMeshLocalIid(const Ip6::InterfaceIdentifier &aIid) { mInfo.mCached.mMeshLocalIid = aIid; } @@ -298,9 +298,9 @@ class AddressResolver : public InstanceLocator, private NonCopyable static constexpr uint16_t kNoNextIndex = 0xffff; // `mNextIndex` value when at end of list. static constexpr uint32_t kInvalidLastTransTime = 0xffffffff; // Value when `mLastTransactionTime` is invalid. - Ip6::Address mTarget; - Mac::ShortAddress mRloc16; - uint16_t mNextIndex; + Ip6::Address mTarget; + uint16_t mRloc16; + uint16_t mNextIndex; union { @@ -348,16 +348,16 @@ class AddressResolver : public InstanceLocator, private NonCopyable CacheEntryPool &GetCacheEntryPool(void) { return mCacheEntryPool; } - Error Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16, bool aAllowAddressQuery); - void Remove(Mac::ShortAddress aRloc16, bool aMatchRouterId); + Error Resolve(const Ip6::Address &aEid, uint16_t &aRloc16, bool aAllowAddressQuery); + void Remove(uint16_t aRloc16, bool aMatchRouterId); void Remove(const Ip6::Address &aEid, Reason aReason); CacheEntry *FindCacheEntry(const Ip6::Address &aEid, CacheEntryList *&aList, CacheEntry *&aPrevEntry); CacheEntry *NewCacheEntry(bool aSnoopedEntry); void RemoveCacheEntry(CacheEntry &aEntry, CacheEntryList &aList, CacheEntry *aPrevEntry, Reason aReason); - Error UpdateCacheEntry(const Ip6::Address &aEid, Mac::ShortAddress aRloc16); + Error UpdateCacheEntry(const Ip6::Address &aEid, uint16_t aRloc16); Error SendAddressQuery(const Ip6::Address &aEid); #if OPENTHREAD_CONFIG_TMF_ALLOW_ADDRESS_RESOLUTION_USING_NET_DATA_SERVICES - Error ResolveUsingNetDataServices(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16); + Error ResolveUsingNetDataServices(const Ip6::Address &aEid, uint16_t &aRloc16); #endif static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); diff --git a/src/core/thread/anycast_locator.cpp b/src/core/thread/anycast_locator.cpp index ed926a4c4..03cf14563 100644 --- a/src/core/thread/anycast_locator.cpp +++ b/src/core/thread/anycast_locator.cpp @@ -91,7 +91,7 @@ void AnycastLocator::HandleResponse(Coap::Message *aMessage, const Ip6::MessageI { OT_UNUSED_VARIABLE(aMessageInfo); - uint16_t rloc16 = Mac::kShortAddrInvalid; + uint16_t rloc16 = Mle::kInvalidRloc16; const Ip6::Address *address = nullptr; Ip6::Address meshLocalAddress; diff --git a/src/core/thread/child_table.cpp b/src/core/thread/child_table.cpp index 1f9b3b6d3..2762bad31 100644 --- a/src/core/thread/child_table.cpp +++ b/src/core/thread/child_table.cpp @@ -192,7 +192,7 @@ Error ChildTable::GetChildInfoById(uint16_t aChildId, Child::Info &aChildInfo) aChildId = Mle::ChildIdFromRloc16(aChildId); } - rloc16 = Get().GetShortAddress() | aChildId; + rloc16 = Get().GetRloc16() | aChildId; child = FindChild(rloc16, Child::kInStateValidOrRestoring); VerifyOrExit(child != nullptr, error = kErrorNotFound); diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 38b70a045..966b7f628 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -376,7 +376,7 @@ Error MeshForwarder::UpdateMeshRoute(Message &aMessage) nextHop = Get().GetNextHop(meshHeader.GetDestination()); - if (nextHop != Mac::kShortAddrInvalid) + if (nextHop != Mle::kInvalidRloc16) { neighbor = Get().FindNeighbor(nextHop); } @@ -391,7 +391,7 @@ Error MeshForwarder::UpdateMeshRoute(Message &aMessage) } mMacAddrs.mDestination.SetShort(neighbor->GetRloc16()); - mMacAddrs.mSource.SetShort(Get().GetShortAddress()); + mMacAddrs.mSource.SetShort(Get().GetRloc16()); mAddMeshHeader = true; mMeshDest = meshHeader.GetDestination(); @@ -412,7 +412,7 @@ void MeshForwarder::EvaluateRoutingCost(uint16_t aDest, uint8_t &aBestCost, uint { uint8_t cost = Get().GetPathCost(aDest); - if ((aBestDest == Mac::kShortAddrInvalid) || (cost < aBestCost)) + if ((aBestDest == Mle::kInvalidRloc16) || (cost < aBestCost)) { aBestDest = aDest; aBestCost = cost; @@ -423,7 +423,7 @@ Error MeshForwarder::AnycastRouteLookup(uint8_t aServiceId, AnycastType aType, u { NetworkData::Iterator iterator = NetworkData::kIteratorInit; uint8_t bestCost = Mle::kMaxRouteCost; - uint16_t bestDest = Mac::kShortAddrInvalid; + uint16_t bestDest = Mle::kInvalidRloc16; switch (aType) { @@ -501,7 +501,7 @@ Error MeshForwarder::AnycastRouteLookup(uint8_t aServiceId, AnycastType aType, u aMeshDest = bestDest; exit: - return (bestDest != Mac::kShortAddrInvalid) ? kErrorNone : kErrorNoRoute; + return (bestDest != Mle::kInvalidRloc16) ? kErrorNone : kErrorNoRoute; } Error MeshForwarder::UpdateIp6RouteFtd(const Ip6::Header &aIp6Header, Message &aMessage) @@ -592,9 +592,9 @@ Error MeshForwarder::UpdateIp6RouteFtd(const Ip6::Header &aIp6Header, Message &a Get().RouteLookup(aIp6Header.GetSource(), aIp6Header.GetDestination(), mMeshDest)); } - VerifyOrExit(mMeshDest != Mac::kShortAddrInvalid, error = kErrorDrop); + VerifyOrExit(mMeshDest != Mle::kInvalidRloc16, error = kErrorDrop); - mMeshSource = Get().GetShortAddress(); + mMeshSource = Get().GetRloc16(); SuccessOrExit(error = CheckReachability(mMeshDest, aIp6Header)); aMessage.SetMeshDest(mMeshDest); @@ -703,7 +703,7 @@ Error MeshForwarder::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aI ExitNow(); } - isReachable = (Get().GetNextHop(aMeshDest) != Mac::kShortAddrInvalid); + isReachable = (Get().GetNextHop(aMeshDest) != Mle::kInvalidRloc16); exit: return isReachable ? kErrorNone : kErrorNoRoute; @@ -735,7 +735,7 @@ void MeshForwarder::HandleMesh(FrameData &aFrameData, const Mac::Address &aMacSo UpdateRoutes(aFrameData, meshAddrs); - if (meshAddrs.mDestination.GetShort() == Get().GetShortAddress() || + if (meshAddrs.mDestination.GetShort() == Get().GetRloc16() || Get().HasMinimalChild(meshAddrs.mDestination.GetShort())) { if (Lowpan::FragmentHeader::IsFragmentHeader(aFrameData)) @@ -838,7 +838,7 @@ void MeshForwarder::UpdateRoutes(const FrameData &aFrameData, const Mac::Address neighbor = Get().FindNeighbor(ip6Headers.GetSourceAddress()); VerifyOrExit(neighbor != nullptr && !neighbor->IsFullThreadDevice()); - if (!Mle::RouterIdMatch(aMeshAddrs.mSource.GetShort(), Get().GetShortAddress())) + if (!Mle::RouterIdMatch(aMeshAddrs.mSource.GetShort(), Get().GetRloc16())) { Get().RemoveNeighbor(*neighbor); } diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 00d754c50..62cc1b4c7 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -95,8 +95,8 @@ Mle::Mle(Instance &aInstance) #if OPENTHREAD_FTD , mLinkRequestAttempts(0) #endif - , mRloc16(Mac::kShortAddrInvalid) - , mPreviousParentRloc(Mac::kShortAddrInvalid) + , mRloc16(kInvalidRloc16) + , mPreviousParentRloc(kInvalidRloc16) , mAttachCounter(0) , mAnnounceDelay(kAnnounceTimeout) , mAlternatePanId(Mac::kPanIdBroadcast) @@ -209,7 +209,7 @@ Error Mle::Start(StartMode aMode) mReattachState = kReattachStart; } - if ((aMode == kAnnounceAttach) || (GetRloc16() == Mac::kShortAddrInvalid)) + if ((aMode == kAnnounceAttach) || (GetRloc16() == kInvalidRloc16)) { Attach(kAnyPartition); } @@ -407,7 +407,7 @@ void Mle::Restore(void) mMeshLocalEid.GetAddress().SetIid(networkInfo.GetMeshLocalIid()); - if (networkInfo.GetRloc16() == Mac::kShortAddrInvalid) + if (networkInfo.GetRloc16() == kInvalidRloc16) { ExitNow(); } @@ -540,7 +540,7 @@ Error Mle::BecomeDetached(void) SetStateDetached(); mParent.SetState(Neighbor::kStateInvalid); - SetRloc16(Mac::kShortAddrInvalid); + SetRloc16(kInvalidRloc16); Attach(kAnyPartition); exit: @@ -749,7 +749,7 @@ void Mle::SetStateChild(uint16_t aRloc16) mParentSearch.UpdateState(); #endif - if ((mPreviousParentRloc != Mac::kShortAddrInvalid) && (mPreviousParentRloc != mParent.GetRloc16())) + if ((mPreviousParentRloc != kInvalidRloc16) && (mPreviousParentRloc != mParent.GetRloc16())) { mCounters.mParentChanges++; @@ -960,7 +960,7 @@ void Mle::SetRloc16(uint16_t aRloc16) Get().SetShortAddress(aRloc16); mRloc16 = aRloc16; - if (aRloc16 != Mac::kShortAddrInvalid) + if (aRloc16 != kInvalidRloc16) { // We can always call `AddUnicastAddress(mMeshLocat16)` and if // the address is already added, it will perform no action. @@ -3948,7 +3948,7 @@ void Mle::ParentSearch::UpdateState(void) if (mIsInBackoff && !mBackoffWasCanceled && mRecentlyDetached) { - if ((Get().mPreviousParentRloc != Mac::kShortAddrInvalid) && + if ((Get().mPreviousParentRloc != kInvalidRloc16) && (Get().mPreviousParentRloc != Get().mParent.GetRloc16())) { mIsInBackoff = false; @@ -3972,7 +3972,7 @@ void Mle::ParentSearch::UpdateState(void) #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) void Mle::Log(MessageAction aAction, MessageType aType, const Ip6::Address &aAddress) { - Log(aAction, aType, aAddress, Mac::kShortAddrInvalid); + Log(aAction, aType, aAddress, kInvalidRloc16); } void Mle::Log(MessageAction aAction, MessageType aType, const Ip6::Address &aAddress, uint16_t aRloc) @@ -3984,7 +3984,7 @@ void Mle::Log(MessageAction aAction, MessageType aType, const Ip6::Address &aAdd String rlocString; - if (aRloc != Mac::kShortAddrInvalid) + if (aRloc != kInvalidRloc16) { rlocString.Append(",0x%04x", aRloc); } diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 466f799ec..1dfcfed13 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1166,7 +1166,7 @@ class Mle : public InstanceLocator, private NonCopyable class ServiceAloc : public Ip6::Netif::UnicastAddress { public: - static constexpr uint16_t kNotInUse = Mac::kShortAddrInvalid; + static constexpr uint16_t kNotInUse = kInvalidRloc16; ServiceAloc(void); diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index ca3476fe5..9e9b21caa 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -1084,7 +1084,7 @@ Error MleRouter::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo) // `RouterTable`). Error error = kErrorNone; - uint16_t neighborRloc16 = Mac::kShortAddrInvalid; + uint16_t neighborRloc16 = kInvalidRloc16; if ((aRxInfo.mNeighbor != nullptr) && Get().Contains(*aRxInfo.mNeighbor)) { @@ -1099,7 +1099,7 @@ Error MleRouter::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo) error = kErrorNoRoute; } - if (neighborRloc16 != Mac::kShortAddrInvalid) + if (neighborRloc16 != kInvalidRloc16) { aRxInfo.mNeighbor = Get().FindNeighbor(neighborRloc16); } @@ -3415,7 +3415,7 @@ template <> void MleRouter::HandleTmf(Coap::Message &aMessag case kErrorNone: break; case kErrorNotFound: - rloc16 = Mac::kShortAddrInvalid; + rloc16 = kInvalidRloc16; break; default: ExitNow(error = kErrorParse); @@ -3464,7 +3464,7 @@ template <> void MleRouter::HandleTmf(Coap::Message &aMessag ExitNow(); } - if (rloc16 != Mac::kShortAddrInvalid) + if (rloc16 != kInvalidRloc16) { router = mRouterTable.Allocate(RouterIdFromRloc16(rloc16)); diff --git a/src/core/thread/neighbor.hpp b/src/core/thread/neighbor.hpp index 903715d44..b830b4be3 100644 --- a/src/core/thread/neighbor.hpp +++ b/src/core/thread/neighbor.hpp @@ -154,8 +154,7 @@ class Neighbor : public InstanceLocatorInit */ AddressMatcher(const Mac::Address &aMacAddress, StateFilter aStateFilter) : AddressMatcher(aStateFilter, - aMacAddress.IsShort() ? aMacAddress.GetShort() - : static_cast(Mac::kShortAddrInvalid), + aMacAddress.IsShort() ? aMacAddress.GetShort() : Mac::kShortAddrInvalid, aMacAddress.IsExtended() ? &aMacAddress.GetExtended() : nullptr) { } diff --git a/src/core/thread/network_data_leader_ftd.cpp b/src/core/thread/network_data_leader_ftd.cpp index 9c2914706..4b8b4cb52 100644 --- a/src/core/thread/network_data_leader_ftd.cpp +++ b/src/core/thread/network_data_leader_ftd.cpp @@ -616,7 +616,7 @@ void Leader::CheckForNetDataGettingFull(const NetworkData &aNetworkData, uint16_ leaderClone.MarkAsClone(); SuccessOrAssert(CopyNetworkData(kFullSet, leaderClone)); - if (aOldRloc16 != Mac::kShortAddrInvalid) + if (aOldRloc16 != Mle::kInvalidRloc16) { leaderClone.RemoveBorderRouter(aOldRloc16, kMatchModeRloc16); } diff --git a/src/core/thread/network_data_notifier.cpp b/src/core/thread/network_data_notifier.cpp index 8d086baa2..bbcd35bf3 100644 --- a/src/core/thread/network_data_notifier.cpp +++ b/src/core/thread/network_data_notifier.cpp @@ -57,7 +57,7 @@ Notifier::Notifier(Instance &aInstance) , mNetDataFullTask(aInstance) #endif , mNextDelay(0) - , mOldRloc(Mac::kShortAddrInvalid) + , mOldRloc(Mle::kInvalidRloc16) , mWaitingForResponse(false) #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE , mDidRequestRouterRoleUpgrade(false) @@ -177,7 +177,7 @@ Error Notifier::UpdateInconsistentData(void) if (mOldRloc == deviceRloc) { - mOldRloc = Mac::kShortAddrInvalid; + mOldRloc = Mle::kInvalidRloc16; } SuccessOrExit(error = SendServerDataNotification(mOldRloc, &Get())); @@ -211,7 +211,7 @@ Error Notifier::SendServerDataNotification(uint16_t aOldRloc16, const NetworkDat #endif } - if (aOldRloc16 != Mac::kShortAddrInvalid) + if (aOldRloc16 != Mle::kInvalidRloc16) { SuccessOrExit(error = Tlv::Append(*message, aOldRloc16)); } diff --git a/src/core/thread/network_data_service.cpp b/src/core/thread/network_data_service.cpp index 2eb0edf21..2891e4c57 100644 --- a/src/core/thread/network_data_service.cpp +++ b/src/core/thread/network_data_service.cpp @@ -103,7 +103,7 @@ void Manager::GetBackboneRouterPrimary(ot::BackboneRouter::Config &aConfig) cons serviceData.Init(&BackboneRouter::kServiceData, BackboneRouter::kServiceDataMinSize); - aConfig.mServer16 = Mac::kShortAddrInvalid; + aConfig.mServer16 = Mle::kInvalidRloc16; while ((serviceTlv = Get().FindNextThreadService(serviceTlv, serviceData, NetworkData::kServicePrefixMatch)) != nullptr) diff --git a/src/core/thread/network_data_tlvs.hpp b/src/core/thread/network_data_tlvs.hpp index 7b15fb275..aefe911d4 100644 --- a/src/core/thread/network_data_tlvs.hpp +++ b/src/core/thread/network_data_tlvs.hpp @@ -43,6 +43,7 @@ #include "common/encoding.hpp" #include "common/equatable.hpp" #include "net/ip6_address.hpp" +#include "thread/mle_types.hpp" #include "thread/network_data_types.hpp" namespace ot { @@ -412,7 +413,7 @@ class HasRouteEntry : public Equatable */ void Init(void) { - SetRloc(Mac::kShortAddrInvalid); + SetRloc(Mle::kInvalidRloc16); mFlags = 0; } @@ -923,7 +924,7 @@ class BorderRouterEntry : public Equatable */ void Init(void) { - SetRloc(Mac::kShortAddrInvalid); + SetRloc(Mle::kInvalidRloc16); mFlags = 0; } diff --git a/src/core/utils/history_tracker.hpp b/src/core/utils/history_tracker.hpp index 173292d74..1aa582999 100644 --- a/src/core/utils/history_tracker.hpp +++ b/src/core/utils/history_tracker.hpp @@ -292,7 +292,7 @@ class HistoryTracker : public InstanceLocator, private NonCopyable static constexpr AddressEvent kAddressAdded = OT_HISTORY_TRACKER_ADDRESS_EVENT_ADDED; static constexpr AddressEvent kAddressRemoved = OT_HISTORY_TRACKER_ADDRESS_EVENT_REMOVED; - static constexpr uint16_t kInvalidRloc16 = Mac::kShortAddrInvalid; + static constexpr uint16_t kInvalidRloc16 = Mle::kInvalidRloc16; typedef otHistoryTrackerNeighborEvent NeighborEvent; From 588dfae6f4be08106b355b18835241291497c08a Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Wed, 26 Jun 2024 23:00:46 +0800 Subject: [PATCH 58/65] [posix] check the max number of RCP supported sleepy children (#10399) This commit adds a diag command to rcp capbility diag module to check the max number of RCP supported sleepy children. --- src/posix/platform/README_RCP_CAPS_DIAG.md | 12 ++++ src/posix/platform/rcp_caps_diag.cpp | 73 ++++++++++++++++++++++ src/posix/platform/rcp_caps_diag.hpp | 6 ++ 3 files changed, 91 insertions(+) diff --git a/src/posix/platform/README_RCP_CAPS_DIAG.md b/src/posix/platform/README_RCP_CAPS_DIAG.md index c4f675f6e..faf9909e8 100644 --- a/src/posix/platform/README_RCP_CAPS_DIAG.md +++ b/src/posix/platform/README_RCP_CAPS_DIAG.md @@ -8,6 +8,7 @@ This module provides diag commands for checking RCP capabilities. - [capflags](#capflags) - [spinel](#spinel) +- [srcmatchtable](#srcmatchtable) ## Command Details @@ -112,3 +113,14 @@ PROP_VALUE_SET PHY_TX_POWER ------------------------------- OK PROP_VALUE_SET RADIO_COEX_ENABLE -------------------------- OK Done ``` + +### srcmatchtable + +Check the source match table size supported by the RCP. + +```bash +> diag rcpcaps srcmatchtable +ShortSrcMatchTableSize ------------------------------------ 128 +ExtendedSrcMatchTableSize --------------------------------- 128 +Done +``` diff --git a/src/posix/platform/rcp_caps_diag.cpp b/src/posix/platform/rcp_caps_diag.cpp index 7a2242e38..e972f0e48 100644 --- a/src/posix/platform/rcp_caps_diag.cpp +++ b/src/posix/platform/rcp_caps_diag.cpp @@ -457,6 +457,10 @@ otError RcpCapsDiag::DiagProcess(char *aArgs[], uint8_t aArgsLength) { ProcessCapabilityFlags(); } + else if (strcmp(aArgs[1], "srcmatchtable") == 0) + { + ProcessSrcMatchTable(); + } else if (strcmp(aArgs[1], "spinel") == 0) { ProcessSpinel(); @@ -616,6 +620,66 @@ bool RcpCapsDiag::IsSpinelCapabilitySupported(const uint8_t *aCapsData, spinel_s return ret; } +void RcpCapsDiag::ProcessSrcMatchTable(void) +{ + OutputShortSrcMatchTableSize(); + OutputExtendedSrcMatchTableSize(); +} + +void RcpCapsDiag::OutputShortSrcMatchTableSize(void) +{ + constexpr uint8_t kRouterIdOffset = 10; + constexpr uint8_t kRouterId = 5; + uint16_t num = 0; + uint16_t shortAddress; + + SuccessOrExit(mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_ENABLED, SPINEL_DATATYPE_BOOL_S, true /* aEnable */)); + SuccessOrExit(mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, nullptr)); + + for (num = 0; num < kMaxNumChildren; num++) + { + shortAddress = num | (kRouterId << kRouterIdOffset); + SuccessOrExit( + mRadioSpinel.Insert(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, SPINEL_DATATYPE_UINT16_S, shortAddress)); + } + +exit: + if (num != 0) + { + IgnoreReturnValue(mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, nullptr)); + IgnoreReturnValue( + mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_ENABLED, SPINEL_DATATYPE_BOOL_S, false /* aEnable */)); + } + + OutputFormat("ShortSrcMatchTableSize", num); +} + +void RcpCapsDiag::OutputExtendedSrcMatchTableSize(void) +{ + otExtAddress extAddress = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + uint16_t num = 0; + + SuccessOrExit(mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_ENABLED, SPINEL_DATATYPE_BOOL_S, true /* aEnable */)); + SuccessOrExit(mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, nullptr)); + + for (num = 0; num < kMaxNumChildren; num++) + { + *reinterpret_cast(extAddress.m8) = num; + SuccessOrExit( + mRadioSpinel.Insert(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, SPINEL_DATATYPE_EUI64_S, extAddress.m8)); + } + +exit: + if (num != 0) + { + IgnoreReturnValue(mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, nullptr)); + IgnoreReturnValue( + mRadioSpinel.Set(SPINEL_PROP_MAC_SRC_MATCH_ENABLED, SPINEL_DATATYPE_BOOL_S, false /* aEnable */)); + } + + OutputFormat("ExtendedSrcMatchTableSize", num); +} + void RcpCapsDiag::OutputFormat(const char *aName, const char *aValue) { static constexpr uint8_t kMaxNameLength = 56; @@ -628,6 +692,15 @@ void RcpCapsDiag::OutputFormat(const char *aName, const char *aValue) Output("%.*s %s %s\r\n", kMaxNameLength, aName, &kPadding[paddingOffset], aValue); } +void RcpCapsDiag::OutputFormat(const char *aName, uint32_t aValue) +{ + static constexpr uint16_t kValueLength = 11; + char value[kValueLength]; + + snprintf(value, sizeof(value), "%u", aValue); + OutputFormat(aName, value); +} + void RcpCapsDiag::OutputResult(const SpinelEntry &aEntry, otError error) { static constexpr uint8_t kSpaceLength = 1; diff --git a/src/posix/platform/rcp_caps_diag.hpp b/src/posix/platform/rcp_caps_diag.hpp index 05e06498b..0431f6167 100644 --- a/src/posix/platform/rcp_caps_diag.hpp +++ b/src/posix/platform/rcp_caps_diag.hpp @@ -108,8 +108,11 @@ class RcpCapsDiag RcpCapsDiag::SpinelCommandHandler mHandler; }; + static constexpr uint16_t kMaxNumChildren = 512; + void ProcessSpinel(void); void ProcessCapabilityFlags(void); + void ProcessSrcMatchTable(void); void TestSpinelCommands(Category aCategory); void TestRadioCapbilityFlags(void); void OutputRadioCapFlags(Category aCategory, uint32_t aRadioCaps, const uint32_t *aFlags, uint16_t aNumbFlags); @@ -120,7 +123,10 @@ class RcpCapsDiag const uint32_t *aFlags, uint16_t aNumbFlags); bool IsSpinelCapabilitySupported(const uint8_t *aCapsData, spinel_size_t aCapsLength, uint32_t aCapability); + void OutputExtendedSrcMatchTableSize(void); + void OutputShortSrcMatchTableSize(void); void OutputFormat(const char *aName, const char *aValue); + void OutputFormat(const char *aName, uint32_t aValue); void OutputResult(const SpinelEntry &aEntry, otError error); void Output(const char *aFormat, ...); From c8681ff8e49de7d0a2556182463ed54beeb2d989 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 26 Jun 2024 08:03:23 -0700 Subject: [PATCH 59/65] [routing-manager] centralize `RxRaTracker` decision logic and signaling (#10389) This commit enhances `RoutingManager::RxRaTracker`: - A new private `Evaluate()` method centralizes logic for handling changes in tracked routers and advertised prefixes. It removes expired entries, determines decision factors used by other `RoutingManager` components, and schedules timers. - A new class `DecisionFactors` is added to track factors used by `RoutingManager`, including the favored on-link prefix, presence of ULA/non-ULA prefixes, and M/O flags for mirroring in emitted RA messages. - `Evaluate()` determines these factors and signals changes using `HandleRaPrefixTableChanged()` only when necessary, simplifying signaling and avoiding redundant calculations. --- src/core/border_router/routing_manager.cpp | 347 +++++++++------------ src/core/border_router/routing_manager.hpp | 68 ++-- 2 files changed, 181 insertions(+), 234 deletions(-) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index b3ec00fe4..07b2c6379 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -594,7 +594,7 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) header.SetToDefault(); } - mRxRaTracker.DetermineAndSetFlags(header); + mRxRaTracker.SetHeaderFlagsOn(header); SuccessOrExit(error = raMsg.AppendHeader(header)); @@ -980,12 +980,11 @@ void RoutingManager::RxRaTracker::Stop(void) { mRouters.Free(); mLocalRaHeader.Clear(); + mDecisionFactors.Clear(); mExpirationTimer.Stop(); mStaleTimer.Stop(); mRouterTimer.Stop(); - - SignalTableChanged(); } void RoutingManager::RxRaTracker::ProcessRouterAdvertMessage(const RouterAdvert::RxMessage &aRaMessage, @@ -1048,9 +1047,9 @@ void RoutingManager::RxRaTracker::ProcessRouterAdvertMessage(const RouterAdvert: router->mIsLocalDevice = (aRaOrigin == kThisBrOtherEntity); - UpdateRouterOnRx(*router); + router->ResetReachabilityState(); - RemoveRoutersWithNoEntriesOrFlags(); + Evaluate(); exit: return; @@ -1070,13 +1069,11 @@ void RoutingManager::RxRaTracker::ProcessRaHeader(const RouterAdvert::Header &aR if (aRouter.mManagedAddressConfigFlag != managedFlag) { aRouter.mManagedAddressConfigFlag = managedFlag; - SignalTableChanged(); } if (aRouter.mOtherConfigFlag != otherFlag) { aRouter.mOtherConfigFlag = otherFlag; - SignalTableChanged(); } if (aRaOrigin == kThisBrOtherEntity) @@ -1104,7 +1101,6 @@ void RoutingManager::RxRaTracker::ProcessRaHeader(const RouterAdvert::Header &aR if (mLocalRaHeader != oldHeader) { - SignalTableChanged(); Get().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); } } @@ -1134,10 +1130,6 @@ void RoutingManager::RxRaTracker::ProcessRaHeader(const RouterAdvert::Header &aR entry->SetFrom(aRaHeader); } - mExpirationTimer.FireAtIfEarlier(entry->GetExpireTime()); - - SignalTableChanged(); - exit: return; } @@ -1185,10 +1177,6 @@ void RoutingManager::RxRaTracker::ProcessPrefixInfoOption(const PrefixInfoOption entry->AdoptValidAndPreferredLifetimesFrom(newPrefix); } - mExpirationTimer.FireAtIfEarlier(entry->GetExpireTime()); - - SignalTableChanged(); - exit: return; } @@ -1241,10 +1229,6 @@ void RoutingManager::RxRaTracker::ProcessRouteInfoOption(const RouteInfoOption & entry->SetFrom(aRio); } - mExpirationTimer.FireAtIfEarlier(entry->GetExpireTime()); - - SignalTableChanged(); - exit: return; } @@ -1311,73 +1295,6 @@ template void RoutingManager::RxRaTracker::Entry: #endif // !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE -bool RoutingManager::RxRaTracker::ContainsDefaultOrNonUlaRoutePrefix(void) const -{ - bool contains = false; - - for (const Router &router : mRouters) - { - if (router.mRoutePrefixes.ContainsMatching(RoutePrefix::kIsNotUla)) - { - contains = true; - break; - } - } - - return contains; -} - -bool RoutingManager::RxRaTracker::ContainsOnLinkPrefix(OnLinkPrefix::UlaChecker aUlaChecker) const -{ - bool contains = false; - - for (const Router &router : mRouters) - { - if (router.mOnLinkPrefixes.ContainsMatching(aUlaChecker)) - { - contains = true; - break; - } - } - - return contains; -} - -bool RoutingManager::RxRaTracker::ContainsNonUlaOnLinkPrefix(void) const -{ - return ContainsOnLinkPrefix(OnLinkPrefix::kIsNotUla); -} - -bool RoutingManager::RxRaTracker::ContainsUlaOnLinkPrefix(void) const -{ - return ContainsOnLinkPrefix(OnLinkPrefix::kIsUla); -} - -void RoutingManager::RxRaTracker::FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const -{ - // Find the smallest preferred on-link prefix entry in the table - // and return it in `aPrefix`. If there is none, `aPrefix` is - // cleared (prefix length is set to zero). - - aPrefix.Clear(); - - for (const Router &router : mRouters) - { - for (const OnLinkPrefix &entry : router.mOnLinkPrefixes) - { - if (entry.IsDeprecated() || (entry.GetPreferredLifetime() < kFavoredOnLinkPrefixMinPreferredLifetime)) - { - continue; - } - - if ((aPrefix.GetLength() == 0) || (entry.GetPrefix() < aPrefix)) - { - aPrefix = entry.GetPrefix(); - } - } - } -} - void RoutingManager::RxRaTracker::HandleLocalOnLinkPrefixChanged(void) { const Ip6::Prefix &prefix = Get().mOnLinkPrefixManager.GetLocalPrefix(); @@ -1390,9 +1307,7 @@ void RoutingManager::RxRaTracker::HandleLocalOnLinkPrefixChanged(void) VerifyOrExit(didRemove); - RemoveRoutersWithNoEntriesOrFlags(); - - SignalTableChanged(); + Evaluate(); exit: return; @@ -1419,8 +1334,7 @@ void RoutingManager::RxRaTracker::HandleNetDataChange(void) if (didRemove) { - RemoveRoutersWithNoEntriesOrFlags(); - SignalTableChanged(); + Evaluate(); } } @@ -1436,7 +1350,6 @@ void RoutingManager::RxRaTracker::RemoveOrDeprecateOldEntries(TimeMilli aTimeThr if (entry.GetLastUpdateTime() <= aTimeThreshold) { entry.ClearPreferredLifetime(); - SignalTableChanged(); } } @@ -1445,7 +1358,6 @@ void RoutingManager::RxRaTracker::RemoveOrDeprecateOldEntries(TimeMilli aTimeThr if (entry.GetLastUpdateTime() <= aTimeThreshold) { entry.ClearValidLifetime(); - SignalTableChanged(); } } } @@ -1453,42 +1365,66 @@ void RoutingManager::RxRaTracker::RemoveOrDeprecateOldEntries(TimeMilli aTimeThr if (mLocalRaHeader.IsValid() && (mLocalRaHeaderUpdateTime <= aTimeThreshold)) { mLocalRaHeader.Clear(); - SignalTableChanged(); } - RemoveExpiredEntries(); + Evaluate(); } -void RoutingManager::RxRaTracker::ScheduleAllTimers(void) +void RoutingManager::RxRaTracker::Evaluate(void) { - TimeMilli now = TimerMilli::GetNow(); - NextFireTime routerTimeout(now); - NextFireTime entryExpireTime(now); - NextFireTime staleTime(now); + DecisionFactors oldFactors = mDecisionFactors; + TimeMilli now = TimerMilli::GetNow(); + NextFireTime routerTimeout(now); + NextFireTime entryExpireTime(now); + NextFireTime staleTime(now); - // If multiple routers advertise the same on-link or route prefix, - // the stale time for the prefix is determined by the latest stale - // time among all corresponding entries. - // - // The "StaleTimeCalculated" flag is used to ensure stale time is - // calculated only once for each unique prefix. Initially, this - // flag is cleared on all entries. As we iterate over routers and - // their entries, `DetermineStaleTimeFor()` will consider all - // matching entries and mark "StaleTimeCalculated" flag on them. + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Remove expired prefix entries in routers and then remove any + // router that has with no prefix entries or flags. + + mRouters.RemoveAndFreeAllMatching(Router::EmptyChecker(now)); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Determine decision factors (favored on-link prefix, has any + // ULA/non-ULA on-link/route prefix, M/O flags). + + mDecisionFactors.Clear(); for (Router &router : mRouters) { + mDecisionFactors.UpdateFlagsFrom(router); + for (OnLinkPrefix &entry : router.mOnLinkPrefixes) { + mDecisionFactors.UpdateFrom(entry); entry.SetStaleTimeCalculated(false); } for (RoutePrefix &entry : router.mRoutePrefixes) { + mDecisionFactors.UpdateFrom(entry); entry.SetStaleTimeCalculated(false); } } + if (oldFactors != mDecisionFactors) + { + mSignalTask.Post(); + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Schedule timers + + // If multiple routers advertise the same on-link or route prefix, + // the stale time for the prefix is determined by the latest stale + // time among all corresponding entries. + // + // The "StaleTimeCalculated" flag is used to ensure stale time is + // calculated only once for each unique prefix. Initially, this + // flag is cleared on all entries. As we iterate over routers and + // their entries, `DetermineStaleTimeFor()` will consider all + // matching entries and mark "StaleTimeCalculated" flag on them. + for (const Router &router : mRouters) { if (router.ShouldCheckReachability()) @@ -1604,43 +1540,9 @@ void RoutingManager::RxRaTracker::HandleStaleTimer(void) return; } -void RoutingManager::RxRaTracker::RemoveRoutersWithNoEntriesOrFlags(void) -{ - mRouters.RemoveAndFreeAllMatching(Router::kContainsNoEntriesOrFlags); -} - -void RoutingManager::RxRaTracker::HandleExpirationTimer(void) { RemoveExpiredEntries(); } - -void RoutingManager::RxRaTracker::RemoveExpiredEntries(void) -{ - TimeMilli now = TimerMilli::GetNow(); - bool didRemove = false; - - for (Router &router : mRouters) - { - LifetimedPrefix::ExpirationChecker expirationChecker(now); - - didRemove |= router.mOnLinkPrefixes.RemoveAndFreeAllMatching(expirationChecker); - didRemove |= router.mRoutePrefixes.RemoveAndFreeAllMatching(expirationChecker); - } +void RoutingManager::RxRaTracker::HandleExpirationTimer(void) { Evaluate(); } - RemoveRoutersWithNoEntriesOrFlags(); - - if (didRemove) - { - SignalTableChanged(); - } - - ScheduleAllTimers(); -} - -void RoutingManager::RxRaTracker::SignalTableChanged(void) { mSignalTask.Post(); } - -void RoutingManager::RxRaTracker::HandleSignalTask(void) -{ - ScheduleAllTimers(); - Get().HandleRaPrefixTableChanged(); -} +void RoutingManager::RxRaTracker::HandleSignalTask(void) { Get().HandleRaPrefixTableChanged(); } void RoutingManager::RxRaTracker::ProcessNeighborAdvertMessage(const NeighborAdvertMessage &aNaMessage) { @@ -1653,22 +1555,14 @@ void RoutingManager::RxRaTracker::ProcessNeighborAdvertMessage(const NeighborAdv LogInfo("Received NA from router %s", router->mAddress.ToString().AsCString()); - UpdateRouterOnRx(*router); + router->ResetReachabilityState(); + + Evaluate(); exit: return; } -void RoutingManager::RxRaTracker::UpdateRouterOnRx(Router &aRouter) -{ - aRouter.mNsProbeCount = 0; - aRouter.mLastUpdateTime = TimerMilli::GetNow(); - - aRouter.mTimeout = - aRouter.mLastUpdateTime + Random::NonCrypto::AddJitter(Router::kReachableTimeout, Router::kJitter); - mRouterTimer.FireAtIfEarlier(aRouter.mTimeout); -} - void RoutingManager::RxRaTracker::HandleRouterTimer(void) { TimeMilli now = TimerMilli::GetNow(); @@ -1701,21 +1595,17 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void) if (!entry.IsDeprecated()) { entry.ClearPreferredLifetime(); - SignalTableChanged(); } } for (RoutePrefix &entry : router.mRoutePrefixes) { entry.ClearValidLifetime(); - SignalTableChanged(); } } } - RemoveExpiredEntries(); - - ScheduleAllTimers(); + Evaluate(); } void RoutingManager::RxRaTracker::SendNeighborSolicitToRouter(const Router &aRouter) @@ -1737,39 +1627,16 @@ void RoutingManager::RxRaTracker::SendNeighborSolicitToRouter(const Router &aRou return; } -void RoutingManager::RxRaTracker::DetermineAndSetFlags(RouterAdvert::Header &aHeader) const +void RoutingManager::RxRaTracker::SetHeaderFlagsOn(RouterAdvert::Header &aHeader) const { - // Determine the `M` and `O` flags to include in the RA message - // header to be emitted. - // - // If any discovered router on infrastructure which is not itself a - // stub router (e.g., another Thread BR) includes the `M` or `O` - // flag, we also include the same flag. - // - // If a router has failed to respond to max number of NS probe - // attempts, we consider it as offline and ignore its flags. - - for (const Router &router : mRouters) + if (mDecisionFactors.mHeaderManagedAddressConfigFlag) { - if (router.mStubRouterFlag) - { - continue; - } - - if (!router.IsReachable()) - { - continue; - } - - if (router.mManagedAddressConfigFlag) - { - aHeader.SetManagedAddressConfigFlag(); - } + aHeader.SetManagedAddressConfigFlag(); + } - if (router.mOtherConfigFlag) - { - aHeader.SetOtherConfigFlag(); - } + if (mDecisionFactors.mHeaderOtherConfigFlag) + { + aHeader.SetOtherConfigFlag(); } } @@ -1923,19 +1790,31 @@ bool RoutingManager::RxRaTracker::Router::ShouldCheckReachability(void) const return IsReachable() && !mIsLocalDevice; } -bool RoutingManager::RxRaTracker::Router::Matches(EmptyChecker aChecker) const +void RoutingManager::RxRaTracker::Router::ResetReachabilityState(void) { - // Checks whether or not a `Router` instance has any useful info. An - // entry can be removed if it does not advertise M or O flags and + // Called when an RA or NA is received and processed. + + mNsProbeCount = 0; + mLastUpdateTime = TimerMilli::GetNow(); + mTimeout = mLastUpdateTime + Random::NonCrypto::AddJitter(kReachableTimeout, kJitter); +} + +bool RoutingManager::RxRaTracker::Router::Matches(const EmptyChecker &aChecker) +{ + // First removes all expired on-link or router prefixes. Then + // checks whether or not the router has any useful info. + + bool hasFlags = false; + + mOnLinkPrefixes.RemoveAndFreeAllMatching(aChecker); + mRoutePrefixes.RemoveAndFreeAllMatching(aChecker); + + // Router can be removed if it does not advertise M or O flags and // also does not have any advertised prefix entries (RIO/PIO). If // the router already failed to respond to max NS probe attempts, // we consider it as offline and therefore do not consider its // flags anymore. - OT_UNUSED_VARIABLE(aChecker); - - bool hasFlags = false; - if (IsReachable()) { hasFlags = (mManagedAddressConfigFlag || mOtherConfigFlag); @@ -1955,6 +1834,68 @@ void RoutingManager::RxRaTracker::Router::CopyInfoTo(RouterEntry &aEntry, TimeMi aEntry.mIsReachable = IsReachable(); } +//--------------------------------------------------------------------------------------------------------------------- +// RxRaTracker::DecisionFactors + +void RoutingManager::RxRaTracker::DecisionFactors::UpdateFlagsFrom(const Router &aRouter) +{ + // Determine the `M` and `O` flags to include in the RA message + // header to be emitted. + // + // If any discovered router on infrastructure which is not itself a + // stub router (e.g., another Thread BR) includes the `M` or `O` + // flag, we also include the same flag. + + VerifyOrExit(!aRouter.mStubRouterFlag); + VerifyOrExit(aRouter.IsReachable()); + + if (aRouter.mManagedAddressConfigFlag) + { + mHeaderManagedAddressConfigFlag = true; + } + + if (aRouter.mOtherConfigFlag) + { + mHeaderOtherConfigFlag = true; + } + +exit: + return; +} + +void RoutingManager::RxRaTracker::DecisionFactors::UpdateFrom(const OnLinkPrefix &aOnLinkPrefix) +{ + if (aOnLinkPrefix.GetPrefix().IsUniqueLocal()) + { + mHasUlaOnLink = true; + } + else + { + mHasNonUlaOnLink = true; + } + + // Determine favored on-link prefix + + VerifyOrExit(!aOnLinkPrefix.IsDeprecated()); + VerifyOrExit(aOnLinkPrefix.GetPreferredLifetime() >= kFavoredOnLinkPrefixMinPreferredLifetime); + + if ((mFavoredOnLinkPrefix.GetLength() == 0) || (aOnLinkPrefix.GetPrefix() < mFavoredOnLinkPrefix)) + { + mFavoredOnLinkPrefix = aOnLinkPrefix.GetPrefix(); + } + +exit: + return; +} + +void RoutingManager::RxRaTracker::DecisionFactors::UpdateFrom(const RoutePrefix &aRoutePrefix) +{ + if (!mHasNonUlaRoute) + { + mHasNonUlaRoute = !aRoutePrefix.GetPrefix().IsUniqueLocal(); + } +} + //--------------------------------------------------------------------------------------------------------------------- // FavoredOmrPrefix @@ -2379,7 +2320,7 @@ void RoutingManager::OnLinkPrefixManager::Evaluate(void) { VerifyOrExit(!Get().mRsSender.IsInProgress()); - Get().mRxRaTracker.FindFavoredOnLinkPrefix(mFavoredDiscoveredPrefix); + mFavoredDiscoveredPrefix = Get().mRxRaTracker.GetFavoredOnLinkPrefix(); if ((mFavoredDiscoveredPrefix.GetLength() == 0) || (mFavoredDiscoveredPrefix == mLocalPrefix)) { @@ -2431,11 +2372,7 @@ void RoutingManager::OnLinkPrefixManager::HandleRaPrefixTableChanged(void) // prefix has changed, we trigger a re-evaluation of the routing // policy. - Ip6::Prefix newFavoredPrefix; - - Get().mRxRaTracker.FindFavoredOnLinkPrefix(newFavoredPrefix); - - if (newFavoredPrefix != mFavoredDiscoveredPrefix) + if (Get().mRxRaTracker.GetFavoredOnLinkPrefix() != mFavoredDiscoveredPrefix) { Get().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); } diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 16286658b..dec8ccc5e 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -54,6 +54,7 @@ #include "border_router/infra_if.hpp" #include "common/array.hpp" #include "common/callback.hpp" +#include "common/equatable.hpp" #include "common/error.hpp" #include "common/heap_allocatable.hpp" #include "common/heap_array.hpp" @@ -658,12 +659,6 @@ class RoutingManager : public InstanceLocator // base class for `OnLinkPrefix` or `RoutePrefix`. public: - enum UlaChecker : bool - { - kIsNotUla = false, - kIsUla = true, - }; - struct ExpirationChecker { explicit ExpirationChecker(TimeMilli aNow) { mNow = aNow; } @@ -677,7 +672,6 @@ class RoutingManager : public InstanceLocator TimeMilli GetExpireTime(void) const { return CalculateExpirationTime(mValidLifetime); } bool Matches(const Ip6::Prefix &aPrefix) const { return (mPrefix == aPrefix); } - bool Matches(const UlaChecker &aIsUla) const { return (mPrefix.IsUniqueLocal() == aIsUla); } bool Matches(const ExpirationChecker &aChecker) const { return (GetExpireTime() <= aChecker.mNow); } void SetStaleTimeCalculated(bool aFlag) { mStaleTimeCalculated = aFlag; } @@ -761,25 +755,27 @@ class RoutingManager : public InstanceLocator RouterAdvOrigin aRaOrigin); void ProcessNeighborAdvertMessage(const NeighborAdvertMessage &aNaMessage); - bool ContainsDefaultOrNonUlaRoutePrefix(void) const; - bool ContainsNonUlaOnLinkPrefix(void) const; - bool ContainsUlaOnLinkPrefix(void) const; + // Decision factors + bool ContainsDefaultOrNonUlaRoutePrefix(void) const { return mDecisionFactors.mHasNonUlaRoute; } + bool ContainsNonUlaOnLinkPrefix(void) const { return mDecisionFactors.mHasNonUlaOnLink; } + bool ContainsUlaOnLinkPrefix(void) const { return mDecisionFactors.mHasUlaOnLink; } - void FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const; - - void HandleLocalOnLinkPrefixChanged(void); - void HandleNetDataChange(void); - - void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold); + const Ip6::Prefix &GetFavoredOnLinkPrefix(void) const { return mDecisionFactors.mFavoredOnLinkPrefix; } + void SetHeaderFlagsOn(RouterAdvert::Header &aHeader) const; const RouterAdvert::Header &GetLocalRaHeaderToMirror(void) const { return mLocalRaHeader; } - void DetermineAndSetFlags(RouterAdvert::Header &aHeader) const; - + // Iterating over discovered items void InitIterator(PrefixTableIterator &aIterator) const; Error GetNextEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const; Error GetNextRouter(PrefixTableIterator &aIterator, RouterEntry &aEntry) const; + // Callbacks notifying of changes + void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold); + void HandleLocalOnLinkPrefixChanged(void); + void HandleNetDataChange(void); + + // Tasklet or timer callbacks void HandleSignalTask(void); void HandleExpirationTimer(void); void HandleStaleTimer(void); @@ -822,15 +818,13 @@ class RoutingManager : public InstanceLocator static_assert(kMaxNsProbes < 255, "kMaxNsProbes MUST not be 255"); - enum EmptyChecker : uint8_t - { - kContainsNoEntriesOrFlags - }; + typedef LifetimedPrefix::ExpirationChecker EmptyChecker; bool IsReachable(void) const { return mNsProbeCount <= kMaxNsProbes; } bool ShouldCheckReachability(void) const; + void ResetReachabilityState(void); bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; } - bool Matches(EmptyChecker aChecker) const; + bool Matches(const EmptyChecker &aChecker); void CopyInfoTo(RouterEntry &aEntry, TimeMilli aNow) const; using OnLinkPrefixList = OwningList>; @@ -911,18 +905,32 @@ class RoutingManager : public InstanceLocator //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + struct DecisionFactors : public Clearable, public Equatable + { + DecisionFactors(void) { Clear(); } + + bool HasFavoredOnLink(void) const { return (mFavoredOnLinkPrefix.GetLength() != 0); } + void UpdateFlagsFrom(const Router &aRouter); + void UpdateFrom(const OnLinkPrefix &aOnLinkPrefix); + void UpdateFrom(const RoutePrefix &aRoutePrefix); + + Ip6::Prefix mFavoredOnLinkPrefix; + bool mHasNonUlaRoute : 1; + bool mHasNonUlaOnLink : 1; + bool mHasUlaOnLink : 1; + bool mHeaderManagedAddressConfigFlag : 1; + bool mHeaderOtherConfigFlag : 1; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void ProcessRaHeader(const RouterAdvert::Header &aRaHeader, Router &aRouter, RouterAdvOrigin aRaOrigin); void ProcessPrefixInfoOption(const PrefixInfoOption &aPio, Router &aRouter); void ProcessRouteInfoOption(const RouteInfoOption &aRio, Router &aRouter); void ProcessRaFlagsExtOption(const RaFlagsExtOption &aFlagsOption, Router &aRouter); - bool ContainsOnLinkPrefix(OnLinkPrefix::UlaChecker aUlaChecker) const; - void RemoveRoutersWithNoEntriesOrFlags(void); - void RemoveExpiredEntries(void); - void SignalTableChanged(void); - void ScheduleAllTimers(void); + void Evaluate(void); void DetermineStaleTimeFor(const OnLinkPrefix &aPrefix, NextFireTime &aStaleTime); void DetermineStaleTimeFor(const RoutePrefix &aPrefix, NextFireTime &aStaleTime); - void UpdateRouterOnRx(Router &aRouter); void SendNeighborSolicitToRouter(const Router &aRouter); #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE template Entry *AllocateEntry(void) { return Entry::Allocate(); } @@ -936,6 +944,7 @@ class RoutingManager : public InstanceLocator using RouterTimer = TimerMilliIn; using RouterList = OwningList>; + DecisionFactors mDecisionFactors; RouterList mRouters; ExpirationTimer mExpirationTimer; StaleTimer mStaleTimer; @@ -943,6 +952,7 @@ class RoutingManager : public InstanceLocator SignalTask mSignalTask; RouterAdvert::Header mLocalRaHeader; TimeMilli mLocalRaHeaderUpdateTime; + #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE Pool mEntryPool; Pool, kMaxRouters> mRouterPool; From 21b5764686b4ead0d13096db75fb8b0208b02030 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 26 Jun 2024 08:12:02 -0700 Subject: [PATCH 60/65] [child] add `GetIp6Addresses()` and simplify MLR state tracking (#10424) This commit introduces several changes to the `Child` class for managing registered IPv6 addresses by MTD children: - A new method, `Child::GetIp6Addresses()`, is added, returning the `Array` of registered IPv6 address entries. This array includes all tracked child IPv6 addresses except for the mesh-local EID, which can be retrieved using `Child::GetMeshLocalIp6Address()`. - The simplified model enables easy iteration over the address array using `Array` range-based `for` loops. With this change, the complex `AddressIterator` and `AddressIteratorBuilder` nested classes are removed, streamlining the code. - MLR state tracking for child IPv6 address entries is simplified with the introduction of a new class, `Child::Ip6AddrEntry`, representing a registered IPv6 address entry. This class provides `GetMlrState()` and `SetMlrState()`, enforcing that the MLR state can only be set on a child IPv6 address entry. --- src/core/api/thread_ftd_api.cpp | 10 +- src/core/thread/child.cpp | 139 +++++++------ src/core/thread/child.hpp | 257 +++++++------------------ src/core/thread/mle.cpp | 11 +- src/core/thread/mle_router.cpp | 12 +- src/core/thread/mlr_manager.cpp | 76 +++++--- src/core/thread/network_diagnostic.cpp | 17 +- tests/unit/test_child.cpp | 97 +--------- 8 files changed, 228 insertions(+), 391 deletions(-) diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index ec3b9b4d4..6b3f554ee 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -250,15 +250,7 @@ otError otThreadGetChildNextIp6Address(otInstance *aInstance, VerifyOrExit(child != nullptr, error = kErrorInvalidArgs); VerifyOrExit(child->IsStateValidOrRestoring(), error = kErrorInvalidArgs); - { - Child::AddressIterator iter(*child, *aIterator); - - VerifyOrExit(!iter.IsDone(), error = kErrorNotFound); - *aAddress = *iter.GetAddress(); - - iter++; - *aIterator = iter.GetAsIndex(); - } + error = child->GetNextIp6Address(*aIterator, AsCoreType(aAddress)); exit: return error; diff --git a/src/core/thread/child.cpp b/src/core/thread/child.cpp index a91512587..0f4efacd9 100644 --- a/src/core/thread/child.cpp +++ b/src/core/thread/child.cpp @@ -44,6 +44,9 @@ namespace ot { #if OPENTHREAD_FTD +//--------------------------------------------------------------------------------------------------------------------- +// Child::Info + void Child::Info::SetFrom(const Child &aChild) { Clear(); @@ -75,50 +78,49 @@ void Child::Info::SetFrom(const Child &aChild) #endif } -const Ip6::Address *Child::AddressIterator::GetAddress(void) const +//--------------------------------------------------------------------------------------------------------------------- +// Child::Ip6AddrEntry + +#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE + +MlrState Child::Ip6AddrEntry::GetMlrState(const Child &aChild) const { - // `mIndex` value of zero indicates mesh-local IPv6 address. - // Non-zero value specifies the index into address array starting - // from one for first element (i.e, `mIndex - 1` gives the array - // index). + MlrState state = kMlrStateRegistering; + Ip6AddressArray::IndexType index; - const Ip6::Address *address = nullptr; + OT_ASSERT(aChild.mIp6Addresses.IsInArrayBuffer(this)); - if (mIndex == 0) + index = aChild.mIp6Addresses.IndexOf(*this); + + if (aChild.mMlrToRegisterMask.Get(index)) { - address = &mMeshLocalAddress; - ExitNow(); + state = kMlrStateToRegister; + } + else if (aChild.mMlrRegisteredMask.Get(index)) + { + state = kMlrStateRegistered; } - VerifyOrExit(mIndex - 1 < mChild.mIp6Addresses.GetLength()); - address = &mChild.mIp6Addresses[static_cast(mIndex - 1)]; - -exit: - return address; + return state; } -void Child::AddressIterator::Update(void) +// NOLINTNEXTLINE(readability-make-member-function-const) +void Child::Ip6AddrEntry::SetMlrState(MlrState aState, Child &aChild) { - const Ip6::Address *address; + Ip6AddressArray::IndexType index; - if ((mIndex == 0) && (mChild.GetMeshLocalIp6Address(mMeshLocalAddress) != kErrorNone)) - { - mIndex++; - } + OT_ASSERT(aChild.mIp6Addresses.IsInArrayBuffer(this)); - while (true) - { - address = GetAddress(); + index = aChild.mIp6Addresses.IndexOf(*this); - VerifyOrExit((address != nullptr) && !address->IsUnspecified(), mIndex = kMaxIndex); + aChild.mMlrToRegisterMask.Set(index, aState == kMlrStateToRegister); + aChild.mMlrRegisteredMask.Set(index, aState == kMlrStateRegistered); +} - VerifyOrExit(!address->MatchesFilter(mFilter)); - mIndex++; - } +#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE -exit: - return; -} +//--------------------------------------------------------------------------------------------------------------------- +// Child void Child::Clear(void) { @@ -164,6 +166,29 @@ Error Child::GetMeshLocalIp6Address(Ip6::Address &aAddress) const return error; } +Error Child::GetNextIp6Address(AddressIterator &aIterator, Ip6::Address &aAddress) const +{ + Error error = kErrorNone; + + if (aIterator == 0) + { + aIterator++; + + if (GetMeshLocalIp6Address(aAddress) == kErrorNone) + { + ExitNow(); + } + } + + VerifyOrExit(aIterator - 1 < mIp6Addresses.GetLength(), error = kErrorNotFound); + + aAddress = mIp6Addresses[static_cast(aIterator - 1)]; + aIterator++; + +exit: + return error; +} + Error Child::AddIp6Address(const Ip6::Address &aAddress) { Error error = kErrorNone; @@ -177,8 +202,8 @@ Error Child::AddIp6Address(const Ip6::Address &aAddress) ExitNow(); } - VerifyOrExit(!mIp6Addresses.Contains(aAddress), error = kErrorAlready); - error = mIp6Addresses.PushBack(aAddress); + VerifyOrExit(!mIp6Addresses.ContainsMatching(aAddress), error = kErrorAlready); + error = mIp6Addresses.PushBack(static_cast(aAddress)); exit: return error; @@ -187,7 +212,7 @@ Error Child::AddIp6Address(const Ip6::Address &aAddress) Error Child::RemoveIp6Address(const Ip6::Address &aAddress) { Error error = kErrorNotFound; - Ip6::Address *entry; + Ip6AddrEntry *entry; if (Get().IsMeshLocalAddress(aAddress)) { @@ -200,7 +225,7 @@ Error Child::RemoveIp6Address(const Ip6::Address &aAddress) ExitNow(); } - entry = mIp6Addresses.Find(aAddress); + entry = mIp6Addresses.FindMatching(aAddress); VerifyOrExit(entry != nullptr); #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE @@ -239,7 +264,7 @@ bool Child::HasIp6Address(const Ip6::Address &aAddress) const ExitNow(); } - hasAddress = mIp6Addresses.Contains(aAddress); + hasAddress = mIp6Addresses.ContainsMatching(aAddress); exit: return hasAddress; @@ -266,49 +291,21 @@ Error Child::GetDomainUnicastAddress(Ip6::Address &aAddress) const #endif #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE + bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const { - bool has = false; - - VerifyOrExit(mMlrRegisteredMask.HasAny()); + bool hasAddress = false; + const Ip6AddrEntry *entry; - for (const Ip6::Address &address : IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) - { - if (GetAddressMlrState(address) == kMlrStateRegistered && address == aAddress) - { - ExitNow(has = true); - } - } + entry = mIp6Addresses.FindMatching(aAddress); + VerifyOrExit(entry != nullptr); + hasAddress = entry->GetMlrState(*this) == kMlrStateRegistered; exit: - return has; -} - -MlrState Child::GetAddressMlrState(const Ip6::Address &aAddress) const -{ - uint16_t addressIndex; - - OT_ASSERT(mIp6Addresses.IsInArrayBuffer(&aAddress)); - - addressIndex = mIp6Addresses.IndexOf(aAddress); - - return mMlrToRegisterMask.Get(addressIndex) - ? kMlrStateToRegister - : (mMlrRegisteredMask.Get(addressIndex) ? kMlrStateRegistered : kMlrStateRegistering); + return hasAddress; } -void Child::SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState) -{ - uint16_t addressIndex; - - OT_ASSERT(mIp6Addresses.IsInArrayBuffer(&aAddress)); - - addressIndex = mIp6Addresses.IndexOf(aAddress); - - mMlrToRegisterMask.Set(addressIndex, aState == kMlrStateToRegister); - mMlrRegisteredMask.Set(addressIndex, aState == kMlrStateRegistered); -} -#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE +#endif #endif // OPENTHREAD_FTD diff --git a/src/core/thread/child.hpp b/src/core/thread/child.hpp index d2f707f72..1069c7393 100644 --- a/src/core/thread/child.hpp +++ b/src/core/thread/child.hpp @@ -42,6 +42,10 @@ namespace ot { #if OPENTHREAD_FTD +#if OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD < 2 +#error OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD should be at least set to 2. +#endif + /** * Represents a Thread Child. * @@ -54,11 +58,27 @@ class Child : public Neighbor, public CslTxScheduler::ChildInfo #endif { - class AddressIteratorBuilder; - public: static constexpr uint8_t kMaxRequestTlvs = 6; + /** + * Maximum number of registered IPv6 addresses per child (excluding the mesh-local EID). + * + */ + static constexpr uint16_t kNumIp6Addresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1; + + /** + * Represents the iterator for registered IPv6 address list of an MTD child. + * + */ + typedef otChildIp6AddressIterator AddressIterator; + + /** + * The initial value for an `AddressIterator`. + * + */ + static constexpr AddressIterator kAddressIteratorInit = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT; + /** * Represents diagnostic information for a Thread Child. * @@ -76,146 +96,53 @@ class Child : public Neighbor, }; /** - * Defines an iterator used to go through IPv6 address entries of a child. + * Represents an IPv6 address entry registered by an MTD child. * */ - class AddressIterator : public Unequatable + class Ip6AddrEntry : public Ip6::Address { - friend class AddressIteratorBuilder; - public: /** - * Represents an index indicating the current IPv6 address entry to which the iterator is pointing. - * - */ - typedef otChildIp6AddressIterator Index; - - /** - * Initializes the iterator associated with a given `Child` starting from beginning of the - * IPv6 address list. - * - * @param[in] aChild A reference to a child entry. - * @param[in] aFilter An IPv6 address type filter restricting iterator to certain type of addresses. - * - */ - explicit AddressIterator(const Child &aChild, Ip6::Address::TypeFilter aFilter = Ip6::Address::kTypeAny) - : AddressIterator(aChild, 0, aFilter) - { - } - - /** - * Initializes the iterator associated with a given `Child` starting from a given index - * - * @param[in] aChild A reference to the child entry. - * @param[in] aIndex An index (`Index`) with which to initialize the iterator. - * @param[in] aFilter An IPv6 address type filter restricting iterator to certain type of addresses. - * - */ - AddressIterator(const Child &aChild, Index aIndex, Ip6::Address::TypeFilter aFilter = Ip6::Address::kTypeAny) - : mChild(aChild) - , mFilter(aFilter) - , mIndex(aIndex) - { - Update(); - } - - /** - * Converts the iterator into an index. - * - * @returns An index corresponding to the iterator. - * - */ - Index GetAsIndex(void) const { return mIndex; } - - /** - * Gets the iterator's associated `Child` entry. - * - * @returns The associated child entry. - * - */ - const Child &GetChild(void) const { return mChild; } - - /** - * Gets the current `Child` IPv6 Address to which the iterator is pointing. - * - * @returns A pointer to the associated IPv6 Address, or `nullptr` if iterator is done. - * - */ - const Ip6::Address *GetAddress(void) const; - - /** - * Indicates whether the iterator has reached end of the list. - * - * @retval TRUE There are no more entries in the list (reached end of the list). - * @retval FALSE The current entry is valid. - * - */ - bool IsDone(void) const { return (mIndex >= kMaxIndex); } - - /** - * Overloads `++` operator (pre-increment) to advance the iterator. + * Indicates whether the entry matches a given IPv6 address. * - * The iterator is moved to point to the next `Address` entry. If there are no more `Ip6::Address` entries - * `IsDone()` returns `true`. + * @param[in] aAddress The IPv6 address. * - */ - void operator++(void) { mIndex++, Update(); } - - /** - * Overloads `++` operator (post-increment) to advance the iterator. - * - * The iterator is moved to point to the next `Address` entry. If there are no more `Ip6::Address` entries - * `IsDone()` returns `true`. + * @retval TRUE The entry matches @p aAddress. + * @retval FALSE The entry does not match @p aAddress. * */ - void operator++(int) { mIndex++, Update(); } + bool Matches(const Ip6::Address &aAddress) const { return (*this == aAddress); } +#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE /** - * Overloads the `*` dereference operator and gets a reference to `Ip6::Address` to which the - * iterator is currently pointing. + * Gets the MLR state of the IPv6 address entry. * - * MUST be used when the iterator is not done (i.e., `IsDone()` returns `false`). + * @param[in] aChild The child owning this address entry. * - * @returns A reference to the `Ip6::Address` entry currently pointed by the iterator. + * @returns The MLR state of IPv6 address entry. * */ - const Ip6::Address &operator*(void) const { return *GetAddress(); } + MlrState GetMlrState(const Child &aChild) const; /** - * Overloads operator `==` to evaluate whether or not two `Iterator` instances are equal. - * - * MUST be used when the two iterators are associated with the same `Child` entry. + * Sets the MLR state of the IPv6 address entry. * - * @param[in] aOther The other `Iterator` to compare with. - * - * @retval TRUE If the two `Iterator` objects are equal. - * @retval FALSE If the two `Iterator` objects are not equal. + * @param[in] aState The MLR state. + * @param[in] aChild The child owning this address entry. * */ - bool operator==(const AddressIterator &aOther) const { return (mIndex == aOther.mIndex); } - - private: - enum IteratorType : uint8_t - { - kEndIterator, - }; - - static constexpr uint16_t kMaxIndex = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD; - - AddressIterator(const Child &aChild, IteratorType) - : mChild(aChild) - , mIndex(kMaxIndex) - { - } - - void Update(void); - - const Child &mChild; - Ip6::Address::TypeFilter mFilter; - Index mIndex; - Ip6::Address mMeshLocalAddress; + void SetMlrState(MlrState aState, Child &aChild); +#endif }; + /** + * Represents an array of IPv6 address entries registered by an MTD child. + * + * This array does not include the mesh-local EID. + * + */ + typedef Array Ip6AddressArray; + /** * Initializes the `Child` object. * @@ -264,26 +191,37 @@ class Child : public Neighbor, const Ip6::InterfaceIdentifier &GetMeshLocalIid(void) const { return mMeshLocalIid; } /** - * Enables range-based `for` loop iteration over all (or a subset of) IPv6 addresses. + * Gets an array of registered IPv6 address entries by the child. * - * Should be used as follows: to iterate over all addresses + * The array does not include the mesh-local EID. The ML-EID can retrieved using `GetMeshLocalIp6Address()`. * - * for (const Ip6::Address &address : child.IterateIp6Addresses()) { ... } + * @returns The array of registered IPv6 addresses by the child. * - * or to iterate over a subset of IPv6 addresses determined by a given address type filter + */ + const Ip6AddressArray &GetIp6Addresses(void) const { return mIp6Addresses; } + + /** + * Gets an array of registered IPv6 address entries by the child. + * + * The array does not include the mesh-local EID. The ML-EID can retrieved using `GetMeshLocalIp6Address()`. * - * for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticast)) { ... } + * @returns The array of registered IPv6 addresses by the child. * - * @param[in] aFilter An IPv6 address type filter restricting iteration to certain type of addresses (default is - * to accept any address type). + */ + Ip6AddressArray &GetIp6Addresses(void) { return mIp6Addresses; } + + /** + * Iterates over all registered IPv6 addresses (using an iterator). * - * @returns An IteratorBuilder instance. + * @param[in,out] aIterator The iterator to use. On success the iterator will be updated. + * To get the first IPv6 address the iterator should be set to `kAddressIteratorInit` + * @param[out] aAddress A reference to an IPv6 address to return the address. + * + * @retval kErrorNone Successfully got the next IPv6 address. @p aIterator and @p aAddress are updated. + * @retval kErrorNotFound No more address. * */ - AddressIteratorBuilder IterateIp6Addresses(Ip6::Address::TypeFilter aFilter = Ip6::Address::kTypeAny) const - { - return AddressIteratorBuilder(*this, aFilter); - } + Error GetNextIp6Address(AddressIterator &aIterator, Ip6::Address &aAddress) const; /** * Adds an IPv6 address to the list. @@ -441,30 +379,7 @@ class Child : public Neighbor, */ void ResetSecondsSinceLastSupervision(void) { mSecondsSinceSupervision = 0; } -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - /** - * Returns MLR state of an IPv6 multicast address. - * - * @note The @p aAddress reference MUST be from `IterateIp6Addresses()` or `AddressIterator`. - * - * @param[in] aAddress The IPv6 multicast address. - * - * @returns MLR state of the IPv6 multicast address. - * - */ - MlrState GetAddressMlrState(const Ip6::Address &aAddress) const; - - /** - * Sets MLR state of an IPv6 multicast address. - * - * @note The @p aAddress reference MUST be from `IterateIp6Addresses()` or `AddressIterator`. - * - * @param[in] aAddress The IPv6 multicast address. - * @param[in] aState The target MLR state. - * - */ - void SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState); - +#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE /** * Returns if the Child has IPv6 address @p aAddress of MLR state `kMlrStateRegistered`. * @@ -493,40 +408,16 @@ class Child : public Neighbor, * */ bool HasAnyMlrToRegisterAddress(void) const { return mMlrToRegisterMask.HasAny(); } -#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE +#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE private: -#if OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD < 2 -#error OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD should be at least set to 2. -#endif - - static constexpr uint16_t kNumIp6Addresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1; - - typedef BitVector ChildIp6AddressMask; - typedef Array Ip6AddressArray; - - class AddressIteratorBuilder - { - public: - AddressIteratorBuilder(const Child &aChild, Ip6::Address::TypeFilter aFilter) - : mChild(aChild) - , mFilter(aFilter) - { - } - - AddressIterator begin(void) { return AddressIterator(mChild, mFilter); } - AddressIterator end(void) { return AddressIterator(mChild, AddressIterator::kEndIterator); } - - private: - const Child &mChild; - Ip6::Address::TypeFilter mFilter; - }; + typedef BitVector ChildIp6AddressMask; uint32_t mTimeout; Ip6::InterfaceIdentifier mMeshLocalIid; Ip6AddressArray mIp6Addresses; -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE +#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE ChildIp6AddressMask mMlrToRegisterMask; ChildIp6AddressMask mMlrRegisteredMask; #endif diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 62cc1b4c7..4a009cad9 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -4844,19 +4844,18 @@ Error Mle::TxMessage::AppendAddressRegistrationTlv(Child &aChild) tlv.SetType(Tlv::kAddressRegistration); SuccessOrExit(error = Append(tlv)); - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) + // The parent must echo back all registered IPv6 addresses except + // for the ML-EID, which is excluded by `Child::GetIp6Addresses()`. + + for (const Ip6::Address &address : aChild.GetIp6Addresses()) { if (address.IsMulticast() || Get().GetContext(address, context) != kErrorNone) { SuccessOrExit(error = AppendAddressEntry(address)); } - else if (context.mContextId != kMeshLocalPrefixContextId) - { - SuccessOrExit(error = AppendCompressedAddressEntry(context.mContextId, address)); - } else { - continue; + SuccessOrExit(error = AppendCompressedAddressEntry(context.mContextId, address)); } } diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 9e9b21caa..9ee57cfa6 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -1790,12 +1790,16 @@ Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) { OT_ASSERT(aChild.IsStateValid()); - for (const Ip6::Address &childAddress : - aChild.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (const Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses()) { - if (aChild.GetAddressMlrState(childAddress) == kMlrStateRegistered) + if (!addrEntry.IsMulticastLargerThanRealmLocal()) { - IgnoreError(oldMlrRegisteredAddresses.PushBack(childAddress)); + continue; + } + + if (addrEntry.GetMlrState(aChild) == kMlrStateRegistered) + { + IgnoreError(oldMlrRegisteredAddresses.PushBack(addrEntry)); } } } diff --git a/src/core/thread/mlr_manager.cpp b/src/core/thread/mlr_manager.cpp index 76d7378c3..43f896e70 100644 --- a/src/core/thread/mlr_manager.cpp +++ b/src/core/thread/mlr_manager.cpp @@ -151,18 +151,25 @@ void MlrManager::UpdateProxiedSubscriptions(Child &aChild, const MlrAddressArray VerifyOrExit(aChild.IsStateValid()); // Search the new multicast addresses and set its flag accordingly - for (const Ip6::Address &address : aChild.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses()) { - bool isMlrRegistered = aOldMlrRegisteredAddresses.Contains(address); + bool isMlrRegistered; + + if (!addrEntry.IsMulticastLargerThanRealmLocal()) + { + continue; + } + + isMlrRegistered = aOldMlrRegisteredAddresses.Contains(addrEntry); #if OPENTHREAD_CONFIG_MLR_ENABLE // Check if it's a new multicast address against parent Netif - isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByNetif(address); + isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByNetif(addrEntry); #endif // Check if it's a new multicast address against other Children - isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByAnyChildExcept(address, &aChild); + isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByAnyChildExcept(addrEntry, &aChild); - aChild.SetAddressMlrState(address, isMlrRegistered ? kMlrStateRegistered : kMlrStateToRegister); + addrEntry.SetMlrState(isMlrRegistered ? kMlrStateRegistered : kMlrStateToRegister, aChild); } exit: @@ -253,17 +260,22 @@ void MlrManager::SendMlr(void) continue; } - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { + if (!addrEntry.IsMulticastLargerThanRealmLocal()) + { + continue; + } + if (addresses.IsFull()) { break; } - if (child.GetAddressMlrState(address) == kMlrStateToRegister) + if (addrEntry.GetMlrState(child) == kMlrStateToRegister) { - addresses.AddUnique(address); - child.SetAddressMlrState(address, kMlrStateRegistering); + addresses.AddUnique(addrEntry); + addrEntry.SetMlrState(kMlrStateRegistering, child); } } } @@ -514,11 +526,16 @@ void MlrManager::SetMulticastAddressMlrState(MlrState aFromState, MlrState aToSt #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE for (Child &child : Get().Iterate(Child::kInStateValid)) { - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { - if (child.GetAddressMlrState(address) == aFromState) + if (!addrEntry.IsMulticastLargerThanRealmLocal()) + { + continue; + } + + if (addrEntry.GetMlrState(child) == aFromState) { - child.SetAddressMlrState(address, aToState); + addrEntry.SetMlrState(aToState, child); } } } @@ -546,13 +563,18 @@ void MlrManager::FinishMlr(bool aSuccess, const AddressArray &aFailedAddresses) #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE for (Child &child : Get().Iterate(Child::kInStateValid)) { - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { - if (child.GetAddressMlrState(address) == kMlrStateRegistering) + if (!addrEntry.IsMulticastLargerThanRealmLocal()) { - bool success = aSuccess || !aFailedAddresses.IsEmptyOrContains(address); + continue; + } + + if (addrEntry.GetMlrState(child) == kMlrStateRegistering) + { + bool success = aSuccess || !aFailedAddresses.IsEmptyOrContains(addrEntry); - child.SetAddressMlrState(address, success ? kMlrStateRegistered : kMlrStateToRegister); + addrEntry.SetMlrState(success ? kMlrStateRegistered : kMlrStateToRegister, child); } } } @@ -648,11 +670,16 @@ void MlrManager::LogMulticastAddresses(void) #endif #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - for (Child &child : Get().Iterate(Child::kInStateValid)) + for (const Child &child : Get().Iterate(Child::kInStateValid)) { - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (const Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { - LogDebg("%-32s%c %04x", address.ToString().AsCString(), "-rR"[child.GetAddressMlrState(address)], + if (!addrEntry.IsMulticastLargerThanRealmLocal()) + { + continue; + } + + LogDebg("%-32s%c %04x", addrEntry.ToString().AsCString(), "-rR"[addrEntry.GetMlrState(child)], child.GetRloc16()); } } @@ -709,11 +736,16 @@ void MlrManager::CheckInvariants(void) const } #endif #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - for (Child &child : Get().Iterate(Child::kInStateValid)) + for (const Child &child : Get().Iterate(Child::kInStateValid)) { - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (const Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { - registeringNum += (child.GetAddressMlrState(address) == kMlrStateRegistering); + if (!addrEntry.IsMulticastLargerThanRealmLocal()) + { + continue; + } + + registeringNum += (addrEntry.GetMlrState(child) == kMlrStateRegistering); } } #endif diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index af92d417a..6e168c290 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -750,14 +750,18 @@ Error Server::AppendChildTableIp6AddressList(Coap::Message *&aAnswer, AnswerInfo Error Server::AppendChildIp6AddressListTlv(Coap::Message &aAnswer, const Child &aChild) { Error error = kErrorNone; - uint16_t numIp6Addr = 0; + uint16_t numIp6Addr = aChild.GetIp6Addresses().GetLength(); ChildIp6AddressListTlvValue tlvValue; + Ip6::Address mlEid; - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) + if (aChild.GetMeshLocalIp6Address(mlEid) == kErrorNone) { - OT_UNUSED_VARIABLE(address); numIp6Addr++; } + else + { + mlEid.Clear(); + } VerifyOrExit(numIp6Addr > 0); @@ -782,7 +786,12 @@ Error Server::AppendChildIp6AddressListTlv(Coap::Message &aAnswer, const Child & SuccessOrExit(error = aAnswer.Append(tlvValue)); - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) + if (!mlEid.IsUnspecified()) + { + SuccessOrExit(error = aAnswer.Append(mlEid)); + } + + for (const Ip6::Address &address : aChild.GetIp6Addresses()) { SuccessOrExit(error = aAnswer.Append(address)); } diff --git a/tests/unit/test_child.cpp b/tests/unit/test_child.cpp index feec4b573..560fc9a9f 100644 --- a/tests/unit/test_child.cpp +++ b/tests/unit/test_child.cpp @@ -57,7 +57,7 @@ void VerifyChildIp6Addresses(const Child &aChild, uint8_t aAddressListLength, co memset(addressObserved, 0, sizeof(addressObserved)); - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) + for (const Ip6::Address &address : aChild.GetIp6Addresses()) { bool addressIsInList = false; @@ -78,14 +78,16 @@ void VerifyChildIp6Addresses(const Child &aChild, uint8_t aAddressListLength, co { Ip6::Address address; - VerifyOrQuit(addressObserved[index], "Child::IterateIp6Addresses() missed an entry from the expected list"); - if (sInstance->Get().IsMeshLocalAddress(aAddressList[index])) { SuccessOrQuit(aChild.GetMeshLocalIp6Address(address)); VerifyOrQuit(address == aAddressList[index], "GetMeshLocalIp6Address() did not return expected address"); hasMeshLocal = true; } + else + { + VerifyOrQuit(addressObserved[index], "Child::IterateIp6Addresses() missed an entry from the expected list"); + } } if (!hasMeshLocal) @@ -95,95 +97,6 @@ void VerifyChildIp6Addresses(const Child &aChild, uint8_t aAddressListLength, co VerifyOrQuit(aChild.GetMeshLocalIp6Address(address) == kErrorNotFound, "Child::GetMeshLocalIp6Address() returned an address not in the expected list"); } - - // Iterate over unicast and multicast addresses separately. - - memset(addressObserved, 0, sizeof(addressObserved)); - - for (Ip6::Address::TypeFilter filter : filters) - { - for (const Ip6::Address &address : aChild.IterateIp6Addresses(filter)) - { - bool addressIsInList = false; - - switch (filter) - { - case Ip6::Address::kTypeMulticast: - VerifyOrQuit(address.IsMulticast(), "Address::TypeFilter failed"); - break; - - case Ip6::Address::kTypeUnicast: - VerifyOrQuit(!address.IsMulticast(), "Address::TypeFilter failed"); - break; - - default: - break; - } - - VerifyOrQuit(address.MatchesFilter(filter)); - - for (uint8_t index = 0; index < aAddressListLength; index++) - { - if (address == aAddressList[index]) - { - VerifyOrQuit(addressObserved[index] == false, - "Child::IterateIp6Addresses() returned duplicate addr"); - addressObserved[index] = true; - addressIsInList = true; - break; - } - } - - VerifyOrQuit(addressIsInList, "Child::IterateIp6Addresses() returned an address not in the expected list"); - } - } - - for (uint8_t index = 0; index < aAddressListLength; index++) - { - VerifyOrQuit(addressObserved[index], "Child::IterateIp6Addresses() missed an entry from the expected list"); - } - - // Verify behavior of `Child::AddressIterator - { - Child::AddressIterator iter1(aChild); - Child::AddressIterator iter2(aChild); - Child::AddressIterator::Index iterIndex; - - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) - { - VerifyOrQuit(iter1 == iter2); - VerifyOrQuit(!iter1.IsDone()); - VerifyOrQuit(*iter1.GetAddress() == address); - VerifyOrQuit(*iter1.GetAddress() == *iter2.GetAddress()); - - iterIndex = iter1.GetAsIndex(); - VerifyOrQuit(iter2.GetAsIndex() == iterIndex); - - { - Child::AddressIterator iter3(aChild, iterIndex); - VerifyOrQuit(iter3 == iter1, "AddressIterator(iterIndex) failed"); - - iter3++; - VerifyOrQuit(iter3 != iter1, "AddressIterator(iterIndex) failed"); - } - - iter1++; - VerifyOrQuit(iter1 != iter2); - iter2++; - } - - VerifyOrQuit(iter1.IsDone()); - VerifyOrQuit(iter2.IsDone()); - VerifyOrQuit(iter1 == iter2); - - iterIndex = iter1.GetAsIndex(); - VerifyOrQuit(iter2.GetAsIndex() == iterIndex); - - { - Child::AddressIterator iter3(aChild, iterIndex); - VerifyOrQuit(iter3 == iter1, "AddressIterator(iterIndex) failed"); - } - } } void TestChildIp6Address(void) From 975ffd72fc44eaacaea7b30900773929a6cc9b38 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 26 Jun 2024 08:52:55 -0700 Subject: [PATCH 61/65] [meshcop] simplify appending and parsing of `NetworkNameTlv` (#10441) This commit simplifies the appending and parsing of `NetworkNameTlv` using `Append()` and `Read()` TLV helper methods. --- src/core/meshcop/meshcop_tlvs.hpp | 2 +- src/core/thread/discover_scanner.cpp | 7 +------ src/core/thread/mle_router.cpp | 6 ++---- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index 084f84d8b..e35abf834 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -270,7 +270,7 @@ typedef SimpleTlvInfo ExtendedPanIdTlv; * */ OT_TOOL_PACKED_BEGIN -class NetworkNameTlv : public Tlv, public TlvInfo +class NetworkNameTlv : public Tlv, public StringTlvInfo { public: /** diff --git a/src/core/thread/discover_scanner.cpp b/src/core/thread/discover_scanner.cpp index 9cd997892..e264a7be8 100644 --- a/src/core/thread/discover_scanner.cpp +++ b/src/core/thread/discover_scanner.cpp @@ -311,7 +311,6 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const Error error = kErrorNone; MeshCoP::Tlv meshcopTlv; MeshCoP::DiscoveryResponseTlv discoveryResponse; - MeshCoP::NetworkNameTlv networkName; ScanResult result; uint16_t offset; uint16_t end; @@ -353,11 +352,7 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const break; case MeshCoP::Tlv::kNetworkName: - IgnoreError(aRxInfo.mMessage.Read(offset, networkName)); - if (networkName.IsValid()) - { - IgnoreError(AsCoreType(&result.mNetworkName).Set(networkName.GetNetworkName())); - } + SuccessOrExit(error = Tlv::Read(aRxInfo.mMessage, offset, result.mNetworkName.m8)); break; case MeshCoP::Tlv::kSteeringData: diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 9ee57cfa6..542cb370b 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2700,7 +2700,6 @@ Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const M uint16_t startOffset; Tlv tlv; MeshCoP::DiscoveryResponseTlv discoveryResponseTlv; - MeshCoP::NetworkNameTlv networkNameTlv; uint16_t delay; VerifyOrExit((message = NewMleMessage(kCommandDiscoveryResponse)) != nullptr, error = kErrorNoBufs); @@ -2744,9 +2743,8 @@ Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const M SuccessOrExit( error = Tlv::Append(*message, Get().GetExtPanId())); - networkNameTlv.Init(); - networkNameTlv.SetNetworkName(Get().GetNetworkName().GetAsData()); - SuccessOrExit(error = networkNameTlv.AppendTo(*message)); + SuccessOrExit(error = Tlv::Append( + *message, Get().GetNetworkName().GetAsCString())); SuccessOrExit(error = message->AppendSteeringDataTlv()); From 7252cadb5a4fa77d6a24dcc94c3013a7de05d2b5 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Thu, 27 Jun 2024 01:32:39 +0800 Subject: [PATCH 62/65] [posix] skip 0x00 bytes at the start of the received SPI frame (#10442) The SPI interface may receive the garbage bytes 0xff or 0x00 at the start of the received SPI frame. This commit skips the 0x00 bytes at the start of the received SPI frame. --- src/posix/platform/spi_interface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/posix/platform/spi_interface.cpp b/src/posix/platform/spi_interface.cpp index f3078b46c..2040cd58e 100644 --- a/src/posix/platform/spi_interface.cpp +++ b/src/posix/platform/spi_interface.cpp @@ -326,7 +326,7 @@ uint8_t *SpiInterface::GetRealRxFrameStart(uint8_t *aSpiRxFrameBuffer, uint8_t a uint8_t *start = aSpiRxFrameBuffer; const uint8_t *end = aSpiRxFrameBuffer + aAlignAllowance; - for (; start != end && start[0] == 0xff; start++) + for (; start != end && ((start[0] == 0xff) || (start[0] == 0x00)); start++) ; aSkipLength = static_cast(start - aSpiRxFrameBuffer); @@ -469,7 +469,7 @@ otError SpiInterface::PushPullSpi(void) DieNow(OT_EXIT_FAILURE); } - // Account for misalignment (0xFF bytes at the start) + // Account for misalignment (0xFF or 0x00 bytes at the start) spiRxFrame = GetRealRxFrameStart(spiRxFrameBuffer, mSpiAlignAllowance, skipAlignAllowanceLength); { From f2ed3e9c0d9ba4a4bcc0190102e4af2c987a05f9 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 26 Jun 2024 18:35:30 -0700 Subject: [PATCH 63/65] [dns-client] switch to separate SRV/TXT queries on response timeout (#10444) This commit updates `Dns::Client` so that when resolving a service using `kServiceModeSrvTxtOptimize`, it switches to single-question query mode and sends separate parallel SRV and TXT queries upon the first response timeout. This is in addition to the existing behavior of switching to separate queries upon receiving a response with an error rcode from the server. The `test_dns_client` unit test is also updated to validate this scenario. New `TestMode` configurations are added to server to control its behavior, allowing it to either reject multi-question queries (by sending a "FormatError" rcode) or ignore them (sending no response). --- src/core/net/dns_client.cpp | 14 ++++++++-- src/core/net/dnssd_server.cpp | 17 ++++++++---- src/core/net/dnssd_server.hpp | 7 ++--- tests/unit/test_dns_client.cpp | 48 +++++++++++++++++++++++++++++++--- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/src/core/net/dns_client.cpp b/src/core/net/dns_client.cpp index 1b1b77ee5..49a0d4d5a 100644 --- a/src/core/net/dns_client.cpp +++ b/src/core/net/dns_client.cpp @@ -1520,7 +1520,17 @@ void Client::HandleTimer(void) break; } - IgnoreError(SendQuery(*query, info, /* aUpdateTimer */ false)); +#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE + if (ReplaceWithSeparateSrvTxtQueries(*query) == kErrorNone) + { + LogInfo("Switching to separate SRV/TXT on response timeout"); + info.ReadFrom(*query); + } + else +#endif + { + IgnoreError(SendQuery(*query, info, /* aUpdateTimer */ false)); + } } nextTime.UpdateIfEarlier(info.mRetransmissionTime); @@ -1534,7 +1544,7 @@ void Client::HandleTimer(void) } } - mTimer.FireAt(nextTime); + mTimer.FireAtIfEarlier(nextTime); #if OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE if (!hasTcpQuery && mTcpState != kTcpUninitialized) diff --git a/src/core/net/dnssd_server.cpp b/src/core/net/dnssd_server.cpp index 7d512efc8..35c6cb793 100644 --- a/src/core/net/dnssd_server.cpp +++ b/src/core/net/dnssd_server.cpp @@ -163,7 +163,8 @@ void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessag void Server::ProcessQuery(Request &aRequest) { - ResponseCode rcode = Header::kResponseSuccess; + ResponseCode rcode = Header::kResponseSuccess; + bool shouldRespond = true; Response response(GetInstance()); #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE @@ -193,7 +194,7 @@ void Server::ProcessQuery(Request &aRequest) SuccessOrExit(rcode); #endif - SuccessOrExit(rcode = aRequest.ParseQuestions(mTestMode)); + SuccessOrExit(rcode = aRequest.ParseQuestions(mTestMode, shouldRespond)); SuccessOrExit(rcode = response.AddQuestionsFrom(aRequest)); #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) @@ -225,7 +226,10 @@ void Server::ProcessQuery(Request &aRequest) response.SetResponseCode(rcode); } - response.Send(*aRequest.mMessageInfo); + if (shouldRespond) + { + response.Send(*aRequest.mMessageInfo); + } } Server::Response::Response(Instance &aInstance) @@ -296,7 +300,7 @@ void Server::Response::Send(const Ip6::MessageInfo &aMessageInfo) return; } -Server::ResponseCode Server::Request::ParseQuestions(uint8_t aTestMode) +Server::ResponseCode Server::Request::ParseQuestions(uint8_t aTestMode, bool &aShouldRespond) { // Parse header and questions from a `Request` query message and // determine the `QueryType`. @@ -306,6 +310,8 @@ Server::ResponseCode Server::Request::ParseQuestions(uint8_t aTestMode) uint16_t questionCount = mHeader.GetQuestionCount(); Question question; + aShouldRespond = true; + VerifyOrExit(mHeader.GetQueryType() == Header::kQueryTypeStandard, rcode = Header::kResponseNotImplemented); VerifyOrExit(!mHeader.IsTruncationFlagSet()); @@ -335,7 +341,8 @@ Server::ResponseCode Server::Request::ParseQuestions(uint8_t aTestMode) if (questionCount > 1) { - VerifyOrExit(!(aTestMode & kTestModeSingleQuestionOnly)); + VerifyOrExit(!(aTestMode & kTestModeRejectMultiQuestionQuery)); + VerifyOrExit(!(aTestMode & kTestModeIgnoreMultiQuestionQuery), aShouldRespond = false); VerifyOrExit(questionCount == 2); diff --git a/src/core/net/dnssd_server.hpp b/src/core/net/dnssd_server.hpp index ea8f7e7d7..f584e3b12 100644 --- a/src/core/net/dnssd_server.hpp +++ b/src/core/net/dnssd_server.hpp @@ -291,8 +291,9 @@ class Server : public InstanceLocator, private NonCopyable */ enum TestModeFlags : uint8_t { - kTestModeSingleQuestionOnly = 1 << 0, ///< Allow single question in query, send `FormatError` otherwise. - kTestModeEmptyAdditionalSection = 1 << 1, ///< Do not include any RR in additional section. + kTestModeRejectMultiQuestionQuery = 1 << 0, ///< Send `FormatError` for a query with multiple questions. + kTestModeIgnoreMultiQuestionQuery = 1 << 1, ///< Ignore a query with multiple questions (send no response). + kTestModeEmptyAdditionalSection = 1 << 2, ///< Do not include any RR in additional section. }; static constexpr uint8_t kTestModeDisabled = 0; ///< Test mode is disabled (no flags). @@ -346,7 +347,7 @@ class Server : public InstanceLocator, private NonCopyable struct Request { - ResponseCode ParseQuestions(uint8_t aTestMode); + ResponseCode ParseQuestions(uint8_t aTestMode, bool &aShouldRespond); const Message *mMessage; const Ip6::MessageInfo *mMessageInfo; diff --git a/tests/unit/test_dns_client.cpp b/tests/unit/test_dns_client.cpp index 176654c0f..e91376689 100644 --- a/tests/unit/test_dns_client.cpp +++ b/tests/unit/test_dns_client.cpp @@ -671,8 +671,8 @@ void TestDnsClient(void) Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); - Log("Set TestMode on server to only accept single question"); - dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeSingleQuestionOnly); + Log("Set TestMode on server to reject multi-question queries and send error"); + dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeRejectMultiQuestionQuery); Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName, ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize)); @@ -706,6 +706,48 @@ void TestDnsClient(void) dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled); + Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); + + Log("Set TestMode on server to ignore multi-question queries (send no response)"); + dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeIgnoreMultiQuestionQuery); + + Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName, + ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize)); + + queryConfig.Clear(); + queryConfig.mServiceMode = static_cast(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize); + + sResolveServiceInfo.Reset(); + SuccessOrQuit( + dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig)); + + AdvanceTime(10 * 1000); // Wait longer than client response timeout. + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); + SuccessOrQuit(sResolveServiceInfo.mError); + + // Use `kServiceModeSrvTxt` and check that server does ignore two questions. + + Log("ResolveService(%s,%s) with ServiceMode %s", kInstance1Label, kService1FullName, + ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxt)); + + queryConfig.Clear(); + queryConfig.mServiceMode = static_cast(Dns::Client::QueryConfig::kServiceModeSrvTxt); + + sResolveServiceInfo.Reset(); + SuccessOrQuit( + dnsClient->ResolveService(kInstance1Label, kService1FullName, ServiceCallback, sInstance, &queryConfig)); + + // Wait for the client to time out after exhausting all retry attempts, and + // ensure that a `kErrorResponseTimeout` error is reported. + + AdvanceTime(45 * 1000); + + VerifyOrQuit(sResolveServiceInfo.mCallbackCount == 1); + VerifyOrQuit(sResolveServiceInfo.mError == kErrorResponseTimeout); + + dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeDisabled); + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Validate DNS Client `ResolveService()` using all service modes // when sever does not provide any RR in the addition data section. @@ -832,7 +874,7 @@ void TestDnsClient(void) Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); Log("Set TestMode on server to not include any RR in additional section AND to only accept single question"); dnsServer->SetTestMode(Dns::ServiceDiscovery::Server::kTestModeEmptyAdditionalSection + - Dns::ServiceDiscovery::Server::kTestModeSingleQuestionOnly); + Dns::ServiceDiscovery::Server::kTestModeRejectMultiQuestionQuery); Log("ResolveServiceAndHostAddress(%s,%s) with ServiceMode: %s", kInstance1Label, kService1FullName, ServiceModeToString(Dns::Client::QueryConfig::kServiceModeSrvTxtOptimize)); From 7ca21a38f27b1040384178661a72a0d2b426e9e3 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 26 Jun 2024 18:37:01 -0700 Subject: [PATCH 64/65] [tlv] ensure handling of extended TLVs when iterating over sub-TLVs (#10439) This commit adds the `Tlv::ParseAndSkipTlv()` static method, which parses a TLV (regular or extended) in a message at a given offset. It validates that the TLV is fully contained within the message and updates the offset to skip over the entire parsed TLV. This helper method is used in various modules where manual iteration over a sequence of TLVs is performed, specifically to skip over extended TLVs. The following methods are updated to utilize this new method and perform additional TLV checks: - `DiscoverScanner::HandleDiscoveryResponse()` - `MleRouter::HandleDiscoveryRequest()` - `LinkMetrics::SubJect::AppendReport()` - `LinkMetrics::Subject::HandleManagementRequest()` - `LinkMetrics::Initiator::HandleReport()` --- src/core/common/tlvs.cpp | 18 ++++++++++++++++++ src/core/common/tlvs.hpp | 15 +++++++++++++++ src/core/thread/discover_scanner.cpp | 13 +++++++++++-- src/core/thread/link_metrics.cpp | 27 ++++++++++++++++++++++++++- src/core/thread/mle_router.cpp | 13 +++++++++++-- 5 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/core/common/tlvs.cpp b/src/core/common/tlvs.cpp index 04756d24a..2848e7f0c 100644 --- a/src/core/common/tlvs.cpp +++ b/src/core/common/tlvs.cpp @@ -56,6 +56,24 @@ const uint8_t *Tlv::GetValue(void) const Error Tlv::AppendTo(Message &aMessage) const { return aMessage.AppendBytes(this, static_cast(GetSize())); } +Error Tlv::ParseAndSkipTlv(const Message &aMessage, uint16_t &aOffset) +{ + Error error; + ParsedInfo info; + + SuccessOrExit(error = info.ParseFrom(aMessage, aOffset)); + + // `ParseFrom()` has already validated that the entire TLV is + // present within `aMessage`. This ensures that `aOffset + mSize` + // is less than `aMessage.GetLength()`, and therefore we cannot + // have an overflow here. + + aOffset += info.mSize; + +exit: + return error; +} + Error Tlv::FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv) { uint16_t offset; diff --git a/src/core/common/tlvs.hpp b/src/core/common/tlvs.hpp index 1acc80694..7baf529a3 100644 --- a/src/core/common/tlvs.hpp +++ b/src/core/common/tlvs.hpp @@ -244,6 +244,21 @@ class Tlv //------------------------------------------------------------------------------------------------------------------ // Static methods for reading/finding/appending TLVs in a `Message`. + /** + * Parses a TLV in a message at a given offset, validating that it is fully contained within the message and then + * updating the offset to skip over the entire parsed TLV. + * + * Can be used independent of whether the read TLV (from the message) is an Extended TLV or not. + * + * @param[in] aMessage The message to read from. + * @param[in,out] aOffset The offset to read from. On success, it is updated to point after the parsed TLV. + * + * @retval kErrorNone Successfully parsed a TLV from @p aMessage. @p aOffset is updated. + * @retval kErrorParse The TLV was not well-formed or was not fully contained in @p aMessage. + * + */ + static Error ParseAndSkipTlv(const Message &aMessage, uint16_t &aOffset); + /** * Reads a TLV's value in a message at a given offset expecting a minimum length for the value. * diff --git a/src/core/thread/discover_scanner.cpp b/src/core/thread/discover_scanner.cpp index e264a7be8..03e2ca4eb 100644 --- a/src/core/thread/discover_scanner.cpp +++ b/src/core/thread/discover_scanner.cpp @@ -335,12 +335,21 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const // Process MeshCoP TLVs while (offset < end) { - IgnoreError(aRxInfo.mMessage.Read(offset, meshcopTlv)); + SuccessOrExit(error = aRxInfo.mMessage.Read(offset, meshcopTlv)); + + if (meshcopTlv.IsExtended()) + { + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aRxInfo.mMessage, offset)); + VerifyOrExit(offset <= end, error = kErrorParse); + continue; + } + + VerifyOrExit(meshcopTlv.GetSize() + offset <= aRxInfo.mMessage.GetLength(), error = kErrorParse); switch (meshcopTlv.GetType()) { case MeshCoP::Tlv::kDiscoveryResponse: - IgnoreError(aRxInfo.mMessage.Read(offset, discoveryResponse)); + SuccessOrExit(error = aRxInfo.mMessage.Read(offset, discoveryResponse)); VerifyOrExit(discoveryResponse.IsValid(), error = kErrorParse); result.mVersion = discoveryResponse.GetVersion(); result.mIsNative = discoveryResponse.IsNativeCommissioner(); diff --git a/src/core/thread/link_metrics.cpp b/src/core/thread/link_metrics.cpp index a8936f371..840d28e34 100644 --- a/src/core/thread/link_metrics.cpp +++ b/src/core/thread/link_metrics.cpp @@ -146,7 +146,14 @@ void Initiator::HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t { SuccessOrExit(error = aMessage.Read(offset, tlv)); - VerifyOrExit(offset + sizeof(Tlv) + tlv.GetLength() <= endOffset, error = kErrorParse); + if (tlv.IsExtended()) + { + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, offset)); + VerifyOrExit(offset <= endOffset, error = kErrorParse); + continue; + } + + VerifyOrExit(tlv.GetSize() + offset <= endOffset, error = kErrorParse); // The report must contain either: // - One or more Report Sub-TLVs (in case of success), or @@ -320,6 +327,15 @@ Error Initiator::HandleManagementResponse(const Message &aMessage, const Ip6::Ad SuccessOrExit(error = aMessage.Read(offset, tlv)); + if (tlv.IsExtended()) + { + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, offset)); + VerifyOrExit(offset <= endOffset, error = kErrorParse); + continue; + } + + VerifyOrExit(tlv.GetSize() + offset <= endOffset, error = kErrorParse); + switch (tlv.GetType()) { case StatusSubTlv::kType: @@ -440,6 +456,15 @@ Error Subject::AppendReport(Message &aMessage, const Message &aRequestMessage, N { SuccessOrExit(error = aRequestMessage.Read(offset, tlv)); + if (tlv.IsExtended()) + { + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aMessage, offset)); + VerifyOrExit(offset <= endOffset, error = kErrorParse); + continue; + } + + VerifyOrExit(tlv.GetSize() + offset <= endOffset, error = kErrorParse); + switch (tlv.GetType()) { case SubTlv::kQueryId: diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 542cb370b..e03712345 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2637,12 +2637,21 @@ void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo) while (offset < end) { - IgnoreError(aRxInfo.mMessage.Read(offset, meshcopTlv)); + SuccessOrExit(error = aRxInfo.mMessage.Read(offset, meshcopTlv)); + + if (meshcopTlv.IsExtended()) + { + SuccessOrExit(error = Tlv::ParseAndSkipTlv(aRxInfo.mMessage, offset)); + VerifyOrExit(offset <= end, error = kErrorParse); + continue; + } + + VerifyOrExit(meshcopTlv.GetSize() + offset <= aRxInfo.mMessage.GetLength(), error = kErrorParse); switch (meshcopTlv.GetType()) { case MeshCoP::Tlv::kDiscoveryRequest: - IgnoreError(aRxInfo.mMessage.Read(offset, discoveryRequestTlv)); + SuccessOrExit(error = aRxInfo.mMessage.Read(offset, discoveryRequestTlv)); VerifyOrExit(discoveryRequestTlv.IsValid(), error = kErrorParse); break; From e10a92570f94ff1e0bc5e0da9ecf0ee135d955a6 Mon Sep 17 00:00:00 2001 From: jrhodie <139580534+jrhodie@users.noreply.github.com> Date: Wed, 26 Jun 2024 18:48:01 -0700 Subject: [PATCH 65/65] [srp] fix `otSrpClientStart` documentation (#10435) --- include/openthread/instance.h | 2 +- include/openthread/srp_client.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 887c58cb6..b1079aab7 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (423) +#define OPENTHREAD_API_VERSION (424) /** * @addtogroup api-instance diff --git a/include/openthread/srp_client.h b/include/openthread/srp_client.h index 71a217c37..27c87f3d0 100644 --- a/include/openthread/srp_client.h +++ b/include/openthread/srp_client.h @@ -201,7 +201,7 @@ typedef void (*otSrpClientAutoStartCallback)(const otSockAddr *aServerSockAddr, * * - The SRP client is started - `otSrpClientStart()` is called. * - Host name is set - `otSrpClientSetHostName()` is called. - * - At least one host IPv6 address is set - `otSrpClientSetHostName()` is called. + * - At least one host IPv6 address is set - `otSrpClientSetHostAddresses()` is called. * - At least one service is added - `otSrpClientAddService()` is called. * * It does not matter in which order these functions are called. When all conditions are met, the SRP client will