[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 14:19:41 -05: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 Server::AppendRequestedTlvs(const Message &aRequest, Message &aResponse)
{ {
Error error; Error error;
OffsetRange offsetRange; TlvTypeListIterator iterator;
TlvTypeBitSet processedTlvs; uint8_t tlvType;
processedTlvs.Clear(); SuccessOrExit(error = iterator.InitForTypeListTlv(aRequest));
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRequest, Tlv::kTypeList, offsetRange)); while (iterator.ReadNextTlvType(tlvType) == kErrorNone)
while (!offsetRange.IsEmpty())
{ {
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)); SuccessOrExit(error = AppendDiagTlv(tlvType, aResponse));
} }
@@ -328,25 +314,14 @@ exit:
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
Error Server::AppendRequestedTlvsForTcat(const Message &aRequest, Message &aResponse, OffsetRange &aOffsetRange) Error Server::AppendRequestedTlvsForTcat(const Message &aRequest, Message &aResponse, OffsetRange &aOffsetRange)
{ {
Error error = kErrorNone; Error error = kErrorNone;
TlvTypeBitSet processedTlvs; 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 #if OPENTHREAD_FTD
switch (tlvType) switch (tlvType)
{ {
@@ -669,11 +644,12 @@ void Server::FreeAllRelatedAnswers(Coap::Message &aFirstAnswer)
void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Message &aRequest) void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Message &aRequest)
{ {
Coap::Message *answer; Coap::Message *answer;
Error error; Error error;
AnswerInfo info; AnswerInfo info;
OffsetRange offsetRange; uint8_t tlvType;
AnswerTlv answerTlv; TlvTypeListIterator iterator;
AnswerTlv answerTlv;
if (Tlv::Find<QueryIdTlv>(aRequest, info.mQueryId) == kErrorNone) 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 = 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) switch (tlvType)
{ {
case ChildTlv::kType: case ChildTlv::kType:
@@ -924,26 +895,19 @@ exit:
template <> void Server::HandleTmf<kUriDiagnosticReset>(Coap::Msg &aMsg) template <> void Server::HandleTmf<kUriDiagnosticReset>(Coap::Msg &aMsg)
{ {
uint16_t offset = 0; TlvTypeListIterator iterator;
uint8_t type; uint8_t tlvType;
Tlv tlv;
VerifyOrExit(aMsg.IsConfirmable()); VerifyOrExit(aMsg.IsConfirmable());
LogInfo("Received %s from %s", UriToString<kUriDiagnosticReset>(), LogInfo("Received %s from %s", UriToString<kUriDiagnosticReset>(),
aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString()); aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString());
SuccessOrExit(aMsg.mMessage.Read(aMsg.mMessage.GetOffset(), tlv)); SuccessOrExit(iterator.InitForTypeListTlv(aMsg.mMessage));
VerifyOrExit(tlv.GetType() == Tlv::kTypeList); while (iterator.ReadNextTlvType(tlvType) == kErrorNone)
offset = aMsg.mMessage.GetOffset() + sizeof(Tlv);
for (uint8_t i = 0; i < tlv.GetLength(); i++)
{ {
SuccessOrExit(aMsg.mMessage.Read(offset + i, type)); switch (tlvType)
switch (type)
{ {
case Tlv::kMacCounters: case Tlv::kMacCounters:
Get<Mac::Mac>().ResetCounters(); Get<Mac::Mac>().ResetCounters();
@@ -968,6 +932,51 @@ exit:
return; 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 #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 kMaxChildEntries = 398;
static constexpr uint16_t kAnswerMessageLengthThreshold = 800; 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 #if OPENTHREAD_FTD
struct AnswerInfo struct AnswerInfo
+2 -14
View File
@@ -630,21 +630,9 @@ private:
} OT_TOOL_PACKED_END; } OT_TOOL_PACKED_END;
/** /**
* Implements IPv6 Address List TLV generation and parsing. * Defines Type List TLV constants and types.
*/ */
OT_TOOL_PACKED_BEGIN typedef TlvInfo<Tlv::kTypeList> TypeListTlv;
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;
#if OPENTHREAD_FTD #if OPENTHREAD_FTD