From bd47a31674886543472aacdf7eba3978fad73350 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 21 May 2026 08:41:01 -0700 Subject: [PATCH] [tlv] add `Tlv::AppendTlvWithValueFromMessage()` helper (#13120) This commit introduces a new helper method that allows appending a TLV by copying its value directly from a specified `OffsetRange` of another `Message`. This helper automatically handles formatting the TLV as an Extended TLV if the length exceeds 254 bytes, eliminating the need for manual length checks and TLV header construction at the call sites. Key changes: - Added `Tlv::AppendTlvWithValueFromMessage()`. - Refactored TLV header construction into a private helper `Tlv::AppendTlvHeader()` to share logic between `AppendTlv` variants and `StartTlv()`. - Updated `Commissioner::SendRelayTransmit()` and `JoinerRouter::HandleUdpReceive()` to use the new helper for `JoinerDtlsEncapsulation` TLVs. - Updated `TcatAgent::HandlePing()` to use the new helper, significantly simplifying the payload response generation. --- src/core/common/tlvs.cpp | 50 +++++++++++++++++++++--------- src/core/common/tlvs.hpp | 20 ++++++++++++ src/core/meshcop/commissioner.cpp | 9 +++--- src/core/meshcop/joiner_router.cpp | 8 ++--- src/core/meshcop/tcat_agent.cpp | 20 ++---------- 5 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/core/common/tlvs.cpp b/src/core/common/tlvs.cpp index 9e9db1b98..6844024a8 100644 --- a/src/core/common/tlvs.cpp +++ b/src/core/common/tlvs.cpp @@ -253,25 +253,38 @@ template Error Tlv::AppendUintTlv(Message &aMessage, uint8_t aType, ui Error Tlv::AppendEmptyTlv(Message &aMessage, uint8_t aType) { return AppendTlv(aMessage, aType, nullptr, 0); } -Error Tlv::AppendTlv(Message &aMessage, uint8_t aType, const void *aValue, uint16_t aLength) +Error Tlv::AppendTlvHeader(Message &aMessage, uint8_t aType, uint16_t aLength) { - Error error = kErrorNone; - ExtendedTlv extTlv; - Tlv tlv; + uint16_t size; + + union + { + Tlv tlv; + ExtendedTlv extTlv; + }; + + tlv.SetType(aType); if (aLength > kBaseTlvMaxLength) { - extTlv.SetType(aType); extTlv.SetLength(aLength); - SuccessOrExit(error = aMessage.Append(extTlv)); + size = sizeof(ExtendedTlv); } else { - tlv.SetType(aType); tlv.SetLength(static_cast(aLength)); - SuccessOrExit(error = aMessage.Append(tlv)); + size = sizeof(Tlv); } + return aMessage.AppendBytes(&tlv, size); +} + +Error Tlv::AppendTlv(Message &aMessage, uint8_t aType, const void *aValue, uint16_t aLength) +{ + Error error; + + SuccessOrExit(error = AppendTlvHeader(aMessage, aType, aLength)); + VerifyOrExit(aLength > 0); error = aMessage.AppendBytes(aValue, aLength); @@ -279,16 +292,25 @@ exit: return error; } +Error Tlv::AppendTlvWithValueFromMessage(Message &aMessage, + uint8_t aType, + const Message &aValueMsg, + const OffsetRange &aValueMsgOffsetRange) +{ + Error error; + + SuccessOrExit(error = AppendTlvHeader(aMessage, aType, aValueMsgOffsetRange.GetLength())); + error = aMessage.AppendBytesFromMessage(aValueMsg, aValueMsgOffsetRange); + +exit: + return error; +} + Error Tlv::StartTlv(Message &aMessage, uint8_t aType, Bookmark &aBookmark) { - Tlv tlv; - - tlv.SetType(aType); - tlv.SetLength(0); - aBookmark = aMessage.GetLength(); - return aMessage.Append(tlv); + return AppendTlvHeader(aMessage, aType, 0); } Error Tlv::AdjustTlv(Message &aMessage, Bookmark aBookmark) diff --git a/src/core/common/tlvs.hpp b/src/core/common/tlvs.hpp index 12a46835a..d7ed2cdad 100644 --- a/src/core/common/tlvs.hpp +++ b/src/core/common/tlvs.hpp @@ -598,6 +598,25 @@ public: */ static Error AppendTlv(Message &aMessage, uint8_t aType, const void *aValue, uint16_t aLength); + /** + * Appends a TLV with a given type and value read from another message. + * + * This method automatically formats the TLV as an Extended TLV if the length exceeds `kBaseTlvMaxLength` (254). + * + * @param[in] aMessage The message to append the TLV to. + * @param[in] aType The TLV type to append. + * @param[in] aValueMsg The message to read the TLV value from. + * @param[in] aValueMsgOffsetRange The offset range in @p aValueMsg to read the value from. + * + * @retval kErrorNone Successfully appended the TLV. + * @retval kErrorNoBufs Insufficient available buffers to grow the message. + * @retval kErrorParse Not enough bytes in @p aValueMsg to read the @p aValueMsgOffsetRange. + */ + static Error AppendTlvWithValueFromMessage(Message &aMessage, + uint8_t aType, + const Message &aValueMsg, + const OffsetRange &aValueMsgOffsetRange); + /** * Appends a TLV with a given type and value to a message. * @@ -820,6 +839,7 @@ protected: static const uint8_t kExtendedLength = 255; // Extended Length value. private: + static Error AppendTlvHeader(Message &aMessage, uint8_t aType, uint16_t aLength); static Error FindTlv(const Message &aMessage, uint8_t aType, void *aValue, uint16_t aLength); static Error FindStringTlv(const Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, char *aValue); static Error AppendStringTlv(Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, const char *aValue); diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 16d48af5f..dec9ee6b2 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -971,7 +971,7 @@ Error Commissioner::SendRelayTransmit(Message &aMessage, const Ip6::MessageInfo OT_UNUSED_VARIABLE(aMessageInfo); Error error = kErrorNone; - ExtendedTlv tlv; + OffsetRange offsetRange; OwnedPtr message; Kek kek; @@ -989,10 +989,9 @@ Error Commissioner::SendRelayTransmit(Message &aMessage, const Ip6::MessageInfo SuccessOrExit(error = Tlv::Append(*message, kek)); } - tlv.SetType(Tlv::kJoinerDtlsEncapsulation); - tlv.SetLength(aMessage.GetLength()); - SuccessOrExit(error = message->Append(tlv)); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, 0, aMessage.GetLength())); + offsetRange.InitFromMessageFullLength(aMessage); + SuccessOrExit( + error = Tlv::AppendTlvWithValueFromMessage(*message, Tlv::kJoinerDtlsEncapsulation, aMessage, offsetRange)); SuccessOrExit(error = Get().SendMessageToRloc(*message, mJoinerRloc)); message.Release(); diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp index 243635826..f61cbc237 100644 --- a/src/core/meshcop/joiner_router.cpp +++ b/src/core/meshcop/joiner_router.cpp @@ -118,7 +118,6 @@ void JoinerRouter::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &a { Error error; Coap::Message *message = nullptr; - ExtendedTlv tlv; uint16_t borderAgentRloc; OffsetRange offsetRange; @@ -134,11 +133,8 @@ void JoinerRouter::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &a SuccessOrExit(error = Tlv::Append(*message, Get().GetRloc16())); offsetRange.InitFromMessageOffsetToEnd(aMessage); - - tlv.SetType(Tlv::kJoinerDtlsEncapsulation); - tlv.SetLength(offsetRange.GetLength()); - SuccessOrExit(error = message->Append(tlv)); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); + SuccessOrExit( + error = Tlv::AppendTlvWithValueFromMessage(*message, Tlv::kJoinerDtlsEncapsulation, aMessage, offsetRange)); SuccessOrExit(error = Get().SendMessageToRloc(*message, borderAgentRloc)); diff --git a/src/core/meshcop/tcat_agent.cpp b/src/core/meshcop/tcat_agent.cpp index 74b80a1cf..67cafe2cd 100644 --- a/src/core/meshcop/tcat_agent.cpp +++ b/src/core/meshcop/tcat_agent.cpp @@ -693,26 +693,12 @@ Error TcatAgent::HandlePing(const Message &aIncomingMessage, const OffsetRange &aOffsetRange, bool &aResponse) { - Error error = kErrorNone; - ot::ExtendedTlv extTlv; - ot::Tlv tlv; + Error error; VerifyOrExit(aOffsetRange.GetLength() <= kPingPayloadMaxLength, error = kErrorParse); - if (aOffsetRange.GetLength() > ot::Tlv::kBaseTlvMaxLength) - { - extTlv.SetType(kTlvResponseWithPayload); - extTlv.SetLength(aOffsetRange.GetLength()); - SuccessOrExit(error = aOutgoingMessage.Append(extTlv)); - } - else - { - tlv.SetType(kTlvResponseWithPayload); - tlv.SetLength(static_cast(aOffsetRange.GetLength())); - SuccessOrExit(error = aOutgoingMessage.Append(tlv)); - } - - SuccessOrExit(error = aOutgoingMessage.AppendBytesFromMessage(aIncomingMessage, aOffsetRange)); + SuccessOrExit(error = Tlv::AppendTlvWithValueFromMessage(aOutgoingMessage, kTlvResponseWithPayload, + aIncomingMessage, aOffsetRange)); aResponse = true; exit: