[net-diag] define AppendDiagTlv() (#8805)

This commit adds `AppendDiagTlv()` to append a dig TLV with a given
type to a `Message`. It also simplifies the `AppendRequestedTlvs()`
to directly parse the "Type List TLV".
This commit is contained in:
Abtin Keshavarzian
2023-02-27 11:43:25 -08:00
committed by GitHub
parent ea9533cdaf
commit 2b8779ec0b
2 changed files with 148 additions and 180 deletions
+145 -178
View File
@@ -226,7 +226,9 @@ exit:
Error NetworkDiagnostic::AppendChildTable(Message &aMessage) Error NetworkDiagnostic::AppendChildTable(Message &aMessage)
{ {
Error error = kErrorNone; Error error = kErrorNone;
uint16_t count = 0; uint16_t count;
VerifyOrExit(Get<Mle::MleRouter>().IsRouterOrLeader());
count = Min(Get<ChildTable>().GetNumChildren(Child::kInStateValid), kMaxChildEntries); count = Min(Get<ChildTable>().GetNumChildren(Child::kInStateValid), kMaxChildEntries);
@@ -273,179 +275,156 @@ exit:
} }
#endif // OPENTHREAD_FTD #endif // OPENTHREAD_FTD
void NetworkDiagnostic::FillMacCountersTlv(MacCountersTlv &aTlv) Error NetworkDiagnostic::AppendMacCounters(Message &aMessage)
{ {
MacCountersTlv tlv;
const otMacCounters &counters = Get<Mac::Mac>().GetCounters(); const otMacCounters &counters = Get<Mac::Mac>().GetCounters();
aTlv.SetIfInUnknownProtos(counters.mRxOther); memset(&tlv, 0, sizeof(tlv));
aTlv.SetIfInErrors(counters.mRxErrNoFrame + counters.mRxErrUnknownNeighbor + counters.mRxErrInvalidSrcAddr +
counters.mRxErrSec + counters.mRxErrFcs + counters.mRxErrOther); tlv.Init();
aTlv.SetIfOutErrors(counters.mTxErrCca); tlv.SetIfInUnknownProtos(counters.mRxOther);
aTlv.SetIfInUcastPkts(counters.mRxUnicast); tlv.SetIfInErrors(counters.mRxErrNoFrame + counters.mRxErrUnknownNeighbor + counters.mRxErrInvalidSrcAddr +
aTlv.SetIfInBroadcastPkts(counters.mRxBroadcast); counters.mRxErrSec + counters.mRxErrFcs + counters.mRxErrOther);
aTlv.SetIfInDiscards(counters.mRxAddressFiltered + counters.mRxDestAddrFiltered + counters.mRxDuplicated); tlv.SetIfOutErrors(counters.mTxErrCca);
aTlv.SetIfOutUcastPkts(counters.mTxUnicast); tlv.SetIfInUcastPkts(counters.mRxUnicast);
aTlv.SetIfOutBroadcastPkts(counters.mTxBroadcast); tlv.SetIfInBroadcastPkts(counters.mRxBroadcast);
aTlv.SetIfOutDiscards(counters.mTxErrBusyChannel); tlv.SetIfInDiscards(counters.mRxAddressFiltered + counters.mRxDestAddrFiltered + counters.mRxDuplicated);
tlv.SetIfOutUcastPkts(counters.mTxUnicast);
tlv.SetIfOutBroadcastPkts(counters.mTxBroadcast);
tlv.SetIfOutDiscards(counters.mTxErrBusyChannel);
return tlv.AppendTo(aMessage);
} }
Error NetworkDiagnostic::AppendRequestedTlvs(const Message &aRequest, Message &aResponse, Tlv &aTlv) Error NetworkDiagnostic::AppendRequestedTlvs(const Message &aRequest, Message &aResponse)
{ {
Error error = kErrorNone; Error error;
uint16_t offset = 0; uint16_t offset;
uint8_t type; uint16_t length;
uint16_t endOffset;
offset = aRequest.GetOffset() + sizeof(Tlv); SuccessOrExit(error = Tlv::FindTlvValueOffset(aRequest, Tlv::kTypeList, offset, length));
endOffset = offset + length;
for (uint32_t i = 0; i < aTlv.GetLength(); i++) for (; offset < endOffset; offset++)
{ {
SuccessOrExit(error = aRequest.Read(offset, type)); uint8_t tlvType;
switch (type) SuccessOrExit(error = aRequest.Read(offset, tlvType));
SuccessOrExit(error = AppendDiagTlv(tlvType, aResponse));
}
exit:
return error;
}
Error NetworkDiagnostic::AppendDiagTlv(uint8_t aTlvType, Message &aMessage)
{
Error error = kErrorNone;
switch (aTlvType)
{
case Tlv::kExtMacAddress:
error = Tlv::Append<ExtMacAddressTlv>(aMessage, Get<Mac::Mac>().GetExtAddress());
break;
case Tlv::kAddress16:
error = Tlv::Append<Address16Tlv>(aMessage, Get<Mle::MleRouter>().GetRloc16());
break;
case Tlv::kMode:
error = Tlv::Append<ModeTlv>(aMessage, Get<Mle::MleRouter>().GetDeviceMode().Get());
break;
case Tlv::kTimeout:
VerifyOrExit(!Get<Mle::MleRouter>().IsRxOnWhenIdle());
error = Tlv::Append<TimeoutTlv>(aMessage, Get<Mle::MleRouter>().GetTimeout());
break;
case Tlv::kLeaderData:
{
LeaderDataTlv tlv;
tlv.Init();
tlv.Set(Get<Mle::MleRouter>().GetLeaderData());
error = tlv.AppendTo(aMessage);
break;
}
case Tlv::kNetworkData:
error = Tlv::Append<NetworkDataTlv>(aMessage, Get<NetworkData::Leader>().GetBytes(),
Get<NetworkData::Leader>().GetLength());
break;
case Tlv::kIp6AddressList:
error = AppendIp6AddressList(aMessage);
break;
case Tlv::kMacCounters:
error = AppendMacCounters(aMessage);
break;
case Tlv::kChannelPages:
{
ChannelPagesTlv tlv;
uint8_t length = 0;
tlv.Init();
for (uint8_t page = 0; page < sizeof(Radio::kSupportedChannelPages) * CHAR_BIT; page++)
{ {
case Tlv::kExtMacAddress: if (Radio::kSupportedChannelPages & (1 << page))
SuccessOrExit(error = Tlv::Append<ExtMacAddressTlv>(aResponse, Get<Mac::Mac>().GetExtAddress()));
break;
case Tlv::kAddress16:
SuccessOrExit(error = Tlv::Append<Address16Tlv>(aResponse, Get<Mle::MleRouter>().GetRloc16()));
break;
case Tlv::kMode:
SuccessOrExit(error = Tlv::Append<ModeTlv>(aResponse, Get<Mle::MleRouter>().GetDeviceMode().Get()));
break;
case Tlv::kTimeout:
if (!Get<Mle::MleRouter>().IsRxOnWhenIdle())
{ {
SuccessOrExit(error = Tlv::Append<TimeoutTlv>(aResponse, Get<Mle::MleRouter>().GetTimeout())); tlv.GetChannelPages()[length++] = page;
} }
}
break; tlv.SetLength(length);
error = tlv.AppendTo(aMessage);
break;
}
#if OPENTHREAD_FTD #if OPENTHREAD_FTD
case Tlv::kConnectivity:
{
ConnectivityTlv tlv;
tlv.Init(); case Tlv::kConnectivity:
Get<Mle::MleRouter>().FillConnectivityTlv(tlv); {
SuccessOrExit(error = tlv.AppendTo(aResponse)); ConnectivityTlv tlv;
break;
}
case Tlv::kRoute: tlv.Init();
{ Get<Mle::MleRouter>().FillConnectivityTlv(tlv);
RouteTlv tlv; error = tlv.AppendTo(aMessage);
break;
}
tlv.Init(); case Tlv::kRoute:
Get<RouterTable>().FillRouteTlv(tlv); {
SuccessOrExit(error = tlv.AppendTo(aResponse)); RouteTlv tlv;
break;
}
#endif
case Tlv::kLeaderData: tlv.Init();
{ Get<RouterTable>().FillRouteTlv(tlv);
LeaderDataTlv tlv; SuccessOrExit(error = tlv.AppendTo(aMessage));
break;
}
tlv.Init(); case Tlv::kChildTable:
tlv.Set(Get<Mle::MleRouter>().GetLeaderData()); error = AppendChildTable(aMessage);
SuccessOrExit(error = tlv.AppendTo(aResponse)); break;
break;
}
case Tlv::kNetworkData: case Tlv::kMaxChildTimeout:
{ {
NetworkData::NetworkData &netData = Get<NetworkData::Leader>(); uint32_t maxTimeout;
SuccessOrExit(error = Tlv::Append<NetworkDataTlv>(aResponse, netData.GetBytes(), netData.GetLength())); SuccessOrExit(Get<Mle::MleRouter>().GetMaxChildTimeout(maxTimeout));
break; error = Tlv::Append<MaxChildTimeoutTlv>(aMessage, maxTimeout);
} break;
}
case Tlv::kIp6AddressList: #endif // OPENTHREAD_FTD
SuccessOrExit(error = AppendIp6AddressList(aResponse));
break;
case Tlv::kMacCounters: default:
{ break;
MacCountersTlv tlv;
memset(&tlv, 0, sizeof(tlv));
tlv.Init();
FillMacCountersTlv(tlv);
SuccessOrExit(error = tlv.AppendTo(aResponse));
break;
}
case Tlv::kBatteryLevel:
{
// Thread 1.1.1 Specification Section 10.11.4.2:
// Omitted if the battery level is not measured, is unknown or the device does not
// operate on battery power.
break;
}
case Tlv::kSupplyVoltage:
{
// Thread 1.1.1 Specification Section 10.11.4.3:
// Omitted if the supply voltage is not measured, is unknown.
break;
}
#if OPENTHREAD_FTD
case Tlv::kChildTable:
{
// Thread 1.1.1 Specification Section 10.11.2.2:
// If a Thread device is unable to supply a specific Diagnostic TLV, that TLV is omitted.
// Here only Leader or Router may have children.
if (Get<Mle::MleRouter>().IsRouterOrLeader())
{
SuccessOrExit(error = AppendChildTable(aResponse));
}
break;
}
#endif
case Tlv::kChannelPages:
{
uint8_t length = 0;
uint32_t pageMask = Radio::kSupportedChannelPages;
ChannelPagesTlv tlv;
tlv.Init();
for (uint8_t page = 0; page < sizeof(pageMask) * 8; page++)
{
if (pageMask & (1 << page))
{
tlv.GetChannelPages()[length++] = page;
}
}
tlv.SetLength(length);
SuccessOrExit(error = tlv.AppendTo(aResponse));
break;
}
#if OPENTHREAD_FTD
case Tlv::kMaxChildTimeout:
{
uint32_t maxTimeout;
if (Get<Mle::MleRouter>().GetMaxChildTimeout(maxTimeout) == kErrorNone)
{
SuccessOrExit(error = Tlv::Append<MaxChildTimeoutTlv>(aResponse, maxTimeout));
}
break;
}
#endif
default:
// Skip unrecognized TLV type.
break;
}
offset += sizeof(type);
} }
exit: exit:
@@ -455,61 +434,49 @@ exit:
template <> template <>
void NetworkDiagnostic::HandleTmf<kUriDiagnosticGetQuery>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) void NetworkDiagnostic::HandleTmf<kUriDiagnosticGetQuery>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{ {
Error error = kErrorNone; Error error = kErrorNone;
Coap::Message *message = nullptr; Coap::Message *response = nullptr;
Tlv networkDiagnosticTlv; Tmf::MessageInfo responseInfo(GetInstance());
Tmf::MessageInfo messageInfo(GetInstance());
VerifyOrExit(aMessage.IsPostRequest(), error = kErrorDrop); VerifyOrExit(aMessage.IsPostRequest(), error = kErrorDrop);
Log(kMessageReceive, kUriDiagnosticGetQuery, aMessageInfo.GetPeerAddr()); Log(kMessageReceive, kUriDiagnosticGetQuery, aMessageInfo.GetPeerAddr());
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), networkDiagnosticTlv)); // DIAG_GET.qry may be sent as a confirmable request.
VerifyOrExit(networkDiagnosticTlv.GetType() == Tlv::kTypeList, error = kErrorParse);
// DIAG_GET.qry may be sent as a confirmable message.
if (aMessage.IsConfirmable()) if (aMessage.IsConfirmable())
{ {
IgnoreError(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo)); IgnoreError(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo));
} }
message = Get<Tmf::Agent>().NewConfirmablePostMessage(kUriDiagnosticGetAnswer); response = Get<Tmf::Agent>().NewConfirmablePostMessage(kUriDiagnosticGetAnswer);
VerifyOrExit(message != nullptr, error = kErrorNoBufs); VerifyOrExit(response != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = AppendRequestedTlvs(aMessage, *message, networkDiagnosticTlv)); SuccessOrExit(error = AppendRequestedTlvs(aMessage, *response));
PrepareMessageInfoForDest(aMessageInfo.GetPeerAddr(), messageInfo); PrepareMessageInfoForDest(aMessageInfo.GetPeerAddr(), responseInfo);
SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*response, responseInfo));
SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
exit: exit:
FreeMessageOnError(message, error); FreeMessageOnError(response, error);
} }
template <> template <>
void NetworkDiagnostic::HandleTmf<kUriDiagnosticGetRequest>(Coap::Message &aMessage, void NetworkDiagnostic::HandleTmf<kUriDiagnosticGetRequest>(Coap::Message &aMessage,
const Ip6::MessageInfo &aMessageInfo) const Ip6::MessageInfo &aMessageInfo)
{ {
Error error = kErrorNone; Error error = kErrorNone;
Coap::Message *message = nullptr; Coap::Message *response = nullptr;
Tlv networkDiagnosticTlv;
VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorDrop); VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorDrop);
Log(kMessageReceive, kUriDiagnosticGetRequest, aMessageInfo.GetPeerAddr()); Log(kMessageReceive, kUriDiagnosticGetRequest, aMessageInfo.GetPeerAddr());
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), networkDiagnosticTlv)); response = Get<Tmf::Agent>().NewResponseMessage(aMessage);
VerifyOrExit(response != nullptr, error = kErrorNoBufs);
VerifyOrExit(networkDiagnosticTlv.GetType() == Tlv::kTypeList, error = kErrorParse); SuccessOrExit(error = AppendRequestedTlvs(aMessage, *response));
SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*response, aMessageInfo));
message = Get<Tmf::Agent>().NewResponseMessage(aMessage);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = AppendRequestedTlvs(aMessage, *message, networkDiagnosticTlv));
SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
exit: exit:
FreeMessageOnError(message, error); FreeMessageOnError(response, error);
} }
Error NetworkDiagnostic::SendDiagnosticReset(const Ip6::Address &aDestination, Error NetworkDiagnostic::SendDiagnosticReset(const Ip6::Address &aDestination,
+3 -2
View File
@@ -140,10 +140,11 @@ private:
Coap::ResponseHandler aHandler = nullptr, Coap::ResponseHandler aHandler = nullptr,
void *aContext = nullptr); void *aContext = nullptr);
Error AppendDiagTlv(uint8_t aTlvType, Message &aMessage);
Error AppendIp6AddressList(Message &aMessage); Error AppendIp6AddressList(Message &aMessage);
Error AppendMacCounters(Message &aMessage);
Error AppendChildTable(Message &aMessage); Error AppendChildTable(Message &aMessage);
void FillMacCountersTlv(MacCountersTlv &aTlv); Error AppendRequestedTlvs(const Message &aRequest, Message &aResponse);
Error AppendRequestedTlvs(const Message &aRequest, Message &aResponse, Tlv &aTlv);
void PrepareMessageInfoForDest(const Ip6::Address &aDestination, Tmf::MessageInfo &aMessageInfo) const; void PrepareMessageInfoForDest(const Ip6::Address &aDestination, Tmf::MessageInfo &aMessageInfo) const;
static void HandleGetResponse(void *aContext, static void HandleGetResponse(void *aContext,