diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index bde0550ed..c9f671197 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1045,277 +1045,6 @@ const LeaderData &Mle::GetLeaderData(void) return mLeaderData; } -Mle::TxMessage *Mle::NewMleMessage(Command aCommand) -{ - Error error = kErrorNone; - TxMessage * message; - Message::Settings settings(Message::kNoLinkSecurity, Message::kPriorityNet); - Message::SubType subType; - uint8_t securitySuite; - - message = static_cast(mSocket.NewMessage(0, settings)); - VerifyOrExit(message != nullptr, error = kErrorNoBufs); - - securitySuite = k154Security; - subType = Message::kSubTypeMleGeneral; - - switch (aCommand) - { - case kCommandAnnounce: - subType = Message::kSubTypeMleAnnounce; - break; - - case kCommandDiscoveryRequest: - subType = Message::kSubTypeMleDiscoverRequest; - securitySuite = kNoSecurity; - break; - - case kCommandDiscoveryResponse: - subType = Message::kSubTypeMleDiscoverResponse; - securitySuite = kNoSecurity; - break; - - case kCommandChildUpdateRequest: - subType = Message::kSubTypeMleChildUpdateRequest; - break; - - case kCommandDataResponse: - subType = Message::kSubTypeMleDataResponse; - break; - - case kCommandChildIdRequest: - subType = Message::kSubTypeMleChildIdRequest; - break; - - case kCommandDataRequest: - subType = Message::kSubTypeMleDataRequest; - break; - - default: - break; - } - - message->SetSubType(subType); - - SuccessOrExit(error = message->Append(securitySuite)); - - if (securitySuite == k154Security) - { - SecurityHeader securityHeader; - - // The other fields in security header are updated in the - // message in `TxMessage::SendTo()` before message is sent. - - securityHeader.InitSecurityControl(); - SuccessOrExit(error = message->Append(securityHeader)); - } - - error = message->Append(aCommand); - -exit: - FreeAndNullMessageOnError(message, error); - return message; -} - -Error Mle::TxMessage::AppendSourceAddressTlv(void) -{ - return Tlv::Append(*this, Get().GetRloc16()); -} - -Error Mle::TxMessage::AppendStatusTlv(StatusTlv::Status aStatus) -{ - return Tlv::Append(*this, aStatus); -} - -Error Mle::TxMessage::AppendModeTlv(DeviceMode aMode) -{ - return Tlv::Append(*this, aMode.Get()); -} - -Error Mle::TxMessage::AppendTimeoutTlv(uint32_t aTimeout) -{ - return Tlv::Append(*this, aTimeout); -} - -Error Mle::TxMessage::AppendChallengeTlv(const Challenge &aChallenge) -{ - return Tlv::Append(*this, aChallenge.mBuffer, aChallenge.mLength); -} - -Error Mle::TxMessage::AppendChallengeTlv(const uint8_t *aChallenge, uint8_t aChallengeLength) -{ - return Tlv::Append(*this, aChallenge, aChallengeLength); -} - -Error Mle::TxMessage::AppendResponseTlv(const Challenge &aResponse) -{ - return Tlv::Append(*this, aResponse.mBuffer, aResponse.mLength); -} - -Error Mle::RxMessage::ReadChallengeOrResponse(uint8_t aTlvType, Challenge &aBuffer) const -{ - Error error; - uint16_t offset; - uint16_t length; - - SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, aTlvType, offset, length)); - VerifyOrExit(length >= kMinChallengeSize, error = kErrorParse); - - if (length > kMaxChallengeSize) - { - length = kMaxChallengeSize; - } - - ReadBytes(offset, aBuffer.mBuffer, length); - aBuffer.mLength = static_cast(length); - -exit: - return error; -} - -Error Mle::RxMessage::ReadChallengeTlv(Challenge &aChallenge) const -{ - return ReadChallengeOrResponse(Tlv::kChallenge, aChallenge); -} - -Error Mle::RxMessage::ReadResponseTlv(Challenge &aResponse) const -{ - return ReadChallengeOrResponse(Tlv::kResponse, aResponse); -} - -Error Mle::TxMessage::AppendLinkFrameCounterTlv(void) -{ - uint32_t counter; - - // When including Link-layer Frame Counter TLV in an MLE message - // the value is set to the maximum MAC frame counter on all - // supported radio links. All radio links must also start using - // the same counter value as the value included in the TLV. - - counter = Get().GetMaximumMacFrameCounter(); - -#if OPENTHREAD_CONFIG_MULTI_RADIO - Get().SetAllMacFrameCounters(counter); -#endif - - return Tlv::Append(*this, counter); -} - -Error Mle::TxMessage::AppendMleFrameCounterTlv(void) -{ - return Tlv::Append(*this, Get().GetMleFrameCounter()); -} - -Error Mle::RxMessage::ReadFrameCounterTlvs(uint32_t &aLinkFrameCounter, uint32_t &aMleFrameCounter) const -{ - Error error; - - SuccessOrExit(error = Tlv::Find(*this, aLinkFrameCounter)); - - switch (Tlv::Find(*this, aMleFrameCounter)) - { - case kErrorNone: - break; - case kErrorNotFound: - aMleFrameCounter = aLinkFrameCounter; - break; - default: - error = kErrorParse; - break; - } - -exit: - return error; -} - -Error Mle::TxMessage::AppendAddress16Tlv(uint16_t aRloc16) -{ - return Tlv::Append(*this, aRloc16); -} - -Error Mle::TxMessage::AppendLeaderDataTlv(void) -{ - LeaderDataTlv leaderDataTlv; - - Get().mLeaderData.SetDataVersion(Get().GetVersion(NetworkData::kFullSet)); - Get().mLeaderData.SetStableDataVersion(Get().GetVersion(NetworkData::kStableSubset)); - - leaderDataTlv.Init(); - leaderDataTlv.Set(Get().mLeaderData); - - return leaderDataTlv.AppendTo(*this); -} - -Error Mle::RxMessage::ReadLeaderDataTlv(LeaderData &aLeaderData) const -{ - Error error; - LeaderDataTlv leaderDataTlv; - - SuccessOrExit(error = Tlv::FindTlv(*this, leaderDataTlv)); - VerifyOrExit(leaderDataTlv.IsValid(), error = kErrorParse); - leaderDataTlv.Get(aLeaderData); - -exit: - return error; -} - -Error Mle::TxMessage::AppendNetworkDataTlv(NetworkData::Type aType) -{ - Error error = kErrorNone; - uint8_t networkData[NetworkData::NetworkData::kMaxSize]; - uint8_t length; - - VerifyOrExit(!Get().mRetrieveNewNetworkData, error = kErrorInvalidState); - - length = sizeof(networkData); - IgnoreError(Get().CopyNetworkData(aType, networkData, length)); - - error = Tlv::Append(*this, networkData, length); - -exit: - return error; -} - -Error Mle::TxMessage::AppendTlvRequestTlv(const uint8_t *aTlvs, uint8_t aTlvsLength) -{ - return Tlv::Append(*this, aTlvs, aTlvsLength); -} - -Error Mle::RxMessage::ReadTlvRequestTlv(RequestedTlvs &aRequestedTlvs) const -{ - Error error; - uint16_t offset; - uint16_t length; - - SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, Tlv::kTlvRequest, offset, length)); - - if (length > sizeof(aRequestedTlvs.mTlvs)) - { - length = sizeof(aRequestedTlvs.mTlvs); - } - - ReadBytes(offset, aRequestedTlvs.mTlvs, length); - aRequestedTlvs.mNumTlvs = static_cast(length); - -exit: - return error; -} - -Error Mle::TxMessage::AppendScanMaskTlv(uint8_t aScanMask) -{ - return Tlv::Append(*this, aScanMask); -} - -Error Mle::TxMessage::AppendLinkMarginTlv(uint8_t aLinkMargin) -{ - return Tlv::Append(*this, aLinkMargin); -} - -Error Mle::TxMessage::AppendVersionTlv(void) -{ - return Tlv::Append(*this, kThreadVersion); -} - bool Mle::HasUnregisteredAddress(void) { bool retval = false; @@ -1344,206 +1073,7 @@ exit: return retval; } -Error Mle::TxMessage::AppendAddressRegistrationTlv(AddressRegistrationMode aMode) -{ - Error error = kErrorNone; - Tlv tlv; - AddressRegistrationEntry entry; - Lowpan::Context context; - uint8_t length = 0; - uint8_t counter = 0; - uint16_t startOffset = GetLength(); -#if OPENTHREAD_CONFIG_DUA_ENABLE - Ip6::Address domainUnicastAddress; -#endif - - tlv.SetType(Tlv::kAddressRegistration); - SuccessOrExit(error = Append(tlv)); - - // Prioritize ML-EID - entry.SetContextId(kMeshLocalPrefixContextId); - entry.SetIid(Get().GetMeshLocal64().GetIid()); - SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); - length += entry.GetLength(); - - // Continue to append the other addresses if not `kAppendMeshLocalOnly` mode - VerifyOrExit(aMode != kAppendMeshLocalOnly); - counter++; - -#if OPENTHREAD_CONFIG_DUA_ENABLE - // Cache Domain Unicast Address. - domainUnicastAddress = Get().GetDomainUnicastAddress(); - - if (Get().HasUnicastAddress(domainUnicastAddress)) - { - SuccessOrAssert(Get().GetContext(domainUnicastAddress, context)); - - // Prioritize DUA, compressed entry - entry.SetContextId(context.mContextId); - entry.SetIid(domainUnicastAddress.GetIid()); - SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); - length += entry.GetLength(); - counter++; - } -#endif // OPENTHREAD_CONFIG_DUA_ENABLE - - for (const Ip6::Netif::UnicastAddress &addr : Get().GetUnicastAddresses()) - { - if (addr.GetAddress().IsLinkLocal() || Get().IsRoutingLocator(addr.GetAddress()) || - Get().IsAnycastLocator(addr.GetAddress()) || addr.GetAddress() == Get().GetMeshLocal64()) - { - continue; - } - -#if OPENTHREAD_CONFIG_DUA_ENABLE - // Skip DUA that was already appended above. - if (addr.GetAddress() == domainUnicastAddress) - { - continue; - } -#endif - - if (Get().GetContext(addr.GetAddress(), context) == kErrorNone) - { - // compressed entry - entry.SetContextId(context.mContextId); - entry.SetIid(addr.GetAddress().GetIid()); - } - else - { - // uncompressed entry - entry.SetUncompressed(); - entry.SetIp6Address(addr.GetAddress()); - } - - SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); - length += entry.GetLength(); - counter++; - // only continue to append if there is available entry. - VerifyOrExit(counter < OPENTHREAD_CONFIG_MLE_IP_ADDRS_TO_REGISTER); - } - - // Append external multicast addresses. For sleepy end device, - // register all external multicast addresses with the parent for - // indirect transmission. Since Thread 1.2, non-sleepy MED should - // also register external multicast addresses of scope larger than - // realm with a 1.2 or higher parent. - if (!Get().IsRxOnWhenIdle() -#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) - || !Get().GetParent().IsThreadVersion1p1() -#endif - ) - { - for (const Ip6::Netif::MulticastAddress &addr : Get().IterateExternalMulticastAddresses()) - { -#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) - // For Thread 1.2 MED, skip multicast address with scope not - // larger than realm local when registering. - if (Get().IsRxOnWhenIdle() && !addr.GetAddress().IsMulticastLargerThanRealmLocal()) - { - continue; - } -#endif - - entry.SetUncompressed(); - entry.SetIp6Address(addr.GetAddress()); - SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); - length += entry.GetLength(); - - counter++; - // only continue to append if there is available entry. - VerifyOrExit(counter < OPENTHREAD_CONFIG_MLE_IP_ADDRS_TO_REGISTER); - } - } - -exit: - - if (error == kErrorNone && length > 0) - { - tlv.SetLength(length); - Write(startOffset, tlv); - } - - return error; -} - -#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE -Error Mle::TxMessage::AppendTimeRequestTlv(void) -{ - // `TimeRequestTlv` has no value. - return Tlv::Append(*this, nullptr, 0); -} - -Error Mle::TxMessage::AppendTimeParameterTlv(void) -{ - TimeParameterTlv tlv; - - tlv.Init(); - tlv.SetTimeSyncPeriod(Get().GetTimeSyncPeriod()); - tlv.SetXtalThreshold(Get().GetXtalThreshold()); - - return tlv.AppendTo(*this); -} - -Error Mle::TxMessage::AppendXtalAccuracyTlv(void) -{ - return Tlv::Append(*this, otPlatTimeGetXtalAccuracy()); -} -#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE - -Error Mle::TxMessage::AppendActiveTimestampTlv(void) -{ - Error error = kErrorNone; - const MeshCoP::Timestamp *timestamp = Get().GetTimestamp(); - - VerifyOrExit(timestamp != nullptr); - error = Tlv::Append(*this, *timestamp); - -exit: - return error; -} - -Error Mle::TxMessage::AppendPendingTimestampTlv(void) -{ - Error error = kErrorNone; - const MeshCoP::Timestamp *timestamp = Get().GetTimestamp(); - - VerifyOrExit(timestamp != nullptr && timestamp->GetSeconds() != 0); - error = Tlv::Append(*this, *timestamp); - -exit: - return error; -} - #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE -Error Mle::TxMessage::AppendCslChannelTlv(void) -{ - Error error = kErrorNone; - CslChannelTlv cslChannel; - - // In current implementation, it's allowed to set CSL Channel unspecified. As `0` is not valid for Channel value - // in CSL Channel TLV, if CSL channel is not specified, we don't append CSL Channel TLV. - // And on transmitter side, it would also set CSL Channel for the child to `0` if it doesn't find a CSL Channel - // TLV. - VerifyOrExit(Get().IsCslChannelSpecified()); - - cslChannel.Init(); - cslChannel.SetChannelPage(0); - cslChannel.SetChannel(Get().GetCslChannel()); - - SuccessOrExit(error = Append(cslChannel)); - -exit: - return error; -} - -Error Mle::TxMessage::AppendCslTimeoutTlv(void) -{ - OT_ASSERT(Get().IsCslEnabled()); - return Tlv::Append(*this, - Get().mCslTimeout == 0 ? Get().mTimeout : Get().mCslTimeout); -} - void Mle::SetCslTimeout(uint32_t aTimeout) { VerifyOrExit(mCslTimeout != aTimeout); @@ -1560,24 +1090,6 @@ void Mle::SetCslTimeout(uint32_t aTimeout) exit: return; } -#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - -#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE -Error Mle::TxMessage::AppendCslClockAccuracyTlv(void) -{ - Error error = kErrorNone; - CslClockAccuracyTlv cslClockAccuracy; - - cslClockAccuracy.Init(); - - cslClockAccuracy.SetCslClockAccuracy(Get().GetCslAccuracy()); - cslClockAccuracy.SetCslUncertainty(Get().GetCslUncertainty()); - - SuccessOrExit(error = Append(cslClockAccuracy)); - -exit: - return error; -} #endif void Mle::HandleNotifierEvents(Events aEvents) @@ -2807,62 +2319,6 @@ exit: return error; } -Error Mle::TxMessage::SendTo(const Ip6::Address &aDestination) -{ - Error error = kErrorNone; - uint16_t offset = 0; - uint8_t securitySuite; - Ip6::MessageInfo messageInfo; - - messageInfo.SetPeerAddr(aDestination); - messageInfo.SetSockAddr(Get().mLinkLocal64.GetAddress()); - messageInfo.SetPeerPort(kUdpPort); - messageInfo.SetHopLimit(kMleHopLimit); - - IgnoreError(Read(offset, securitySuite)); - offset += sizeof(securitySuite); - - if (securitySuite == k154Security) - { - SecurityHeader header; - - // Update the fields in the security header - - IgnoreError(Read(offset, header)); - header.SetFrameCounter(Get().GetMleFrameCounter()); - header.SetKeyId(Get().GetCurrentKeySequence()); - Write(offset, header); - offset += sizeof(SecurityHeader); - - SuccessOrExit( - error = Get().ProcessMessageSecurity(Crypto::AesCcm::kEncrypt, *this, messageInfo, offset, header)); - - Get().IncrementMleFrameCounter(); - } - - SuccessOrExit(error = Get().mSocket.SendTo(*this, messageInfo)); - -exit: - return error; -} - -Error Mle::TxMessage::SendAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay) -{ - Error error = kErrorNone; - DelayedResponseMetadata metadata; - - metadata.mSendTime = TimerMilli::GetNow() + aDelay; - metadata.mDestination = aDestination; - - SuccessOrExit(error = metadata.AppendTo(*this)); - Get().mDelayedResponses.Enqueue(*this); - - Get().mDelayedResponseTimer.FireAtIfEarlier(metadata.mSendTime); - -exit: - return error; -} - void Mle::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) { static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); @@ -4745,30 +4201,6 @@ uint64_t Mle::CalcParentCslMetric(uint8_t aCslClockAccuracy, uint8_t aCslUncerta } #endif -void Mle::Challenge::GenerateRandom(void) -{ - mLength = kMaxChallengeSize; - IgnoreError(Random::Crypto::FillBuffer(mBuffer, mLength)); -} - -bool Mle::Challenge::Matches(const uint8_t *aBuffer, uint8_t aLength) const -{ - return (mLength == aLength) && (memcmp(mBuffer, aBuffer, aLength) == 0); -} - -void Mle::DelayedResponseMetadata::ReadFrom(const Message &aMessage) -{ - uint16_t length = aMessage.GetLength(); - - OT_ASSERT(length >= sizeof(*this)); - IgnoreError(aMessage.Read(length - sizeof(*this), *this)); -} - -void Mle::DelayedResponseMetadata::RemoveFrom(Message &aMessage) const -{ - SuccessOrAssert(aMessage.SetLength(aMessage.GetLength() - sizeof(*this))); -} - Error Mle::DetachGracefully(otDetachGracefullyCallback aCallback, void *aContext) { Error error = kErrorNone; @@ -4838,5 +4270,663 @@ void Mle::HandleDetachGracefullyAddressReleaseResponse(void) } #endif // OPENTHREAD_FTD +//--------------------------------------------------------------------------------------------------------------------- +// Challenge + +void Mle::Challenge::GenerateRandom(void) +{ + mLength = kMaxChallengeSize; + IgnoreError(Random::Crypto::FillBuffer(mBuffer, mLength)); +} + +bool Mle::Challenge::Matches(const uint8_t *aBuffer, uint8_t aLength) const +{ + return (mLength == aLength) && (memcmp(mBuffer, aBuffer, aLength) == 0); +} + +//--------------------------------------------------------------------------------------------------------------------- +// DelayedResponseMetadata + +void Mle::DelayedResponseMetadata::ReadFrom(const Message &aMessage) +{ + uint16_t length = aMessage.GetLength(); + + OT_ASSERT(length >= sizeof(*this)); + IgnoreError(aMessage.Read(length - sizeof(*this), *this)); +} + +void Mle::DelayedResponseMetadata::RemoveFrom(Message &aMessage) const +{ + SuccessOrAssert(aMessage.SetLength(aMessage.GetLength() - sizeof(*this))); +} + +//--------------------------------------------------------------------------------------------------------------------- +// TxMessage + +Mle::TxMessage *Mle::NewMleMessage(Command aCommand) +{ + Error error = kErrorNone; + TxMessage * message; + Message::Settings settings(Message::kNoLinkSecurity, Message::kPriorityNet); + Message::SubType subType; + uint8_t securitySuite; + + message = static_cast(mSocket.NewMessage(0, settings)); + VerifyOrExit(message != nullptr, error = kErrorNoBufs); + + securitySuite = k154Security; + subType = Message::kSubTypeMleGeneral; + + switch (aCommand) + { + case kCommandAnnounce: + subType = Message::kSubTypeMleAnnounce; + break; + + case kCommandDiscoveryRequest: + subType = Message::kSubTypeMleDiscoverRequest; + securitySuite = kNoSecurity; + break; + + case kCommandDiscoveryResponse: + subType = Message::kSubTypeMleDiscoverResponse; + securitySuite = kNoSecurity; + break; + + case kCommandChildUpdateRequest: + subType = Message::kSubTypeMleChildUpdateRequest; + break; + + case kCommandDataResponse: + subType = Message::kSubTypeMleDataResponse; + break; + + case kCommandChildIdRequest: + subType = Message::kSubTypeMleChildIdRequest; + break; + + case kCommandDataRequest: + subType = Message::kSubTypeMleDataRequest; + break; + + default: + break; + } + + message->SetSubType(subType); + + SuccessOrExit(error = message->Append(securitySuite)); + + if (securitySuite == k154Security) + { + SecurityHeader securityHeader; + + // The other fields in security header are updated in the + // message in `TxMessage::SendTo()` before message is sent. + + securityHeader.InitSecurityControl(); + SuccessOrExit(error = message->Append(securityHeader)); + } + + error = message->Append(aCommand); + +exit: + FreeAndNullMessageOnError(message, error); + return message; +} + +Error Mle::TxMessage::AppendSourceAddressTlv(void) +{ + return Tlv::Append(*this, Get().GetRloc16()); +} + +Error Mle::TxMessage::AppendStatusTlv(StatusTlv::Status aStatus) +{ + return Tlv::Append(*this, aStatus); +} + +Error Mle::TxMessage::AppendModeTlv(DeviceMode aMode) +{ + return Tlv::Append(*this, aMode.Get()); +} + +Error Mle::TxMessage::AppendTimeoutTlv(uint32_t aTimeout) +{ + return Tlv::Append(*this, aTimeout); +} + +Error Mle::TxMessage::AppendChallengeTlv(const Challenge &aChallenge) +{ + return Tlv::Append(*this, aChallenge.mBuffer, aChallenge.mLength); +} + +Error Mle::TxMessage::AppendChallengeTlv(const uint8_t *aChallenge, uint8_t aChallengeLength) +{ + return Tlv::Append(*this, aChallenge, aChallengeLength); +} + +Error Mle::TxMessage::AppendResponseTlv(const Challenge &aResponse) +{ + return Tlv::Append(*this, aResponse.mBuffer, aResponse.mLength); +} + +Error Mle::TxMessage::AppendLinkFrameCounterTlv(void) +{ + uint32_t counter; + + // When including Link-layer Frame Counter TLV in an MLE message + // the value is set to the maximum MAC frame counter on all + // supported radio links. All radio links must also start using + // the same counter value as the value included in the TLV. + + counter = Get().GetMaximumMacFrameCounter(); + +#if OPENTHREAD_CONFIG_MULTI_RADIO + Get().SetAllMacFrameCounters(counter); +#endif + + return Tlv::Append(*this, counter); +} + +Error Mle::TxMessage::AppendMleFrameCounterTlv(void) +{ + return Tlv::Append(*this, Get().GetMleFrameCounter()); +} + +Error Mle::TxMessage::AppendAddress16Tlv(uint16_t aRloc16) +{ + return Tlv::Append(*this, aRloc16); +} + +Error Mle::TxMessage::AppendLeaderDataTlv(void) +{ + LeaderDataTlv leaderDataTlv; + + Get().mLeaderData.SetDataVersion(Get().GetVersion(NetworkData::kFullSet)); + Get().mLeaderData.SetStableDataVersion(Get().GetVersion(NetworkData::kStableSubset)); + + leaderDataTlv.Init(); + leaderDataTlv.Set(Get().mLeaderData); + + return leaderDataTlv.AppendTo(*this); +} + +Error Mle::TxMessage::AppendNetworkDataTlv(NetworkData::Type aType) +{ + Error error = kErrorNone; + uint8_t networkData[NetworkData::NetworkData::kMaxSize]; + uint8_t length; + + VerifyOrExit(!Get().mRetrieveNewNetworkData, error = kErrorInvalidState); + + length = sizeof(networkData); + IgnoreError(Get().CopyNetworkData(aType, networkData, length)); + + error = Tlv::Append(*this, networkData, length); + +exit: + return error; +} + +Error Mle::TxMessage::AppendTlvRequestTlv(const uint8_t *aTlvs, uint8_t aTlvsLength) +{ + return Tlv::Append(*this, aTlvs, aTlvsLength); +} + +Error Mle::TxMessage::AppendScanMaskTlv(uint8_t aScanMask) +{ + return Tlv::Append(*this, aScanMask); +} + +Error Mle::TxMessage::AppendLinkMarginTlv(uint8_t aLinkMargin) +{ + return Tlv::Append(*this, aLinkMargin); +} + +Error Mle::TxMessage::AppendVersionTlv(void) +{ + return Tlv::Append(*this, kThreadVersion); +} + +Error Mle::TxMessage::AppendAddressRegistrationTlv(AddressRegistrationMode aMode) +{ + Error error = kErrorNone; + Tlv tlv; + AddressRegistrationEntry entry; + Lowpan::Context context; + uint8_t length = 0; + uint8_t counter = 0; + uint16_t startOffset = GetLength(); +#if OPENTHREAD_CONFIG_DUA_ENABLE + Ip6::Address domainUnicastAddress; +#endif + + tlv.SetType(Tlv::kAddressRegistration); + SuccessOrExit(error = Append(tlv)); + + // Prioritize ML-EID + entry.SetContextId(kMeshLocalPrefixContextId); + entry.SetIid(Get().GetMeshLocal64().GetIid()); + SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); + length += entry.GetLength(); + + // Continue to append the other addresses if not `kAppendMeshLocalOnly` mode + VerifyOrExit(aMode != kAppendMeshLocalOnly); + counter++; + +#if OPENTHREAD_CONFIG_DUA_ENABLE + // Cache Domain Unicast Address. + domainUnicastAddress = Get().GetDomainUnicastAddress(); + + if (Get().HasUnicastAddress(domainUnicastAddress)) + { + SuccessOrAssert(Get().GetContext(domainUnicastAddress, context)); + + // Prioritize DUA, compressed entry + entry.SetContextId(context.mContextId); + entry.SetIid(domainUnicastAddress.GetIid()); + SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); + length += entry.GetLength(); + counter++; + } +#endif // OPENTHREAD_CONFIG_DUA_ENABLE + + for (const Ip6::Netif::UnicastAddress &addr : Get().GetUnicastAddresses()) + { + if (addr.GetAddress().IsLinkLocal() || Get().IsRoutingLocator(addr.GetAddress()) || + Get().IsAnycastLocator(addr.GetAddress()) || addr.GetAddress() == Get().GetMeshLocal64()) + { + continue; + } + +#if OPENTHREAD_CONFIG_DUA_ENABLE + // Skip DUA that was already appended above. + if (addr.GetAddress() == domainUnicastAddress) + { + continue; + } +#endif + + if (Get().GetContext(addr.GetAddress(), context) == kErrorNone) + { + // compressed entry + entry.SetContextId(context.mContextId); + entry.SetIid(addr.GetAddress().GetIid()); + } + else + { + // uncompressed entry + entry.SetUncompressed(); + entry.SetIp6Address(addr.GetAddress()); + } + + SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); + length += entry.GetLength(); + counter++; + // only continue to append if there is available entry. + VerifyOrExit(counter < OPENTHREAD_CONFIG_MLE_IP_ADDRS_TO_REGISTER); + } + + // Append external multicast addresses. For sleepy end device, + // register all external multicast addresses with the parent for + // indirect transmission. Since Thread 1.2, non-sleepy MED should + // also register external multicast addresses of scope larger than + // realm with a 1.2 or higher parent. + if (!Get().IsRxOnWhenIdle() +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + || !Get().GetParent().IsThreadVersion1p1() +#endif + ) + { + for (const Ip6::Netif::MulticastAddress &addr : Get().IterateExternalMulticastAddresses()) + { +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + // For Thread 1.2 MED, skip multicast address with scope not + // larger than realm local when registering. + if (Get().IsRxOnWhenIdle() && !addr.GetAddress().IsMulticastLargerThanRealmLocal()) + { + continue; + } +#endif + + entry.SetUncompressed(); + entry.SetIp6Address(addr.GetAddress()); + SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); + length += entry.GetLength(); + + counter++; + // only continue to append if there is available entry. + VerifyOrExit(counter < OPENTHREAD_CONFIG_MLE_IP_ADDRS_TO_REGISTER); + } + } + +exit: + + if (error == kErrorNone && length > 0) + { + tlv.SetLength(length); + Write(startOffset, tlv); + } + + return error; +} + +#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE +Error Mle::TxMessage::AppendTimeRequestTlv(void) +{ + // `TimeRequestTlv` has no value. + return Tlv::Append(*this, nullptr, 0); +} + +Error Mle::TxMessage::AppendTimeParameterTlv(void) +{ + TimeParameterTlv tlv; + + tlv.Init(); + tlv.SetTimeSyncPeriod(Get().GetTimeSyncPeriod()); + tlv.SetXtalThreshold(Get().GetXtalThreshold()); + + return tlv.AppendTo(*this); +} + +Error Mle::TxMessage::AppendXtalAccuracyTlv(void) +{ + return Tlv::Append(*this, otPlatTimeGetXtalAccuracy()); +} +#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE + +Error Mle::TxMessage::AppendActiveTimestampTlv(void) +{ + Error error = kErrorNone; + const MeshCoP::Timestamp *timestamp = Get().GetTimestamp(); + + VerifyOrExit(timestamp != nullptr); + error = Tlv::Append(*this, *timestamp); + +exit: + return error; +} + +Error Mle::TxMessage::AppendPendingTimestampTlv(void) +{ + Error error = kErrorNone; + const MeshCoP::Timestamp *timestamp = Get().GetTimestamp(); + + VerifyOrExit(timestamp != nullptr && timestamp->GetSeconds() != 0); + error = Tlv::Append(*this, *timestamp); + +exit: + return error; +} + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE +Error Mle::TxMessage::AppendCslChannelTlv(void) +{ + Error error = kErrorNone; + CslChannelTlv cslChannel; + + // In current implementation, it's allowed to set CSL Channel unspecified. As `0` is not valid for Channel value + // in CSL Channel TLV, if CSL channel is not specified, we don't append CSL Channel TLV. + // And on transmitter side, it would also set CSL Channel for the child to `0` if it doesn't find a CSL Channel + // TLV. + VerifyOrExit(Get().IsCslChannelSpecified()); + + cslChannel.Init(); + cslChannel.SetChannelPage(0); + cslChannel.SetChannel(Get().GetCslChannel()); + + SuccessOrExit(error = Append(cslChannel)); + +exit: + return error; +} + +Error Mle::TxMessage::AppendCslTimeoutTlv(void) +{ + OT_ASSERT(Get().IsCslEnabled()); + return Tlv::Append(*this, + Get().mCslTimeout == 0 ? Get().mTimeout : Get().mCslTimeout); +} +#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + +#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE +Error Mle::TxMessage::AppendCslClockAccuracyTlv(void) +{ + Error error = kErrorNone; + CslClockAccuracyTlv cslClockAccuracy; + + cslClockAccuracy.Init(); + + cslClockAccuracy.SetCslClockAccuracy(Get().GetCslAccuracy()); + cslClockAccuracy.SetCslUncertainty(Get().GetCslUncertainty()); + + SuccessOrExit(error = Append(cslClockAccuracy)); + +exit: + return error; +} +#endif + +Error Mle::TxMessage::SendTo(const Ip6::Address &aDestination) +{ + Error error = kErrorNone; + uint16_t offset = 0; + uint8_t securitySuite; + Ip6::MessageInfo messageInfo; + + messageInfo.SetPeerAddr(aDestination); + messageInfo.SetSockAddr(Get().mLinkLocal64.GetAddress()); + messageInfo.SetPeerPort(kUdpPort); + messageInfo.SetHopLimit(kMleHopLimit); + + IgnoreError(Read(offset, securitySuite)); + offset += sizeof(securitySuite); + + if (securitySuite == k154Security) + { + SecurityHeader header; + + // Update the fields in the security header + + IgnoreError(Read(offset, header)); + header.SetFrameCounter(Get().GetMleFrameCounter()); + header.SetKeyId(Get().GetCurrentKeySequence()); + Write(offset, header); + offset += sizeof(SecurityHeader); + + SuccessOrExit( + error = Get().ProcessMessageSecurity(Crypto::AesCcm::kEncrypt, *this, messageInfo, offset, header)); + + Get().IncrementMleFrameCounter(); + } + + SuccessOrExit(error = Get().mSocket.SendTo(*this, messageInfo)); + +exit: + return error; +} + +Error Mle::TxMessage::SendAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay) +{ + Error error = kErrorNone; + DelayedResponseMetadata metadata; + + metadata.mSendTime = TimerMilli::GetNow() + aDelay; + metadata.mDestination = aDestination; + + SuccessOrExit(error = metadata.AppendTo(*this)); + Get().mDelayedResponses.Enqueue(*this); + + Get().mDelayedResponseTimer.FireAtIfEarlier(metadata.mSendTime); + +exit: + return error; +} + +#if OPENTHREAD_FTD + +Error Mle::TxMessage::AppendConnectivityTlv(void) +{ + ConnectivityTlv tlv; + + tlv.Init(); + Get().FillConnectivityTlv(tlv); + + return tlv.AppendTo(*this); +} + +Error Mle::TxMessage::AppendAddresseRegisterationTlv(Child &aChild) +{ + Error error; + Tlv tlv; + AddressRegistrationEntry entry; + Lowpan::Context context; + uint8_t length = 0; + uint16_t startOffset = GetLength(); + + tlv.SetType(Tlv::kAddressRegistration); + SuccessOrExit(error = Append(tlv)); + + for (const Ip6::Address &address : aChild.IterateIp6Addresses()) + { + if (address.IsMulticast() || Get().GetContext(address, context) != kErrorNone) + { + // uncompressed entry + entry.SetUncompressed(); + entry.SetIp6Address(address); + } + else if (context.mContextId != kMeshLocalPrefixContextId) + { + // compressed entry + entry.SetContextId(context.mContextId); + entry.SetIid(address.GetIid()); + } + else + { + continue; + } + + SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); + length += entry.GetLength(); + } + + tlv.SetLength(length); + Write(startOffset, tlv); + +exit: + return error; +} + +Error Mle::TxMessage::AppendRouteTlv(Neighbor *aNeighbor) +{ + RouteTlv tlv; + + tlv.Init(); + Get().FillRouteTlv(tlv, aNeighbor); + + return tlv.AppendTo(*this); +} + +Error Mle::TxMessage::AppendActiveDatasetTlv(void) +{ + return Get().AppendMleDatasetTlv(*this); +} + +Error Mle::TxMessage::AppendPendingDatasetTlv(void) +{ + return Get().AppendMleDatasetTlv(*this); +} + +#endif // OPENTHREAD_FTD + +//--------------------------------------------------------------------------------------------------------------------- +// RxMessage + +Error Mle::RxMessage::ReadChallengeOrResponse(uint8_t aTlvType, Challenge &aBuffer) const +{ + Error error; + uint16_t offset; + uint16_t length; + + SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, aTlvType, offset, length)); + VerifyOrExit(length >= kMinChallengeSize, error = kErrorParse); + + if (length > kMaxChallengeSize) + { + length = kMaxChallengeSize; + } + + ReadBytes(offset, aBuffer.mBuffer, length); + aBuffer.mLength = static_cast(length); + +exit: + return error; +} + +Error Mle::RxMessage::ReadChallengeTlv(Challenge &aChallenge) const +{ + return ReadChallengeOrResponse(Tlv::kChallenge, aChallenge); +} + +Error Mle::RxMessage::ReadResponseTlv(Challenge &aResponse) const +{ + return ReadChallengeOrResponse(Tlv::kResponse, aResponse); +} + +Error Mle::RxMessage::ReadFrameCounterTlvs(uint32_t &aLinkFrameCounter, uint32_t &aMleFrameCounter) const +{ + Error error; + + SuccessOrExit(error = Tlv::Find(*this, aLinkFrameCounter)); + + switch (Tlv::Find(*this, aMleFrameCounter)) + { + case kErrorNone: + break; + case kErrorNotFound: + aMleFrameCounter = aLinkFrameCounter; + break; + default: + error = kErrorParse; + break; + } + +exit: + return error; +} + +Error Mle::RxMessage::ReadLeaderDataTlv(LeaderData &aLeaderData) const +{ + Error error; + LeaderDataTlv leaderDataTlv; + + SuccessOrExit(error = Tlv::FindTlv(*this, leaderDataTlv)); + VerifyOrExit(leaderDataTlv.IsValid(), error = kErrorParse); + leaderDataTlv.Get(aLeaderData); + +exit: + return error; +} + +Error Mle::RxMessage::ReadTlvRequestTlv(RequestedTlvs &aRequestedTlvs) const +{ + Error error; + uint16_t offset; + uint16_t length; + + SuccessOrExit(error = Tlv::FindTlvValueOffset(*this, Tlv::kTlvRequest, offset, length)); + + if (length > sizeof(aRequestedTlvs.mTlvs)) + { + length = sizeof(aRequestedTlvs.mTlvs); + } + + ReadBytes(offset, aRequestedTlvs.mTlvs, length); + aRequestedTlvs.mNumTlvs = static_cast(length); + +exit: + return error; +} + } // namespace Mle } // namespace ot diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 3f5016fd7..cc9e2b914 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -4161,58 +4161,6 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv) aTlv.SetSedDatagramCount(OPENTHREAD_CONFIG_DEFAULT_SED_DATAGRAM_COUNT); } -Error Mle::TxMessage::AppendConnectivityTlv(void) -{ - ConnectivityTlv tlv; - - tlv.Init(); - Get().FillConnectivityTlv(tlv); - - return tlv.AppendTo(*this); -} - -Error Mle::TxMessage::AppendAddresseRegisterationTlv(Child &aChild) -{ - Error error; - Tlv tlv; - AddressRegistrationEntry entry; - Lowpan::Context context; - uint8_t length = 0; - uint16_t startOffset = GetLength(); - - tlv.SetType(Tlv::kAddressRegistration); - SuccessOrExit(error = Append(tlv)); - - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) - { - if (address.IsMulticast() || Get().GetContext(address, context) != kErrorNone) - { - // uncompressed entry - entry.SetUncompressed(); - entry.SetIp6Address(address); - } - else if (context.mContextId != kMeshLocalPrefixContextId) - { - // compressed entry - entry.SetContextId(context.mContextId); - entry.SetIid(address.GetIid()); - } - else - { - continue; - } - - SuccessOrExit(error = AppendBytes(&entry, entry.GetLength())); - length += entry.GetLength(); - } - - tlv.SetLength(length); - Write(startOffset, tlv); - -exit: - return error; -} - void MleRouter::FillRouteTlv(RouteTlv &aTlv, Neighbor *aNeighbor) { uint8_t routerIdSequence = mRouterTable.GetRouterIdSequence(); @@ -4314,26 +4262,6 @@ void MleRouter::FillRouteTlv(RouteTlv &aTlv, Neighbor *aNeighbor) aTlv.SetRouteDataLength(routerCount); } -Error Mle::TxMessage::AppendRouteTlv(Neighbor *aNeighbor) -{ - RouteTlv tlv; - - tlv.Init(); - Get().FillRouteTlv(tlv, aNeighbor); - - return tlv.AppendTo(*this); -} - -Error Mle::TxMessage::AppendActiveDatasetTlv(void) -{ - return Get().AppendMleDatasetTlv(*this); -} - -Error Mle::TxMessage::AppendPendingDatasetTlv(void) -{ - return Get().AppendMleDatasetTlv(*this); -} - bool MleRouter::HasMinDowngradeNeighborRouters(void) { uint8_t linkQuality;