[netdiag] define AnswerTlvValue to allow reuse (#12792)

This commit defines `AnswerTlvValue` to represent the value of an
Answer TLV, allowing it to be reused across different modules,
specifically `NetworkDiagnostic` and `HistoryTracker`.

The `AnswerTlv` implementation is also updated to use the
template-based `SimpleTlvInfo` pattern. This enables the use of
generic `Tlv::Append<AnswerTlv>()` and `Tlv::Find<AnswerTlv>()`
methods, which improves type safety and reduces manual TLV handling.
This commit is contained in:
Abtin Keshavarzian
2026-03-29 20:16:00 -07:00
committed by GitHub
parent 9bb7e37ff9
commit 771c430df0
8 changed files with 52 additions and 87 deletions
+14 -14
View File
@@ -511,7 +511,7 @@ void Server::SendAnswer(const Ip6::Address &aDestination, const Message &aReques
{
Error error = kErrorNone;
Coap::Message *answer = nullptr;
AnswerTlv answerTlv;
AnswerTlvValue answerTlvValue;
uint16_t queryId;
answer = Get<Tmf::Agent>().AllocateAndInitConfirmablePostMessage(kUriDiagnosticGetAnswer);
@@ -526,8 +526,8 @@ void Server::SendAnswer(const Ip6::Address &aDestination, const Message &aReques
SuccessOrExit(error = AppendRequestedTlvs(aRequest, *answer));
answerTlv.Init(0, AnswerTlv::kIsLast);
SuccessOrExit(answer->Append(answerTlv));
answerTlvValue.Init(0, AnswerTlvValue::kIsLast);
SuccessOrExit(error = Tlv::Append<AnswerTlv>(*answer, answerTlvValue));
error = Get<Tmf::Agent>().SendMessageAllowMulticastLoop(*answer, aDestination);
@@ -572,13 +572,13 @@ bool Server::IsLastAnswer(const Coap::Message &aAnswer) const
// Indicates whether `aAnswer` is the last one associated with
// the same query.
bool isLast = true;
AnswerTlv answerTlv;
bool isLast = true;
AnswerTlvValue answerTlvValue;
// If there is no Answer TLV, we assume it is the last answer.
SuccessOrExit(Tlv::FindTlv(aAnswer, answerTlv));
isLast = answerTlv.IsLast();
SuccessOrExit(Tlv::Find<AnswerTlv>(aAnswer, answerTlvValue));
isLast = answerTlvValue.IsLast();
exit:
return isLast;
@@ -608,7 +608,7 @@ void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Messa
AnswerInfo info;
uint8_t tlvType;
TlvTypeListIterator iterator;
AnswerTlv answerTlv;
AnswerTlvValue answerTlvValue;
if (Tlv::Find<QueryIdTlv>(aRequest, info.mQueryId) == kErrorNone)
{
@@ -642,8 +642,8 @@ void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Messa
SuccessOrExit(error = CheckAnswerLength(answer, info));
}
answerTlv.Init(info.mAnswerIndex, AnswerTlv::kIsLast);
SuccessOrExit(error = answer->Append(answerTlv));
answerTlvValue.Init(info.mAnswerIndex, AnswerTlvValue::kIsLast);
SuccessOrExit(error = Tlv::Append<AnswerTlv>(*answer, answerTlvValue));
SendNextAnswer(*info.mFirstAnswer, aDestination);
@@ -662,13 +662,13 @@ Error Server::CheckAnswerLength(Coap::Message *&aAnswer, AnswerInfo &aInfo)
// message. In this case, it will also allocate a new answer
// message.
Error error = kErrorNone;
AnswerTlv answerTlv;
Error error = kErrorNone;
AnswerTlvValue answerTlvValue;
VerifyOrExit(aAnswer->GetLength() >= kAnswerMessageLengthThreshold);
answerTlv.Init(aInfo.mAnswerIndex++, AnswerTlv::kMoreToFollow);
SuccessOrExit(error = aAnswer->Append(answerTlv));
answerTlvValue.Init(aInfo.mAnswerIndex++, AnswerTlvValue::kMoreToFollow);
SuccessOrExit(error = Tlv::Append<AnswerTlv>(*aAnswer, answerTlvValue));
error = AllocateAnswer(aAnswer, aInfo);
+2 -5
View File
@@ -197,13 +197,10 @@ void RouterNeighborTlv::InitFrom(const Router &aRouter)
#endif // OPENTHREAD_FTD
//---------------------------------------------------------------------------------------------------------------------
// AnswerTlv
// AnswerTlvValue
void AnswerTlv::Init(uint16_t aIndex, IsLastFlag aIsLastFlag)
void AnswerTlvValue::Init(uint16_t aIndex, IsLastFlag aIsLastFlag)
{
SetType(kAnswer);
SetLength(sizeof(*this) - sizeof(Tlv));
SetFlagsIndex((aIndex & kIndexMask) | (aIsLastFlag == kIsLast ? kIsLastFlag : 0));
}
+8 -3
View File
@@ -802,10 +802,10 @@ private:
} OT_TOOL_PACKED_END;
/**
* Implements Answer TLV generation and parsing.
* Represents an Answer TLV value.
*/
OT_TOOL_PACKED_BEGIN
class AnswerTlv : public Tlv, public TlvInfo<Tlv::kAnswer>
class AnswerTlvValue
{
public:
enum IsLastFlag : uint8_t
@@ -815,7 +815,7 @@ public:
};
/**
* Initializes the TLV.
* Initializes the TLV value.
*
* @param[in] aIndex The index value.
* @param[in] aIsLastFlag Indicates the `IsLastFlag` value.
@@ -847,6 +847,11 @@ private:
uint16_t mFlagsIndex;
} OT_TOOL_PACKED_END;
/**
* Defines Answer TLV constants and types.
*/
typedef SimpleTlvInfo<Tlv::kAnswer, AnswerTlvValue> AnswerTlv;
/**
* Represents the MLE Counters.
*/
+5 -5
View File
@@ -133,9 +133,9 @@ exit:
Error Client::ProcessAnswer(const Coap::Msg &aMsg)
{
Error error = kErrorFailed;
AnswerTlv answerTlv;
uint16_t queryId;
Error error = kErrorFailed;
AnswerTlvValue answerTlvValue;
uint16_t queryId;
VerifyOrExit(mActive);
VerifyOrExit(Get<Mle::Mle>().IsRoutingLocator(aMsg.mMessageInfo.GetPeerAddr()));
@@ -144,9 +144,9 @@ Error Client::ProcessAnswer(const Coap::Msg &aMsg)
SuccessOrExit(Tlv::Find<QueryIdTlv>(aMsg.mMessage, queryId));
VerifyOrExit(queryId == mQueryId);
SuccessOrExit(Tlv::FindTlv(aMsg.mMessage, answerTlv));
SuccessOrExit(Tlv::Find<AnswerTlv>(aMsg.mMessage, answerTlvValue));
if (answerTlv.GetIndex() != mAnswerIndex)
if (answerTlvValue.GetIndex() != mAnswerIndex)
{
Finalize(kErrorResponseTimeout);
ExitNow();
+11 -11
View File
@@ -93,13 +93,13 @@ bool Server::IsLastAnswer(const Coap::Message &aAnswer) const
// Indicates whether `aAnswer` is the last one associated with
// the same query.
bool isLast = true;
AnswerTlv answerTlv;
bool isLast = true;
AnswerTlvValue answerTlvValue;
// If there is no Answer TLV, we assume it is the last answer.
SuccessOrExit(Tlv::FindTlv(aAnswer, answerTlv));
isLast = answerTlv.IsLast();
SuccessOrExit(Tlv::Find<AnswerTlv>(aAnswer, answerTlvValue));
isLast = answerTlvValue.IsLast();
exit:
return isLast;
@@ -130,7 +130,7 @@ void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Messa
OffsetRange offsetRange;
Tlv::Info tlvInfo;
RequestTlv requestTlv;
AnswerTlv answerTlv;
AnswerTlvValue answerTlvValue;
if (Tlv::Find<QueryIdTlv>(aRequest, info.mQueryId) == kErrorNone)
{
@@ -171,8 +171,8 @@ void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Messa
}
}
answerTlv.Init(info.mAnswerIndex, /* aIsLast */ true);
SuccessOrExit(error = answer->Append(answerTlv));
answerTlvValue.Init(info.mAnswerIndex, AnswerTlvValue::kIsLast);
SuccessOrExit(error = Tlv::Append<AnswerTlv>(*answer, answerTlvValue));
SendNextAnswer(*info.mFirstAnswer, aDestination);
@@ -190,13 +190,13 @@ Error Server::CheckAnswerLength(Coap::Message *&aAnswer, AnswerInfo &aInfo)
// appending an Answer TLV with the current index to the message.
// In this case, it will also allocate a new answer message.
Error error = kErrorNone;
AnswerTlv answerTlv;
Error error = kErrorNone;
AnswerTlvValue answerTlvValue;
VerifyOrExit(aAnswer->GetLength() >= kAnswerMessageLengthThreshold);
answerTlv.Init(aInfo.mAnswerIndex++, /* aIsLast */ false);
SuccessOrExit(error = aAnswer->Append(answerTlv));
answerTlvValue.Init(aInfo.mAnswerIndex++, AnswerTlvValue::kMoreToFollow);
SuccessOrExit(error = Tlv::Append<AnswerTlv>(*aAnswer, answerTlvValue));
error = AllocateAnswer(aAnswer, aInfo);
-8
View File
@@ -38,14 +38,6 @@
namespace ot {
namespace HistoryTracker {
void AnswerTlv::Init(uint16_t aIndex, bool aIsLast)
{
SetType(kAnswer);
SetLength(sizeof(*this) - sizeof(Tlv));
SetFlagsIndex((aIndex & kIndexMask) | (aIsLast ? kIsLastFlag : 0));
}
void RequestTlv::Init(uint8_t aTlvType, uint16_t aNumEntries, uint32_t aMaxEntryAge)
{
SetType(kRequest);
+7 -36
View File
@@ -42,6 +42,7 @@
#include "common/encoding.hpp"
#include "common/tlvs.hpp"
#include "thread/network_diagnostic_tlvs.hpp"
#include "utils/history_tracker.hpp"
namespace ot {
@@ -72,44 +73,14 @@ public:
typedef UintTlvInfo<Tlv::kQueryId, uint16_t> QueryIdTlv;
/**
* Implements Answer TLV generation and parsing.
* Represents an Answer TLV value.
*/
OT_TOOL_PACKED_BEGIN
class AnswerTlv : public Tlv, public TlvInfo<Tlv::kAnswer>
{
public:
/**
* Initializes the TLV.
*
* @param[in] aIndex The index value.
* @param[in] aIsLast The "IsLast" flag value.
*/
void Init(uint16_t aIndex, bool aIsLast);
typedef NetworkDiagnostic::AnswerTlvValue AnswerTlvValue;
/**
* Indicates whether or not the "IsLast" flag is set
*
* @retval TRUE "IsLast" flag is set (this is the last answer for this query).
* @retval FALSE "IsLast" flag is not set (more answer messages are expected for this query).
*/
bool IsLast(void) const { return GetFlagsIndex() & kIsLastFlag; }
/**
* Gets the index.
*
* @returns The index.
*/
uint16_t GetIndex(void) const { return GetFlagsIndex() & kIndexMask; }
private:
static constexpr uint16_t kIsLastFlag = 1 << 15;
static constexpr uint16_t kIndexMask = 0x7fff;
uint16_t GetFlagsIndex(void) const { return BigEndian::HostSwap16(mFlagsIndex); }
void SetFlagsIndex(uint16_t aFlagsIndex) { mFlagsIndex = BigEndian::HostSwap16(aFlagsIndex); }
uint16_t mFlagsIndex;
} OT_TOOL_PACKED_END;
/**
* Defines Answer TLV constants and types.
*/
typedef SimpleTlvInfo<Tlv::kAnswer, AnswerTlvValue> AnswerTlv;
/**
* Implements Request TLV generation and parsing.
+5 -5
View File
@@ -258,9 +258,9 @@ Error MeshDiag::ProcessMessage(Coap::Message &aMessage, const Ip6::MessageInfo &
// check whether it is from the intended sender and matches
// the expected query ID and answer index.
Error error = kErrorFailed;
AnswerTlv answerTlv;
uint16_t queryId;
Error error = kErrorFailed;
AnswerTlvValue answerTlvValue;
uint16_t queryId;
VerifyOrExit(Get<Mle::Mle>().IsRoutingLocator(aMessageInfo.GetPeerAddr()));
VerifyOrExit(aMessageInfo.GetPeerAddr().GetIid().GetLocator() == aSenderRloc16);
@@ -268,9 +268,9 @@ Error MeshDiag::ProcessMessage(Coap::Message &aMessage, const Ip6::MessageInfo &
SuccessOrExit(Tlv::Find<QueryIdTlv>(aMessage, queryId));
VerifyOrExit(queryId == mExpectedQueryId);
SuccessOrExit(Tlv::FindTlv(aMessage, answerTlv));
SuccessOrExit(Tlv::Find<AnswerTlv>(aMessage, answerTlvValue));
if (answerTlv.GetIndex() != mExpectedAnswerIndex)
if (answerTlvValue.GetIndex() != mExpectedAnswerIndex)
{
Finalize(kErrorResponseTimeout);
ExitNow();