[network-diag] introduce TlvTypeListIterator (#12672)

This commit introduces a new `TlvTypeListIterator` helper class in
the network diagnostic `Server` to simplify the parsing of Type List
TLVs. This iterator handles deduplication of requested TLV types
using a `BitSet` and centralizes the offset management and iteration
logic.

The iterator is now used in `AppendRequestedTlvs()`,
`AppendRequestedTlvsForTcat()`, `PrepareAndSendAnswers()`, and
`HandleTmf<kUriDiagnosticReset>()`, replacing redundant manual
iteration and deduplication code.

Additionally, the `TypeListTlv` definition is simplified to a
`typedef` of `TlvInfo`, as the dedicated class structure is no
longer needed.
This commit is contained in:
Abtin Keshavarzian
2026-03-11 12:19:41 -07:00
committed by GitHub
parent e3d03f4f14
commit ea94a2edf6
3 changed files with 86 additions and 74 deletions
+68 -59
View File
@@ -296,28 +296,14 @@ exit:
Error Server::AppendRequestedTlvs(const Message &aRequest, Message &aResponse)
{
Error error;
OffsetRange offsetRange;
TlvTypeBitSet processedTlvs;
Error error;
TlvTypeListIterator iterator;
uint8_t tlvType;
processedTlvs.Clear();
SuccessOrExit(error = iterator.InitForTypeListTlv(aRequest));
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRequest, Tlv::kTypeList, offsetRange));
while (!offsetRange.IsEmpty())
while (iterator.ReadNextTlvType(tlvType) == kErrorNone)
{
uint8_t tlvType;
SuccessOrExit(error = aRequest.Read(offsetRange, tlvType));
offsetRange.AdvanceOffset(sizeof(tlvType));
if (processedTlvs.Has(tlvType))
{
continue;
}
processedTlvs.Add(tlvType);
SuccessOrExit(error = AppendDiagTlv(tlvType, aResponse));
}
@@ -328,25 +314,14 @@ exit:
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
Error Server::AppendRequestedTlvsForTcat(const Message &aRequest, Message &aResponse, OffsetRange &aOffsetRange)
{
Error error = kErrorNone;
TlvTypeBitSet processedTlvs;
Error error = kErrorNone;
TlvTypeListIterator iterator;
uint8_t tlvType;
processedTlvs.Clear();
iterator.Init(aRequest, aOffsetRange);
while (!aOffsetRange.IsEmpty())
while (iterator.ReadNextTlvType(tlvType) == kErrorNone)
{
uint8_t tlvType;
SuccessOrExit(error = aRequest.Read(aOffsetRange, tlvType));
aOffsetRange.AdvanceOffset(sizeof(uint8_t));
if (processedTlvs.Has(tlvType))
{
continue;
}
processedTlvs.Add(tlvType);
#if OPENTHREAD_FTD
switch (tlvType)
{
@@ -669,11 +644,12 @@ void Server::FreeAllRelatedAnswers(Coap::Message &aFirstAnswer)
void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Message &aRequest)
{
Coap::Message *answer;
Error error;
AnswerInfo info;
OffsetRange offsetRange;
AnswerTlv answerTlv;
Coap::Message *answer;
Error error;
AnswerInfo info;
uint8_t tlvType;
TlvTypeListIterator iterator;
AnswerTlv answerTlv;
if (Tlv::Find<QueryIdTlv>(aRequest, info.mQueryId) == kErrorNone)
{
@@ -684,15 +660,10 @@ void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Messa
SuccessOrExit(error = AllocateAnswer(answer, info));
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRequest, Tlv::kTypeList, offsetRange));
SuccessOrExit(error = iterator.InitForTypeListTlv(aRequest));
while (!offsetRange.IsEmpty())
while (iterator.ReadNextTlvType(tlvType) == kErrorNone)
{
uint8_t tlvType;
SuccessOrExit(error = aRequest.Read(offsetRange, tlvType));
offsetRange.AdvanceOffset(sizeof(tlvType));
switch (tlvType)
{
case ChildTlv::kType:
@@ -924,26 +895,19 @@ exit:
template <> void Server::HandleTmf<kUriDiagnosticReset>(Coap::Msg &aMsg)
{
uint16_t offset = 0;
uint8_t type;
Tlv tlv;
TlvTypeListIterator iterator;
uint8_t tlvType;
VerifyOrExit(aMsg.IsConfirmable());
LogInfo("Received %s from %s", UriToString<kUriDiagnosticReset>(),
aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString());
SuccessOrExit(aMsg.mMessage.Read(aMsg.mMessage.GetOffset(), tlv));
SuccessOrExit(iterator.InitForTypeListTlv(aMsg.mMessage));
VerifyOrExit(tlv.GetType() == Tlv::kTypeList);
offset = aMsg.mMessage.GetOffset() + sizeof(Tlv);
for (uint8_t i = 0; i < tlv.GetLength(); i++)
while (iterator.ReadNextTlvType(tlvType) == kErrorNone)
{
SuccessOrExit(aMsg.mMessage.Read(offset + i, type));
switch (type)
switch (tlvType)
{
case Tlv::kMacCounters:
Get<Mac::Mac>().ResetCounters();
@@ -968,6 +932,51 @@ exit:
return;
}
//---------------------------------------------------------------------------------------------------------------------
// Server::TlvTypeListIterator
void Server::TlvTypeListIterator::Init(const Message &aMessage, const OffsetRange &aOffsetRange)
{
mMessage = &aMessage;
mOffsetRange = aOffsetRange;
mProcessedTlvs.Clear();
}
Error Server::TlvTypeListIterator::InitForTypeListTlv(const Message &aMessage)
{
Error error;
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Tlv::kTypeList, mOffsetRange));
mMessage = &aMessage;
mProcessedTlvs.Clear();
exit:
return error;
}
Error Server::TlvTypeListIterator::ReadNextTlvType(uint8_t &aTlvType)
{
Error error;
while (!mOffsetRange.IsEmpty())
{
SuccessOrExit(error = mMessage->Read(mOffsetRange, aTlvType));
mOffsetRange.AdvanceOffset(sizeof(uint8_t));
if (!mProcessedTlvs.Has(aTlvType))
{
mProcessedTlvs.Add(aTlvType);
error = kErrorNone;
ExitNow();
}
}
error = kErrorNotFound;
exit:
return error;
}
#if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
//---------------------------------------------------------------------------------------------------------------------
+16 -1
View File
@@ -122,7 +122,22 @@ private:
static constexpr uint16_t kMaxChildEntries = 398;
static constexpr uint16_t kAnswerMessageLengthThreshold = 800;
typedef BitSet<NumericLimits<uint8_t>::kMax + 1> TlvTypeBitSet; // A bitset to store TLV types.
class TlvTypeListIterator
{
// Iterates through a list of TLV types in a message (e.g., in a
// `TypeListTlv`), reading them one by one and skipping over any
// duplicate TLV type in the list.
public:
void Init(const Message &aMessage, const OffsetRange &aOffsetRange);
Error InitForTypeListTlv(const Message &aMessage);
Error ReadNextTlvType(uint8_t &aTlvType);
private:
const Message *mMessage;
OffsetRange mOffsetRange;
BitSet<NumericLimits<uint8_t>::kMax + 1> mProcessedTlvs;
};
#if OPENTHREAD_FTD
struct AnswerInfo
+2 -14
View File
@@ -630,21 +630,9 @@ private:
} OT_TOOL_PACKED_END;
/**
* Implements IPv6 Address List TLV generation and parsing.
* Defines Type List TLV constants and types.
*/
OT_TOOL_PACKED_BEGIN
class TypeListTlv : public Tlv, public TlvInfo<Tlv::kTypeList>
{
public:
/**
* Initializes the TLV.
*/
void Init(void)
{
SetType(kTypeList);
SetLength(sizeof(*this) - sizeof(Tlv));
}
} OT_TOOL_PACKED_END;
typedef TlvInfo<Tlv::kTypeList> TypeListTlv;
#if OPENTHREAD_FTD