[network-diagnostic] improve usability of Network Diagnostic API (#4619)

This commit improves usability of Network Diagnostic API by:

- Define native structures to represent various Network Diagnostic TLV
  values.

- Add facility function otThreadGetNextDiagnosticTlv to parse plain
  otMessage into structured data.

- Dump parsed DIAG_GET.ans/.rsp message in readable format for
  networkdiagnostic CLI command.
This commit is contained in:
kangping
2020-03-26 13:43:40 -07:00
committed by GitHub
parent 315a27bf08
commit e28608cd0b
16 changed files with 1076 additions and 122 deletions
+1
View File
@@ -148,6 +148,7 @@ LOCAL_SRC_FILES := \
src/core/api/logging_api.cpp \
src/core/api/message_api.cpp \
src/core/api/netdata_api.cpp \
src/core/api/netdiag_api.cpp \
src/core/api/random_crypto_api.cpp \
src/core/api/random_noncrypto_api.cpp \
src/core/api/server_api.cpp \
+1
View File
@@ -71,6 +71,7 @@ openthread_headers = \
message.h \
ncp.h \
netdata.h \
netdiag.h \
network_time.h \
random_crypto.h \
random_noncrypto.h \
+350
View File
@@ -0,0 +1,350 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief
* This file defines the OpenThread Network Diagnostic API.
*/
#ifndef OPENTHREAD_NETDIAG_H_
#define OPENTHREAD_NETDIAG_H_
#include <openthread/ip6.h>
#include <openthread/thread.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup api-thread-general
*
* @{
*
*/
/**
* Maximum Number of Network Diagnostic TLV Types to Request or Reset.
*/
#define OT_NETWORK_DIAGNOSTIC_TYPELIST_MAX_ENTRIES 19
/**
* Size of Network Diagnostic Child Table entry.
*/
#define OT_NETWORK_DIAGNOSTIC_CHILD_TABLE_ENTRY_SIZE 3
/**
* Initializer for otNetworkDiagIterator.
*/
#define OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT 0
enum
{
OT_NETWORK_DIAGNOSTIC_TLV_EXT_ADDRESS = 0, ///< MAC Extended Address TLV
OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS = 1, ///< Address16 TLV
OT_NETWORK_DIAGNOSTIC_TLV_MODE = 2, ///< Mode TLV
OT_NETWORK_DIAGNOSTIC_TLV_TIMEOUT = 3, ///< Timeout TLV (the maximum polling time period for SEDs)
OT_NETWORK_DIAGNOSTIC_TLV_CONNECTIVITY = 4, ///< Connectivity TLV
OT_NETWORK_DIAGNOSTIC_TLV_ROUTE = 5, ///< Route64 TLV
OT_NETWORK_DIAGNOSTIC_TLV_LEADER_DATA = 6, ///< Leader Data TLV
OT_NETWORK_DIAGNOSTIC_TLV_NETWORK_DATA = 7, ///< Network Data TLV
OT_NETWORK_DIAGNOSTIC_TLV_IP6_ADDR_LIST = 8, ///< IPv6 Address List TLV
OT_NETWORK_DIAGNOSTIC_TLV_MAC_COUNTERS = 9, ///< MAC Counters TLV
OT_NETWORK_DIAGNOSTIC_TLV_BATTERY_LEVEL = 14, ///< Battery Level TLV
OT_NETWORK_DIAGNOSTIC_TLV_SUPPLY_VOLTAGE = 15, ///< Supply Voltage TLV
OT_NETWORK_DIAGNOSTIC_TLV_CHILD_TABLE = 16, ///< Child Table TLV
OT_NETWORK_DIAGNOSTIC_TLV_CHANNEL_PAGES = 17, ///< Channel Pages TLV
OT_NETWORK_DIAGNOSTIC_TLV_TYPE_LIST = 18, ///< Type List TLV
OT_NETWORK_DIAGNOSTIC_TLV_MAX_CHILD_TIMEOUT = 19, ///< Max Child Timeout TLV
};
typedef uint16_t otNetworkDiagIterator; ///< Used to iterate through Network Diagnostic TLV.
/**
* This structure represents a Network Diagnostic Connectivity value.
*
*/
typedef struct otNetworkDiagConnectivity
{
/**
* The priority of the sender as a parent.
*/
int8_t mParentPriority;
/**
* The number of neighboring devices with which the sender shares a link of quality 3.
*/
uint8_t mLinkQuality3;
/**
* The number of neighboring devices with which the sender shares a link of quality 2.
*/
uint8_t mLinkQuality2;
/**
* The number of neighboring devices with which the sender shares a link of quality 1.
*/
uint8_t mLinkQuality1;
/**
* The sender's routing cost to the Leader.
*/
uint8_t mLeaderCost;
/**
* The most recent ID sequence number received by the sender.
*/
uint8_t mIdSequence;
/**
* The number of active Routers in the sender's Thread Network Partition.
*/
uint8_t mActiveRouters;
/**
* The guaranteed buffer capacity in octets for all IPv6 datagrams destined to a given SED. Optional.
*/
uint16_t mSedBufferSize;
/**
* The guaranteed queue capacity in number of IPv6 datagrams destined to a given SED. Optional.
*/
uint8_t mSedDatagramCount;
} otNetworkDiagConnectivity;
/**
* This structure represents a Network Diagnostic Route data.
*
*/
typedef struct otNetworkDiagRouteData
{
uint8_t mRouterId; ///< The Assigned Router ID.
uint8_t mLinkQualityOut : 2; ///< Link Quality Out.
uint8_t mLinkQualityIn : 2; ///< Link Quality In.
uint8_t mRouteCost : 4; ///< Routing Cost. Infinite routing cost is represented by value 0.
} otNetworkDiagRouteData;
/**
* This structure represents a Network Diagnostic Route TLV value.
*
*/
typedef struct otNetworkDiagRoute
{
/**
* The sequence number associated with the set of Router ID assignments in #mRouteData.
*/
uint8_t mIdSequence;
/**
* Number of elements in #mRouteData.
*/
uint8_t mRouteCount;
/**
* Link Quality and Routing Cost data.
*/
otNetworkDiagRouteData mRouteData[OT_NETWORK_MAX_ROUTER_ID + 1];
} otNetworkDiagRoute;
/**
* This structure represents a Network Diagnostic Mac Counters value.
*
* See <a href="https://www.ietf.org/rfc/rfc2863">RFC 2863</a> for definitions of member fields.
*
*/
typedef struct otNetworkDiagMacCounters
{
uint32_t mIfInUnknownProtos;
uint32_t mIfInErrors;
uint32_t mIfOutErrors;
uint32_t mIfInUcastPkts;
uint32_t mIfInBroadcastPkts;
uint32_t mIfInDiscards;
uint32_t mIfOutUcastPkts;
uint32_t mIfOutBroadcastPkts;
uint32_t mIfOutDiscards;
} otNetworkDiagMacCounters;
/**
* This structure represents a Network Diagnostic Child Table Entry.
*
*/
typedef struct otNetworkDiagChildEntry
{
/**
* Expected poll time expressed as 2^(Timeout-4) seconds.
*/
uint16_t mTimeout : 5;
/**
* Child ID from which an RLOC can be generated.
*/
uint16_t mChildId : 9;
/**
* Link mode bits.
*/
otLinkModeConfig mMode;
} otNetworkDiagChildEntry;
/**
* This structure represents a Network Diagnostic TLV.
*
*/
typedef struct otNetworkDiagTlv
{
/**
* The Network Diagnostic TLV type.
*/
uint8_t mType;
union
{
otExtAddress mExtAddress;
uint16_t mAddr16;
otLinkModeConfig mMode;
uint32_t mTimeout;
otNetworkDiagConnectivity mConnectivity;
otNetworkDiagRoute mRoute;
otLeaderData mLeaderData;
otNetworkDiagMacCounters mMacCounters;
uint8_t mBatteryLevel;
uint16_t mSupplyVoltage;
uint32_t mMaxChildTimeout;
struct
{
uint8_t mNetworkDataCount;
uint8_t mNetworkData[OT_NETWORK_BASE_TLV_MAX_LENGTH];
};
struct
{
uint8_t mIp6AddrCount;
otIp6Address mIp6AddrList[OT_NETWORK_BASE_TLV_MAX_LENGTH / OT_IP6_ADDRESS_SIZE];
};
struct
{
uint8_t mChildCount;
otNetworkDiagChildEntry
mChildTable[OT_NETWORK_BASE_TLV_MAX_LENGTH / OT_NETWORK_DIAGNOSTIC_CHILD_TABLE_ENTRY_SIZE];
};
struct
{
uint8_t mChannelPageCount;
uint8_t mChannelPages[OT_NETWORK_BASE_TLV_MAX_LENGTH];
};
};
} otNetworkDiagTlv;
/**
* This function gets the next Network Diagnostic TLV in the message.
*
* @param[in] aMessage A pointer to a message.
* @param[inout] aIterator A pointer to the Network Diagnostic iterator context. To get the first
* Network Diagnostic TLV it should be set to OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT.
* @param[out] aNetworkDiagTlv A pointer to where the Network Diagnostic TLV information will be placed.
*
* @retval OT_ERROR_NONE Successfully found the next Network Diagnostic TLV.
* @retval OT_ERROR_NOT_FOUND No subsequent Network Diagnostic TLV exists in the message.
* @retval OT_ERROR_PARSE Parsing the next Network Diagnostic failed.
*
* @Note A subsequent call to this function is allowed only when current return value is OT_ERROR_NONE.
*
*/
otError otThreadGetNextDiagnosticTlv(const otMessage * aMessage,
otNetworkDiagIterator *aIterator,
otNetworkDiagTlv * aNetworkDiagTlv);
/**
* This function pointer is called when Network Diagnostic Get response is received.
*
* @param[in] aMessage A pointer to the message buffer containing the received Network Diagnostic
* Get response payload.
* @param[in] aMessageInfo A pointer to the message info for @p aMessage.
* @param[in] aContext A pointer to application-specific context.
*
*/
typedef void (*otReceiveDiagnosticGetCallback)(otMessage *aMessage, const otMessageInfo *aMessageInfo, void *aContext);
/**
* This function registers a callback to provide received raw Network Diagnostic Get response payload.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aCallback A pointer to a function that is called when Network Diagnostic Get response
* is received or NULL to disable the callback.
* @param[in] aCallbackContext A pointer to application-specific context.
*
*/
void otThreadSetReceiveDiagnosticGetCallback(otInstance * aInstance,
otReceiveDiagnosticGetCallback aCallback,
void * aCallbackContext);
/**
* Send a Network Diagnostic Get request.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDestination A pointer to destination address.
* @param[in] aTlvTypes An array of Network Diagnostic TLV types.
* @param[in] aCount Number of types in aTlvTypes.
*
* @retval OT_ERROR_NONE Successfully queued the DIAG_GET.req.
* @retval OT_ERROR_NO_BUFS Insufficient message buffers available to send DIAG_GET.req.
*
*/
otError otThreadSendDiagnosticGet(otInstance * aInstance,
const otIp6Address *aDestination,
const uint8_t aTlvTypes[],
uint8_t aCount);
/**
* Send a Network Diagnostic Reset request.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDestination A pointer to destination address.
* @param[in] aTlvTypes An array of Network Diagnostic TLV types. Currently only Type 9 is allowed.
* @param[in] aCount Number of types in aTlvTypes
*
* @retval OT_ERROR_NONE Successfully queued the DIAG_RST.ntf.
* @retval OT_ERROR_NO_BUFS Insufficient message buffers available to send DIAG_RST.ntf.
*
*/
otError otThreadSendDiagnosticReset(otInstance * aInstance,
const otIp6Address *aDestination,
const uint8_t aTlvTypes[],
uint8_t aCount);
/**
* @}
*
*/
#ifdef __cplusplus
} // extern "C"
#endif
#endif // OPENTHREAD_NETDIAG_H_
+4 -54
View File
@@ -54,9 +54,11 @@ extern "C" {
*/
/**
* Maximum Number of Network Diagnostic TLV Types to Request or Reset.
* Maximum value length of Thread Base TLV.
*/
#define OT_NETWORK_DIAGNOSTIC_TYPELIST_MAX_ENTRIES 19
#define OT_NETWORK_BASE_TLV_MAX_LENGTH 254
#define OT_NETWORK_MAX_ROUTER_ID 62 ///< Maximum Router ID
/**
* Represents a Thread device role.
@@ -662,58 +664,6 @@ otError otThreadGetParentAverageRssi(otInstance *aInstance, int8_t *aParentRssi)
*/
otError otThreadGetParentLastRssi(otInstance *aInstance, int8_t *aLastRssi);
/**
* This function pointer is called when Network Diagnostic Get response is received.
*
* @param[in] aMessage A pointer to the message buffer containing the received Network Diagnostic
* Get response payload.
* @param[in] aMessageInfo A pointer to the message info for @p aMessage.
* @param[in] aContext A pointer to application-specific context.
*
*/
typedef void (*otReceiveDiagnosticGetCallback)(otMessage *aMessage, const otMessageInfo *aMessageInfo, void *aContext);
/**
* This function registers a callback to provide received raw Network Diagnostic Get response payload.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aCallback A pointer to a function that is called when Network Diagnostic Get response
* is received or NULL to disable the callback.
* @param[in] aCallbackContext A pointer to application-specific context.
*
*/
void otThreadSetReceiveDiagnosticGetCallback(otInstance * aInstance,
otReceiveDiagnosticGetCallback aCallback,
void * aCallbackContext);
/**
* Send a Network Diagnostic Get request.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDestination A pointer to destination address.
* @param[in] aTlvTypes An array of Network Diagnostic TLV types.
* @param[in] aCount Number of types in aTlvTypes
*
*/
otError otThreadSendDiagnosticGet(otInstance * aInstance,
const otIp6Address *aDestination,
const uint8_t aTlvTypes[],
uint8_t aCount);
/**
* Send a Network Diagnostic Reset request.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDestination A pointer to destination address.
* @param[in] aTlvTypes An array of Network Diagnostic TLV types. Currently only Type 9 is allowed.
* @param[in] aCount Number of types in aTlvTypes
*
*/
otError otThreadSendDiagnosticReset(otInstance * aInstance,
const otIp6Address *aDestination,
const uint8_t aTlvTypes[],
uint8_t aCount);
/**
* Get the IPv6 counters.
*
+19 -4
View File
@@ -972,12 +972,27 @@ If \<addr\> is unicast address, `Diagnostic Get` will be sent.
if \<addr\> is multicast address, `Diagnostic Query` will be sent.
```bash
> networkdiagnostic get fdde:ad00:beef:0:0:ff:fe00:f400 0 1 6
DIAG_GET.rsp: 00088e18ad17a24b0b740102f400060841dcb82d40bac63d
> networkdiagnostic get fdde:ad00:beef:0:0:ff:fe00:fc00 0 1 6
> DIAG_GET.rsp/ans: 00080e336e1c41494e1c01020c000608640b0f674074c503
Ext Address: '0e336e1c41494e1c'
Rloc16: 0x0c00
Leader Data:
PartitionId: 0x640b0f67
Weighting: 64
DataVersion: 116
StableDataVersion: 197
LeaderRouterId: 0x03
Done
> networkdiagnostic get ff02::1 0 1
DIAG_GET.rsp: 0008567e31a79667a8cc0102f000
DIAG_GET.rsp: 0008aaa7e584759e4e6401025400
> DIAG_GET.rsp/ans: 00080e336e1c41494e1c01020c00
Ext Address: '0e336e1c41494e1c'
Rloc16: 0x0c00
Done
DIAG_GET.rsp/ans: 00083efcdb7e3f9eb0f201021800
Ext Address: '3efcdb7e3f9eb0f2'
Rloc16: 0x1800
Done
```
### networkdiagnostic reset \<addr\> \<type\> ..
+245 -9
View File
@@ -94,6 +94,8 @@
using ot::Encoding::BigEndian::HostSwap16;
using ot::Encoding::BigEndian::HostSwap32;
#define INDENT_SIZE (4)
namespace ot {
namespace Cli {
@@ -3865,27 +3867,29 @@ exit:
AppendResult(error);
}
}
#endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
void Interpreter::HandleDiagnosticGetResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, void *aContext)
{
static_cast<Interpreter *>(aContext)->HandleDiagnosticGetResponse(
*static_cast<Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
*aMessage, *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
void Interpreter::HandleDiagnosticGetResponse(Message &aMessage, const Ip6::MessageInfo &)
void Interpreter::HandleDiagnosticGetResponse(const otMessage &aMessage, const Ip6::MessageInfo &)
{
uint8_t buf[16];
uint16_t bytesToPrint;
uint16_t bytesPrinted = 0;
uint16_t length = aMessage.GetLength() - aMessage.GetOffset();
uint8_t buf[16];
uint16_t bytesToPrint;
uint16_t bytesPrinted = 0;
uint16_t length = otMessageGetLength(&aMessage) - otMessageGetOffset(&aMessage);
otNetworkDiagTlv diagTlv;
otNetworkDiagIterator iterator = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT;
otError error = OT_ERROR_NONE;
mServer->OutputFormat("DIAG_GET.rsp/ans: ");
while (length > 0)
{
bytesToPrint = (length < sizeof(buf)) ? length : sizeof(buf);
aMessage.Read(aMessage.GetOffset() + bytesPrinted, bytesToPrint, buf);
otMessageRead(&aMessage, otMessageGetOffset(&aMessage) + bytesPrinted, buf, bytesToPrint);
OutputBytes(buf, static_cast<uint8_t>(bytesToPrint));
@@ -3895,9 +3899,241 @@ void Interpreter::HandleDiagnosticGetResponse(Message &aMessage, const Ip6::Mess
mServer->OutputFormat("\r\n");
AppendResult(OT_ERROR_NONE);
// Output Network Diagnostic TLV values in standard YAML format.
while ((error = otThreadGetNextDiagnosticTlv(&aMessage, &iterator, &diagTlv)) == OT_ERROR_NONE)
{
uint16_t column = 0;
switch (diagTlv.mType)
{
case OT_NETWORK_DIAGNOSTIC_TLV_EXT_ADDRESS:
mServer->OutputFormat("Ext Address: '");
OutputBytes(diagTlv.mExtAddress.m8, sizeof(diagTlv.mExtAddress.m8));
mServer->OutputFormat("'\r\n");
break;
case OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS:
mServer->OutputFormat("Rloc16: 0x%04x\r\n", diagTlv.mAddr16);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_MODE:
mServer->OutputFormat("Mode:\r\n");
OutputMode(diagTlv.mMode, column + INDENT_SIZE);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_TIMEOUT:
mServer->OutputFormat("Timeout: %u\r\n", diagTlv.mTimeout);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_CONNECTIVITY:
mServer->OutputFormat("Connectivity:\r\n");
OutputConnectivity(diagTlv.mConnectivity, column + INDENT_SIZE);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_ROUTE:
mServer->OutputFormat("Route:\r\n");
OutputRoute(diagTlv.mRoute, column + INDENT_SIZE);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_LEADER_DATA:
mServer->OutputFormat("Leader Data:\r\n");
OutputLeaderData(diagTlv.mLeaderData, column + INDENT_SIZE);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_NETWORK_DATA:
mServer->OutputFormat("Network Data: '");
OutputBytes(diagTlv.mNetworkData, diagTlv.mNetworkDataCount);
mServer->OutputFormat("'\r\n");
break;
case OT_NETWORK_DIAGNOSTIC_TLV_IP6_ADDR_LIST:
mServer->OutputFormat("IP6 Address List:\r\n");
for (uint16_t i = 0; i < diagTlv.mIp6AddrCount; ++i)
{
OutputSpaces(column + INDENT_SIZE);
mServer->OutputFormat("- ");
OutputIp6Address(diagTlv.mIp6AddrList[i]);
mServer->OutputFormat("\r\n");
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_MAC_COUNTERS:
mServer->OutputFormat("MAC Counters:\r\n");
OutputNetworkDiagMacCounters(diagTlv.mMacCounters, column + INDENT_SIZE);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_BATTERY_LEVEL:
mServer->OutputFormat("Battery Level: %u%%\r\n", diagTlv.mBatteryLevel);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_SUPPLY_VOLTAGE:
mServer->OutputFormat("Supply Voltage: %umV\r\n", diagTlv.mSupplyVoltage);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_CHILD_TABLE:
mServer->OutputFormat("Child Table:\r\n");
for (uint16_t i = 0; i < diagTlv.mChildCount; ++i)
{
OutputSpaces(column + INDENT_SIZE);
mServer->OutputFormat("- ");
OutputChildTableEntry(diagTlv.mChildTable[i], column + INDENT_SIZE + 2);
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_CHANNEL_PAGES:
mServer->OutputFormat("Channel Pages: '");
OutputBytes(diagTlv.mChannelPages, diagTlv.mChannelPageCount);
mServer->OutputFormat("'\r\n");
break;
case OT_NETWORK_DIAGNOSTIC_TLV_MAX_CHILD_TIMEOUT:
mServer->OutputFormat("Max Child Timeout: %u\r\n", diagTlv.mMaxChildTimeout);
break;
}
}
AppendResult(error == OT_ERROR_NOT_FOUND ? OT_ERROR_NONE : error);
}
void Interpreter::OutputSpaces(uint16_t aCount)
{
static const uint16_t kSpaceStrLen = 16;
char spaceStr[kSpaceStrLen + 1];
memset(spaceStr, ' ', kSpaceStrLen);
spaceStr[kSpaceStrLen] = '\0';
for (uint16_t i = 0; i < aCount; i += kSpaceStrLen)
{
uint16_t idx = (i + kSpaceStrLen <= aCount) ? 0 : (i + kSpaceStrLen - aCount);
mServer->OutputFormat(&spaceStr[idx]);
}
}
void Interpreter::OutputMode(const otLinkModeConfig &aMode, uint16_t aColumn)
{
OutputSpaces(aColumn);
mServer->OutputFormat("RxOnWhenIdle: %d\r\n", aMode.mRxOnWhenIdle);
OutputSpaces(aColumn);
mServer->OutputFormat("SecureDataRequests: %d\r\n", aMode.mSecureDataRequests);
OutputSpaces(aColumn);
mServer->OutputFormat("DeviceType: %d\r\n", aMode.mDeviceType);
OutputSpaces(aColumn);
mServer->OutputFormat("NetworkData: %d\r\n", aMode.mNetworkData);
}
void Interpreter::OutputConnectivity(const otNetworkDiagConnectivity &aConnectivity, uint16_t aColumn)
{
OutputSpaces(aColumn);
mServer->OutputFormat("ParentPriority: %d\r\n", aConnectivity.mParentPriority);
OutputSpaces(aColumn);
mServer->OutputFormat("LinkQuality3: %u\r\n", aConnectivity.mLinkQuality3);
OutputSpaces(aColumn);
mServer->OutputFormat("LinkQuality2: %u\r\n", aConnectivity.mLinkQuality2);
OutputSpaces(aColumn);
mServer->OutputFormat("LinkQuality1: %u\r\n", aConnectivity.mLinkQuality1);
OutputSpaces(aColumn);
mServer->OutputFormat("LeaderCost: %u\r\n", aConnectivity.mLeaderCost);
OutputSpaces(aColumn);
mServer->OutputFormat("IdSequence: %u\r\n", aConnectivity.mIdSequence);
OutputSpaces(aColumn);
mServer->OutputFormat("ActiveRouters: %u\r\n", aConnectivity.mActiveRouters);
OutputSpaces(aColumn);
mServer->OutputFormat("SedBufferSize: %u\r\n", aConnectivity.mSedBufferSize);
OutputSpaces(aColumn);
mServer->OutputFormat("SedDatagramCount: %u\r\n", aConnectivity.mSedDatagramCount);
}
void Interpreter::OutputRoute(const otNetworkDiagRoute &aRoute, uint16_t aColumn)
{
OutputSpaces(aColumn);
mServer->OutputFormat("IdSequence: %u\r\n", aRoute.mIdSequence);
OutputSpaces(aColumn);
mServer->OutputFormat("RouteData:\r\n");
aColumn += INDENT_SIZE;
for (uint16_t i = 0; i < aRoute.mRouteCount; ++i)
{
OutputSpaces(aColumn);
mServer->OutputFormat("- ");
OutputRouteData(aRoute.mRouteData[i], aColumn + 2);
}
}
void Interpreter::OutputRouteData(const otNetworkDiagRouteData &aRouteData, uint16_t aColumn)
{
mServer->OutputFormat("RouteId: 0x%02x\r\n", aRouteData.mRouterId);
OutputSpaces(aColumn);
mServer->OutputFormat("LinkQualityOut: %u\r\n", aRouteData.mLinkQualityOut);
OutputSpaces(aColumn);
mServer->OutputFormat("LinkQualityIn: %u\r\n", aRouteData.mLinkQualityIn);
OutputSpaces(aColumn);
mServer->OutputFormat("RouteCost: %u\r\n", aRouteData.mRouteCost);
}
void Interpreter::OutputLeaderData(const otLeaderData &aLeaderData, uint16_t aColumn)
{
OutputSpaces(aColumn);
mServer->OutputFormat("PartitionId: 0x%08x\r\n", aLeaderData.mPartitionId);
OutputSpaces(aColumn);
mServer->OutputFormat("Weighting: %u\r\n", aLeaderData.mWeighting);
OutputSpaces(aColumn);
mServer->OutputFormat("DataVersion: %u\r\n", aLeaderData.mDataVersion);
OutputSpaces(aColumn);
mServer->OutputFormat("StableDataVersion: %u\r\n", aLeaderData.mStableDataVersion);
OutputSpaces(aColumn);
mServer->OutputFormat("LeaderRouterId: 0x%02x\r\n", aLeaderData.mLeaderRouterId);
}
void Interpreter::OutputNetworkDiagMacCounters(const otNetworkDiagMacCounters &aMacCounters, uint16_t aColumn)
{
OutputSpaces(aColumn);
mServer->OutputFormat("IfInUnknownProtos: %u\r\n", aMacCounters.mIfInUnknownProtos);
OutputSpaces(aColumn);
mServer->OutputFormat("IfInErrors: %u\r\n", aMacCounters.mIfInErrors);
OutputSpaces(aColumn);
mServer->OutputFormat("IfOutErrors: %u\r\n", aMacCounters.mIfOutErrors);
OutputSpaces(aColumn);
mServer->OutputFormat("IfInUcastPkts: %u\r\n", aMacCounters.mIfInUcastPkts);
OutputSpaces(aColumn);
mServer->OutputFormat("IfInBroadcastPkts: %u\r\n", aMacCounters.mIfInBroadcastPkts);
OutputSpaces(aColumn);
mServer->OutputFormat("IfInDiscards: %u\r\n", aMacCounters.mIfInDiscards);
OutputSpaces(aColumn);
mServer->OutputFormat("IfOutUcastPkts: %u\r\n", aMacCounters.mIfOutUcastPkts);
OutputSpaces(aColumn);
mServer->OutputFormat("IfOutBroadcastPkts: %u\r\n", aMacCounters.mIfOutBroadcastPkts);
OutputSpaces(aColumn);
mServer->OutputFormat("IfOutDiscards: %u\r\n", aMacCounters.mIfOutDiscards);
}
void Interpreter::OutputChildTableEntry(const otNetworkDiagChildEntry &aChildEntry, uint16_t aColumn)
{
mServer->OutputFormat("ChildId: 0x%04x\r\n", aChildEntry.mChildId);
OutputSpaces(aColumn);
mServer->OutputFormat("Timeout: %u\r\n", aChildEntry.mTimeout);
OutputSpaces(aColumn);
mServer->OutputFormat("Mode:\r\n");
OutputMode(aChildEntry.mMode, aColumn + INDENT_SIZE);
}
#endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
void Interpreter::SetUserCommands(const otCliCommand *aCommands, uint8_t aLength)
{
mUserCommands = aCommands;
+12 -1
View File
@@ -359,7 +359,19 @@ private:
static void HandleActiveScanResult(otActiveScanResult *aResult, void *aContext);
static void HandleEnergyScanResult(otEnergyScanResult *aResult, void *aContext);
static void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx, void *aContext);
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
void HandleDiagnosticGetResponse(const otMessage &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleDiagnosticGetResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, void *aContext);
void OutputSpaces(uint16_t aCount);
void OutputMode(const otLinkModeConfig &aMode, uint16_t aColumn);
void OutputConnectivity(const otNetworkDiagConnectivity &aConnectivity, uint16_t aColumn);
void OutputRoute(const otNetworkDiagRoute &aRoute, uint16_t aColumn);
void OutputRouteData(const otNetworkDiagRouteData &aRouteData, uint16_t aColumn);
void OutputLeaderData(const otLeaderData &aLeaderData, uint16_t aColumn);
void OutputNetworkDiagMacCounters(const otNetworkDiagMacCounters &aMacCounters, uint16_t aColumn);
void OutputChildTableEntry(const otNetworkDiagChildEntry &aChildEntry, uint16_t aColumn);
#endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
static void HandleDnsResponse(void * aContext,
@@ -378,7 +390,6 @@ private:
void HandleActiveScanResult(otActiveScanResult *aResult);
void HandleEnergyScanResult(otEnergyScanResult *aResult);
void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx);
void HandleDiagnosticGetResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
void HandleDnsResponse(const char *aHostname, const Ip6::Address *aAddress, uint32_t aTtl, otError aResult);
#endif
+1
View File
@@ -96,6 +96,7 @@ set(COMMON_SOURCES
api/logging_api.cpp
api/message_api.cpp
api/netdata_api.cpp
api/netdiag_api.cpp
api/network_time_api.cpp
api/random_crypto_api.cpp
api/random_noncrypto_api.cpp
+1
View File
@@ -134,6 +134,7 @@ SOURCES_COMMON = \
api/logging_api.cpp \
api/message_api.cpp \
api/netdata_api.cpp \
api/netdiag_api.cpp \
api/network_time_api.cpp \
api/random_crypto_api.cpp \
api/random_noncrypto_api.cpp \
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the OpenThread Network Diagnostic API.
*/
#include "openthread-core-config.h"
#include <openthread/netdiag.h>
#include "common/instance.hpp"
using namespace ot;
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
otError otThreadGetNextDiagnosticTlv(const otMessage * aMessage,
otNetworkDiagIterator *aIterator,
otNetworkDiagTlv * aNetworkDiagTlv)
{
return NetworkDiagnostic::NetworkDiagnostic::GetNextDiagTlv(*static_cast<const Coap::Message *>(aMessage),
*aIterator, *aNetworkDiagTlv);
}
void otThreadSetReceiveDiagnosticGetCallback(otInstance * aInstance,
otReceiveDiagnosticGetCallback aCallback,
void * aCallbackContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<NetworkDiagnostic::NetworkDiagnostic>().SetReceiveDiagnosticGetCallback(aCallback, aCallbackContext);
}
otError otThreadSendDiagnosticGet(otInstance * aInstance,
const otIp6Address *aDestination,
const uint8_t aTlvTypes[],
uint8_t aCount)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkDiagnostic::NetworkDiagnostic>().SendDiagnosticGet(
*static_cast<const Ip6::Address *>(aDestination), aTlvTypes, aCount);
}
otError otThreadSendDiagnosticReset(otInstance * aInstance,
const otIp6Address *aDestination,
const uint8_t aTlvTypes[],
uint8_t aCount)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkDiagnostic::NetworkDiagnostic>().SendDiagnosticReset(
*static_cast<const Ip6::Address *>(aDestination), aTlvTypes, aCount);
}
#endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
-34
View File
@@ -38,7 +38,6 @@
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/locator-getters.hpp"
#include "common/logging.hpp"
#include "common/settings.hpp"
using namespace ot;
@@ -363,39 +362,6 @@ exit:
return error;
}
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
void otThreadSetReceiveDiagnosticGetCallback(otInstance * aInstance,
otReceiveDiagnosticGetCallback aCallback,
void * aCallbackContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<NetworkDiagnostic::NetworkDiagnostic>().SetReceiveDiagnosticGetCallback(aCallback, aCallbackContext);
}
otError otThreadSendDiagnosticGet(otInstance * aInstance,
const otIp6Address *aDestination,
const uint8_t aTlvTypes[],
uint8_t aCount)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkDiagnostic::NetworkDiagnostic>().SendDiagnosticGet(
*static_cast<const Ip6::Address *>(aDestination), aTlvTypes, aCount);
}
otError otThreadSendDiagnosticReset(otInstance * aInstance,
const otIp6Address *aDestination,
const uint8_t aTlvTypes[],
uint8_t aCount)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkDiagnostic::NetworkDiagnostic>().SendDiagnosticReset(
*static_cast<const Ip6::Address *>(aDestination), aTlvTypes, aCount);
}
#endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
otError otThreadSetEnabled(otInstance *aInstance, bool aEnabled)
{
otError error = OT_ERROR_NONE;
+2 -1
View File
@@ -37,6 +37,7 @@
#include "openthread-core-config.h"
#include <openthread/error.h>
#include <openthread/thread.h>
#include <openthread/platform/toolchain.h>
#include "common/encoding.hpp"
@@ -62,7 +63,7 @@ public:
*/
enum
{
kBaseTlvMaxLength = 254, ///< The maximum length of the Base TLV format.
kBaseTlvMaxLength = OT_NETWORK_BASE_TLV_MAX_LENGTH, ///< The maximum length of the Base TLV format.
};
/**
+1 -1
View File
@@ -142,7 +142,7 @@ enum
#else
kMaxRouteCost = 16, ///< MAX_ROUTE_COST
#endif
kMaxRouterId = 62, ///< MAX_ROUTER_ID
kMaxRouterId = OT_NETWORK_MAX_ROUTER_ID, ///< MAX_ROUTER_ID
kInvalidRouterId = kMaxRouterId + 1, ///< Value indicating incorrect Router Id
kMaxRouters = OPENTHREAD_CONFIG_MLE_MAX_ROUTERS, ///< MAX_ROUTERS
kMinDowngradeNeighbors = 7, ///< MIN_DOWNGRADE_NEIGHBORS
+311
View File
@@ -720,6 +720,317 @@ exit:
return;
}
static inline void ParseMode(const Mle::DeviceMode &aMode, otLinkModeConfig &aLinkModeConfig)
{
aLinkModeConfig.mRxOnWhenIdle = aMode.IsRxOnWhenIdle();
aLinkModeConfig.mSecureDataRequests = aMode.IsSecureDataRequest();
aLinkModeConfig.mDeviceType = aMode.IsFullThreadDevice();
aLinkModeConfig.mNetworkData = aMode.IsFullNetworkData();
}
static inline void ParseConnectivity(const ConnectivityTlv & aConnectivityTlv,
otNetworkDiagConnectivity &aNetworkDiagConnectivity)
{
aNetworkDiagConnectivity.mParentPriority = aConnectivityTlv.GetParentPriority();
aNetworkDiagConnectivity.mLinkQuality3 = aConnectivityTlv.GetLinkQuality3();
aNetworkDiagConnectivity.mLinkQuality2 = aConnectivityTlv.GetLinkQuality2();
aNetworkDiagConnectivity.mLinkQuality1 = aConnectivityTlv.GetLinkQuality1();
aNetworkDiagConnectivity.mLeaderCost = aConnectivityTlv.GetLeaderCost();
aNetworkDiagConnectivity.mIdSequence = aConnectivityTlv.GetIdSequence();
aNetworkDiagConnectivity.mActiveRouters = aConnectivityTlv.GetActiveRouters();
aNetworkDiagConnectivity.mSedBufferSize = aConnectivityTlv.GetSedBufferSize();
aNetworkDiagConnectivity.mSedDatagramCount = aConnectivityTlv.GetSedDatagramCount();
}
static void ParseRoute(const RouteTlv &aRouteTlv, otNetworkDiagRoute &aNetworkDiagRoute)
{
uint8_t routeCount = 0;
for (uint8_t i = 0; i <= Mle::kMaxRouterId; ++i)
{
if (!aRouteTlv.IsRouterIdSet(i))
{
continue;
}
aNetworkDiagRoute.mRouteData[routeCount].mRouterId = i;
aNetworkDiagRoute.mRouteData[routeCount].mRouteCost = aRouteTlv.GetRouteCost(routeCount);
aNetworkDiagRoute.mRouteData[routeCount].mLinkQualityIn = aRouteTlv.GetLinkQualityIn(routeCount);
aNetworkDiagRoute.mRouteData[routeCount].mLinkQualityOut = aRouteTlv.GetLinkQualityOut(routeCount);
++routeCount;
}
aNetworkDiagRoute.mRouteCount = routeCount;
aNetworkDiagRoute.mIdSequence = aRouteTlv.GetRouterIdSequence();
}
static inline void ParseLeaderData(const LeaderDataTlv &aLeaderDataTlv, otLeaderData &aLeaderData)
{
aLeaderData.mPartitionId = aLeaderDataTlv.GetPartitionId();
aLeaderData.mWeighting = aLeaderDataTlv.GetWeighting();
aLeaderData.mDataVersion = aLeaderDataTlv.GetDataVersion();
aLeaderData.mStableDataVersion = aLeaderDataTlv.GetStableDataVersion();
aLeaderData.mLeaderRouterId = aLeaderDataTlv.GetLeaderRouterId();
}
static inline void ParseMacCounters(const MacCountersTlv &aMacCountersTlv, otNetworkDiagMacCounters &aMacCounters)
{
aMacCounters.mIfInUnknownProtos = aMacCountersTlv.GetIfInUnknownProtos();
aMacCounters.mIfInErrors = aMacCountersTlv.GetIfInErrors();
aMacCounters.mIfOutErrors = aMacCountersTlv.GetIfOutErrors();
aMacCounters.mIfInUcastPkts = aMacCountersTlv.GetIfInUcastPkts();
aMacCounters.mIfInBroadcastPkts = aMacCountersTlv.GetIfInBroadcastPkts();
aMacCounters.mIfInDiscards = aMacCountersTlv.GetIfInDiscards();
aMacCounters.mIfOutUcastPkts = aMacCountersTlv.GetIfOutUcastPkts();
aMacCounters.mIfOutBroadcastPkts = aMacCountersTlv.GetIfOutBroadcastPkts();
aMacCounters.mIfOutDiscards = aMacCountersTlv.GetIfOutDiscards();
}
static inline void ParseChildEntry(const ChildTableEntry &aChildTableTlvEntry, otNetworkDiagChildEntry &aChildEntry)
{
aChildEntry.mTimeout = aChildTableTlvEntry.GetTimeout();
aChildEntry.mChildId = aChildTableTlvEntry.GetChildId();
ParseMode(aChildTableTlvEntry.GetMode(), aChildEntry.mMode);
}
otError NetworkDiagnostic::GetNextDiagTlv(const otMessage & aMessage,
otNetworkDiagIterator &aIterator,
otNetworkDiagTlv & aNetworkDiagTlv)
{
otError error = OT_ERROR_PARSE;
const Coap::Message &message = static_cast<const Coap::Message &>(aMessage);
uint16_t offset = message.GetOffset();
NetworkDiagnosticTlv tlv;
offset += aIterator;
while (true)
{
uint16_t tlvTotalLength;
VerifyOrExit(message.Read(offset, sizeof(tlv), &tlv) == sizeof(tlv), error = OT_ERROR_NOT_FOUND);
switch (tlv.GetType())
{
case NetworkDiagnosticTlv::kExtMacAddress:
{
ExtMacAddressTlv extMacAddr;
tlvTotalLength = sizeof(extMacAddr);
VerifyOrExit(message.Read(offset, tlvTotalLength, &extMacAddr) == tlvTotalLength);
VerifyOrExit(extMacAddr.IsValid());
aNetworkDiagTlv.mExtAddress = *extMacAddr.GetMacAddr();
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kAddress16:
{
Address16Tlv addr16;
tlvTotalLength = sizeof(addr16);
VerifyOrExit(message.Read(offset, tlvTotalLength, &addr16) == tlvTotalLength);
VerifyOrExit(addr16.IsValid());
aNetworkDiagTlv.mAddr16 = addr16.GetRloc16();
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kMode:
{
ModeTlv linkMode;
tlvTotalLength = sizeof(linkMode);
VerifyOrExit(message.Read(offset, tlvTotalLength, &linkMode) == tlvTotalLength);
VerifyOrExit(linkMode.IsValid());
ParseMode(linkMode.GetMode(), aNetworkDiagTlv.mMode);
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kTimeout:
{
TimeoutTlv timeout;
tlvTotalLength = sizeof(timeout);
VerifyOrExit(message.Read(offset, tlvTotalLength, &timeout) == tlvTotalLength);
VerifyOrExit(timeout.IsValid());
aNetworkDiagTlv.mTimeout = timeout.GetTimeout();
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kConnectivity:
{
ConnectivityTlv connectivity;
tlvTotalLength = sizeof(connectivity);
VerifyOrExit(message.Read(offset, tlvTotalLength, &connectivity) == tlvTotalLength);
VerifyOrExit(connectivity.IsValid());
ParseConnectivity(connectivity, aNetworkDiagTlv.mConnectivity);
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kRoute:
{
RouteTlv route;
tlvTotalLength = sizeof(tlv) + tlv.GetLength();
VerifyOrExit(tlvTotalLength <= sizeof(route));
VerifyOrExit(message.Read(offset, tlvTotalLength, &route) == tlvTotalLength);
VerifyOrExit(route.IsValid());
ParseRoute(route, aNetworkDiagTlv.mRoute);
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kLeaderData:
{
LeaderDataTlv leaderData;
tlvTotalLength = sizeof(leaderData);
VerifyOrExit(message.Read(offset, tlvTotalLength, &leaderData) == tlvTotalLength);
VerifyOrExit(leaderData.IsValid());
ParseLeaderData(leaderData, aNetworkDiagTlv.mLeaderData);
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kNetworkData:
{
NetworkDataTlv networkData;
tlvTotalLength = sizeof(tlv) + tlv.GetLength();
VerifyOrExit(tlvTotalLength <= sizeof(networkData));
VerifyOrExit(message.Read(offset, tlvTotalLength, &networkData) == tlvTotalLength);
VerifyOrExit(networkData.IsValid());
VerifyOrExit(sizeof(aNetworkDiagTlv.mNetworkData) >= networkData.GetLength());
memcpy(aNetworkDiagTlv.mNetworkData, networkData.GetNetworkData(), networkData.GetLength());
aNetworkDiagTlv.mNetworkDataCount = networkData.GetLength();
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kIp6AddressList:
{
Ip6AddressListTlv &ip6AddrList = static_cast<Ip6AddressListTlv &>(tlv);
VerifyOrExit(ip6AddrList.IsValid());
VerifyOrExit(sizeof(aNetworkDiagTlv.mIp6AddrList) >= ip6AddrList.GetLength());
VerifyOrExit(message.Read(offset + sizeof(ip6AddrList), ip6AddrList.GetLength(),
aNetworkDiagTlv.mIp6AddrList) == ip6AddrList.GetLength());
aNetworkDiagTlv.mIp6AddrCount = ip6AddrList.GetLength() / OT_IP6_ADDRESS_SIZE;
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kMacCounters:
{
MacCountersTlv macCounters;
tlvTotalLength = sizeof(MacCountersTlv);
VerifyOrExit(message.Read(offset, tlvTotalLength, &macCounters) == tlvTotalLength);
VerifyOrExit(macCounters.IsValid());
ParseMacCounters(macCounters, aNetworkDiagTlv.mMacCounters);
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kBatteryLevel:
{
BatteryLevelTlv batteryLevel;
tlvTotalLength = sizeof(BatteryLevelTlv);
VerifyOrExit(message.Read(offset, tlvTotalLength, &batteryLevel) == tlvTotalLength);
VerifyOrExit(batteryLevel.IsValid());
aNetworkDiagTlv.mBatteryLevel = batteryLevel.GetBatteryLevel();
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kSupplyVoltage:
{
SupplyVoltageTlv supplyVoltage;
tlvTotalLength = sizeof(SupplyVoltageTlv);
VerifyOrExit(message.Read(offset, tlvTotalLength, &supplyVoltage) == tlvTotalLength);
VerifyOrExit(supplyVoltage.IsValid());
aNetworkDiagTlv.mSupplyVoltage = supplyVoltage.GetSupplyVoltage();
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kChildTable:
{
ChildTableTlv &childTable = static_cast<ChildTableTlv &>(tlv);
VerifyOrExit(childTable.IsValid());
VerifyOrExit(childTable.GetNumEntries() <= OT_ARRAY_LENGTH(aNetworkDiagTlv.mChildTable));
for (uint8_t i = 0; i < childTable.GetNumEntries(); ++i)
{
ChildTableEntry childEntry;
VerifyOrExit(childTable.ReadEntry(childEntry, message, offset, i) == OT_ERROR_NONE);
ParseChildEntry(childEntry, aNetworkDiagTlv.mChildTable[i]);
}
aNetworkDiagTlv.mChildCount = childTable.GetNumEntries();
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kChannelPages:
{
VerifyOrExit(sizeof(aNetworkDiagTlv.mChannelPages) >= tlv.GetLength());
VerifyOrExit(message.Read(offset + sizeof(tlv), tlv.GetLength(), aNetworkDiagTlv.mChannelPages) ==
tlv.GetLength());
aNetworkDiagTlv.mChannelPageCount = tlv.GetLength();
ExitNow(error = OT_ERROR_NONE);
break;
}
case NetworkDiagnosticTlv::kMaxChildTimeout:
{
MaxChildTimeoutTlv maxChildTimeout;
tlvTotalLength = sizeof(maxChildTimeout);
VerifyOrExit(message.Read(offset, tlvTotalLength, &maxChildTimeout) == tlvTotalLength);
VerifyOrExit(maxChildTimeout.IsValid());
aNetworkDiagTlv.mMaxChildTimeout = maxChildTimeout.GetTimeout();
ExitNow(error = OT_ERROR_NONE);
break;
}
default:
// Ignore unrecognized Network Diagnostic TLV silently.
break;
}
// The actual TLV size may exceeds tlvTotalLength.
offset += tlv.GetSize();
}
exit:
if (error == OT_ERROR_NONE)
{
aNetworkDiagTlv.mType = tlv.GetType();
aIterator = offset - message.GetOffset();
}
return error;
}
} // namespace NetworkDiagnostic
} // namespace ot
+6
View File
@@ -36,6 +36,8 @@
#include "openthread-core-config.h"
#include <openthread/netdiag.h>
#include "coap/coap.hpp"
#include "common/locator.hpp"
#include "net/udp6.hpp"
@@ -98,6 +100,10 @@ public:
*/
otError SendDiagnosticReset(const Ip6::Address &aDestination, const uint8_t aTlvTypes[], uint8_t aCount);
static otError GetNextDiagTlv(const otMessage & aMessage,
otNetworkDiagIterator &aIterator,
otNetworkDiagTlv & aNetworkDiagTlv);
private:
otError AppendIp6AddressList(Message &aMessage);
otError AppendChildTable(Message &aMessage);
+39 -18
View File
@@ -82,23 +82,22 @@ public:
*/
enum Type
{
kExtMacAddress = 0, ///< Source Address TLV
kAddress16 = 1, ///< Address16 TLV
kMode = 2, ///< Mode TLV
kTimeout = 3, ///< Timeout TLV
kConnectivity = 4, ///< Connectivity TLV
kRoute = 5, ///< Routing-Table TLV
kLeaderData = 6, ///< Leader Data TLV
kNetworkData = 7, ///< Network Data TLV
kIp6AddressList = 8, ///< Ip6 Address List TLV
kMacCounters = 9, ///< Mac Counters TLV
kBatteryLevel = 14, ///< Battery Level TLV
kSupplyVoltage = 15, ///< Supply Voltage TLV
kChildTable = 16, ///< Child Table TLV
kChannelPages = 17, ///< Channel Pages TLV
kTypeList = 18, ///< Type List TLV
kMaxChildTimeout = 19, ///< Max Child Timeout TLV
kInvalid = 255,
kExtMacAddress = OT_NETWORK_DIAGNOSTIC_TLV_EXT_ADDRESS,
kAddress16 = OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS,
kMode = OT_NETWORK_DIAGNOSTIC_TLV_MODE,
kTimeout = OT_NETWORK_DIAGNOSTIC_TLV_TIMEOUT,
kConnectivity = OT_NETWORK_DIAGNOSTIC_TLV_CONNECTIVITY,
kRoute = OT_NETWORK_DIAGNOSTIC_TLV_ROUTE,
kLeaderData = OT_NETWORK_DIAGNOSTIC_TLV_LEADER_DATA,
kNetworkData = OT_NETWORK_DIAGNOSTIC_TLV_NETWORK_DATA,
kIp6AddressList = OT_NETWORK_DIAGNOSTIC_TLV_IP6_ADDR_LIST,
kMacCounters = OT_NETWORK_DIAGNOSTIC_TLV_MAC_COUNTERS,
kBatteryLevel = OT_NETWORK_DIAGNOSTIC_TLV_BATTERY_LEVEL,
kSupplyVoltage = OT_NETWORK_DIAGNOSTIC_TLV_SUPPLY_VOLTAGE,
kChildTable = OT_NETWORK_DIAGNOSTIC_TLV_CHILD_TABLE,
kChannelPages = OT_NETWORK_DIAGNOSTIC_TLV_CHANNEL_PAGES,
kTypeList = OT_NETWORK_DIAGNOSTIC_TLV_TYPE_LIST,
kMaxChildTimeout = OT_NETWORK_DIAGNOSTIC_TLV_MAX_CHILD_TIMEOUT,
};
/**
@@ -919,6 +918,15 @@ public:
SetLength(sizeof(*this) - sizeof(NetworkDiagnosticTlv));
}
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return !IsExtended() && (GetLength() % OT_IP6_ADDRESS_SIZE == 0); }
/**
* This method returns a pointer to the IPv6 address entry.
*
@@ -1388,7 +1396,7 @@ public:
* @retval OT_ERROR_NOT_FOUND No such entry is found.
* @retval OT_ERROR_NONE Successfully read the entry.
*/
otError ReadEntry(ChildTableEntry &aEntry, Message &aMessage, uint16_t aOffset, uint8_t aIndex) const
otError ReadEntry(ChildTableEntry &aEntry, const Message &aMessage, uint16_t aOffset, uint8_t aIndex) const
{
return (aIndex < GetNumEntries() &&
aMessage.Read(aOffset + sizeof(ChildTableTlv) + (aIndex * sizeof(ChildTableEntry)),
@@ -1417,6 +1425,19 @@ public:
SetLength(sizeof(*this) - sizeof(NetworkDiagnosticTlv));
}
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const
{
// At least one channel page must be included.
return GetLength() >= 1;
}
/**
* This method returns a pointer to the list of Channel Pages.
*