diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 4cb8fce0d..74071fc77 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -1785,26 +1785,28 @@ exit: } #endif -Error MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, uint16_t aLength, Child &aChild) +Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) { - Error error = kErrorNone; - AddressRegistrationEntry entry; - Ip6::Address address; - Lowpan::Context context; - uint8_t registeredCount = 0; - uint8_t storedCount = 0; - uint16_t end = aOffset + aLength; + Error error; + uint16_t offset; + uint16_t length; + uint16_t endOffset; + uint8_t count = 0; + uint8_t storedCount = 0; #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE Ip6::Address oldDua; const Ip6::Address *oldDuaPtr = nullptr; bool hasDua = false; #endif - #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE Ip6::Address oldMlrRegisteredAddresses[kMaxChildIpAddresses - 1]; uint16_t oldMlrRegisteredAddressNum = 0; #endif + SuccessOrExit(error = Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, offset, length)); + + endOffset = offset + length; + #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE if ((oldDuaPtr = aChild.GetDomainUnicastAddress()) != nullptr) { @@ -1831,36 +1833,47 @@ Error MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, aChild.ClearIp6Addresses(); - while (aOffset < end) + while (offset < endOffset) { - uint8_t len; + uint8_t controlByte; + Ip6::Address address; - // read out the control field - SuccessOrExit(error = aMessage.Read(aOffset, &entry, sizeof(uint8_t))); + // Read out the control byte (first byte in entry) + SuccessOrExit(error = aRxInfo.mMessage.Read(offset, controlByte)); + offset++; + count++; - len = entry.GetLength(); + address.Clear(); - SuccessOrExit(error = aMessage.Read(aOffset, &entry, len)); - - aOffset += len; - registeredCount++; - - if (entry.IsCompressed()) + if (AddressRegistrationTlv::IsEntryCompressed(controlByte)) { - if (Get().GetContext(entry.GetContextId(), context) != kErrorNone) + // Compressed entry contains IID with the 64-bit prefix + // determined from 6LoWPAN context identifier (from + // the control byte). + + uint8_t contextId = AddressRegistrationTlv::GetContextId(controlByte); + Lowpan::Context context; + + VerifyOrExit(offset + sizeof(Ip6::InterfaceIdentifier) <= endOffset, error = kErrorParse); + IgnoreError(aRxInfo.mMessage.Read(offset, address.GetIid())); + offset += sizeof(Ip6::InterfaceIdentifier); + + if (Get().GetContext(contextId, context) != kErrorNone) { - LogWarn("Failed to get context %u for compressed address from child 0x%04x", entry.GetContextId(), + LogWarn("Failed to get context %u for compressed address from child 0x%04x", contextId, aChild.GetRloc16()); continue; } - address.Clear(); address.SetPrefix(context.mPrefix); - address.SetIid(entry.GetIid()); } else { - address = entry.GetIp6Address(); + // Uncompressed entry contains the full IPv6 address. + + VerifyOrExit(offset + sizeof(Ip6::Address) <= endOffset, error = kErrorParse); + IgnoreError(aRxInfo.mMessage.Read(offset, address)); + offset += sizeof(Ip6::Address); } #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE @@ -1956,14 +1969,14 @@ Error MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, Get().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses, oldMlrRegisteredAddressNum); #endif - if (registeredCount == 0) + if (count == 0) { LogInfo("Child 0x%04x has no registered IPv6 address", aChild.GetRloc16()); } else { - LogInfo("Child 0x%04x has %u registered IPv6 address%s, %u address%s stored", aChild.GetRloc16(), - registeredCount, (registeredCount == 1) ? "" : "es", storedCount, (storedCount == 1) ? "" : "es"); + LogInfo("Child 0x%04x has %u registered IPv6 address%s, %u address%s stored", aChild.GetRloc16(), count, + (count == 1) ? "" : "es", storedCount, (storedCount == 1) ? "" : "es"); } error = kErrorNone; @@ -2088,11 +2101,7 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo) if (!mode.IsFullThreadDevice()) { - uint16_t offset; - uint16_t length; - - SuccessOrExit(error = Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, offset, length)); - SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, offset, length, *child)); + SuccessOrExit(error = ProcessAddressRegistrationTlv(aRxInfo, *child)); } // Remove from router table @@ -2182,8 +2191,6 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) DeviceMode oldMode; TlvList requestedTlvList; TlvList tlvList; - uint16_t addrOffset; - uint16_t addrLength; bool childDidChange = false; Log(kMessageReceive, kTypeChildUpdateRequestOfChild, aRxInfo.mMessageInfo.GetPeerAddr()); @@ -2246,10 +2253,15 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo) } // IPv6 Address TLV - if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, addrOffset, addrLength) == kErrorNone) + switch (ProcessAddressRegistrationTlv(aRxInfo, *child)) { - SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, addrOffset, addrLength, *child)); + case kErrorNone: tlvList.Add(Tlv::kAddressRegistration); + break; + case kErrorNotFound: + break; + default: + ExitNow(error = kErrorParse); } // Leader Data @@ -2404,8 +2416,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo) uint32_t mleFrameCounter; LeaderData leaderData; Child *child; - uint16_t addrOffset; - uint16_t addrLength; if ((aRxInfo.mNeighbor == nullptr) || IsActiveRouter(aRxInfo.mNeighbor->GetRloc16()) || !Get().Contains(*aRxInfo.mNeighbor)) @@ -2517,9 +2527,13 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo) } // IPv6 Address - if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, addrOffset, addrLength) == kErrorNone) + switch (ProcessAddressRegistrationTlv(aRxInfo, *child)) { - SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, addrOffset, addrLength, *child)); + case kErrorNone: + case kErrorNotFound: + break; + default: + ExitNow(error = kErrorParse); } // Leader Data diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 423550bc7..ac84f757f 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -630,6 +630,7 @@ private: void SetStateRouterOrLeader(DeviceRole aRole, uint16_t aRloc16, LeaderStartMode aStartMode); void StopLeader(void); void SynchronizeChildNetworkData(void); + Error ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild); Error UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, uint16_t aLength, Child &aChild); bool HasNeighborWithGoodLinkQuality(void) const; diff --git a/src/core/thread/mle_tlvs.hpp b/src/core/thread/mle_tlvs.hpp index f3750be68..7449965b9 100644 --- a/src/core/thread/mle_tlvs.hpp +++ b/src/core/thread/mle_tlvs.hpp @@ -999,6 +999,27 @@ public: */ static uint8_t ControlByteFor(uint8_t aContextId) { return kCompressed | (aContextId & kContextIdMask); } + /** + * This static method indicates whether or not an address entry is using compressed format. + * + * @param[in] aControlByte The control byte (the first byte in the entry). + * + * @retval TRUE If the entry uses compressed format. + * @retval FALSE If the entry uses uncompressed format. + * + */ + static bool IsEntryCompressed(uint8_t aControlByte) { return (aControlByte & kCompressed); } + + /** + * This static method gets the context ID in a compressed entry. + * + * @param[in] aControlByte The control byte (the first byte in the entry). + * + * @returns The 6LoWPAN context ID. + * + */ + static uint8_t GetContextId(uint8_t aControlByte) { return (aControlByte & kContextIdMask); } + AddressRegistrationTlv(void) = delete; private: @@ -1006,98 +1027,6 @@ private: static constexpr uint8_t kContextIdMask = 0xf; }; -/** - * This class implements Address Registration Entry generation and parsing. - * - */ -OT_TOOL_PACKED_BEGIN -class AddressRegistrationEntry -{ -public: - /** - * This method returns the IPv6 address or IID length. - * - * @returns The IPv6 address length if the Compressed bit is clear, or the IID length if the Compressed bit is - * set. - * - */ - uint8_t GetLength(void) const { return sizeof(mControl) + (IsCompressed() ? sizeof(mIid) : sizeof(mIp6Address)); } - - /** - * This method indicates whether or not the Compressed flag is set. - * - * @retval TRUE If the Compressed flag is set. - * @retval FALSE If the Compressed flag is not set. - * - */ - bool IsCompressed(void) const { return (mControl & kCompressed) != 0; } - - /** - * This method sets the Uncompressed flag. - * - */ - void SetUncompressed(void) { mControl = 0; } - - /** - * This method returns the Context ID for the compressed form. - * - * @returns The Context ID value. - * - */ - uint8_t GetContextId(void) const { return mControl & kCidMask; } - - /** - * This method sets the Context ID value. - * - * @param[in] aContextId The Context ID value. - * - */ - void SetContextId(uint8_t aContextId) { mControl = kCompressed | aContextId; } - - /** - * This method returns the IID value. - * - * @returns The IID value. - * - */ - const Ip6::InterfaceIdentifier &GetIid(void) const { return mIid; } - - /** - * This method sets the IID value. - * - * @param[in] aIid The IID value. - * - */ - void SetIid(const Ip6::InterfaceIdentifier &aIid) { mIid = aIid; } - - /** - * This method returns the IPv6 Address value. - * - * @returns The IPv6 Address value. - * - */ - const Ip6::Address &GetIp6Address(void) const { return mIp6Address; } - - /** - * This method sets the IPv6 Address value. - * - * @param[in] aAddress A reference to the IPv6 Address value. - * - */ - void SetIp6Address(const Ip6::Address &aAddress) { mIp6Address = aAddress; } - -private: - static constexpr uint8_t kCompressed = 1 << 7; - static constexpr uint8_t kCidMask = 0xf; - - uint8_t mControl; - union - { - Ip6::InterfaceIdentifier mIid; - Ip6::Address mIp6Address; - } OT_TOOL_PACKED_FIELD; -} OT_TOOL_PACKED_END; - /** * This class implements Channel TLV generation and parsing. *