[tlvs] add Start/End/AdjustTlv methods for staged writing (#12250)

This commit introduces a new set of static methods to simplify
writing TLVs with variable lengths to a `Message`.

The new mechanism consists of three methods:
- `Tlv::StartTlv()`: Appends a placeholder TLV header and returns a
  `Bookmark`.
- `Tlv::AdjustTlv()`: Optionally promotes the TLV to an extended TLV
  if the length grows beyond the standard TLV limit. This is an
  optimization to avoid large copies within a message.
- `Tlv::EndTlv()`: Calculates the final length and updates the TLV
  header, promoting to an extended TLV if necessary.

This new set replaces the common but cumbersome pattern of manually
saving the start offset, appending data, and then back-patching the
length field.

The existing code is updated to use this new, simpler, and more
robust mechanism.

This commit also adds unit tests to validate the new functionality.
This commit is contained in:
Abtin Keshavarzian
2025-12-31 14:48:00 -08:00
committed by GitHub
parent b4ad385737
commit da1f792770
9 changed files with 327 additions and 187 deletions
+3 -8
View File
@@ -2795,8 +2795,7 @@ Error Mle::SendDiscoveryResponse(const Ip6::Address &aDestination, const Discove
{
Error error = kErrorNone;
TxMessage *message;
uint16_t startOffset;
Tlv tlv;
Tlv::Bookmark tlvBookmark;
MeshCoP::DiscoveryResponseTlv discoveryResponseTlv;
VerifyOrExit((message = NewMleMessage(kCommandDiscoveryResponse)) != nullptr, error = kErrorNoBufs);
@@ -2806,10 +2805,7 @@ Error Mle::SendDiscoveryResponse(const Ip6::Address &aDestination, const Discove
message->SetRadioType(aInfo.mRadioType);
#endif
tlv.SetType(Tlv::kDiscovery);
SuccessOrExit(error = message->Append(tlv));
startOffset = message->GetLength();
SuccessOrExit(error = Tlv::StartTlv(*message, Tlv::kDiscovery, tlvBookmark));
discoveryResponseTlv.Init();
discoveryResponseTlv.SetVersion(kThreadVersion);
@@ -2854,8 +2850,7 @@ Error Mle::SendDiscoveryResponse(const Ip6::Address &aDestination, const Discove
}
#endif
tlv.SetLength(static_cast<uint8_t>(message->GetLength() - startOffset));
message->Write(startOffset - sizeof(tlv), tlv);
SuccessOrExit(error = Tlv::EndTlv(*message, tlvBookmark));
SuccessOrExit(error = message->SendTo(aDestination));