diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 76bf74cd3..313599542 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -217,6 +217,7 @@ void Mle::Stop(StopMode aMode) VerifyOrExit(!IsDisabled()); + mDelayedSender.Stop(); Get().Stop(); SetStateDetached(); Get().UnsubscribeMulticast(mRealmLocalAllThreadNodes); @@ -1737,22 +1738,17 @@ exit: } Error Mle::SendDataRequest(const Ip6::Address &aDestination) -{ - return SendDataRequestAfterDelay(aDestination, /* aDelay */ 0); -} - -Error Mle::SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay) { static const uint8_t kTlvs[] = {Tlv::kNetworkData, Tlv::kRoute}; - Error error; + Error error = kErrorNone; - mDelayedSender.RemoveDataRequestMessage(aDestination); + VerifyOrExit(IsAttached()); // Based on `mRequestRouteTlv` include both Network Data and Route // TLVs or only Network Data TLV. - error = SendDataRequest(aDestination, kTlvs, mRequestRouteTlv ? 2 : 1, aDelay); + error = SendDataRequest(aDestination, kTlvs, mRequestRouteTlv ? 2 : 1); if (IsChild() && !IsRxOnWhenIdle()) { @@ -1764,6 +1760,7 @@ Error Mle::SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t } } +exit: return error; } @@ -1773,16 +1770,15 @@ Error Mle::SendDataRequestForLinkMetricsReport(const Ip6::Address { static const uint8_t kTlvs[] = {Tlv::kLinkMetricsReport}; - return SendDataRequest(aDestination, kTlvs, sizeof(kTlvs), /* aDelay */ 0, &aQueryInfo); + return SendDataRequest(aDestination, kTlvs, sizeof(kTlvs), &aQueryInfo); } Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, - uint16_t aDelay, const LinkMetrics::Initiator::QueryInfo *aQueryInfo) #else -Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, uint16_t aDelay) +Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength) #endif { Error error = kErrorNone; @@ -1798,22 +1794,14 @@ Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlv } #endif - if (aDelay) - { - SuccessOrExit(error = message->SendAfterDelay(aDestination, aDelay)); - Log(kMessageDelay, kTypeDataRequest, aDestination); - } - else - { - SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs()); + SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs()); - SuccessOrExit(error = message->SendTo(aDestination)); - Log(kMessageSend, kTypeDataRequest, aDestination); + SuccessOrExit(error = message->SendTo(aDestination)); + Log(kMessageSend, kTypeDataRequest, aDestination); - if (!IsRxOnWhenIdle()) - { - Get().SendFastPolls(DataPollSender::kDefaultFastPolls); - } + if (!IsRxOnWhenIdle()) + { + Get().SendFastPolls(DataPollSender::kDefaultFastPolls); } exit: @@ -2719,8 +2707,8 @@ void Mle::HandleAdvertisement(RxInfo &aRxInfo) if (mRetrieveNewNetworkData || IsNetworkDataNewer(leaderData)) { - delay = Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay); - IgnoreError(SendDataRequestAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), delay)); + delay = 1 + Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay); + mDelayedSender.ScheduleDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), delay); } aRxInfo.mClass = RxInfo::kPeerMessage; @@ -2901,7 +2889,7 @@ exit: if (aRxInfo.mMessageInfo.GetSockAddr().IsMulticast()) { - delay = Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay); + delay = 1 + Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay); } else { @@ -2911,7 +2899,7 @@ exit: delay = 10; } - IgnoreError(SendDataRequestAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), delay)); + mDelayedSender.ScheduleDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), delay); } else if (error == kErrorNone) { @@ -4328,100 +4316,210 @@ Mle::DelayedSender::DelayedSender(Instance &aInstance) { } -Error Mle::DelayedSender::SendMessage(TxMessage &aMessage, const Ip6::Address &aDestination, uint16_t aDelay) +void Mle::DelayedSender::Stop(void) { - Error error = kErrorNone; - Metadata metadata; + mTimer.Stop(); + mSchedules.DequeueAndFreeAll(); +} - metadata.mSendTime = TimerMilli::GetNow() + aDelay; - metadata.mDestination = aDestination; - - SuccessOrExit(error = metadata.AppendTo(aMessage)); - mQueue.Enqueue(aMessage); - - mTimer.FireAtIfEarlier(metadata.mSendTime); +void Mle::DelayedSender::ScheduleDataRequest(const Ip6::Address &aDestination, uint16_t aDelay) +{ + VerifyOrExit(!HasMatchingSchedule(kTypeDataRequest, aDestination)); + AddSchedule(kTypeDataRequest, aDestination, aDelay, nullptr, 0); exit: - return error; + return; +} + +#if OPENTHREAD_FTD + +void Mle::DelayedSender::ScheduleParentResponse(const ParentResponseInfo &aInfo, uint16_t aDelay) +{ + Ip6::Address destination; + + destination.SetToLinkLocalAddress(aInfo.mChildExtAddress); + + RemoveMatchingSchedules(kTypeParentResponse, destination); + AddSchedule(kTypeParentResponse, destination, aDelay, &aInfo, sizeof(aInfo)); +} + +void Mle::DelayedSender::ScheduleMulticastDataResponse(uint16_t aDelay) +{ + Ip6::Address destination; + + destination.SetToLinkLocalAllNodesMulticast(); + + Get().RemoveDataResponseMessages(); + RemoveMatchingSchedules(kTypeDataResponse, destination); + AddSchedule(kTypeDataResponse, destination, aDelay, nullptr, 0); +} + +void Mle::DelayedSender::ScheduleLinkAccept(const LinkAcceptInfo &aInfo, uint16_t aDelay) +{ + Ip6::Address destination; + + destination.SetToLinkLocalAddress(aInfo.mExtAddress); + + RemoveMatchingSchedules(kTypeLinkAccept, destination); + AddSchedule(kTypeLinkAccept, destination, aDelay, &aInfo, sizeof(aInfo)); +} + +void Mle::DelayedSender::ScheduleDiscoveryResponse(const Ip6::Address &aDestination, + const DiscoveryResponseInfo &aInfo, + uint16_t aDelay) +{ + AddSchedule(kTypeDiscoveryResponse, aDestination, aDelay, &aInfo, sizeof(aInfo)); +} + +#endif // OPENTHREAD_FTD + +void Mle::DelayedSender::AddSchedule(MessageType aMessageType, + const Ip6::Address &aDestination, + uint16_t aDelay, + const void *aInfo, + uint16_t aInfoSize) +{ + Schedule *schedule = Get().Allocate(Message::kTypeOther); + Header header; + + VerifyOrExit(schedule != nullptr); + + header.mSendTime = TimerMilli::GetNow() + aDelay; + header.mDestination = aDestination; + header.mMessageType = aMessageType; + SuccessOrExit(schedule->Append(header)); + + if (aInfo != nullptr) + { + SuccessOrExit(schedule->AppendBytes(aInfo, aInfoSize)); + } + + mTimer.FireAtIfEarlier(header.mSendTime); + + mSchedules.Enqueue(*schedule); + schedule = nullptr; + + Log(kMessageDelay, aMessageType, aDestination); + +exit: + FreeMessage(schedule); } void Mle::DelayedSender::HandleTimer(void) { NextFireTime nextSendTime; + MessageQueue schedulesToExecute; - for (Message &message : mQueue) + for (Schedule &schedule : mSchedules) { - Metadata metadata; + Header header; - metadata.ReadFrom(message); + header.ReadFrom(schedule); - if (nextSendTime.GetNow() < metadata.mSendTime) + if (nextSendTime.GetNow() < header.mSendTime) { - nextSendTime.UpdateIfEarlier(metadata.mSendTime); + nextSendTime.UpdateIfEarlier(header.mSendTime); } else { - mQueue.Dequeue(message); - Send(static_cast(message), metadata); + mSchedules.Dequeue(schedule); + schedulesToExecute.Enqueue(schedule); } } mTimer.FireAt(nextSendTime); + + for (Schedule &schedule : schedulesToExecute) + { + Execute(schedule); + } + + schedulesToExecute.DequeueAndFreeAll(); } -void Mle::DelayedSender::Send(TxMessage &aMessage, const Metadata &aMetadata) +void Mle::DelayedSender::Execute(const Schedule &aSchedule) { - Error error = kErrorNone; + Header header; - aMetadata.RemoveFrom(aMessage); + header.ReadFrom(aSchedule); - if (aMessage.IsMleCommand(kCommandDataRequest)) + switch (header.mMessageType) { - SuccessOrExit(error = aMessage.AppendActiveAndPendingTimestampTlvs()); + case kTypeDataRequest: + IgnoreError(Get().SendDataRequest(header.mDestination)); + break; + +#if OPENTHREAD_FTD + case kTypeParentResponse: + { + ParentResponseInfo info; + + IgnoreError(aSchedule.Read(sizeof(Header), info)); + Get().SendParentResponse(info); + break; } - SuccessOrExit(error = aMessage.SendTo(aMetadata.mDestination)); + case kTypeDataResponse: + Get().SendMulticastDataResponse(); + break; - Log(kMessageSend, kTypeGenericDelayed, aMetadata.mDestination); - - if (!Get().IsRxOnWhenIdle()) + case kTypeLinkAccept: { - // Start fast poll mode, assuming enqueued msg is MLE Data Request. - // Note: Finer-grade check may be required when deciding whether or - // not to enter fast poll mode for other type of delayed message. + LinkAcceptInfo info; - Get().SendFastPolls(DataPollSender::kDefaultFastPolls); + IgnoreError(aSchedule.Read(sizeof(Header), info)); + IgnoreError(Get().SendLinkAccept(info)); + break; } -exit: - if (error != kErrorNone) + case kTypeDiscoveryResponse: { - aMessage.Free(); + DiscoveryResponseInfo info; + + IgnoreError(aSchedule.Read(sizeof(Header), info)); + IgnoreError(Get().SendDiscoveryResponse(header.mDestination, info)); + break; + } +#endif // OPENTHREAD_FTD + + default: + break; } } -void Mle::DelayedSender::RemoveDataResponseMessage(void) +bool Mle::DelayedSender::Match(const Schedule &aSchedule, MessageType aMessageType, const Ip6::Address &aDestination) { - RemoveMessage(kCommandDataResponse, kTypeDataResponse, nullptr); + Header header; + + header.ReadFrom(aSchedule); + + return (header.mMessageType == aMessageType) && (header.mDestination == aDestination); } -void Mle::DelayedSender::RemoveDataRequestMessage(const Ip6::Address &aDestination) +bool Mle::DelayedSender::HasMatchingSchedule(MessageType aMessageType, const Ip6::Address &aDestination) const { - RemoveMessage(kCommandDataRequest, kTypeDataRequest, &aDestination); -} + bool hasMatching = false; -void Mle::DelayedSender::RemoveMessage(Command aCommand, MessageType aMessageType, const Ip6::Address *aDestination) -{ - for (Message &message : mQueue) + for (const Schedule &schedule : mSchedules) { - Metadata metadata; - - metadata.ReadFrom(message); - - if (message.IsMleCommand(aCommand) && ((aDestination == nullptr) || (metadata.mDestination == *aDestination))) + if (Match(schedule, aMessageType, aDestination)) { - mQueue.DequeueAndFree(message); - Log(kMessageRemoveDelayed, aMessageType, metadata.mDestination); + hasMatching = true; + break; + } + } + + return hasMatching; +} + +void Mle::DelayedSender::RemoveMatchingSchedules(MessageType aMessageType, const Ip6::Address &aDestination) +{ + for (Schedule &schedule : mSchedules) + { + if (Match(schedule, aMessageType, aDestination)) + { + mSchedules.DequeueAndFree(schedule); + Log(kMessageRemoveDelayed, aMessageType, aDestination); } } } @@ -4846,11 +4944,6 @@ exit: return error; } -Error Mle::TxMessage::SendAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay) -{ - return Get().mDelayedSender.SendMessage(*this, aDestination, aDelay); -} - #if OPENTHREAD_FTD Error Mle::TxMessage::AppendConnectivityTlv(void) diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 6dcc552de..4b341a6cc 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -994,7 +994,6 @@ private: } Error SendTo(const Ip6::Address &aDestination); - Error SendAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay); private: Error AppendCompressedAddressEntry(uint8_t aContextId, const Ip6::Address &aAddress); @@ -1064,6 +1063,33 @@ private: //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#if OPENTHREAD_FTD + struct ParentResponseInfo + { + Mac::ExtAddress mChildExtAddress; // The child extended address. + RxChallenge mRxChallenge; // The challenge from the Parent Request. + }; + + struct LinkAcceptInfo + { + Mac::ExtAddress mExtAddress; // The neighbor/router extended address. + TlvList mRequestedTlvList; // The requested TLVs in Link Request. + RxChallenge mRxChallenge; // The challenge in Link Request. + uint8_t mLinkMargin; // Link margin of the received Link Request. + }; + + struct DiscoveryResponseInfo + { + Mac::PanId mPanId; +#if OPENTHREAD_CONFIG_MULTI_RADIO + Mac::RadioType mRadioType; +#endif + }; + +#endif // OPENTHREAD_FTD + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void HandleDelayedSenderTimer(void) { mDelayedSender.HandleTimer(); } class DelayedSender : public InstanceLocator @@ -1071,26 +1097,46 @@ private: public: explicit DelayedSender(Instance &aInstance); - Error SendMessage(TxMessage &aMessage, const Ip6::Address &aDestination, uint16_t aDelay); - void RemoveDataRequestMessage(const Ip6::Address &aDestination); - void RemoveDataResponseMessage(void); - void HandleTimer(void); + void Stop(void); - const MessageQueue &GetQueue(void) const { return mQueue; } + void ScheduleDataRequest(const Ip6::Address &aDestination, uint16_t aDelay); +#if OPENTHREAD_FTD + void ScheduleParentResponse(const ParentResponseInfo &aInfo, uint16_t aDelay); + void ScheduleMulticastDataResponse(uint16_t aDelay); + void ScheduleLinkAccept(const LinkAcceptInfo &aInfo, uint16_t aDelay); + void ScheduleDiscoveryResponse(const Ip6::Address &aDestination, + const DiscoveryResponseInfo &aInfo, + uint16_t aDelay); +#endif + void HandleTimer(void); + const MessageQueue &GetQueue(void) const { return mSchedules; } private: - struct Metadata : public Message::FooterData + typedef Message Schedule; + + struct Header { - Ip6::Address mDestination; + void ReadFrom(const Schedule &aSchedule) { IgnoreError(aSchedule.Read(/* aOffset */ 0, *this)); } + TimeMilli mSendTime; + Ip6::Address mDestination; + MessageType mMessageType; }; - void Send(TxMessage &aMessage, const Metadata &aMetadata); - void RemoveMessage(Command aCommand, MessageType aMessageType, const Ip6::Address *aDestination); + void AddSchedule(MessageType aMessageType, + const Ip6::Address &aDestination, + uint16_t aDelay, + const void *aInfo, + uint16_t aInfoSize); + void Execute(const Schedule &aSchedule); + bool HasMatchingSchedule(MessageType aMessageType, const Ip6::Address &aDestination) const; + void RemoveMatchingSchedules(MessageType aMessageType, const Ip6::Address &aDestination); + + static bool Match(const Schedule &aSchedule, MessageType aMessageType, const Ip6::Address &aDestination); using DelayTimer = TimerMilliIn; - MessageQueue mQueue; + MessageQueue mSchedules; DelayTimer mTimer; }; @@ -1217,7 +1263,6 @@ private: void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void ReestablishLinkWithNeighbor(Neighbor &aNeighbor); Error SendChildUpdateRequest(ChildUpdateRequestMode aMode); - Error SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay); Error SendChildUpdateRequest(void); Error SendChildUpdateResponse(const TlvList &aTlvList, const RxChallenge &aChallenge, @@ -1300,10 +1345,9 @@ private: Error SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, - uint16_t aDelay, const LinkMetrics::Initiator::QueryInfo *aQueryInfo = nullptr); #else - Error SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, uint16_t aDelay); + Error SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength); #endif #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 1fd2ae308..8d2b91ec3 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -668,13 +668,12 @@ exit: void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) { - Error error = kErrorNone; - Neighbor *neighbor = nullptr; - RxChallenge challenge; - uint16_t version; - LeaderData leaderData; - uint16_t sourceAddress; - TlvList requestedTlvList; + Error error = kErrorNone; + Neighbor *neighbor = nullptr; + uint16_t version; + LeaderData leaderData; + uint16_t sourceAddress; + LinkAcceptInfo info; Log(kMessageReceive, kTypeLinkRequest, aRxInfo.mMessageInfo.GetPeerAddr()); @@ -682,7 +681,7 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) VerifyOrExit(!IsAttaching(), error = kErrorInvalidState); - SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge)); + SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(info.mRxChallenge)); SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version)); @@ -697,6 +696,10 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) ExitNow(error = kErrorParse); } + aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(info.mExtAddress); + + info.mLinkMargin = Get().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss()); + switch (Tlv::Find(aRxInfo.mMessage, sourceAddress)) { case kErrorNone: @@ -713,10 +716,7 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) } else { - Mac::ExtAddress extAddr; - - aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr); - VerifyOrExit(neighbor->GetExtAddress() == extAddr); + VerifyOrExit(neighbor->GetExtAddress() == info.mExtAddress); } } @@ -734,7 +734,7 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) ExitNow(error = kErrorParse); } - switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList)) + switch (aRxInfo.mMessage.ReadTlvRequestTlv(info.mRequestedTlvList)) { case kErrorNone: case kErrorNotFound: @@ -760,51 +760,71 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo) aRxInfo.mClass = RxInfo::kPeerMessage; ProcessKeySequence(aRxInfo); - SuccessOrExit(error = SendLinkAccept(aRxInfo, neighbor, requestedTlvList, challenge)); + if (aRxInfo.mMessageInfo.GetSockAddr().IsMulticast()) + { + mDelayedSender.ScheduleLinkAccept(info, 1 + Random::NonCrypto::GetUint16InRange(0, kMaxLinkAcceptDelay)); + } + else + { + error = SendLinkAccept(info); + } exit: LogProcessError(kTypeLinkRequest, error); + OT_UNUSED_VARIABLE(neighbor); } -Error MleRouter::SendLinkAccept(const RxInfo &aRxInfo, - Neighbor *aNeighbor, - const TlvList &aRequestedTlvList, - const RxChallenge &aChallenge) +Error MleRouter::SendLinkAccept(const LinkAcceptInfo &aInfo) { static const uint8_t kRouterTlvs[] = {Tlv::kLinkMargin}; - Error error = kErrorNone; - TxMessage *message; - Command command; - uint8_t linkMargin; + Error error = kErrorNone; + TxMessage *message = nullptr; + Command command = kCommandLinkAccept; + Router *router; + Ip6::Address destination; - command = (aNeighbor == nullptr || aNeighbor->IsStateValid()) ? kCommandLinkAccept : kCommandLinkAcceptAndRequest; + VerifyOrExit(IsAttached()); + + router = mRouterTable.FindRouter(aInfo.mExtAddress); + + if (router != nullptr) + { + if (router->IsStateLinkRequest()) + { + command = kCommandLinkAcceptAndRequest; + router->SetLastHeard(TimerMilli::GetNow()); + } + else + { + VerifyOrExit(router->IsStateValid()); + } + } VerifyOrExit((message = NewMleMessage(command)) != nullptr, error = kErrorNoBufs); SuccessOrExit(error = message->AppendVersionTlv()); SuccessOrExit(error = message->AppendSourceAddressTlv()); - SuccessOrExit(error = message->AppendResponseTlv(aChallenge)); + SuccessOrExit(error = message->AppendResponseTlv(aInfo.mRxChallenge)); SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs()); - linkMargin = Get().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss()); - SuccessOrExit(error = message->AppendLinkMarginTlv(linkMargin)); + SuccessOrExit(error = message->AppendLinkMarginTlv(aInfo.mLinkMargin)); - if (aNeighbor != nullptr && IsRouterRloc16(aNeighbor->GetRloc16())) + if (router != nullptr) { SuccessOrExit(error = message->AppendLeaderDataTlv()); } - for (uint8_t tlvType : aRequestedTlvList) + for (uint8_t tlvType : aInfo.mRequestedTlvList) { switch (tlvType) { case Tlv::kRoute: - SuccessOrExit(error = message->AppendRouteTlv(aNeighbor)); + SuccessOrExit(error = message->AppendRouteTlv(router)); break; case Tlv::kAddress16: - VerifyOrExit(aNeighbor != nullptr, error = kErrorDrop); - SuccessOrExit(error = message->AppendAddress16Tlv(aNeighbor->GetRloc16())); + VerifyOrExit(router != nullptr, error = kErrorDrop); + SuccessOrExit(error = message->AppendAddress16Tlv(router->GetRloc16())); break; case Tlv::kLinkMargin: @@ -815,38 +835,26 @@ Error MleRouter::SendLinkAccept(const RxInfo &aRxInfo, } } - if (aNeighbor != nullptr && !aNeighbor->IsStateValid()) + if (command == kCommandLinkAcceptAndRequest) { - aNeighbor->GenerateChallenge(); + router->GenerateChallenge(); - SuccessOrExit(error = message->AppendChallengeTlv(aNeighbor->GetChallenge())); + SuccessOrExit(error = message->AppendChallengeTlv(router->GetChallenge())); SuccessOrExit(error = message->AppendTlvRequestTlv(kRouterTlvs)); - aNeighbor->SetLastHeard(TimerMilli::GetNow()); - aNeighbor->SetState(Neighbor::kStateLinkRequest); } #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE - if (aNeighbor != nullptr && aNeighbor->IsTimeSyncEnabled()) + if (router != nullptr && router->IsTimeSyncEnabled()) { message->SetTimeSync(true); } #endif - if (aRxInfo.mMessageInfo.GetSockAddr().IsMulticast()) - { - SuccessOrExit(error = message->SendAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), - 1 + Random::NonCrypto::GetUint16InRange(0, kMaxLinkAcceptDelay))); + destination.SetToLinkLocalAddress(aInfo.mExtAddress); - Log(kMessageDelay, (command == kCommandLinkAccept) ? kTypeLinkAccept : kTypeLinkAcceptAndRequest, - aRxInfo.mMessageInfo.GetPeerAddr()); - } - else - { - SuccessOrExit(error = message->SendTo(aRxInfo.mMessageInfo.GetPeerAddr())); + SuccessOrExit(error = message->SendTo(destination)); - Log(kMessageSend, (command == kCommandLinkAccept) ? kTypeLinkAccept : kTypeLinkAcceptAndRequest, - aRxInfo.mMessageInfo.GetPeerAddr()); - } + Log(kMessageSend, (command == kCommandLinkAccept) ? kTypeLinkAccept : kTypeLinkAcceptAndRequest, destination); exit: FreeMessageOnError(message, error); @@ -1049,12 +1057,11 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) if (aRequest) { - RxChallenge challenge; - TlvList requestedTlvList; + LinkAcceptInfo info; - SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge)); + SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(info.mRxChallenge)); - switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList)) + switch (aRxInfo.mMessage.ReadTlvRequestTlv(info.mRequestedTlvList)) { case kErrorNone: case kErrorNotFound: @@ -1063,7 +1070,10 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) ExitNow(error = kErrorParse); } - SuccessOrExit(error = SendLinkAccept(aRxInfo, router, requestedTlvList, challenge)); + info.mExtAddress = router->GetExtAddress(); + info.mLinkMargin = Get().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss()); + + SuccessOrExit(error = SendLinkAccept(info)); } exit: @@ -1360,13 +1370,13 @@ exit: void MleRouter::HandleParentRequest(RxInfo &aRxInfo) { - Error error = kErrorNone; - Mac::ExtAddress extAddr; - uint16_t version; - uint8_t scanMask; - RxChallenge challenge; - Child *child; - DeviceMode mode; + Error error = kErrorNone; + uint16_t version; + uint8_t scanMask; + Child *child; + DeviceMode mode; + uint16_t delay; + ParentResponseInfo info; Log(kMessageReceive, kTypeParentRequest, aRxInfo.mMessageInfo.GetPeerAddr()); @@ -1393,7 +1403,7 @@ void MleRouter::HandleParentRequest(RxInfo &aRxInfo) // the network (because Leader would reject any further address solicit). // ==> Verified below when checking the scan mask. - aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr); + aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(info.mChildExtAddress); SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version)); @@ -1416,9 +1426,9 @@ void MleRouter::HandleParentRequest(RxInfo &aRxInfo) break; } - SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge)); + SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(info.mRxChallenge)); - child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid); + child = mChildTable.FindChild(info.mChildExtAddress, Child::kInStateAnyExceptInvalid); if (child == nullptr) { @@ -1449,7 +1459,10 @@ void MleRouter::HandleParentRequest(RxInfo &aRxInfo) aRxInfo.mClass = RxInfo::kPeerMessage; ProcessKeySequence(aRxInfo); - SendParentResponse(*child, challenge, !ScanMaskTlv::IsEndDeviceFlagSet(scanMask)); + delay = 1 + Random::NonCrypto::GetUint16InRange(0, !ScanMaskTlv::IsEndDeviceFlagSet(scanMask) + ? kParentResponseMaxDelayRouters + : kParentResponseMaxDelayAll); + mDelayedSender.ScheduleParentResponse(info, delay); exit: LogProcessError(kTypeParentRequest, error); @@ -1681,12 +1694,15 @@ exit: return; } -void MleRouter::SendParentResponse(Child &aChild, const RxChallenge &aChallenge, bool aRoutersOnlyRequest) +void MleRouter::SendParentResponse(const ParentResponseInfo &aInfo) { - Error error = kErrorNone; + Error error = kErrorNone; + TxMessage *message = nullptr; + Child *child; Ip6::Address destination; - TxMessage *message; - uint16_t delay; + + child = mChildTable.FindChild(aInfo.mChildExtAddress, Child::kInStateAnyExceptInvalid); + VerifyOrExit(child != nullptr); VerifyOrExit((message = NewMleMessage(kCommandParentResponse)) != nullptr, error = kErrorNoBufs); message->SetDirectTransmission(); @@ -1694,33 +1710,30 @@ void MleRouter::SendParentResponse(Child &aChild, const RxChallenge &aChallenge, SuccessOrExit(error = message->AppendSourceAddressTlv()); SuccessOrExit(error = message->AppendLeaderDataTlv()); SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs()); - SuccessOrExit(error = message->AppendResponseTlv(aChallenge)); + SuccessOrExit(error = message->AppendResponseTlv(aInfo.mRxChallenge)); #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE - if (aChild.IsTimeSyncEnabled()) + if (child->IsTimeSyncEnabled()) { SuccessOrExit(error = message->AppendTimeParameterTlv()); } #endif #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE - if (aChild.IsThreadVersionCslCapable()) + if (child->IsThreadVersionCslCapable()) { SuccessOrExit(error = message->AppendCslClockAccuracyTlv()); } #endif - aChild.GenerateChallenge(); - SuccessOrExit(error = message->AppendChallengeTlv(aChild.GetChallenge())); - SuccessOrExit(error = message->AppendLinkMarginTlv(aChild.GetLinkInfo().GetLinkMargin())); + child->GenerateChallenge(); + SuccessOrExit(error = message->AppendChallengeTlv(child->GetChallenge())); + SuccessOrExit(error = message->AppendLinkMarginTlv(child->GetLinkInfo().GetLinkMargin())); SuccessOrExit(error = message->AppendConnectivityTlv()); SuccessOrExit(error = message->AppendVersionTlv()); - destination.SetToLinkLocalAddress(aChild.GetExtAddress()); + destination.SetToLinkLocalAddress(aInfo.mChildExtAddress); - delay = 1 + Random::NonCrypto::GetUint16InRange(0, aRoutersOnlyRequest ? kParentResponseMaxDelayRouters - : kParentResponseMaxDelayAll); + SuccessOrExit(error = message->SendTo(destination)); - SuccessOrExit(error = message->SendAfterDelay(destination, delay)); - - Log(kMessageDelay, kTypeParentResponse, destination); + Log(kMessageSend, kTypeParentResponse, destination); exit: FreeMessageOnError(message, error); @@ -2538,7 +2551,7 @@ void MleRouter::HandleDataRequest(RxInfo &aRxInfo) aRxInfo.mClass = RxInfo::kPeerMessage; ProcessKeySequence(aRxInfo); - SendDataResponse(aRxInfo.mMessageInfo.GetPeerAddr(), tlvList, /* aDelay */ 0, &aRxInfo.mMessage); + SendDataResponse(aRxInfo.mMessageInfo.GetPeerAddr(), tlvList, &aRxInfo.mMessage); exit: LogProcessError(kTypeDataRequest, error); @@ -2546,17 +2559,19 @@ exit: void MleRouter::HandleNetworkDataUpdateRouter(void) { - Ip6::Address destination; - uint16_t delay; - TlvList tlvList; + uint16_t delay; VerifyOrExit(IsRouterOrLeader()); - destination.SetToLinkLocalAllNodesMulticast(); - tlvList.Add(Tlv::kNetworkData); - - delay = IsLeader() ? 0 : Random::NonCrypto::GetUint16InRange(0, kUnsolicitedDataResponseJitter); - SendDataResponse(destination, tlvList, delay); + if (IsLeader()) + { + SendMulticastDataResponse(); + } + else + { + delay = 1 + Random::NonCrypto::GetUint16InRange(0, kUnsolicitedDataResponseJitter); + mDelayedSender.ScheduleMulticastDataResponse(delay); + } SynchronizeChildNetworkData(); @@ -2622,6 +2637,7 @@ void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo) MeshCoP::DiscoveryRequestTlv discoveryRequestTlv; MeshCoP::ExtendedPanId extPanId; OffsetRange offsetRange; + DiscoveryResponseInfo responseInfo; Log(kMessageReceive, kTypeDiscoveryRequest, aRxInfo.mMessageInfo.GetPeerAddr()); @@ -2687,28 +2703,34 @@ void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo) } } - error = SendDiscoveryResponse(aRxInfo.mMessageInfo.GetPeerAddr(), aRxInfo.mMessage); + responseInfo.mPanId = aRxInfo.mMessage.GetPanId(); + +#if OPENTHREAD_CONFIG_MULTI_RADIO + // Send the MLE Discovery Response message on same radio link + // from which the "MLE Discover Request" message was received. + responseInfo.mRadioType = aRxInfo.mMessage.GetRadioType(); +#endif + + mDelayedSender.ScheduleDiscoveryResponse(aRxInfo.mMessageInfo.GetPeerAddr(), responseInfo, + 1 + Random::NonCrypto::GetUint16InRange(0, kDiscoveryMaxJitter)); exit: LogProcessError(kTypeDiscoveryRequest, error); } -Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const Message &aDiscoverRequestMessage) +Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const DiscoveryResponseInfo &aInfo) { Error error = kErrorNone; TxMessage *message; uint16_t startOffset; Tlv tlv; MeshCoP::DiscoveryResponseTlv discoveryResponseTlv; - uint16_t delay; VerifyOrExit((message = NewMleMessage(kCommandDiscoveryResponse)) != nullptr, error = kErrorNoBufs); message->SetDirectTransmission(); - message->SetPanId(aDiscoverRequestMessage.GetPanId()); + message->SetPanId(aInfo.mPanId); #if OPENTHREAD_CONFIG_MULTI_RADIO - // Send the MLE Discovery Response message on same radio link - // from which the "MLE Discover Request" message was received. - message->SetRadioType(aDiscoverRequestMessage.GetRadioType()); + message->SetRadioType(aInfo.mRadioType); #endif tlv.SetType(Tlv::kDiscovery); @@ -2762,11 +2784,9 @@ Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const M tlv.SetLength(static_cast(message->GetLength() - startOffset)); message->Write(startOffset - sizeof(tlv), tlv); - delay = Random::NonCrypto::GetUint16InRange(0, kDiscoveryMaxJitter + 1); + SuccessOrExit(error = message->SendTo(aDestination)); - SuccessOrExit(error = message->SendAfterDelay(aDestination, delay)); - - Log(kMessageDelay, kTypeDiscoveryResponse, aDestination); + Log(kMessageSend, kTypeDiscoveryResponse, aDestination); exit: FreeMessageOnError(message, error); @@ -3037,9 +3057,18 @@ exit: FreeMessageOnError(message, error); } +void MleRouter::SendMulticastDataResponse(void) +{ + Ip6::Address destination; + TlvList tlvList; + + destination.SetToLinkLocalAllNodesMulticast(); + tlvList.Add(Tlv::kNetworkData); + SendDataResponse(destination, tlvList); +} + void MleRouter::SendDataResponse(const Ip6::Address &aDestination, const TlvList &aTlvList, - uint16_t aDelay, const Message *aRequestMessage) { OT_UNUSED_VARIABLE(aRequestMessage); @@ -3048,6 +3077,8 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination, TxMessage *message = nullptr; Neighbor *neighbor; + VerifyOrExit(IsAttached()); + if (mRetrieveNewNetworkData) { LogInfo("Suppressing Data Response - waiting for new network data"); @@ -3092,20 +3123,8 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination, } } - if (aDelay) - { - Get().RemoveDataResponseMessages(); - - mDelayedSender.RemoveDataResponseMessage(); - - SuccessOrExit(error = message->SendAfterDelay(aDestination, aDelay)); - Log(kMessageDelay, kTypeDataResponse, aDestination); - } - else - { - SuccessOrExit(error = message->SendTo(aDestination)); - Log(kMessageSend, kTypeDataResponse, aDestination); - } + SuccessOrExit(error = message->SendTo(aDestination)); + Log(kMessageSend, kTypeDataResponse, aDestination); exit: FreeMessageOnError(message, error); diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 772c9863c..6168c0ed7 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -616,22 +616,19 @@ private: const Ip6::MessageInfo &aMessageInfo); void SendAddressRelease(void); void SendAdvertisement(void); - Error SendLinkAccept(const RxInfo &aRxInfo, - Neighbor *aNeighbor, - const TlvList &aRequestedTlvList, - const RxChallenge &aChallenge); - void SendParentResponse(Child &aChild, const RxChallenge &aChallenge, bool aRoutersOnlyRequest); + Error SendLinkAccept(const LinkAcceptInfo &aInfo); + void SendParentResponse(const ParentResponseInfo &aInfo); Error SendChildIdResponse(Child &aChild); Error SendChildUpdateRequest(Child &aChild); void SendChildUpdateResponse(Child *aChild, const Ip6::MessageInfo &aMessageInfo, const TlvList &aTlvList, const RxChallenge &aChallenge); + void SendMulticastDataResponse(void); void SendDataResponse(const Ip6::Address &aDestination, const TlvList &aTlvList, - uint16_t aDelay, const Message *aRequestMessage = nullptr); - Error SendDiscoveryResponse(const Ip6::Address &aDestination, const Message &aDiscoverRequestMessage); + Error SendDiscoveryResponse(const Ip6::Address &aDestination, const DiscoveryResponseInfo &aInfo); void SetStateRouter(uint16_t aRloc16); void SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode); void SetStateRouterOrLeader(DeviceRole aRole, uint16_t aRloc16, LeaderStartMode aStartMode); diff --git a/tests/unit/test_dns_client.cpp b/tests/unit/test_dns_client.cpp index 244b04bf6..b8405d856 100644 --- a/tests/unit/test_dns_client.cpp +++ b/tests/unit/test_dns_client.cpp @@ -225,6 +225,8 @@ void InitTest(void) void FinalizeTest(void) { + AdvanceTime(30 * 1000); + SuccessOrQuit(otIp6SetEnabled(sInstance, false)); SuccessOrQuit(otThreadSetEnabled(sInstance, false)); // Make sure there is no message/buffer leak