Support network diagnostic feature. (#652)

* support network diagnostic

* add network diagnostic THCI implementation
This commit is contained in:
Buke Po
2016-09-23 21:06:08 -07:00
committed by Jonathan Hui
parent 61dcf6cf58
commit d283c29f23
22 changed files with 2311 additions and 17 deletions
+3
View File
@@ -126,6 +126,9 @@ void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat
case kLogRegionMeshCoP:
LOG_PRINTF("MCOP ");
break;
case kLogRegionNetDiag:
LOG_PRINTF("NDG ");
}
va_start(args, aFormat);
+2
View File
@@ -139,6 +139,8 @@ typedef enum ThreadError
#define OT_MASTER_KEY_SIZE 16 ///< Size of the Thread Master Key (bytes)
#define OT_NUM_NETDIAG_TLV_TYPES 18 ///< Number of Network Diagnostic TLV types
/**
* This structure represents a Thread Master Key.
*
+20
View File
@@ -2155,6 +2155,26 @@ ThreadError otBindUdpSocket(otUdpSocket *aSocket, otSockAddr *aSockName);
*/
ThreadError otSendUdp(otUdpSocket *aSocket, otMessage aMessage, const otMessageInfo *aMessageInfo);
/**
* Send a Network Diagnostic Get request
*
* @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
*/
ThreadError otSendDiagnosticGet(otInstance *aInstance, otIp6Address *aDestination, 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
*/
ThreadError otSendDiagnosticReset(otInstance *aInstance, otIp6Address *aDestination, uint8_t aTlvTypes[],
uint8_t aCount);
/**
* @}
*
+1
View File
@@ -87,6 +87,7 @@ typedef enum otLogRegion
kLogRegionMem = 8, ///< Memory
kLogRegionNcp = 9, ///< NCP
kLogRegionMeshCoP = 10, ///< Mesh Commissioning Protocol
kLogRegionNetDiag = 11, ///< Network Diagnostic
} otLogRegion;
/**
+34
View File
@@ -103,6 +103,7 @@ const struct Command Interpreter::sCommands[] =
{ "masterkey", &Interpreter::ProcessMasterKey },
{ "mode", &Interpreter::ProcessMode },
{ "netdataregister", &Interpreter::ProcessNetworkDataRegister },
{ "networkdiagnostic", &Interpreter::ProcessNetworkDiagnostic },
{ "networkidtimeout", &Interpreter::ProcessNetworkIdTimeout },
{ "networkname", &Interpreter::ProcessNetworkName },
{ "panid", &Interpreter::ProcessPanId },
@@ -2449,5 +2450,38 @@ exit:
return;
}
void Interpreter::ProcessNetworkDiagnostic(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
struct otIp6Address address;
uint8_t index = 2;
uint8_t tlvTypes[OT_NUM_NETDIAG_TLV_TYPES];
uint8_t count = 0;
VerifyOrExit(argc > 1 + 1, error = kThreadError_Parse);
SuccessOrExit(error = otIp6AddressFromString(argv[1], &address));
while (index < argc && count < sizeof(tlvTypes))
{
long value;
SuccessOrExit(error = ParseLong(argv[index], value));
tlvTypes[count++] = static_cast<uint8_t>(value);
index++;
}
if (strcmp(argv[0], "get") == 0)
{
otSendDiagnosticGet(mInstance, &address, tlvTypes, count);
}
else if (strcmp(argv[0], "reset") == 0)
{
otSendDiagnosticReset(mInstance, &address, tlvTypes, count);
}
exit:
AppendResult(error);
}
} // namespace Cli
} // namespace Thread
+1
View File
@@ -175,6 +175,7 @@ private:
void ProcessMasterKey(int argc, char *argv[]);
void ProcessMode(int argc, char *argv[]);
void ProcessNetworkDataRegister(int argc, char *argv[]);
void ProcessNetworkDiagnostic(int argc, char *argv[]);
void ProcessNetworkIdTimeout(int argc, char *argv[]);
void ProcessNetworkName(int argc, char *argv[]);
void ProcessPanId(int argc, char *argv[]);
+4
View File
@@ -79,6 +79,8 @@ libopenthread_a_SOURCES = \
thread/network_data_local.cpp \
thread/network_data_leader.cpp \
thread/panid_query_server.cpp \
thread/network_diag.cpp \
thread/network_diag_tlvs.cpp \
thread/thread_netif.cpp \
thread/thread_tlvs.cpp \
$(NULL)
@@ -163,6 +165,8 @@ noinst_HEADERS = \
thread/network_data_local.hpp \
thread/network_data_tlvs.hpp \
thread/panid_query_server.hpp \
thread/network_diag.hpp \
thread/network_diag_tlvs.hpp \
thread/thread_netif.hpp \
thread/thread_tlvs.hpp \
thread/thread_uris.hpp \
+51
View File
@@ -1021,6 +1021,57 @@ extern "C" {
#define otDumpDebgMem(aId, aBuf, aLength)
#endif
/**
* @def otLogCritNetDiag
*
* This method generates a log with level critical for the NETDIAG region.
*
* @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification.
*
*/
/**
* @def otLogWarnNetDiag
*
* This method generates a log with level warning for the NETDIAG region.
*
* @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification.
*
*/
/**
* @def otLogInfoNetDiag
*
* This method generates a log with level info for the NETDIAG region.
*
* @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification.
*
*/
/**
* @def otLogDebgNetDiag
*
* This method generates a log with level debug for the NETDIAG region.
*
* @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification.
*
*/
#ifdef OPENTHREAD_CONFIG_LOG_NETDIAG
#define otLogCritNetDiag(aFormat, ...) otLogCrit(kLogRegionNetDiag, aFormat, ## __VA_ARGS__)
#define otLogWarnNetDiag(aFormat, ...) otLogWarn(kLogRegionNetDiag, aFormat, ## __VA_ARGS__)
#define otLogInfoNetDiag(aFormat, ...) otLogInfo(kLogRegionNetDiag, aFormat, ## __VA_ARGS__)
#define otLogDebgNetDiag(aFormat, ...) otLogDebg(kLogRegionNetDiag, aFormat, ## __VA_ARGS__)
#else
#define otLogCritNetDiag(aFormat, ...)
#define otLogWarnNetDiag(aFormat, ...)
#define otLogInfoNetDiag(aFormat, ...)
#define otLogDebgNetDiag(aFormat, ...)
#endif
/**
* This method dumps bytes to the log in a human-readable fashion.
*
@@ -249,5 +249,14 @@
*/
#define OPENTHREAD_CONFIG_LOG_MEM
/**
* @def OPENTHREAD_CONFIG_LOG_NETDIAG
*
* Define to enable network diagnostic logging.
*
*/
#define OPENTHREAD_CONFIG_LOG_NETDIAG
#endif // OPENTHREAD_CORE_DEFAULT_CONFIG_H_
+15
View File
@@ -957,6 +957,21 @@ exit:
#endif
ThreadError otSendDiagnosticGet(otInstance *aInstance, otIp6Address *aDestination, uint8_t aTlvTypes[], uint8_t aCount)
{
(void)aInstance;
return sThreadNetif->GetNetworkDiagnostic().SendDiagnosticGet(*static_cast<Ip6::Address *>(aDestination), aTlvTypes,
aCount);
}
ThreadError otSendDiagnosticReset(otInstance *aInstance, otIp6Address *aDestination, uint8_t aTlvTypes[],
uint8_t aCount)
{
(void)aInstance;
return sThreadNetif->GetNetworkDiagnostic().SendDiagnosticReset(*static_cast<Ip6::Address *>(aDestination), aTlvTypes,
aCount);
}
void otInstanceFinalize(otInstance *aInstance)
{
// Ensure we are disabled
+8 -3
View File
@@ -792,15 +792,20 @@ ThreadError Mle::AppendLeaderData(Message &aMessage)
return aMessage.Append(&mLeaderData, sizeof(mLeaderData));
}
void Mle::FillNetworkDataTlv(NetworkDataTlv &aTlv, bool aStableOnly)
{
uint8_t length;
mNetworkData.GetNetworkData(aStableOnly, aTlv.GetNetworkData(), length);
aTlv.SetLength(length);
}
ThreadError Mle::AppendNetworkData(Message &aMessage, bool aStableOnly)
{
ThreadError error = kThreadError_None;
NetworkDataTlv tlv;
uint8_t length;
tlv.Init();
mNetworkData.GetNetworkData(aStableOnly, tlv.GetNetworkData(), length);
tlv.SetLength(length);
FillNetworkDataTlv(tlv, aStableOnly);
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(Tlv) + tlv.GetLength()));
+9
View File
@@ -662,6 +662,15 @@ public:
*/
static bool IsActiveRouter(uint16_t aRloc16) { return GetChildId(aRloc16) == 0; }
/**
* This method fills the NetworkDataTlv.
*
* @param[out] aTlv The NetworkDataTlv.
* @param[in] aStableOnly TRUE to append stable data, FALSE otherwise.
*
*/
void FillNetworkDataTlv(NetworkDataTlv &aTlv, bool aStableOnly);
protected:
/**
* This method appends an MLE header to a message.
+20 -10
View File
@@ -3295,16 +3295,13 @@ exit:
}
}
ThreadError MleRouter::AppendConnectivity(Message &aMessage)
void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
{
ThreadError error;
ConnectivityTlv tlv;
ConnectivityTlv &tlv = aTlv;
uint8_t cost;
uint8_t lqi;
uint8_t numChildren = 0;
tlv.Init();
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].mState == Neighbor::kStateValid)
@@ -3405,6 +3402,15 @@ ThreadError MleRouter::AppendConnectivity(Message &aMessage)
tlv.SetIdSequence(mRouterIdSequence);
tlv.SetSedBufferSize(1280);
tlv.SetSedDatagramCount(1);
}
ThreadError MleRouter::AppendConnectivity(Message &aMessage)
{
ThreadError error;
ConnectivityTlv tlv;
tlv.Init();
FillConnectivityTlv(tlv);
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(tlv)));
@@ -3455,14 +3461,11 @@ exit:
return error;
}
ThreadError MleRouter::AppendRoute(Message &aMessage)
void MleRouter::FillRouteTlv(RouteTlv &tlv)
{
ThreadError error;
RouteTlv tlv;
uint8_t routeCount = 0;
uint8_t cost;
tlv.Init();
tlv.SetRouterIdSequence(mRouterIdSequence);
tlv.ClearRouterIdMask();
@@ -3515,8 +3518,15 @@ ThreadError MleRouter::AppendRoute(Message &aMessage)
}
tlv.SetRouteDataLength(routeCount);
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(Tlv) + tlv.GetLength()));
}
ThreadError MleRouter::AppendRoute(Message &aMessage)
{
ThreadError error;
RouteTlv tlv;
tlv.Init();
FillRouteTlv(tlv);
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(Tlv) + tlv.GetLength()));
exit:
return error;
}
+16
View File
@@ -481,6 +481,22 @@ public:
*/
static bool IsRouterIdValid(uint8_t aRouterId) { return aRouterId <= kMaxRouterId; }
/**
* This method fills an ConnectivityTlv.
*
* @param[out] aTlv A reference to the tlv to be filled.
*
*/
void FillConnectivityTlv(ConnectivityTlv &aTlv);
/**
* This method fills an RouteTlv.
*
* @param[out] aTlv A reference to the tlv to be filled.
*
*/
void FillRouteTlv(RouteTlv &aTlv);
private:
enum
{
+526
View File
@@ -0,0 +1,526 @@
/*
* Copyright (c) 2016, 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 Thread's Network Diagnostic processing.
*/
#include <coap/coap_header.hpp>
#include <common/code_utils.hpp>
#include <common/debug.hpp>
#include <common/logging.hpp>
#include <common/encoding.hpp>
#include <mac/mac_frame.hpp>
#include <net/netif.hpp>
#include <platform/random.h>
#include <thread/mesh_forwarder.hpp>
#include <thread/mle_router.hpp>
#include <thread/thread_netif.hpp>
#include <thread/thread_tlvs.hpp>
#include <thread/thread_uris.hpp>
#include <thread/network_diag.hpp>
#include <thread/network_diag_tlvs.hpp>
using Thread::Encoding::BigEndian::HostSwap16;
namespace Thread {
namespace NetworkDiagnostic {
NetworkDiagnostic::NetworkDiagnostic(ThreadNetif &aThreadNetif) :
mDiagnosticGet(OPENTHREAD_URI_DIAGNOSTIC_GET, &HandleDiagnosticGet, this),
mDiagnosticReset(OPENTHREAD_URI_DIAGNOSTIC_RESET, &HandleDiagnosticReset, this),
mSocket(aThreadNetif.GetIp6().mUdp),
mCoapServer(aThreadNetif.GetCoapServer()),
mMle(aThreadNetif.GetMle()),
mNetif(aThreadNetif)
{
mCoapServer.AddResource(mDiagnosticGet);
mCoapServer.AddResource(mDiagnosticReset);
mCoapMessageId = static_cast<uint8_t>(otPlatRandomGet());
}
ThreadError NetworkDiagnostic::SendDiagnosticGet(const Ip6::Address &aDestination, uint8_t aTlvTypes[], uint8_t aCount)
{
ThreadError error;
Ip6::SockAddr sockaddr;
Message *message;
Coap::Header header;
Ip6::MessageInfo messageInfo;
sockaddr.mPort = kCoapUdpPort;
mSocket.Open(&HandleUdpReceive, this);
mSocket.Bind(sockaddr);
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
for (size_t i = 0; i < sizeof(mCoapToken); i++)
{
mCoapToken[i] = static_cast<uint8_t>(otPlatRandomGet());
}
header.Init();
header.SetType(Coap::Header::kTypeConfirmable);
header.SetCode(Coap::Header::kCodeGet);
header.SetMessageId(++mCoapMessageId);
header.SetToken(mCoapToken, sizeof(mCoapToken));
header.AppendUriPathOptions(OPENTHREAD_URI_DIAGNOSTIC_GET);
header.Finalize();
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
SuccessOrExit(error = message->Append(aTlvTypes, aCount));
memset(&messageInfo, 0, sizeof(messageInfo));
messageInfo.GetPeerAddr() = aDestination;
messageInfo.GetSockAddr() = *mMle.GetMeshLocal16();
messageInfo.mPeerPort = kCoapUdpPort;
messageInfo.mInterfaceId = mNetif.GetInterfaceId();
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
otLogInfoNetDiag("Sent diagnostic get\n");
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
void NetworkDiagnostic::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
{
NetworkDiagnostic *obj = static_cast<NetworkDiagnostic *>(aContext);
obj->HandleUdpReceive(*static_cast<Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
void NetworkDiagnostic::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
Coap::Header header;
SuccessOrExit(header.FromMessage(aMessage));
VerifyOrExit(header.GetType() == Coap::Header::kTypeAcknowledgment &&
header.GetCode() == Coap::Header::kCodeChanged &&
header.GetMessageId() == mCoapMessageId &&
header.GetTokenLength() == sizeof(mCoapToken) &&
memcmp(mCoapToken, header.GetToken(), sizeof(mCoapToken)) == 0, ;);
otLogInfoNetDiag("Network Diagnostic message acknowledged\n");
exit:
(void)aMessageInfo;
}
ThreadError NetworkDiagnostic::SendDiagnosticReset(const Ip6::Address &aDestination, uint8_t aTlvTypes[],
uint8_t aCount)
{
ThreadError error;
Ip6::SockAddr sockaddr;
Message *message;
Coap::Header header;
Ip6::MessageInfo messageInfo;
sockaddr.mPort = kCoapUdpPort;
mSocket.Open(&HandleUdpReceive, this);
mSocket.Bind(sockaddr);
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
for (size_t i = 0; i < sizeof(mCoapToken); i++)
{
mCoapToken[i] = static_cast<uint8_t>(otPlatRandomGet());
}
header.Init();
header.SetType(Coap::Header::kTypeConfirmable);
header.SetCode(Coap::Header::kCodePost);
header.SetMessageId(++mCoapMessageId);
header.SetToken(mCoapToken, sizeof(mCoapToken));
header.AppendUriPathOptions(OPENTHREAD_URI_DIAGNOSTIC_RESET);
header.Finalize();
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
SuccessOrExit(error = message->Append(aTlvTypes, aCount));
memset(&messageInfo, 0, sizeof(messageInfo));
messageInfo.GetPeerAddr() = aDestination;
messageInfo.GetSockAddr() = *mMle.GetMeshLocal16();
messageInfo.mPeerPort = kCoapUdpPort;
messageInfo.mInterfaceId = mNetif.GetInterfaceId();
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
otLogInfoNetDiag("Sent network diagnostic reset\n");
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
void NetworkDiagnostic::HandleDiagnosticGet(void *aContext, Coap::Header &aHeader,
Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
NetworkDiagnostic *obj = reinterpret_cast<NetworkDiagnostic *>(aContext);
obj->HandleDiagnosticGet(aHeader, aMessage, aMessageInfo);
}
ThreadError NetworkDiagnostic::AppendIPv6AddressList(Message &aMessage)
{
ThreadError error = kThreadError_None;
IPv6AddressListTlv tlv;
uint8_t count = 0;
tlv.Init();
for (const Ip6::NetifUnicastAddress *addr = mNetif.GetUnicastAddresses(); addr; addr = addr->GetNext())
{
count++;
}
tlv.SetLength(count * sizeof(Ip6::Address));
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(tlv)));
for (const Ip6::NetifUnicastAddress *addr = mNetif.GetUnicastAddresses(); addr; addr = addr->GetNext())
{
SuccessOrExit(error = aMessage.Append(&addr->GetAddress(), sizeof(Ip6::Address)));
}
exit:
return error;
}
ThreadError NetworkDiagnostic::AppendChildTable(Message &aMessage)
{
ThreadError error = kThreadError_None;
uint8_t numChildren;
const Child *children = mMle.GetChildren(&numChildren);
{
uint8_t count = 0;
for (int i = 0; i < numChildren; i++)
{
if (children[i].mState != Neighbor::kStateInvalid)
{
continue;
}
count++;
}
ChildTableTlv tlv;
tlv.Init();
tlv.SetLength(count * sizeof(ChildTableEntry));
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(ChildTableTlv)));
}
for (int i = 0; i < numChildren; i++)
{
if (children[i].mState != Neighbor::kStateInvalid)
{
continue;
}
const Child &child = children[i];
ChildTableEntry entry;
uint8_t timeout = 0;
while (static_cast<uint32_t>(1 << timeout) < child.mTimeout) { timeout++; }
entry.SetTimeout(timeout + 4);
entry.SetChildId(child.mValid.mRloc16);
entry.SetMode(child.mMode);
SuccessOrExit(error = aMessage.Append(&entry, sizeof(ChildTableEntry)));
}
exit:
return error;
}
void NetworkDiagnostic::HandleDiagnosticGet(Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
uint8_t tlvTypeSet[kNumTlvTypes];
uint16_t numTlvTypes;
ThreadError error = kThreadError_None;
Message *message = NULL;
Coap::Header header;
Ip6::MessageInfo messageInfo;
VerifyOrExit(aHeader.GetType() == Coap::Header::kTypeConfirmable &&
aHeader.GetCode() == Coap::Header::kCodeGet, error = kThreadError_Drop);
otLogInfoNetDiag("Received diagnostic get request\n");
header.Init();
header.SetType(Coap::Header::kTypeAcknowledgment);
header.SetCode(Coap::Header::kCodeChanged);
header.SetMessageId(aHeader.GetMessageId());
header.SetToken(aHeader.GetToken(), aHeader.GetTokenLength());
header.Finalize();
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
numTlvTypes = aMessage.Read(aMessage.GetOffset(), kNumTlvTypes, tlvTypeSet);
for (uint8_t i = 0; i < numTlvTypes; i++)
{
otLogInfoNetDiag("Received diagnostic get type %d\n", tlvTypeSet[i]);
switch (tlvTypeSet[i])
{
case NetworkDiagnosticTlv::kExtMacAddress:
{
ExtMacAddressTlv tlv;
tlv.Init();
tlv.SetMacAddr(*mNetif.GetMac().GetExtAddress());
SuccessOrExit(error = message->Append(&tlv, sizeof(tlv)));
break;
}
case NetworkDiagnosticTlv::kAddress16:
{
Address16Tlv tlv;
tlv.Init();
tlv.SetRloc16(mMle.GetRloc16());
SuccessOrExit(error = message->Append(&tlv, sizeof(tlv)));
break;
}
case NetworkDiagnosticTlv::kMode:
{
ModeTlv tlv;
tlv.Init();
tlv.SetMode(mMle.GetDeviceMode());
SuccessOrExit(error = message->Append(&tlv, sizeof(tlv)));
break;
}
case NetworkDiagnosticTlv::kTimeout:
{
if ((mMle.GetDeviceMode() & ModeTlv::kModeRxOnWhenIdle) == 0)
{
TimeoutTlv tlv;
tlv.Init();
tlv.SetTimeout(mMle.GetTimeout());
SuccessOrExit(error = message->Append(&tlv, sizeof(tlv)));
}
break;
}
case NetworkDiagnosticTlv::kConnectivity:
{
ConnectivityTlv tlv;
tlv.Init();
mMle.FillConnectivityTlv(*reinterpret_cast<Mle::ConnectivityTlv *>(&tlv));
SuccessOrExit(error = message->Append(&tlv, sizeof(tlv)));
break;
}
case NetworkDiagnosticTlv::kRoute:
{
RouteTlv tlv;
tlv.Init();
mMle.FillRouteTlv(*reinterpret_cast<Mle::RouteTlv *>(&tlv));
SuccessOrExit(error = message->Append(&tlv, tlv.GetSize()));
break;
}
case NetworkDiagnosticTlv::kLeaderData:
{
LeaderDataTlv tlv;
memcpy(&tlv, &mMle.GetLeaderDataTlv(), sizeof(tlv));
tlv.Init();
SuccessOrExit(error = message->Append(&tlv, tlv.GetSize()));
break;
}
case NetworkDiagnosticTlv::kNetworkData:
{
NetworkDataTlv tlv;
tlv.Init();
mMle.FillNetworkDataTlv((*reinterpret_cast<Mle::NetworkDataTlv *>(&tlv)), true);
SuccessOrExit(error = message->Append(&tlv, tlv.GetSize()));
break;
}
case NetworkDiagnosticTlv::kIPv6AddressList:
{
SuccessOrExit(error = AppendIPv6AddressList(*message));
break;
}
case NetworkDiagnosticTlv::kMacCounters:
{
MacCountersTlv tlv;
memset(&tlv, 0, sizeof(tlv));
tlv.Init();
SuccessOrExit(error = message->Append(&tlv, tlv.GetSize()));
break;
}
case NetworkDiagnosticTlv::kBatteryLevel:
{
// TODO Need more api from driver
BatteryLevelTlv tlv;
tlv.Init();
tlv.SetBatteryLevel(100);
SuccessOrExit(error = message->Append(&tlv, tlv.GetSize()));
break;
}
case NetworkDiagnosticTlv::kSupplyVoltage:
{
// TODO Need more api from driver
SupplyVoltageTlv tlv;
tlv.Init();
tlv.SetSupplyVoltage(0);
SuccessOrExit(error = message->Append(&tlv, tlv.GetSize()));
break;
}
case NetworkDiagnosticTlv::kChildTable:
{
SuccessOrExit(error = AppendChildTable(*message));
break;
}
case NetworkDiagnosticTlv::kChannelPages:
{
ChannelPagesTlv tlv;
tlv.Init();
tlv.GetChannelPages()[0] = 0;
tlv.SetLength(1);
SuccessOrExit(error = message->Append(&tlv, tlv.GetSize()));
break;
}
default:
ExitNow();
}
}
memcpy(&messageInfo, &aMessageInfo, sizeof(messageInfo));
memset(&messageInfo.mSockAddr, 0, sizeof(messageInfo.mSockAddr));
otLogInfoNetDiag("Sending diagnostic get acknowledgment\n");
SuccessOrExit(error = mCoapServer.SendMessage(*message, messageInfo));
otLogInfoNetDiag("Sent diagnostic get acknowledgment\n");
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
}
void NetworkDiagnostic::HandleDiagnosticReset(void *aContext, Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
NetworkDiagnostic *obj = reinterpret_cast<NetworkDiagnostic *>(aContext);
obj->HandleDiagnosticReset(aHeader, aMessage, aMessageInfo);
}
void NetworkDiagnostic::HandleDiagnosticReset(Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
uint8_t tlvTypeSet[kNumResetTlvTypes];
uint16_t numTlvTypes;
Message *message = NULL;
Coap::Header header;
Ip6::MessageInfo messageInfo;
otLogInfoNetDiag("Received diagnostic reset request\n");
VerifyOrExit(aHeader.GetType() == Coap::Header::kTypeConfirmable &&
aHeader.GetCode() == Coap::Header::kCodePost, error = kThreadError_Drop);
otLogInfoNetDiag("Received diagnostic reset request\n");
numTlvTypes = aMessage.Read(aMessage.GetOffset(), kNumResetTlvTypes, tlvTypeSet);
otLogInfoNetDiag("Received diagnostic reset request\n");
for (uint8_t i = 0; i < numTlvTypes; i++)
{
switch (tlvTypeSet[i])
{
case NetworkDiagnosticTlv::kMacCounters:
break;
default:
ExitNow();
}
}
otLogInfoNetDiag("Received diagnostic reset request\n");
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
otLogInfoNetDiag("Received diagnostic reset request\n");
header.Init();
header.SetType(Coap::Header::kTypeAcknowledgment);
header.SetCode(Coap::Header::kCodeChanged);
header.SetMessageId(aHeader.GetMessageId());
header.SetToken(aHeader.GetToken(), aHeader.GetTokenLength());
header.Finalize();
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
memcpy(&messageInfo, &aMessageInfo, sizeof(messageInfo));
memset(&messageInfo.mSockAddr, 0, sizeof(messageInfo.mSockAddr));
SuccessOrExit(error = mCoapServer.SendMessage(*message, messageInfo));
otLogInfoNetDiag("Sent diagnostic reset acknowledgment\n");
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
}
} // namespace NetworkDiagnostic
} // namespace Thread
+142
View File
@@ -0,0 +1,142 @@
/*
* Copyright (c) 2016, 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 includes definitions for handle network diagnostic.
*/
#ifndef NETWORK_DIAGNOSTIC_HPP_
#define NETWORK_DIAGNOSTIC_HPP_
#include <openthread-core-config.h>
#include <openthread-types.h>
#include <coap/coap_server.hpp>
#include <net/udp6.hpp>
namespace Thread {
class ThreadNetif;
using namespace Coap;
namespace NetworkDiagnostic {
class IPv6AddressListTlv;
class ChildTableTlv;
/**
* @addtogroup core-netdiag
*
* @brief
* This module includes definitions for sending and handling Network Diagnostic Commands.
*
* @{
*/
/**
* This class implements the Network Diagnostic processing.
*
*/
class NetworkDiagnostic
{
public:
/**
* This constructor initializes the object.
*
*/
explicit NetworkDiagnostic(ThreadNetif &aThreadNetif);
/**
* This method sends Diagnostic Get request.
*
* @param[in] aDestination A reference to the destination address.
* @param[in] aTlvTypes An array of Network Diagnostic TLV types.
* @param[in] aCount Number of types in aTlvTypes
*
*/
ThreadError SendDiagnosticGet(const Ip6::Address &aDestination, uint8_t aTlvTypes[], uint8_t aCount);
/**
* This method sends Diagnostic Reset request.
*
* @param[in] aDestination A reference to the destination address.
* @param[in] aTlvTypes An array of Network Diagnostic TLV types.
* @param[in] aCount Number of types in aTlvTypes
*
*/
ThreadError SendDiagnosticReset(const Ip6::Address &aDestination, uint8_t aTlvTypes[], uint8_t aCount);
/**
* This method fills IPv6AddressListTlv.
*
* @param[out] aTlv A reference to the tlv.
*
*/
ThreadError AppendIPv6AddressList(Message &aMessage);
/**
* This method fills ChildTableTlv.
*
* @param[out] aTlv A reference to the tlv.
*
*/
ThreadError AppendChildTable(Message &aMessage);
private:
static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo);
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleDiagnosticGet(void *aContext, Coap::Header &aHeader,
Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandleDiagnosticGet(Thread::Coap::Header &aHeader, Thread::Message &aMessage,
const Thread::Ip6::MessageInfo &aMessageInfo);
static void HandleDiagnosticReset(void *aContext, Thread::Coap::Header &aHeader, Thread::Message &,
const Thread::Ip6::MessageInfo &aMessageInfo);
void HandleDiagnosticReset(Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo);
Coap::Resource mDiagnosticGet;
Coap::Resource mDiagnosticReset;
Ip6::UdpSocket mSocket;
uint8_t mCoapToken[2];
uint16_t mCoapMessageId;
Coap::Server &mCoapServer;
Mle::MleRouter &mMle;
ThreadNetif &mNetif;
};
/**
* @}
*/
} // namespace NetworkDiagnostic
} // namespace Thread
#endif // NETWORK_DIAGNOSTIC_HPP_
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2016, 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 common methods for manipulating Network Diagnostic TLVs.
*/
#include <common/code_utils.hpp>
#include <common/message.hpp>
#include <thread/network_diag_tlvs.hpp>
namespace Thread {
namespace NetworkDiagnostic {
ThreadError NetworkDiagnosticTlv::GetTlv(const Message &aMessage, Type aType, uint16_t aMaxLength,
NetworkDiagnosticTlv &aTlv)
{
ThreadError error = kThreadError_Parse;
uint16_t offset;
SuccessOrExit(error = GetOffset(aMessage, aType, offset));
aMessage.Read(offset, sizeof(NetworkDiagnosticTlv), &aTlv);
if (aMaxLength > sizeof(aTlv) + aTlv.GetLength())
{
aMaxLength = sizeof(aTlv) + aTlv.GetLength();
}
aMessage.Read(offset, aMaxLength, &aTlv);
exit:
return error;
}
ThreadError NetworkDiagnosticTlv::GetOffset(const Message &aMessage, Type aType, uint16_t &aOffset)
{
ThreadError error = kThreadError_Parse;
uint16_t offset = aMessage.GetOffset();
uint16_t end = aMessage.GetLength();
NetworkDiagnosticTlv tlv;
while (offset < end)
{
aMessage.Read(offset, sizeof(NetworkDiagnosticTlv), &tlv);
if (tlv.GetType() == aType && (offset + sizeof(tlv) + tlv.GetLength()) <= end)
{
aOffset = offset;
ExitNow(error = kThreadError_None);
}
offset += sizeof(tlv) + tlv.GetLength();
}
exit:
return error;
}
} // namespace NetworkDiagnostic
} // namespace Thread
File diff suppressed because it is too large Load Diff
+1
View File
@@ -67,6 +67,7 @@ ThreadNetif::ThreadNetif(Ip6::Ip6 &aIp6):
mMleRouter(*this),
mNetworkDataLocal(*this),
mNetworkDataLeader(*this),
mNetworkDiagnostic(*this),
#if OPENTHREAD_ENABLE_COMMISSIONER
mCommissioner(*this),
#endif // OPENTHREAD_ENABLE_COMMISSIONER
+10
View File
@@ -49,6 +49,7 @@
#include <net/netif.hpp>
#include <thread/address_resolver.hpp>
#include <thread/energy_scan_server.hpp>
#include <thread/network_diag.hpp>
#include <thread/key_manager.hpp>
#include <thread/meshcop_dataset_manager.hpp>
#include <thread/mesh_forwarder.hpp>
@@ -159,6 +160,14 @@ public:
*/
AddressResolver &GetAddressResolver(void) { return mAddressResolver; }
/**
* This method returns a pointer to the network diagnostic object.
*
* @returns A reference to the address resolver object.
*
*/
NetworkDiagnostic::NetworkDiagnostic &GetNetworkDiagnostic(void) { return mNetworkDiagnostic; }
/**
* This method returns a pointer to the coap server object.
*
@@ -262,6 +271,7 @@ private:
Mle::MleRouter mMleRouter;
NetworkData::Local mNetworkDataLocal;
NetworkData::Leader mNetworkDataLeader;
NetworkDiagnostic::NetworkDiagnostic mNetworkDiagnostic;
bool mIsUp;
#if OPENTHREAD_ENABLE_COMMISSIONER
+16
View File
@@ -210,6 +210,22 @@ namespace Thread {
*/
#define OPENTHREAD_URI_COMMISSIONER_SET "c/cs"
/**
* @def OPENTHREAD_URI_DIAGNOSTIC_GET
*
* The URI Path for Network Diagnostic Get.
*
*/
#define OPENTHREAD_URI_DIAGNOSTIC_GET "d/dg"
/**
* @def OPENTHREAD_URI_DIAG_RST
*
* The URI Path for Network Diagnostic Reset.
*
*/
#define OPENTHREAD_URI_DIAGNOSTIC_RESET "d/dr"
} // namespace Thread
#endif // THREAD_URIS_HPP_
+22 -4
View File
@@ -1570,11 +1570,29 @@ class ARM(IThci):
def setSleepyNodePollTime(self):
pass
def diagnosticGet(self, strDestinationAddr, TLV_ids=0):
pass
def diagnosticGet(self, strDestinationAddr, listTLV_ids=[]):
if not listTLV_ids:
return
def diagnosticReset(self, strDestinationAddr, iTLV_id):
pass
if not len(listTLV_ids):
return
cmd = 'networkdiagnostic get %s %s' % (strDestinationAddr, ' '.join([str(tlv) for tlv in listTLV_ids]))
print(cmd)
return self.__sendCommand(cmd)
def diagnosticReset(self, strDestinationAddr, listTLV_ids=[]):
if not listTLV_ids:
return
if not len(listTLV_ids):
return
cmd = 'networkdiagnostic reset %s %s' % (strDestinationAddr, ' '.join([str(tlv) for tlv in listTLV_ids]))
print(cmd)
return self.__sendCommand(cmd)
def startNativeCommissioner(self, strPSKc='GRLpassWord'):
pass