mirror of
https://github.com/espressif/openthread.git
synced 2026-09-14 21:20:11 +00:00
[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:
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user