diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index 1bc0a857a..352580603 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -775,6 +775,7 @@ openthread_core_files = [ "thread/thread_link_info.hpp", "thread/thread_netif.cpp", "thread/thread_netif.hpp", + "thread/thread_tlvs.cpp", "thread/thread_tlvs.hpp", "thread/time_sync_service.cpp", "thread/time_sync_service.hpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ef1a4115e..f4f99ed67 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -278,6 +278,7 @@ set(COMMON_SOURCES thread/src_match_controller.cpp thread/thread_link_info.cpp thread/thread_netif.cpp + thread/thread_tlvs.cpp thread/time_sync_service.cpp thread/tmf.cpp thread/uri_paths.cpp diff --git a/src/core/backbone_router/bbr_manager.cpp b/src/core/backbone_router/bbr_manager.cpp index d1736a9a3..e5ae28073 100644 --- a/src/core/backbone_router/bbr_manager.cpp +++ b/src/core/backbone_router/bbr_manager.cpp @@ -291,16 +291,7 @@ void Manager::SendMulticastListenerRegistrationResponse(const Coap::Msg &aMsg, if (aFailedAddressNum > 0) { - Tlv::Bookmark tlvBookmark; - - SuccessOrExit(error = Tlv::StartTlv(*message, Ip6AddressesTlv::kType, tlvBookmark)); - - for (uint8_t i = 0; i < aFailedAddressNum; i++) - { - SuccessOrExit(error = message->Append(aFailedAddresses[i])); - } - - SuccessOrExit(error = Tlv::EndTlv(*message, tlvBookmark)); + SuccessOrExit(error = Ip6AddressesTlv::AppendTo(*message, aFailedAddresses, aFailedAddressNum)); } SuccessOrExit(error = Get().SendMessage(*message, aMsg.mMessageInfo)); @@ -317,7 +308,6 @@ void Manager::SendBackboneMulticastListenerRegistration(const Ip6::Address *aAdd Error error = kErrorNone; Coap::Message *message = nullptr; Ip6::MessageInfo messageInfo; - Tlv::Bookmark tlvBookmark; BackboneTmfAgent &backboneTmf = Get(); OT_ASSERT(aAddressNum >= kMlrMinIp6Addresses && aAddressNum <= kMlrMaxIp6Addresses); @@ -325,9 +315,7 @@ void Manager::SendBackboneMulticastListenerRegistration(const Ip6::Address *aAdd message = backboneTmf.AllocateAndInitNonConfirmablePostMessage(kUriBackboneMlr); VerifyOrExit(message != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = Tlv::StartTlv(*message, Ip6AddressesTlv::kType, tlvBookmark)); - SuccessOrExit(error = message->AppendBytes(aAddresses, sizeof(Ip6::Address) * aAddressNum)); - SuccessOrExit(error = Tlv::EndTlv(*message, tlvBookmark)); + SuccessOrExit(error = Ip6AddressesTlv::AppendTo(*message, aAddresses, aAddressNum)); SuccessOrExit(error = Tlv::Append(*message, aTimeout)); diff --git a/src/core/thread/mlr_manager.cpp b/src/core/thread/mlr_manager.cpp index 2fa285312..fb493461f 100644 --- a/src/core/thread/mlr_manager.cpp +++ b/src/core/thread/mlr_manager.cpp @@ -358,16 +358,13 @@ Error MlrManager::SendMlrMessage(const Ip6::Address *aAddresses, Error error = kErrorNone; Coap::Message *message = nullptr; Ip6::Address destAddr; - Tlv::Bookmark tlvBookmark; VerifyOrExit(Get().HasPrimary(), error = kErrorInvalidState); message = Get().AllocateAndInitConfirmablePostMessage(kUriMlr); VerifyOrExit(message != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = Tlv::StartTlv(*message, Ip6AddressesTlv::kType, tlvBookmark)); - SuccessOrExit(error = message->AppendBytes(aAddresses, sizeof(Ip6::Address) * aAddressNum)); - SuccessOrExit(error = Tlv::EndTlv(*message, tlvBookmark)); + SuccessOrExit(error = Ip6AddressesTlv::AppendTo(*message, aAddresses, aAddressNum)); #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE if (Get().IsActive()) diff --git a/src/core/thread/thread_tlvs.cpp b/src/core/thread/thread_tlvs.cpp new file mode 100644 index 000000000..8c72cae06 --- /dev/null +++ b/src/core/thread/thread_tlvs.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2026, 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. + */ + +/** + * @file + * This file implements methods for generating and processing Thread Network Layer TLVs. + */ + +#include "thread_tlvs.hpp" + +namespace ot { + +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + +Error Ip6AddressesTlv::AppendTo(Message &aMessage, const Ip6::Address *aAddresses, uint16_t aNumAddresses) +{ + Error error; + Tlv::Bookmark tlvBookmark; + + SuccessOrExit(error = Tlv::StartTlv(aMessage, kType, tlvBookmark)); + SuccessOrExit(error = aMessage.AppendBytes(aAddresses, aNumAddresses * sizeof(Ip6::Address))); + error = Tlv::EndTlv(aMessage, tlvBookmark); + +exit: + return error; +} + +#endif + +} // namespace ot diff --git a/src/core/thread/thread_tlvs.hpp b/src/core/thread/thread_tlvs.hpp index 14a7358eb..32209dd04 100644 --- a/src/core/thread/thread_tlvs.hpp +++ b/src/core/thread/thread_tlvs.hpp @@ -149,9 +149,25 @@ typedef TlvInfo ThreadNetworkDataTlv; #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 /** - * Defines IPv6 Addresses TLV constants and types. + * Defines IPv6 Addresses TLV constants and types and helper methods. */ -typedef TlvInfo Ip6AddressesTlv; +class Ip6AddressesTlv : public TlvInfo +{ +public: + /** + * Appends an IPv6 Addresses TLV to a message. + * + * @param[in,out] aMessage The message to append to. + * @param[in] aAddresses A pointer to an array of IPv6 addresses. + * @param[in] aNumAddresses The number of IPv6 addresses in the @p aAddresses array. + * + * @retval kErrorNone Successfully appended the TLV. + * @retval kErrorNoBufs Insufficient available buffers to grow the message. + */ + static Error AppendTo(Message &aMessage, const Ip6::Address *aAddresses, uint16_t aNumAddresses); + + Ip6AddressesTlv(void) = delete; +}; #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 diff --git a/tests/nexus/test_1_2_BBR_TC_2.cpp b/tests/nexus/test_1_2_BBR_TC_2.cpp index d62670ef0..0673377df 100644 --- a/tests/nexus/test_1_2_BBR_TC_2.cpp +++ b/tests/nexus/test_1_2_BBR_TC_2.cpp @@ -295,7 +295,6 @@ void Test_1_2_BBR_TC_2(void) { Ip6::Address ma1; Coap::Message *message; - Tlv::Bookmark tlvBookmark; Ip6::Address destAddr; SuccessOrQuit(ma1.FromString(kMa1Address)); @@ -303,9 +302,7 @@ void Test_1_2_BBR_TC_2(void) message = router1.Get().AllocateAndInitConfirmablePostMessage(kUriMlr); VerifyOrQuit(message != nullptr); - SuccessOrQuit(Tlv::StartTlv(*message, Ip6AddressesTlv::kType, tlvBookmark)); - SuccessOrQuit(message->Append(ma1)); - SuccessOrQuit(Tlv::EndTlv(*message, tlvBookmark)); + SuccessOrQuit(Ip6AddressesTlv::AppendTo(*message, &ma1, 1)); destAddr = br1.Get().GetMeshLocalEid(); SuccessOrQuit(router1.Get().SendMessageTo(*message, destAddr, nullptr, nullptr));