diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index 461637233..e5cebc895 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -226,7 +226,9 @@ exit: Error NetworkDiagnostic::AppendChildTable(Message &aMessage) { Error error = kErrorNone; - uint16_t count = 0; + uint16_t count; + + VerifyOrExit(Get().IsRouterOrLeader()); count = Min(Get().GetNumChildren(Child::kInStateValid), kMaxChildEntries); @@ -273,179 +275,156 @@ exit: } #endif // OPENTHREAD_FTD -void NetworkDiagnostic::FillMacCountersTlv(MacCountersTlv &aTlv) +Error NetworkDiagnostic::AppendMacCounters(Message &aMessage) { + MacCountersTlv tlv; const otMacCounters &counters = Get().GetCounters(); - aTlv.SetIfInUnknownProtos(counters.mRxOther); - aTlv.SetIfInErrors(counters.mRxErrNoFrame + counters.mRxErrUnknownNeighbor + counters.mRxErrInvalidSrcAddr + - counters.mRxErrSec + counters.mRxErrFcs + counters.mRxErrOther); - aTlv.SetIfOutErrors(counters.mTxErrCca); - aTlv.SetIfInUcastPkts(counters.mRxUnicast); - aTlv.SetIfInBroadcastPkts(counters.mRxBroadcast); - aTlv.SetIfInDiscards(counters.mRxAddressFiltered + counters.mRxDestAddrFiltered + counters.mRxDuplicated); - aTlv.SetIfOutUcastPkts(counters.mTxUnicast); - aTlv.SetIfOutBroadcastPkts(counters.mTxBroadcast); - aTlv.SetIfOutDiscards(counters.mTxErrBusyChannel); + memset(&tlv, 0, sizeof(tlv)); + + tlv.Init(); + tlv.SetIfInUnknownProtos(counters.mRxOther); + tlv.SetIfInErrors(counters.mRxErrNoFrame + counters.mRxErrUnknownNeighbor + counters.mRxErrInvalidSrcAddr + + counters.mRxErrSec + counters.mRxErrFcs + counters.mRxErrOther); + tlv.SetIfOutErrors(counters.mTxErrCca); + tlv.SetIfInUcastPkts(counters.mRxUnicast); + tlv.SetIfInBroadcastPkts(counters.mRxBroadcast); + 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; - uint16_t offset = 0; - uint8_t type; + Error error; + uint16_t offset; + 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(aMessage, Get().GetExtAddress()); + break; + + case Tlv::kAddress16: + error = Tlv::Append(aMessage, Get().GetRloc16()); + break; + + case Tlv::kMode: + error = Tlv::Append(aMessage, Get().GetDeviceMode().Get()); + break; + + case Tlv::kTimeout: + VerifyOrExit(!Get().IsRxOnWhenIdle()); + error = Tlv::Append(aMessage, Get().GetTimeout()); + break; + + case Tlv::kLeaderData: + { + LeaderDataTlv tlv; + + tlv.Init(); + tlv.Set(Get().GetLeaderData()); + error = tlv.AppendTo(aMessage); + break; + } + + case Tlv::kNetworkData: + error = Tlv::Append(aMessage, Get().GetBytes(), + Get().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: - SuccessOrExit(error = Tlv::Append(aResponse, Get().GetExtAddress())); - break; - - case Tlv::kAddress16: - SuccessOrExit(error = Tlv::Append(aResponse, Get().GetRloc16())); - break; - - case Tlv::kMode: - SuccessOrExit(error = Tlv::Append(aResponse, Get().GetDeviceMode().Get())); - break; - - case Tlv::kTimeout: - if (!Get().IsRxOnWhenIdle()) + if (Radio::kSupportedChannelPages & (1 << page)) { - SuccessOrExit(error = Tlv::Append(aResponse, Get().GetTimeout())); + tlv.GetChannelPages()[length++] = page; } + } - break; + tlv.SetLength(length); + error = tlv.AppendTo(aMessage); + + break; + } #if OPENTHREAD_FTD - case Tlv::kConnectivity: - { - ConnectivityTlv tlv; - tlv.Init(); - Get().FillConnectivityTlv(tlv); - SuccessOrExit(error = tlv.AppendTo(aResponse)); - break; - } + case Tlv::kConnectivity: + { + ConnectivityTlv tlv; - case Tlv::kRoute: - { - RouteTlv tlv; + tlv.Init(); + Get().FillConnectivityTlv(tlv); + error = tlv.AppendTo(aMessage); + break; + } - tlv.Init(); - Get().FillRouteTlv(tlv); - SuccessOrExit(error = tlv.AppendTo(aResponse)); - break; - } -#endif + case Tlv::kRoute: + { + RouteTlv tlv; - case Tlv::kLeaderData: - { - LeaderDataTlv tlv; + tlv.Init(); + Get().FillRouteTlv(tlv); + SuccessOrExit(error = tlv.AppendTo(aMessage)); + break; + } - tlv.Init(); - tlv.Set(Get().GetLeaderData()); - SuccessOrExit(error = tlv.AppendTo(aResponse)); - break; - } + case Tlv::kChildTable: + error = AppendChildTable(aMessage); + break; - case Tlv::kNetworkData: - { - NetworkData::NetworkData &netData = Get(); + case Tlv::kMaxChildTimeout: + { + uint32_t maxTimeout; - SuccessOrExit(error = Tlv::Append(aResponse, netData.GetBytes(), netData.GetLength())); - break; - } + SuccessOrExit(Get().GetMaxChildTimeout(maxTimeout)); + error = Tlv::Append(aMessage, maxTimeout); + break; + } - case Tlv::kIp6AddressList: - SuccessOrExit(error = AppendIp6AddressList(aResponse)); - break; +#endif // OPENTHREAD_FTD - case Tlv::kMacCounters: - { - 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().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().GetMaxChildTimeout(maxTimeout) == kErrorNone) - { - SuccessOrExit(error = Tlv::Append(aResponse, maxTimeout)); - } - - break; - } -#endif - - default: - // Skip unrecognized TLV type. - break; - } - - offset += sizeof(type); + default: + break; } exit: @@ -455,61 +434,49 @@ exit: template <> void NetworkDiagnostic::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - Error error = kErrorNone; - Coap::Message *message = nullptr; - Tlv networkDiagnosticTlv; - Tmf::MessageInfo messageInfo(GetInstance()); + Error error = kErrorNone; + Coap::Message *response = nullptr; + Tmf::MessageInfo responseInfo(GetInstance()); VerifyOrExit(aMessage.IsPostRequest(), error = kErrorDrop); Log(kMessageReceive, kUriDiagnosticGetQuery, aMessageInfo.GetPeerAddr()); - SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), networkDiagnosticTlv)); - - VerifyOrExit(networkDiagnosticTlv.GetType() == Tlv::kTypeList, error = kErrorParse); - - // DIAG_GET.qry may be sent as a confirmable message. + // DIAG_GET.qry may be sent as a confirmable request. if (aMessage.IsConfirmable()) { IgnoreError(Get().SendEmptyAck(aMessage, aMessageInfo)); } - message = Get().NewConfirmablePostMessage(kUriDiagnosticGetAnswer); - VerifyOrExit(message != nullptr, error = kErrorNoBufs); + response = Get().NewConfirmablePostMessage(kUriDiagnosticGetAnswer); + VerifyOrExit(response != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = AppendRequestedTlvs(aMessage, *message, networkDiagnosticTlv)); + SuccessOrExit(error = AppendRequestedTlvs(aMessage, *response)); - PrepareMessageInfoForDest(aMessageInfo.GetPeerAddr(), messageInfo); - - SuccessOrExit(error = Get().SendMessage(*message, messageInfo)); + PrepareMessageInfoForDest(aMessageInfo.GetPeerAddr(), responseInfo); + SuccessOrExit(error = Get().SendMessage(*response, responseInfo)); exit: - FreeMessageOnError(message, error); + FreeMessageOnError(response, error); } template <> void NetworkDiagnostic::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - Error error = kErrorNone; - Coap::Message *message = nullptr; - Tlv networkDiagnosticTlv; + Error error = kErrorNone; + Coap::Message *response = nullptr; VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorDrop); Log(kMessageReceive, kUriDiagnosticGetRequest, aMessageInfo.GetPeerAddr()); - SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), networkDiagnosticTlv)); + response = Get().NewResponseMessage(aMessage); + VerifyOrExit(response != nullptr, error = kErrorNoBufs); - VerifyOrExit(networkDiagnosticTlv.GetType() == Tlv::kTypeList, error = kErrorParse); - - message = Get().NewResponseMessage(aMessage); - VerifyOrExit(message != nullptr, error = kErrorNoBufs); - - SuccessOrExit(error = AppendRequestedTlvs(aMessage, *message, networkDiagnosticTlv)); - - SuccessOrExit(error = Get().SendMessage(*message, aMessageInfo)); + SuccessOrExit(error = AppendRequestedTlvs(aMessage, *response)); + SuccessOrExit(error = Get().SendMessage(*response, aMessageInfo)); exit: - FreeMessageOnError(message, error); + FreeMessageOnError(response, error); } Error NetworkDiagnostic::SendDiagnosticReset(const Ip6::Address &aDestination, diff --git a/src/core/thread/network_diagnostic.hpp b/src/core/thread/network_diagnostic.hpp index f0fa72c64..40259443d 100644 --- a/src/core/thread/network_diagnostic.hpp +++ b/src/core/thread/network_diagnostic.hpp @@ -140,10 +140,11 @@ private: Coap::ResponseHandler aHandler = nullptr, void *aContext = nullptr); + Error AppendDiagTlv(uint8_t aTlvType, Message &aMessage); Error AppendIp6AddressList(Message &aMessage); + Error AppendMacCounters(Message &aMessage); Error AppendChildTable(Message &aMessage); - void FillMacCountersTlv(MacCountersTlv &aTlv); - Error AppendRequestedTlvs(const Message &aRequest, Message &aResponse, Tlv &aTlv); + Error AppendRequestedTlvs(const Message &aRequest, Message &aResponse); void PrepareMessageInfoForDest(const Ip6::Address &aDestination, Tmf::MessageInfo &aMessageInfo) const; static void HandleGetResponse(void *aContext,