mirror of
https://github.com/espressif/openthread.git
synced 2026-07-08 13:20:25 +00:00
d236546304
- The method `otGetChildInfoByIndex()` is changed to return thread error `NotFound` when there is no valid child with given index. - Usage of this method is updated in `NcpBase` and `cli` to iterate over all children.
2736 lines
77 KiB
C++
2736 lines
77 KiB
C++
/*
|
|
* 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 the CLI interpreter.
|
|
*/
|
|
|
|
#ifdef OPENTHREAD_CONFIG_FILE
|
|
#include OPENTHREAD_CONFIG_FILE
|
|
#else
|
|
#include <openthread-config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <openthread.h>
|
|
#include <openthread-instance.h>
|
|
#include <openthread-diag.h>
|
|
#include <commissioning/commissioner.h>
|
|
#include <commissioning/joiner.h>
|
|
#include <dhcp6/dhcp6_server.h>
|
|
#include <dhcp6/dhcp6_client.h>
|
|
|
|
#include "cli.hpp"
|
|
#include "cli_dataset.hpp"
|
|
#include "cli_uart.hpp"
|
|
#include <common/encoding.hpp>
|
|
#include <common/new.hpp>
|
|
#include <net/ip6.hpp>
|
|
#include <platform/uart.h>
|
|
|
|
using Thread::Encoding::BigEndian::HostSwap16;
|
|
using Thread::Encoding::BigEndian::HostSwap32;
|
|
|
|
namespace Thread {
|
|
|
|
namespace Cli {
|
|
|
|
const struct Command Interpreter::sCommands[] =
|
|
{
|
|
{ "help", &Interpreter::ProcessHelp },
|
|
{ "blacklist", &Interpreter::ProcessBlacklist },
|
|
{ "bufferinfo", &Interpreter::ProcessBufferInfo },
|
|
{ "channel", &Interpreter::ProcessChannel },
|
|
{ "child", &Interpreter::ProcessChild },
|
|
{ "childmax", &Interpreter::ProcessChildMax },
|
|
{ "childtimeout", &Interpreter::ProcessChildTimeout },
|
|
#if OPENTHREAD_ENABLE_COMMISSIONER
|
|
{ "commissioner", &Interpreter::ProcessCommissioner },
|
|
#endif
|
|
{ "contextreusedelay", &Interpreter::ProcessContextIdReuseDelay },
|
|
{ "counter", &Interpreter::ProcessCounters },
|
|
{ "dataset", &Interpreter::ProcessDataset },
|
|
#if OPENTHREAD_ENABLE_DIAG
|
|
{ "diag", &Interpreter::ProcessDiag },
|
|
#endif
|
|
{ "discover", &Interpreter::ProcessDiscover },
|
|
{ "eidcache", &Interpreter::ProcessEidCache },
|
|
{ "eui64", &Interpreter::ProcessEui64 },
|
|
#ifdef OPENTHREAD_EXAMPLES_POSIX
|
|
{ "exit", &Interpreter::ProcessExit },
|
|
#endif
|
|
{ "extaddr", &Interpreter::ProcessExtAddress },
|
|
{ "extpanid", &Interpreter::ProcessExtPanId },
|
|
{ "factoryreset", &Interpreter::ProcessFactoryReset },
|
|
{ "hashmacaddr", &Interpreter::ProcessHashMacAddress },
|
|
{ "ifconfig", &Interpreter::ProcessIfconfig },
|
|
{ "ipaddr", &Interpreter::ProcessIpAddr },
|
|
{ "ipmaddr", &Interpreter::ProcessIpMulticastAddr },
|
|
#if OPENTHREAD_ENABLE_JOINER
|
|
{ "joiner", &Interpreter::ProcessJoiner },
|
|
#endif
|
|
{ "joinerport", &Interpreter::ProcessJoinerPort },
|
|
{ "keysequence", &Interpreter::ProcessKeySequence },
|
|
{ "leaderdata", &Interpreter::ProcessLeaderData },
|
|
{ "leaderpartitionid", &Interpreter::ProcessLeaderPartitionId },
|
|
{ "leaderweight", &Interpreter::ProcessLeaderWeight },
|
|
{ "linkquality", &Interpreter::ProcessLinkQuality },
|
|
{ "masterkey", &Interpreter::ProcessMasterKey },
|
|
{ "mode", &Interpreter::ProcessMode },
|
|
{ "netdataregister", &Interpreter::ProcessNetworkDataRegister },
|
|
{ "networkdiagnostic", &Interpreter::ProcessNetworkDiagnostic },
|
|
{ "networkidtimeout", &Interpreter::ProcessNetworkIdTimeout },
|
|
{ "networkname", &Interpreter::ProcessNetworkName },
|
|
{ "panid", &Interpreter::ProcessPanId },
|
|
{ "parent", &Interpreter::ProcessParent },
|
|
{ "ping", &Interpreter::ProcessPing },
|
|
{ "pollperiod", &Interpreter::ProcessPollPeriod },
|
|
{ "promiscuous", &Interpreter::ProcessPromiscuous },
|
|
{ "prefix", &Interpreter::ProcessPrefix },
|
|
{ "releaserouterid", &Interpreter::ProcessReleaseRouterId },
|
|
{ "reset", &Interpreter::ProcessReset },
|
|
{ "rloc16", &Interpreter::ProcessRloc16 },
|
|
{ "route", &Interpreter::ProcessRoute },
|
|
{ "router", &Interpreter::ProcessRouter },
|
|
{ "routerdowngradethreshold", &Interpreter::ProcessRouterDowngradeThreshold },
|
|
{ "routerrole", &Interpreter::ProcessRouterRole },
|
|
{ "routerselectionjitter", &Interpreter::ProcessRouterSelectionJitter },
|
|
{ "routerupgradethreshold", &Interpreter::ProcessRouterUpgradeThreshold },
|
|
{ "scan", &Interpreter::ProcessScan },
|
|
{ "singleton", &Interpreter::ProcessSingleton },
|
|
{ "state", &Interpreter::ProcessState },
|
|
{ "thread", &Interpreter::ProcessThread },
|
|
{ "version", &Interpreter::ProcessVersion },
|
|
{ "whitelist", &Interpreter::ProcessWhitelist },
|
|
};
|
|
|
|
Interpreter::Interpreter(otInstance *aInstance):
|
|
sServer(NULL),
|
|
sLength(8),
|
|
sCount(1),
|
|
sInterval(1000),
|
|
sPingTimer(aInstance->mIp6.mTimerScheduler, &Interpreter::s_HandlePingTimer, this),
|
|
mInstance(aInstance)
|
|
{
|
|
memset(mSlaacAddresses, 0, sizeof(mSlaacAddresses));
|
|
mInstance->mIp6.mIcmp.SetEchoReplyHandler(&s_HandleEchoResponse, this);
|
|
otSetStateChangedCallback(mInstance, &Interpreter::s_HandleNetifStateChanged, this);
|
|
otSetReceiveDiagnosticGetCallback(mInstance, &Interpreter::s_HandleDiagnosticGetResponse, this);
|
|
|
|
#if OPENTHREAD_ENABLE_DHCP6_CLIENT
|
|
memset(mDhcpAddresses, 0, sizeof(mDhcpAddresses));
|
|
#endif // OPENTHREAD_ENABLE_DHCP6_CLIENT
|
|
}
|
|
|
|
int Interpreter::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength)
|
|
{
|
|
size_t hexLength = strlen(aHex);
|
|
const char *hexEnd = aHex + hexLength;
|
|
uint8_t *cur = aBin;
|
|
uint8_t numChars = hexLength & 1;
|
|
uint8_t byte = 0;
|
|
|
|
if ((hexLength + 1) / 2 > aBinLength)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
while (aHex < hexEnd)
|
|
{
|
|
if ('A' <= *aHex && *aHex <= 'F')
|
|
{
|
|
byte |= 10 + (*aHex - 'A');
|
|
}
|
|
else if ('a' <= *aHex && *aHex <= 'f')
|
|
{
|
|
byte |= 10 + (*aHex - 'a');
|
|
}
|
|
else if ('0' <= *aHex && *aHex <= '9')
|
|
{
|
|
byte |= *aHex - '0';
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
aHex++;
|
|
numChars++;
|
|
|
|
if (numChars >= 2)
|
|
{
|
|
numChars = 0;
|
|
*cur++ = byte;
|
|
byte = 0;
|
|
}
|
|
else
|
|
{
|
|
byte <<= 4;
|
|
}
|
|
}
|
|
|
|
return static_cast<int>(cur - aBin);
|
|
}
|
|
|
|
void Interpreter::AppendResult(ThreadError error)
|
|
{
|
|
if (error == kThreadError_None)
|
|
{
|
|
sServer->OutputFormat("Done\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("Error %d\r\n", error);
|
|
}
|
|
}
|
|
|
|
void Interpreter::OutputBytes(const uint8_t *aBytes, uint8_t aLength)
|
|
{
|
|
for (int i = 0; i < aLength; i++)
|
|
{
|
|
sServer->OutputFormat("%02x", aBytes[i]);
|
|
}
|
|
}
|
|
|
|
ThreadError Interpreter::ParseLong(char *argv, long &value)
|
|
{
|
|
char *endptr;
|
|
value = strtol(argv, &endptr, 0);
|
|
return (*endptr == '\0') ? kThreadError_None : kThreadError_Parse;
|
|
}
|
|
|
|
ThreadError Interpreter::ParseUnsignedLong(char *argv, unsigned long &value)
|
|
{
|
|
char *endptr;
|
|
value = strtoul(argv, &endptr, 0);
|
|
return (*endptr == '\0') ? kThreadError_None : kThreadError_Parse;
|
|
}
|
|
|
|
void Interpreter::ProcessHelp(int argc, char *argv[])
|
|
{
|
|
for (unsigned int i = 0; i < sizeof(sCommands) / sizeof(sCommands[0]); i++)
|
|
{
|
|
sServer->OutputFormat("%s\r\n", sCommands[i].mName);
|
|
}
|
|
|
|
(void)argc;
|
|
(void)argv;
|
|
}
|
|
|
|
void Interpreter::ProcessBlacklist(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otMacBlacklistEntry entry;
|
|
int argcur = 0;
|
|
uint8_t extAddr[8];
|
|
|
|
if (argcur >= argc)
|
|
{
|
|
if (otIsMacBlacklistEnabled(mInstance))
|
|
{
|
|
sServer->OutputFormat("Enabled\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("Disabled\r\n");
|
|
}
|
|
|
|
for (uint8_t i = 0; ; i++)
|
|
{
|
|
if (otGetMacBlacklistEntry(mInstance, i, &entry) != kThreadError_None)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (entry.mValid == false)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
OutputBytes(entry.mExtAddress.m8, OT_EXT_ADDRESS_SIZE);
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
}
|
|
else if (strcmp(argv[argcur], "add") == 0)
|
|
{
|
|
VerifyOrExit(++argcur < argc, error = kThreadError_Parse);
|
|
VerifyOrExit(Hex2Bin(argv[argcur], extAddr, sizeof(extAddr)) == sizeof(extAddr), error = kThreadError_Parse);
|
|
|
|
otAddMacBlacklist(mInstance, extAddr);
|
|
VerifyOrExit(otAddMacBlacklist(mInstance, extAddr) == kThreadError_None, error = kThreadError_Parse);
|
|
}
|
|
else if (strcmp(argv[argcur], "clear") == 0)
|
|
{
|
|
otClearMacBlacklist(mInstance);
|
|
}
|
|
else if (strcmp(argv[argcur], "disable") == 0)
|
|
{
|
|
otDisableMacBlacklist(mInstance);
|
|
}
|
|
else if (strcmp(argv[argcur], "enable") == 0)
|
|
{
|
|
otEnableMacBlacklist(mInstance);
|
|
}
|
|
else if (strcmp(argv[argcur], "remove") == 0)
|
|
{
|
|
VerifyOrExit(++argcur < argc, error = kThreadError_Parse);
|
|
VerifyOrExit(Hex2Bin(argv[argcur], extAddr, sizeof(extAddr)) == sizeof(extAddr), error = kThreadError_Parse);
|
|
otRemoveMacBlacklist(mInstance, extAddr);
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessBufferInfo(int argc, char *argv[])
|
|
{
|
|
otBufferInfo bufferInfo;
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
otGetMessageBufferInfo(mInstance, &bufferInfo);
|
|
|
|
sServer->OutputFormat("total: %d\r\n", bufferInfo.mTotalBuffers);
|
|
sServer->OutputFormat("free: %d\r\n", bufferInfo.mFreeBuffers);
|
|
sServer->OutputFormat("6lo send: %d %d\r\n", bufferInfo.m6loSendMessages, bufferInfo.m6loSendBuffers);
|
|
sServer->OutputFormat("6lo reas: %d %d\r\n", bufferInfo.m6loReassemblyMessages, bufferInfo.m6loReassemblyBuffers);
|
|
sServer->OutputFormat("ip6: %d %d\r\n", bufferInfo.mIp6Messages, bufferInfo.mIp6Buffers);
|
|
sServer->OutputFormat("mpl: %d %d\r\n", bufferInfo.mMplMessages, bufferInfo.mMplBuffers);
|
|
sServer->OutputFormat("mle: %d %d\r\n", bufferInfo.mMleMessages, bufferInfo.mMleBuffers);
|
|
sServer->OutputFormat("arp: %d %d\r\n", bufferInfo.mArpMessages, bufferInfo.mArpBuffers);
|
|
sServer->OutputFormat("coap: %d %d\r\n", bufferInfo.mCoapClientMessages, bufferInfo.mCoapClientBuffers);
|
|
|
|
AppendResult(kThreadError_None);
|
|
}
|
|
|
|
void Interpreter::ProcessChannel(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetChannel(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
otSetChannel(mInstance, static_cast<uint8_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessChild(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otChildInfo childInfo;
|
|
uint8_t maxChildren;
|
|
long value;
|
|
bool isTable = false;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
if (strcmp(argv[0], "list") == 0 || (isTable = (strcmp(argv[0], "table") == 0)))
|
|
{
|
|
if (isTable)
|
|
{
|
|
sServer->OutputFormat("| ID | RLOC16 | Timeout | Age | LQI In | C_VN |R|S|D|N| Extended MAC |\r\n");
|
|
sServer->OutputFormat("+-----+--------+------------+------------+--------+------+-+-+-+-+------------------+\r\n");
|
|
}
|
|
|
|
maxChildren = otGetMaxAllowedChildren(mInstance);
|
|
|
|
for (uint8_t i = 0; i < maxChildren ; i++)
|
|
{
|
|
if (otGetChildInfoByIndex(mInstance, i, &childInfo) != kThreadError_None)
|
|
{
|
|
sServer->OutputFormat("\r\n");
|
|
ExitNow();
|
|
}
|
|
|
|
if (childInfo.mTimeout > 0)
|
|
{
|
|
if (isTable)
|
|
{
|
|
sServer->OutputFormat("| %3d ", childInfo.mChildId);
|
|
sServer->OutputFormat("| 0x%04x ", childInfo.mRloc16);
|
|
sServer->OutputFormat("| %10d ", childInfo.mTimeout);
|
|
sServer->OutputFormat("| %10d ", childInfo.mAge);
|
|
sServer->OutputFormat("| %6d ", childInfo.mLinkQualityIn);
|
|
sServer->OutputFormat("| %4d ", childInfo.mNetworkDataVersion);
|
|
sServer->OutputFormat("|%1d", childInfo.mRxOnWhenIdle);
|
|
sServer->OutputFormat("|%1d", childInfo.mSecureDataRequest);
|
|
sServer->OutputFormat("|%1d", childInfo.mFullFunction);
|
|
sServer->OutputFormat("|%1d", childInfo.mFullNetworkData);
|
|
sServer->OutputFormat("| ");
|
|
|
|
for (size_t j = 0; j < sizeof(childInfo.mExtAddress); j++)
|
|
{
|
|
sServer->OutputFormat("%02x", childInfo.mExtAddress.m8[j]);
|
|
}
|
|
|
|
sServer->OutputFormat(" |\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("%d ", childInfo.mChildId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
SuccessOrExit(error = otGetChildInfoById(mInstance, static_cast<uint16_t>(value), &childInfo));
|
|
|
|
sServer->OutputFormat("Child ID: %d\r\n", childInfo.mChildId);
|
|
sServer->OutputFormat("Rloc: %04x\r\n", childInfo.mRloc16);
|
|
sServer->OutputFormat("Ext Addr: ");
|
|
|
|
for (size_t j = 0; j < sizeof(childInfo.mExtAddress); j++)
|
|
{
|
|
sServer->OutputFormat("%02x", childInfo.mExtAddress.m8[j]);
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
sServer->OutputFormat("Mode: ");
|
|
|
|
if (childInfo.mRxOnWhenIdle)
|
|
{
|
|
sServer->OutputFormat("r");
|
|
}
|
|
|
|
if (childInfo.mSecureDataRequest)
|
|
{
|
|
sServer->OutputFormat("s");
|
|
}
|
|
|
|
if (childInfo.mFullFunction)
|
|
{
|
|
sServer->OutputFormat("d");
|
|
}
|
|
|
|
if (childInfo.mFullNetworkData)
|
|
{
|
|
sServer->OutputFormat("n");
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
|
|
sServer->OutputFormat("Net Data: %d\r\n", childInfo.mNetworkDataVersion);
|
|
sServer->OutputFormat("Timeout: %d\r\n", childInfo.mTimeout);
|
|
sServer->OutputFormat("Age: %d\r\n", childInfo.mAge);
|
|
sServer->OutputFormat("LQI: %d\r\n", childInfo.mLinkQualityIn);
|
|
sServer->OutputFormat("RSSI: %d\r\n", childInfo.mAverageRssi);
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessChildMax(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetMaxAllowedChildren(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
SuccessOrExit(error = otSetMaxAllowedChildren(mInstance, static_cast<uint8_t>(value)));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessChildTimeout(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetChildTimeout(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
otSetChildTimeout(mInstance, static_cast<uint32_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessContextIdReuseDelay(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetContextIdReuseDelay(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(ParseLong(argv[0], value));
|
|
otSetContextIdReuseDelay(mInstance, static_cast<uint32_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessCounters(int argc, char *argv[])
|
|
{
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("mac\r\n");
|
|
sServer->OutputFormat("Done\r\n");
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(argv[0], "mac") == 0)
|
|
{
|
|
const otMacCounters *counters = otGetMacCounters(mInstance);
|
|
sServer->OutputFormat("TxTotal: %d\r\n", counters->mTxTotal);
|
|
sServer->OutputFormat(" TxUnicast: %d\r\n", counters->mTxUnicast);
|
|
sServer->OutputFormat(" TxBroadcast: %d\r\n", counters->mTxBroadcast);
|
|
sServer->OutputFormat(" TxAckRequested: %d\r\n", counters->mTxAckRequested);
|
|
sServer->OutputFormat(" TxAcked: %d\r\n", counters->mTxAcked);
|
|
sServer->OutputFormat(" TxNoAckRequested: %d\r\n", counters->mTxNoAckRequested);
|
|
sServer->OutputFormat(" TxData: %d\r\n", counters->mTxData);
|
|
sServer->OutputFormat(" TxDataPoll: %d\r\n", counters->mTxDataPoll);
|
|
sServer->OutputFormat(" TxBeacon: %d\r\n", counters->mTxBeacon);
|
|
sServer->OutputFormat(" TxBeaconRequest: %d\r\n", counters->mTxBeaconRequest);
|
|
sServer->OutputFormat(" TxOther: %d\r\n", counters->mTxOther);
|
|
sServer->OutputFormat(" TxRetry: %d\r\n", counters->mTxRetry);
|
|
sServer->OutputFormat(" TxErrCca: %d\r\n", counters->mTxErrCca);
|
|
sServer->OutputFormat("RxTotal: %d\r\n", counters->mRxTotal);
|
|
sServer->OutputFormat(" RxUnicast: %d\r\n", counters->mRxUnicast);
|
|
sServer->OutputFormat(" RxBroadcast: %d\r\n", counters->mRxBroadcast);
|
|
sServer->OutputFormat(" RxData: %d\r\n", counters->mRxData);
|
|
sServer->OutputFormat(" RxDataPoll: %d\r\n", counters->mRxDataPoll);
|
|
sServer->OutputFormat(" RxBeacon: %d\r\n", counters->mRxBeacon);
|
|
sServer->OutputFormat(" RxBeaconRequest: %d\r\n", counters->mRxBeaconRequest);
|
|
sServer->OutputFormat(" RxOther: %d\r\n", counters->mRxOther);
|
|
sServer->OutputFormat(" RxWhitelistFiltered: %d\r\n", counters->mRxWhitelistFiltered);
|
|
sServer->OutputFormat(" RxDestAddrFiltered: %d\r\n", counters->mRxDestAddrFiltered);
|
|
sServer->OutputFormat(" RxDuplicated: %d\r\n", counters->mRxDuplicated);
|
|
sServer->OutputFormat(" RxErrNoFrame: %d\r\n", counters->mRxErrNoFrame);
|
|
sServer->OutputFormat(" RxErrNoUnknownNeighbor: %d\r\n", counters->mRxErrUnknownNeighbor);
|
|
sServer->OutputFormat(" RxErrInvalidSrcAddr: %d\r\n", counters->mRxErrInvalidSrcAddr);
|
|
sServer->OutputFormat(" RxErrSec: %d\r\n", counters->mRxErrSec);
|
|
sServer->OutputFormat(" RxErrFcs: %d\r\n", counters->mRxErrFcs);
|
|
sServer->OutputFormat(" RxErrOther: %d\r\n", counters->mRxErrOther);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Interpreter::ProcessDataset(int argc, char *argv[])
|
|
{
|
|
ThreadError error;
|
|
error = Dataset::Process(mInstance, argc, argv, *sServer);
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessDiscover(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
uint32_t scanChannels = 0;
|
|
long value;
|
|
|
|
if (argc > 0)
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
scanChannels = 1 << value;
|
|
}
|
|
|
|
SuccessOrExit(error = otDiscover(mInstance, scanChannels, 0, OT_PANID_BROADCAST,
|
|
&Interpreter::s_HandleActiveScanResult, this));
|
|
sServer->OutputFormat("| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |\r\n");
|
|
sServer->OutputFormat("+---+------------------+------------------+------+------------------+----+-----+-----+\r\n");
|
|
|
|
return;
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessEidCache(int argc, char *argv[])
|
|
{
|
|
otEidCacheEntry entry;
|
|
|
|
for (uint8_t i = 0; ; i++)
|
|
{
|
|
SuccessOrExit(otGetEidCacheEntry(mInstance, i, &entry));
|
|
|
|
if (entry.mValid == false)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
sServer->OutputFormat("%x:%x:%x:%x:%x:%x:%x:%x %04x\r\n",
|
|
HostSwap16(entry.mTarget.mFields.m16[0]),
|
|
HostSwap16(entry.mTarget.mFields.m16[1]),
|
|
HostSwap16(entry.mTarget.mFields.m16[2]),
|
|
HostSwap16(entry.mTarget.mFields.m16[3]),
|
|
HostSwap16(entry.mTarget.mFields.m16[4]),
|
|
HostSwap16(entry.mTarget.mFields.m16[5]),
|
|
HostSwap16(entry.mTarget.mFields.m16[6]),
|
|
HostSwap16(entry.mTarget.mFields.m16[7]),
|
|
entry.mRloc16);
|
|
}
|
|
|
|
exit:
|
|
(void)argc;
|
|
(void)argv;
|
|
AppendResult(kThreadError_None);
|
|
}
|
|
|
|
void Interpreter::ProcessEui64(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otExtAddress extAddress;
|
|
|
|
VerifyOrExit(argc == 0, error = kThreadError_Parse);
|
|
|
|
otGetFactoryAssignedIeeeEui64(mInstance, &extAddress);
|
|
OutputBytes(extAddress.m8, OT_EXT_ADDRESS_SIZE);
|
|
sServer->OutputFormat("\r\n");
|
|
|
|
exit:
|
|
(void)argv;
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessExtAddress(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
OutputBytes(otGetExtendedAddress(mInstance), OT_EXT_ADDRESS_SIZE);
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
else
|
|
{
|
|
otExtAddress extAddress;
|
|
|
|
VerifyOrExit(Hex2Bin(argv[0], extAddress.m8, sizeof(otExtAddress)) >= 0, error = kThreadError_Parse);
|
|
|
|
otSetExtendedAddress(mInstance, &extAddress);
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
#ifdef OPENTHREAD_EXAMPLES_POSIX
|
|
void Interpreter::ProcessExit(int argc, char *argv[])
|
|
{
|
|
exit(0);
|
|
(void)argc;
|
|
(void)argv;
|
|
}
|
|
#endif
|
|
|
|
void Interpreter::ProcessExtPanId(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
OutputBytes(otGetExtendedPanId(mInstance), OT_EXT_PAN_ID_SIZE);
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
else
|
|
{
|
|
uint8_t extPanId[8];
|
|
|
|
VerifyOrExit(Hex2Bin(argv[0], extPanId, sizeof(extPanId)) >= 0, error = kThreadError_Parse);
|
|
|
|
otSetExtendedPanId(mInstance, extPanId);
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessFactoryReset(int argc, char *argv[])
|
|
{
|
|
otFactoryReset(mInstance);
|
|
(void)argc;
|
|
(void)argv;
|
|
}
|
|
|
|
void Interpreter::ProcessHashMacAddress(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otExtAddress hashMacAddress;
|
|
|
|
VerifyOrExit(argc == 0, error = kThreadError_Parse);
|
|
|
|
otGetHashMacAddress(mInstance, &hashMacAddress);
|
|
OutputBytes(hashMacAddress.m8, OT_EXT_ADDRESS_SIZE);
|
|
sServer->OutputFormat("\r\n");
|
|
|
|
exit:
|
|
(void)argv;
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessIfconfig(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
if (otIsInterfaceUp(mInstance))
|
|
{
|
|
sServer->OutputFormat("up\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("down\r\n");
|
|
}
|
|
}
|
|
else if (strcmp(argv[0], "up") == 0)
|
|
{
|
|
SuccessOrExit(error = otInterfaceUp(mInstance));
|
|
}
|
|
else if (strcmp(argv[0], "down") == 0)
|
|
{
|
|
SuccessOrExit(error = otInterfaceDown(mInstance));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessIpAddrAdd(int argc, char *argv[])
|
|
{
|
|
ThreadError error;
|
|
otNetifAddress aAddress;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[0], &aAddress.mAddress));
|
|
aAddress.mPrefixLength = 64;
|
|
aAddress.mPreferred = true;
|
|
aAddress.mValid = true;
|
|
error = otAddUnicastAddress(mInstance, &aAddress);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessIpAddrDel(int argc, char *argv[])
|
|
{
|
|
ThreadError error;
|
|
struct otIp6Address address;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[0], &address));
|
|
error = otRemoveUnicastAddress(mInstance, &address);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
void Interpreter::ProcessIpAddr(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
for (const otNetifAddress *addr = otGetUnicastAddresses(mInstance); addr; addr = addr->mNext)
|
|
{
|
|
sServer->OutputFormat("%x:%x:%x:%x:%x:%x:%x:%x\r\n",
|
|
HostSwap16(addr->mAddress.mFields.m16[0]),
|
|
HostSwap16(addr->mAddress.mFields.m16[1]),
|
|
HostSwap16(addr->mAddress.mFields.m16[2]),
|
|
HostSwap16(addr->mAddress.mFields.m16[3]),
|
|
HostSwap16(addr->mAddress.mFields.m16[4]),
|
|
HostSwap16(addr->mAddress.mFields.m16[5]),
|
|
HostSwap16(addr->mAddress.mFields.m16[6]),
|
|
HostSwap16(addr->mAddress.mFields.m16[7]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(argv[0], "add") == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessIpAddrAdd(argc - 1, argv + 1));
|
|
}
|
|
else if (strcmp(argv[0], "del") == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessIpAddrDel(argc - 1, argv + 1));
|
|
}
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessIpMulticastAddrAdd(int argc, char *argv[])
|
|
{
|
|
ThreadError error;
|
|
struct otIp6Address address;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[0], &address));
|
|
error = otSubscribeMulticastAddress(mInstance, &address);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessIpMulticastAddrDel(int argc, char *argv[])
|
|
{
|
|
ThreadError error;
|
|
struct otIp6Address address;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[0], &address));
|
|
error = otUnsubscribeMulticastAddress(mInstance, &address);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessMulticastPromiscuous(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
if (otIsMulticastPromiscuousModeEnabled(mInstance))
|
|
{
|
|
sServer->OutputFormat("Enabled\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("Disabled\r\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(argv[0], "enable") == 0)
|
|
{
|
|
otEnableMulticastPromiscuousMode(mInstance);
|
|
}
|
|
else if (strcmp(argv[0], "disable") == 0)
|
|
{
|
|
otDisableMulticastPromiscuousMode(mInstance);
|
|
}
|
|
else
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
void Interpreter::ProcessIpMulticastAddr(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
for (const otNetifMulticastAddress *addr = otGetMulticastAddresses(mInstance); addr; addr = addr->mNext)
|
|
{
|
|
sServer->OutputFormat("%x:%x:%x:%x:%x:%x:%x:%x\r\n",
|
|
HostSwap16(addr->mAddress.mFields.m16[0]),
|
|
HostSwap16(addr->mAddress.mFields.m16[1]),
|
|
HostSwap16(addr->mAddress.mFields.m16[2]),
|
|
HostSwap16(addr->mAddress.mFields.m16[3]),
|
|
HostSwap16(addr->mAddress.mFields.m16[4]),
|
|
HostSwap16(addr->mAddress.mFields.m16[5]),
|
|
HostSwap16(addr->mAddress.mFields.m16[6]),
|
|
HostSwap16(addr->mAddress.mFields.m16[7]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(argv[0], "add") == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessIpMulticastAddrAdd(argc - 1, argv + 1));
|
|
}
|
|
else if (strcmp(argv[0], "del") == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessIpMulticastAddrDel(argc - 1, argv + 1));
|
|
}
|
|
else if (strcmp(argv[0], "promiscuous") == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessMulticastPromiscuous(argc - 1, argv + 1));
|
|
}
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessKeySequence(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
VerifyOrExit(argc == 1 || argc == 2, error = kThreadError_Parse);
|
|
|
|
if (strcmp(argv[0], "counter") == 0)
|
|
{
|
|
if (argc == 1)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetKeySequenceCounter(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[1], value));
|
|
otSetKeySequenceCounter(mInstance, static_cast<uint32_t>(value));
|
|
}
|
|
}
|
|
else if (strcmp(argv[0], "guardtime") == 0)
|
|
{
|
|
if (argc == 1)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetKeySwitchGuardTime(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[1], value));
|
|
otSetKeySwitchGuardTime(mInstance, static_cast<uint32_t>(value));
|
|
}
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessLeaderData(int argc, char *argv[])
|
|
{
|
|
ThreadError error;
|
|
otLeaderData leaderData;
|
|
|
|
SuccessOrExit(error = otGetLeaderData(mInstance, &leaderData));
|
|
|
|
sServer->OutputFormat("Partition ID: %u\r\n", leaderData.mPartitionId);
|
|
sServer->OutputFormat("Weighting: %d\r\n", leaderData.mWeighting);
|
|
sServer->OutputFormat("Data Version: %d\r\n", leaderData.mDataVersion);
|
|
sServer->OutputFormat("Stable Data Version: %d\r\n", leaderData.mStableDataVersion);
|
|
sServer->OutputFormat("Leader Router ID: %d\r\n", leaderData.mLeaderRouterId);
|
|
|
|
exit:
|
|
(void)argc;
|
|
(void)argv;
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessLeaderPartitionId(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
unsigned long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%u\r\n", otGetLocalLeaderPartitionId(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseUnsignedLong(argv[0], value));
|
|
otSetLocalLeaderPartitionId(mInstance, static_cast<uint32_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessLeaderWeight(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetLocalLeaderWeight(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
otSetLocalLeaderWeight(mInstance, static_cast<uint8_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessLinkQuality(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
uint8_t extAddress[8];
|
|
uint8_t linkQuality;
|
|
long value;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_InvalidArgs);
|
|
VerifyOrExit(Hex2Bin(argv[0], extAddress, OT_EXT_ADDRESS_SIZE) >= 0, error = kThreadError_Parse);
|
|
|
|
if (argc == 1)
|
|
{
|
|
VerifyOrExit(otGetAssignLinkQuality(mInstance, extAddress, &linkQuality) == kThreadError_None,
|
|
error = kThreadError_InvalidArgs);
|
|
sServer->OutputFormat("%d\r\n", linkQuality);
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[1], value));
|
|
otSetAssignLinkQuality(mInstance, extAddress, static_cast<uint8_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessMasterKey(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
uint8_t keyLength;
|
|
const uint8_t *key = otGetMasterKey(mInstance, &keyLength);
|
|
|
|
for (int i = 0; i < keyLength; i++)
|
|
{
|
|
sServer->OutputFormat("%02x", key[i]);
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
else
|
|
{
|
|
int keyLength;
|
|
uint8_t key[OT_MASTER_KEY_SIZE];
|
|
|
|
VerifyOrExit((keyLength = Hex2Bin(argv[0], key, sizeof(key))) == OT_MASTER_KEY_SIZE, error = kThreadError_Parse);
|
|
SuccessOrExit(error = otSetMasterKey(mInstance, key, static_cast<uint8_t>(keyLength)));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessMode(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otLinkModeConfig linkMode;
|
|
|
|
memset(&linkMode, 0, sizeof(otLinkModeConfig));
|
|
|
|
if (argc == 0)
|
|
{
|
|
linkMode = otGetLinkMode(mInstance);
|
|
|
|
if (linkMode.mRxOnWhenIdle)
|
|
{
|
|
sServer->OutputFormat("r");
|
|
}
|
|
|
|
if (linkMode.mSecureDataRequests)
|
|
{
|
|
sServer->OutputFormat("s");
|
|
}
|
|
|
|
if (linkMode.mDeviceType)
|
|
{
|
|
sServer->OutputFormat("d");
|
|
}
|
|
|
|
if (linkMode.mNetworkData)
|
|
{
|
|
sServer->OutputFormat("n");
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
else
|
|
{
|
|
for (char *arg = argv[0]; *arg != '\0'; arg++)
|
|
{
|
|
switch (*arg)
|
|
{
|
|
case 'r':
|
|
linkMode.mRxOnWhenIdle = 1;
|
|
break;
|
|
|
|
case 's':
|
|
linkMode.mSecureDataRequests = 1;
|
|
break;
|
|
|
|
case 'd':
|
|
linkMode.mDeviceType = 1;
|
|
break;
|
|
|
|
case 'n':
|
|
linkMode.mNetworkData = 1;
|
|
break;
|
|
|
|
default:
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
}
|
|
|
|
SuccessOrExit(error = otSetLinkMode(mInstance, linkMode));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessNetworkDataRegister(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
SuccessOrExit(error = otSendServerData(mInstance));
|
|
|
|
exit:
|
|
(void)argc;
|
|
(void)argv;
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessNetworkIdTimeout(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetNetworkIdTimeout(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
otSetNetworkIdTimeout(mInstance, static_cast<uint8_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessNetworkName(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%.*s\r\n", OT_NETWORK_NAME_MAX_SIZE, otGetNetworkName(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = otSetNetworkName(mInstance, argv[0]));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessPanId(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%04x\r\n", otGetPanId(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
otSetPanId(mInstance, static_cast<otPanId>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessParent(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otRouterInfo parentInfo;
|
|
|
|
SuccessOrExit(error = otGetParentInfo(mInstance, &parentInfo));
|
|
sServer->OutputFormat("Ext Addr: ");
|
|
|
|
for (size_t i = 0; i < sizeof(parentInfo.mExtAddress); i++)
|
|
{
|
|
sServer->OutputFormat("%02x", parentInfo.mExtAddress.m8[i]);
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
|
|
sServer->OutputFormat("Rloc: %x\r\n", parentInfo.mRloc16);
|
|
|
|
exit:
|
|
(void)argc;
|
|
(void)argv;
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::s_HandleEchoResponse(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
|
{
|
|
static_cast<Interpreter *>(aContext)->HandleEchoResponse(aMessage, aMessageInfo);
|
|
}
|
|
|
|
void Interpreter::HandleEchoResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
|
{
|
|
Ip6::IcmpHeader icmp6Header;
|
|
uint32_t timestamp = 0;
|
|
|
|
aMessage.Read(aMessage.GetOffset(), sizeof(icmp6Header), &icmp6Header);
|
|
|
|
sServer->OutputFormat("%d bytes from ", aMessage.GetLength() - aMessage.GetOffset());
|
|
sServer->OutputFormat("%x:%x:%x:%x:%x:%x:%x:%x",
|
|
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[0]),
|
|
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[1]),
|
|
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[2]),
|
|
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[3]),
|
|
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[4]),
|
|
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[5]),
|
|
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[6]),
|
|
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[7]));
|
|
sServer->OutputFormat(": icmp_seq=%d hlim=%d", icmp6Header.GetSequence(), aMessageInfo.mHopLimit);
|
|
|
|
if (aMessage.Read(aMessage.GetOffset() + sizeof(icmp6Header), sizeof(uint32_t), ×tamp) >=
|
|
static_cast<int>(sizeof(uint32_t)))
|
|
{
|
|
sServer->OutputFormat(" time=%dms", Timer::GetNow() - HostSwap32(timestamp));
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
|
|
void Interpreter::ProcessPing(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
uint8_t index = 1;
|
|
long value;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
VerifyOrExit(!sPingTimer.IsRunning(), error = kThreadError_Busy);
|
|
|
|
memset(&sMessageInfo, 0, sizeof(sMessageInfo));
|
|
SuccessOrExit(error = sMessageInfo.GetPeerAddr().FromString(argv[0]));
|
|
sMessageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
|
|
|
|
sLength = 8;
|
|
sCount = 1;
|
|
sInterval = 1000;
|
|
|
|
while (index < argc)
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[index], value));
|
|
|
|
switch (index)
|
|
{
|
|
case 1:
|
|
sLength = (uint16_t)value;
|
|
break;
|
|
|
|
case 2:
|
|
sCount = (uint16_t)value;
|
|
break;
|
|
|
|
case 3:
|
|
sInterval = (uint32_t)value;
|
|
sInterval = sInterval * 1000;
|
|
break;
|
|
|
|
default:
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
HandlePingTimer();
|
|
|
|
return;
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::s_HandlePingTimer(void *aContext)
|
|
{
|
|
static_cast<Interpreter *>(aContext)->HandlePingTimer();
|
|
}
|
|
|
|
void Interpreter::HandlePingTimer()
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
uint32_t timestamp = HostSwap32(Timer::GetNow());
|
|
Message *message;
|
|
|
|
VerifyOrExit((message = mInstance->mIp6.mIcmp.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
|
SuccessOrExit(error = message->Append(×tamp, sizeof(timestamp)));
|
|
SuccessOrExit(error = message->SetLength(sLength));
|
|
|
|
SuccessOrExit(error = mInstance->mIp6.mIcmp.SendEchoRequest(*message, sMessageInfo));
|
|
sCount--;
|
|
|
|
exit:
|
|
|
|
if (error != kThreadError_None && message != NULL)
|
|
{
|
|
message->Free();
|
|
}
|
|
|
|
if (sCount)
|
|
{
|
|
sPingTimer.Start(sInterval);
|
|
}
|
|
}
|
|
|
|
void Interpreter::ProcessPollPeriod(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", (otGetPollPeriod(mInstance) / 1000)); // ms->s
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
otSetPollPeriod(mInstance, static_cast<uint32_t>(value * 1000)); // s->ms
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessPromiscuous(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
if (otIsLinkPromiscuous(mInstance) && otPlatRadioGetPromiscuous(mInstance))
|
|
{
|
|
sServer->OutputFormat("Enabled\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("Disabled\r\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(argv[0], "enable") == 0)
|
|
{
|
|
otSetLinkPcapCallback(mInstance, &s_HandleLinkPcapReceive, this);
|
|
SuccessOrExit(error = otSetLinkPromiscuous(mInstance, true));
|
|
}
|
|
else if (strcmp(argv[0], "disable") == 0)
|
|
{
|
|
otSetLinkPcapCallback(mInstance, NULL, NULL);
|
|
SuccessOrExit(error = otSetLinkPromiscuous(mInstance, false));
|
|
}
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::s_HandleLinkPcapReceive(const RadioPacket *aFrame, void *aContext)
|
|
{
|
|
static_cast<Interpreter *>(aContext)->HandleLinkPcapReceive(aFrame);
|
|
}
|
|
|
|
void Interpreter::HandleLinkPcapReceive(const RadioPacket *aFrame)
|
|
{
|
|
sServer->OutputFormat("\r\n");
|
|
|
|
for (size_t i = 0; i < 44; i++)
|
|
{
|
|
sServer->OutputFormat("=");
|
|
}
|
|
|
|
sServer->OutputFormat("[len = %3u]", aFrame->mLength);
|
|
|
|
for (size_t i = 0; i < 28; i++)
|
|
{
|
|
sServer->OutputFormat("=");
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
|
|
for (size_t i = 0; i < aFrame->mLength; i += 16)
|
|
{
|
|
sServer->OutputFormat("|");
|
|
|
|
for (size_t j = 0; j < 16; j++)
|
|
{
|
|
if (i + j < aFrame->mLength)
|
|
{
|
|
sServer->OutputFormat(" %02X", aFrame->mPsdu[i + j]);
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat(" ..");
|
|
}
|
|
}
|
|
|
|
sServer->OutputFormat("|");
|
|
|
|
for (size_t j = 0; j < 16; j++)
|
|
{
|
|
if (i + j < aFrame->mLength)
|
|
{
|
|
if (31 < aFrame->mPsdu[i + j] && aFrame->mPsdu[i + j] < 127)
|
|
{
|
|
sServer->OutputFormat(" %c", aFrame->mPsdu[i + j]);
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat(" ?");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat(" .");
|
|
}
|
|
}
|
|
|
|
sServer->OutputFormat("|\r\n");
|
|
}
|
|
|
|
for (size_t i = 0; i < 83; i++)
|
|
{
|
|
sServer->OutputFormat("-");
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessPrefixAdd(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otBorderRouterConfig config;
|
|
int argcur = 0;
|
|
|
|
memset(&config, 0, sizeof(otBorderRouterConfig));
|
|
|
|
char *prefixLengthStr;
|
|
char *endptr;
|
|
|
|
if ((prefixLengthStr = strchr(argv[argcur], '/')) == NULL)
|
|
{
|
|
ExitNow();
|
|
}
|
|
|
|
*prefixLengthStr++ = '\0';
|
|
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[argcur], &config.mPrefix.mPrefix));
|
|
|
|
config.mPrefix.mLength = static_cast<uint8_t>(strtol(prefixLengthStr, &endptr, 0));
|
|
|
|
if (*endptr != '\0')
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
|
|
argcur++;
|
|
|
|
for (; argcur < argc; argcur++)
|
|
{
|
|
if (strcmp(argv[argcur], "high") == 0)
|
|
{
|
|
config.mPreference = 1;
|
|
}
|
|
else if (strcmp(argv[argcur], "med") == 0)
|
|
{
|
|
config.mPreference = 0;
|
|
}
|
|
else if (strcmp(argv[argcur], "low") == 0)
|
|
{
|
|
config.mPreference = -1;
|
|
}
|
|
else
|
|
{
|
|
for (char *arg = argv[argcur]; *arg != '\0'; arg++)
|
|
{
|
|
switch (*arg)
|
|
{
|
|
case 'p':
|
|
config.mPreferred = true;
|
|
break;
|
|
|
|
case 'a':
|
|
config.mSlaac = true;
|
|
break;
|
|
|
|
case 'd':
|
|
config.mDhcp = true;
|
|
break;
|
|
|
|
case 'c':
|
|
config.mConfigure = true;
|
|
break;
|
|
|
|
case 'r':
|
|
config.mDefaultRoute = true;
|
|
break;
|
|
|
|
case 'o':
|
|
config.mOnMesh = true;
|
|
break;
|
|
|
|
case 's':
|
|
config.mStable = true;
|
|
break;
|
|
|
|
default:
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
error = otAddBorderRouter(mInstance, &config);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessPrefixRemove(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
struct otIp6Prefix prefix;
|
|
int argcur = 0;
|
|
|
|
memset(&prefix, 0, sizeof(otIp6Prefix));
|
|
|
|
char *prefixLengthStr;
|
|
char *endptr;
|
|
|
|
if ((prefixLengthStr = strchr(argv[argcur], '/')) == NULL)
|
|
{
|
|
ExitNow();
|
|
}
|
|
|
|
*prefixLengthStr++ = '\0';
|
|
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[argcur], &prefix.mPrefix));
|
|
|
|
prefix.mLength = static_cast<uint8_t>(strtol(prefixLengthStr, &endptr, 0));
|
|
|
|
if (*endptr != '\0')
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
|
|
error = otRemoveBorderRouter(mInstance, &prefix);
|
|
|
|
exit:
|
|
(void)argc;
|
|
return error;
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessPrefixList(void)
|
|
{
|
|
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
|
|
otBorderRouterConfig config;
|
|
|
|
while (otGetNextOnMeshPrefix(mInstance, true, &iterator, &config) == kThreadError_None)
|
|
{
|
|
sServer->OutputFormat("%x:%x:%x:%x::/%d ",
|
|
HostSwap16(config.mPrefix.mPrefix.mFields.m16[0]),
|
|
HostSwap16(config.mPrefix.mPrefix.mFields.m16[1]),
|
|
HostSwap16(config.mPrefix.mPrefix.mFields.m16[2]),
|
|
HostSwap16(config.mPrefix.mPrefix.mFields.m16[3]),
|
|
config.mPrefix.mLength);
|
|
|
|
if (config.mPreferred)
|
|
{
|
|
sServer->OutputFormat("p");
|
|
}
|
|
|
|
if (config.mSlaac)
|
|
{
|
|
sServer->OutputFormat("a");
|
|
}
|
|
|
|
if (config.mDhcp)
|
|
{
|
|
sServer->OutputFormat("d");
|
|
}
|
|
|
|
if (config.mConfigure)
|
|
{
|
|
sServer->OutputFormat("c");
|
|
}
|
|
|
|
if (config.mDefaultRoute)
|
|
{
|
|
sServer->OutputFormat("r");
|
|
}
|
|
|
|
if (config.mOnMesh)
|
|
{
|
|
sServer->OutputFormat("o");
|
|
}
|
|
|
|
if (config.mStable)
|
|
{
|
|
sServer->OutputFormat("s");
|
|
}
|
|
|
|
switch (config.mPreference)
|
|
{
|
|
case -1:
|
|
sServer->OutputFormat(" low\r\n");
|
|
break;
|
|
|
|
case 0:
|
|
sServer->OutputFormat(" med\r\n");
|
|
break;
|
|
|
|
case 1:
|
|
sServer->OutputFormat(" high\r\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return kThreadError_None;
|
|
}
|
|
|
|
void Interpreter::ProcessPrefix(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessPrefixList());
|
|
}
|
|
else if (strcmp(argv[0], "add") == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessPrefixAdd(argc - 1, argv + 1));
|
|
}
|
|
else if (strcmp(argv[0], "remove") == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessPrefixRemove(argc - 1, argv + 1));
|
|
}
|
|
else
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessReleaseRouterId(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
SuccessOrExit(error = otReleaseRouterId(mInstance, static_cast<uint8_t>(value)));
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessReset(int argc, char *argv[])
|
|
{
|
|
otPlatformReset(mInstance);
|
|
(void)argc;
|
|
(void)argv;
|
|
}
|
|
|
|
void Interpreter::ProcessRloc16(int argc, char *argv[])
|
|
{
|
|
sServer->OutputFormat("%04x\r\n", otGetRloc16(mInstance));
|
|
sServer->OutputFormat("Done\r\n");
|
|
(void)argc;
|
|
(void)argv;
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessRouteAdd(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otExternalRouteConfig config;
|
|
int argcur = 0;
|
|
|
|
memset(&config, 0, sizeof(otExternalRouteConfig));
|
|
|
|
char *prefixLengthStr;
|
|
char *endptr;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
if ((prefixLengthStr = strchr(argv[argcur], '/')) == NULL)
|
|
{
|
|
ExitNow();
|
|
}
|
|
|
|
*prefixLengthStr++ = '\0';
|
|
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[argcur], &config.mPrefix.mPrefix));
|
|
|
|
config.mPrefix.mLength = static_cast<uint8_t>(strtol(prefixLengthStr, &endptr, 0));
|
|
|
|
if (*endptr != '\0')
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
|
|
argcur++;
|
|
|
|
for (; argcur < argc; argcur++)
|
|
{
|
|
if (strcmp(argv[argcur], "s") == 0)
|
|
{
|
|
config.mStable = true;
|
|
}
|
|
else if (strcmp(argv[argcur], "high") == 0)
|
|
{
|
|
config.mPreference = 1;
|
|
}
|
|
else if (strcmp(argv[argcur], "med") == 0)
|
|
{
|
|
config.mPreference = 0;
|
|
}
|
|
else if (strcmp(argv[argcur], "low") == 0)
|
|
{
|
|
config.mPreference = -1;
|
|
}
|
|
else
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
}
|
|
|
|
error = otAddExternalRoute(mInstance, &config);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
ThreadError Interpreter::ProcessRouteRemove(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
struct otIp6Prefix prefix;
|
|
int argcur = 0;
|
|
|
|
memset(&prefix, 0, sizeof(struct otIp6Prefix));
|
|
char *prefixLengthStr;
|
|
char *endptr;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
if ((prefixLengthStr = strchr(argv[argcur], '/')) == NULL)
|
|
{
|
|
ExitNow();
|
|
}
|
|
|
|
*prefixLengthStr++ = '\0';
|
|
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[argcur], &prefix.mPrefix));
|
|
|
|
prefix.mLength = static_cast<uint8_t>(strtol(prefixLengthStr, &endptr, 0));
|
|
|
|
if (*endptr != '\0')
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
|
|
error = otRemoveExternalRoute(mInstance, &prefix);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
void Interpreter::ProcessRoute(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
if (strcmp(argv[0], "add") == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessRouteAdd(argc - 1, argv + 1));
|
|
}
|
|
else if (strcmp(argv[0], "remove") == 0)
|
|
{
|
|
SuccessOrExit(error = ProcessRouteRemove(argc - 1, argv + 1));
|
|
}
|
|
else
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessRouter(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otRouterInfo routerInfo;
|
|
long value;
|
|
bool isTable = false;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
if (strcmp(argv[0], "list") == 0 || (isTable = (strcmp(argv[0], "table") == 0)))
|
|
{
|
|
if (isTable)
|
|
{
|
|
sServer->OutputFormat("| ID | RLOC16 | Next Hop | Path Cost | LQI In | LQI Out | Age | Extended MAC |\r\n");
|
|
sServer->OutputFormat("+----+--------+----------+-----------+--------+---------+-----+------------------+\r\n");
|
|
}
|
|
|
|
for (uint8_t i = 0; ; i++)
|
|
{
|
|
if (otGetRouterInfo(mInstance, i, &routerInfo) != kThreadError_None)
|
|
{
|
|
sServer->OutputFormat("\r\n");
|
|
ExitNow();
|
|
}
|
|
|
|
if (routerInfo.mAllocated)
|
|
{
|
|
if (isTable)
|
|
{
|
|
sServer->OutputFormat("| %2d ", routerInfo.mRouterId);
|
|
sServer->OutputFormat("| 0x%04x ", routerInfo.mRloc16);
|
|
sServer->OutputFormat("| %8d ", routerInfo.mNextHop);
|
|
sServer->OutputFormat("| %9d ", routerInfo.mPathCost);
|
|
sServer->OutputFormat("| %6d ", routerInfo.mLinkQualityIn);
|
|
sServer->OutputFormat("| %7d ", routerInfo.mLinkQualityOut);
|
|
sServer->OutputFormat("| %3d ", routerInfo.mAge);
|
|
sServer->OutputFormat("| ");
|
|
|
|
for (size_t j = 0; j < sizeof(routerInfo.mExtAddress); j++)
|
|
{
|
|
sServer->OutputFormat("%02x", routerInfo.mExtAddress.m8[j]);
|
|
}
|
|
|
|
sServer->OutputFormat(" |\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("%d ", i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
SuccessOrExit(error = otGetRouterInfo(mInstance, static_cast<uint16_t>(value), &routerInfo));
|
|
|
|
sServer->OutputFormat("Alloc: %d\r\n", routerInfo.mAllocated);
|
|
|
|
if (routerInfo.mAllocated)
|
|
{
|
|
sServer->OutputFormat("Router ID: %d\r\n", routerInfo.mRouterId);
|
|
sServer->OutputFormat("Rloc: %04x\r\n", routerInfo.mRloc16);
|
|
sServer->OutputFormat("Next Hop: %04x\r\n", static_cast<uint16_t>(routerInfo.mNextHop) << 10);
|
|
sServer->OutputFormat("Link: %d\r\n", routerInfo.mLinkEstablished);
|
|
|
|
if (routerInfo.mLinkEstablished)
|
|
{
|
|
sServer->OutputFormat("Ext Addr: ");
|
|
|
|
for (size_t j = 0; j < sizeof(routerInfo.mExtAddress); j++)
|
|
{
|
|
sServer->OutputFormat("%02x", routerInfo.mExtAddress.m8[j]);
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
sServer->OutputFormat("Cost: %d\r\n", routerInfo.mPathCost);
|
|
sServer->OutputFormat("LQI In: %d\r\n", routerInfo.mLinkQualityIn);
|
|
sServer->OutputFormat("LQI Out: %d\r\n", routerInfo.mLinkQualityOut);
|
|
sServer->OutputFormat("Age: %d\r\n", routerInfo.mAge);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessRouterDowngradeThreshold(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetRouterDowngradeThreshold(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
otSetRouterDowngradeThreshold(mInstance, static_cast<uint8_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessRouterRole(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
if (otIsRouterRoleEnabled(mInstance))
|
|
{
|
|
sServer->OutputFormat("Enabled\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("Disabled\r\n");
|
|
}
|
|
}
|
|
else if (strcmp(argv[0], "enable") == 0)
|
|
{
|
|
otSetRouterRoleEnabled(mInstance, true);
|
|
}
|
|
else if (strcmp(argv[0], "disable") == 0)
|
|
{
|
|
otSetRouterRoleEnabled(mInstance, false);
|
|
}
|
|
else
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessRouterSelectionJitter(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetRouterSelectionJitter(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
VerifyOrExit(0 < value && value < 256, error = kThreadError_InvalidArgs);
|
|
otSetRouterSelectionJitter(mInstance, static_cast<uint8_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessRouterUpgradeThreshold(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetRouterUpgradeThreshold(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
otSetRouterUpgradeThreshold(mInstance, static_cast<uint8_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessScan(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
uint32_t scanChannels = 0;
|
|
long value;
|
|
|
|
if (argc > 0)
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
scanChannels = 1 << value;
|
|
}
|
|
|
|
SuccessOrExit(error = otActiveScan(mInstance, scanChannels, 0, &Interpreter::s_HandleActiveScanResult, this));
|
|
sServer->OutputFormat("| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |\r\n");
|
|
sServer->OutputFormat("+---+------------------+------------------+------+------------------+----+-----+-----+\r\n");
|
|
|
|
return;
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::s_HandleActiveScanResult(otActiveScanResult *aResult, void *aContext)
|
|
{
|
|
static_cast<Interpreter *>(aContext)->HandleActiveScanResult(aResult);
|
|
}
|
|
|
|
void Interpreter::HandleActiveScanResult(otActiveScanResult *aResult)
|
|
{
|
|
if (aResult == NULL)
|
|
{
|
|
sServer->OutputFormat("Done\r\n");
|
|
ExitNow();
|
|
}
|
|
|
|
sServer->OutputFormat("| %d ", aResult->mIsJoinable);
|
|
|
|
sServer->OutputFormat("| %-16s ", aResult->mNetworkName.m8);
|
|
|
|
sServer->OutputFormat("| ");
|
|
OutputBytes(aResult->mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE);
|
|
sServer->OutputFormat(" ");
|
|
|
|
sServer->OutputFormat("| %04x | ", aResult->mPanId);
|
|
OutputBytes(aResult->mExtAddress.m8, OT_EXT_ADDRESS_SIZE);
|
|
sServer->OutputFormat(" | %2d ", aResult->mChannel);
|
|
sServer->OutputFormat("| %3d ", aResult->mRssi);
|
|
sServer->OutputFormat("| %3d |\r\n", aResult->mLqi);
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
void Interpreter::ProcessSingleton(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (otIsSingleton(mInstance))
|
|
{
|
|
sServer->OutputFormat("true\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("false\r\n");
|
|
}
|
|
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessState(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
if (argc == 0)
|
|
{
|
|
switch (otGetDeviceRole(mInstance))
|
|
{
|
|
case kDeviceRoleOffline:
|
|
sServer->OutputFormat("offline\r\n");
|
|
break;
|
|
|
|
case kDeviceRoleDisabled:
|
|
sServer->OutputFormat("disabled\r\n");
|
|
break;
|
|
|
|
case kDeviceRoleDetached:
|
|
sServer->OutputFormat("detached\r\n");
|
|
break;
|
|
|
|
case kDeviceRoleChild:
|
|
sServer->OutputFormat("child\r\n");
|
|
break;
|
|
|
|
case kDeviceRoleRouter:
|
|
sServer->OutputFormat("router\r\n");
|
|
break;
|
|
|
|
case kDeviceRoleLeader:
|
|
sServer->OutputFormat("leader\r\n");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(argv[0], "detached") == 0)
|
|
{
|
|
SuccessOrExit(error = otBecomeDetached(mInstance));
|
|
}
|
|
else if (strcmp(argv[0], "child") == 0)
|
|
{
|
|
SuccessOrExit(error = otBecomeChild(mInstance, kMleAttachSamePartition1));
|
|
}
|
|
else if (strcmp(argv[0], "router") == 0)
|
|
{
|
|
SuccessOrExit(error = otBecomeRouter(mInstance));
|
|
}
|
|
else if (strcmp(argv[0], "leader") == 0)
|
|
{
|
|
SuccessOrExit(error = otBecomeLeader(mInstance));
|
|
}
|
|
else
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessThread(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_Parse;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
if (strcmp(argv[0], "start") == 0)
|
|
{
|
|
SuccessOrExit(error = otThreadStart(mInstance));
|
|
}
|
|
else if (strcmp(argv[0], "stop") == 0)
|
|
{
|
|
SuccessOrExit(error = otThreadStop(mInstance));
|
|
}
|
|
|
|
exit:
|
|
(void)argc;
|
|
(void)argv;
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessVersion(int argc, char *argv[])
|
|
{
|
|
sServer->OutputFormat("%s\r\n", otGetVersionString());
|
|
AppendResult(kThreadError_None);
|
|
(void)argc;
|
|
(void)argv;
|
|
}
|
|
|
|
#if OPENTHREAD_ENABLE_COMMISSIONER
|
|
|
|
void Interpreter::ProcessCommissioner(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
if (strcmp(argv[0], "start") == 0)
|
|
{
|
|
SuccessOrExit(error = otCommissionerStart(mInstance));
|
|
}
|
|
else if (strcmp(argv[0], "stop") == 0)
|
|
{
|
|
SuccessOrExit(error = otCommissionerStop(mInstance));
|
|
}
|
|
else if (strcmp(argv[0], "joiner") == 0)
|
|
{
|
|
otExtAddress addr;
|
|
const otExtAddress *addrPtr;
|
|
|
|
VerifyOrExit(argc > 2, error = kThreadError_Parse);
|
|
|
|
if (strcmp(argv[2], "*") == 0)
|
|
{
|
|
addrPtr = NULL;
|
|
}
|
|
else
|
|
{
|
|
VerifyOrExit(Hex2Bin(argv[2], addr.m8, sizeof(addr)) == sizeof(addr), error = kThreadError_Parse);
|
|
addrPtr = &addr;
|
|
}
|
|
|
|
if (strcmp(argv[1], "add") == 0)
|
|
{
|
|
VerifyOrExit(argc > 3, error = kThreadError_Parse);
|
|
SuccessOrExit(error = otCommissionerAddJoiner(mInstance, addrPtr, argv[3]));
|
|
}
|
|
else if (strcmp(argv[1], "remove") == 0)
|
|
{
|
|
SuccessOrExit(error = otCommissionerRemoveJoiner(mInstance, addrPtr));
|
|
}
|
|
}
|
|
else if (strcmp(argv[0], "provisioningurl") == 0)
|
|
{
|
|
SuccessOrExit(error = otCommissionerSetProvisioningUrl(mInstance, (argc > 1) ? argv[1] : NULL));
|
|
}
|
|
else if (strcmp(argv[0], "announce") == 0)
|
|
{
|
|
long mask;
|
|
long count;
|
|
long period;
|
|
otIp6Address address;
|
|
|
|
VerifyOrExit(argc > 4, error = kThreadError_Parse);
|
|
|
|
// mask
|
|
SuccessOrExit(error = ParseLong(argv[1], mask));
|
|
|
|
// count
|
|
SuccessOrExit(error = ParseLong(argv[2], count));
|
|
|
|
// period
|
|
SuccessOrExit(error = ParseLong(argv[3], period));
|
|
|
|
// destination
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[4], &address));
|
|
|
|
SuccessOrExit(error = otCommissionerAnnounceBegin(mInstance,
|
|
static_cast<uint32_t>(mask),
|
|
static_cast<uint8_t>(count),
|
|
static_cast<uint16_t>(period),
|
|
&address));
|
|
}
|
|
else if (strcmp(argv[0], "energy") == 0)
|
|
{
|
|
long mask;
|
|
long count;
|
|
long period;
|
|
long scanDuration;
|
|
otIp6Address address;
|
|
|
|
VerifyOrExit(argc > 5, error = kThreadError_Parse);
|
|
|
|
// mask
|
|
SuccessOrExit(error = ParseLong(argv[1], mask));
|
|
|
|
// count
|
|
SuccessOrExit(error = ParseLong(argv[2], count));
|
|
|
|
// period
|
|
SuccessOrExit(error = ParseLong(argv[3], period));
|
|
|
|
// scan duration
|
|
SuccessOrExit(error = ParseLong(argv[4], scanDuration));
|
|
|
|
// destination
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[5], &address));
|
|
|
|
SuccessOrExit(error = otCommissionerEnergyScan(mInstance,
|
|
static_cast<uint32_t>(mask),
|
|
static_cast<uint8_t>(count),
|
|
static_cast<uint16_t>(period),
|
|
static_cast<uint16_t>(scanDuration),
|
|
&address,
|
|
Interpreter::s_HandleEnergyReport,
|
|
this));
|
|
}
|
|
else if (strcmp(argv[0], "panid") == 0)
|
|
{
|
|
long panid;
|
|
long mask;
|
|
otIp6Address address;
|
|
|
|
VerifyOrExit(argc > 3, error = kThreadError_Parse);
|
|
|
|
// panid
|
|
SuccessOrExit(error = ParseLong(argv[1], panid));
|
|
|
|
// mask
|
|
SuccessOrExit(error = ParseLong(argv[2], mask));
|
|
|
|
// destination
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[3], &address));
|
|
|
|
SuccessOrExit(error = otCommissionerPanIdQuery(mInstance,
|
|
static_cast<uint16_t>(panid),
|
|
static_cast<uint32_t>(mask),
|
|
&address,
|
|
Interpreter::s_HandlePanIdConflict,
|
|
this));
|
|
}
|
|
else if (strcmp(argv[0], "mgmtget") == 0)
|
|
{
|
|
uint8_t tlvs[32];
|
|
long value;
|
|
int length = 0;
|
|
|
|
for (uint8_t index = 1; index < argc; index++)
|
|
{
|
|
VerifyOrExit(static_cast<size_t>(length) < sizeof(tlvs), error = kThreadError_NoBufs);
|
|
|
|
if (strcmp(argv[index], "locator") == 0)
|
|
{
|
|
tlvs[length++] = OT_MESHCOP_TLV_BORDER_AGENT_RLOC;
|
|
}
|
|
else if (strcmp(argv[index], "sessionid") == 0)
|
|
{
|
|
tlvs[length++] = OT_MESHCOP_TLV_COMM_SESSION_ID;
|
|
}
|
|
else if (strcmp(argv[index], "steeringdata") == 0)
|
|
{
|
|
tlvs[length++] = OT_MESHCOP_TLV_STEERING_DATA;
|
|
}
|
|
else if (strcmp(argv[index], "joinerudpport") == 0)
|
|
{
|
|
tlvs[length++] = OT_MESHCOP_TLV_JOINER_UDP_PORT;
|
|
}
|
|
else if (strcmp(argv[index], "binary") == 0)
|
|
{
|
|
VerifyOrExit(++index < argc, error = kThreadError_Parse);
|
|
value = static_cast<long>(strlen(argv[index]) + 1) / 2;
|
|
VerifyOrExit(static_cast<size_t>(value) <= (sizeof(tlvs) - static_cast<size_t>(length)), error = kThreadError_NoBufs);
|
|
VerifyOrExit(Interpreter::Hex2Bin(argv[index], tlvs + length, static_cast<uint16_t>(value)) >= 0,
|
|
error = kThreadError_Parse);
|
|
length += value;
|
|
}
|
|
else
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
}
|
|
|
|
SuccessOrExit(error = otSendMgmtCommissionerGet(mInstance, tlvs, static_cast<uint8_t>(length)));
|
|
}
|
|
else if (strcmp(argv[0], "mgmtset") == 0)
|
|
{
|
|
otCommissioningDataset dataset;
|
|
uint8_t tlvs[32];
|
|
long value;
|
|
int length = 0;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
memset(&dataset, 0, sizeof(dataset));
|
|
|
|
for (uint8_t index = 1; index < argc; index++)
|
|
{
|
|
VerifyOrExit(static_cast<size_t>(length) < sizeof(tlvs), error = kThreadError_NoBufs);
|
|
|
|
if (strcmp(argv[index], "locator") == 0)
|
|
{
|
|
VerifyOrExit(++index < argc, error = kThreadError_Parse);
|
|
dataset.mIsLocatorSet = true;
|
|
SuccessOrExit(error = Interpreter::ParseLong(argv[index], value));
|
|
dataset.mLocator = static_cast<uint16_t>(value);
|
|
}
|
|
else if (strcmp(argv[index], "sessionid") == 0)
|
|
{
|
|
VerifyOrExit(++index < argc, error = kThreadError_Parse);
|
|
dataset.mIsSessionIdSet = true;
|
|
SuccessOrExit(error = Interpreter::ParseLong(argv[index], value));
|
|
dataset.mSessionId = static_cast<uint16_t>(value);
|
|
}
|
|
else if (strcmp(argv[index], "steeringdata") == 0)
|
|
{
|
|
VerifyOrExit(++index < argc, error = kThreadError_Parse);
|
|
dataset.mIsSteeringDataSet = true;
|
|
length = static_cast<int>((strlen(argv[index]) + 1) / 2);
|
|
VerifyOrExit(static_cast<size_t>(length) <= OT_STEERING_DATA_MAX_LENGTH, error = kThreadError_NoBufs);
|
|
VerifyOrExit(Interpreter::Hex2Bin(argv[index], dataset.mSteeringData.m8, static_cast<uint16_t>(length)) >= 0,
|
|
error = kThreadError_Parse);
|
|
dataset.mSteeringData.mLength = static_cast<uint8_t>(length);
|
|
length = 0;
|
|
}
|
|
else if (strcmp(argv[index], "joinerudpport") == 0)
|
|
{
|
|
VerifyOrExit(++index < argc, error = kThreadError_Parse);
|
|
dataset.mIsJoinerUdpPortSet = true;
|
|
SuccessOrExit(error = Interpreter::ParseLong(argv[index], value));
|
|
dataset.mJoinerUdpPort = static_cast<uint16_t>(value);
|
|
}
|
|
else if (strcmp(argv[index], "binary") == 0)
|
|
{
|
|
VerifyOrExit(++index < argc, error = kThreadError_Parse);
|
|
length = static_cast<int>((strlen(argv[index]) + 1) / 2);
|
|
VerifyOrExit(static_cast<size_t>(length) <= sizeof(tlvs), error = kThreadError_NoBufs);
|
|
VerifyOrExit(Interpreter::Hex2Bin(argv[index], tlvs, static_cast<uint16_t>(length)) >= 0,
|
|
error = kThreadError_Parse);
|
|
}
|
|
else
|
|
{
|
|
ExitNow(error = kThreadError_Parse);
|
|
}
|
|
}
|
|
|
|
SuccessOrExit(error = otSendMgmtCommissionerSet(mInstance, &dataset, tlvs, static_cast<uint8_t>(length)));
|
|
}
|
|
else if (strcmp(argv[0], "sessionid") == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otCommissionerGetSessionId(mInstance));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::s_HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength,
|
|
void *aContext)
|
|
{
|
|
static_cast<Interpreter *>(aContext)->HandleEnergyReport(aChannelMask, aEnergyList, aEnergyListLength);
|
|
}
|
|
|
|
void Interpreter::HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength)
|
|
{
|
|
sServer->OutputFormat("Energy: %08x ", aChannelMask);
|
|
|
|
for (uint8_t i = 0; i < aEnergyListLength; i++)
|
|
{
|
|
sServer->OutputFormat("%d ", aEnergyList[i]);
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
|
|
void Interpreter::s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext)
|
|
{
|
|
static_cast<Interpreter *>(aContext)->HandlePanIdConflict(aPanId, aChannelMask);
|
|
}
|
|
|
|
void Interpreter::HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask)
|
|
{
|
|
sServer->OutputFormat("Conflict: %04x, %08x\r\n", aPanId, aChannelMask);
|
|
}
|
|
|
|
#endif // OPENTHREAD_ENABLE_COMMISSIONER
|
|
|
|
#if OPENTHREAD_ENABLE_JOINER
|
|
|
|
void Interpreter::ProcessJoiner(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
|
|
VerifyOrExit(argc > 0, error = kThreadError_Parse);
|
|
|
|
if (strcmp(argv[0], "start") == 0)
|
|
{
|
|
const char *provisioningUrl;
|
|
VerifyOrExit(argc > 1, error = kThreadError_Parse);
|
|
provisioningUrl = (argc > 2) ? argv[2] : NULL;
|
|
otJoinerStart(mInstance, argv[1], provisioningUrl,
|
|
PACKAGE_NAME, PLATFORM_INFO, PACKAGE_VERSION, NULL,
|
|
&Interpreter::s_HandleJoinerCallback, this);
|
|
}
|
|
else if (strcmp(argv[0], "stop") == 0)
|
|
{
|
|
otJoinerStop(mInstance);
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
#endif // OPENTHREAD_ENABLE_JOINER
|
|
|
|
void Interpreter::s_HandleJoinerCallback(ThreadError aError, void *aContext)
|
|
{
|
|
static_cast<Interpreter *>(aContext)->HandleJoinerCallback(aError);
|
|
}
|
|
|
|
void Interpreter::HandleJoinerCallback(ThreadError aError)
|
|
{
|
|
switch (aError)
|
|
{
|
|
case kThreadError_None:
|
|
sServer->OutputFormat("Join success\r\n");
|
|
break;
|
|
|
|
default:
|
|
sServer->OutputFormat("Join failed [%s]\r\n", otThreadErrorToString(aError));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Interpreter::ProcessJoinerPort(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
long value;
|
|
|
|
if (argc == 0)
|
|
{
|
|
sServer->OutputFormat("%d\r\n", otGetJoinerUdpPort(mInstance));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrExit(error = ParseLong(argv[0], value));
|
|
error = otSetJoinerUdpPort(mInstance, static_cast<uint16_t>(value));
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::ProcessWhitelist(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
otMacWhitelistEntry entry;
|
|
int argcur = 0;
|
|
uint8_t extAddr[8];
|
|
int8_t rssi;
|
|
|
|
if (argcur >= argc)
|
|
{
|
|
if (otIsMacWhitelistEnabled(mInstance))
|
|
{
|
|
sServer->OutputFormat("Enabled\r\n");
|
|
}
|
|
else
|
|
{
|
|
sServer->OutputFormat("Disabled\r\n");
|
|
}
|
|
|
|
for (uint8_t i = 0; ; i++)
|
|
{
|
|
if (otGetMacWhitelistEntry(mInstance, i, &entry) != kThreadError_None)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (entry.mValid == false)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
OutputBytes(entry.mExtAddress.m8, OT_EXT_ADDRESS_SIZE);
|
|
|
|
if (entry.mFixedRssi)
|
|
{
|
|
sServer->OutputFormat(" %d", entry.mRssi);
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
}
|
|
else if (strcmp(argv[argcur], "add") == 0)
|
|
{
|
|
VerifyOrExit(++argcur < argc, error = kThreadError_Parse);
|
|
VerifyOrExit(Hex2Bin(argv[argcur], extAddr, sizeof(extAddr)) == sizeof(extAddr), error = kThreadError_Parse);
|
|
|
|
if (++argcur < argc)
|
|
{
|
|
rssi = static_cast<int8_t>(strtol(argv[argcur], NULL, 0));
|
|
VerifyOrExit(otAddMacWhitelistRssi(mInstance, extAddr, rssi) == kThreadError_None, error = kThreadError_Parse);
|
|
}
|
|
else
|
|
{
|
|
otAddMacWhitelist(mInstance, extAddr);
|
|
VerifyOrExit(otAddMacWhitelist(mInstance, extAddr) == kThreadError_None, error = kThreadError_Parse);
|
|
}
|
|
}
|
|
else if (strcmp(argv[argcur], "clear") == 0)
|
|
{
|
|
otClearMacWhitelist(mInstance);
|
|
}
|
|
else if (strcmp(argv[argcur], "disable") == 0)
|
|
{
|
|
otDisableMacWhitelist(mInstance);
|
|
}
|
|
else if (strcmp(argv[argcur], "enable") == 0)
|
|
{
|
|
otEnableMacWhitelist(mInstance);
|
|
}
|
|
else if (strcmp(argv[argcur], "remove") == 0)
|
|
{
|
|
VerifyOrExit(++argcur < argc, error = kThreadError_Parse);
|
|
VerifyOrExit(Hex2Bin(argv[argcur], extAddr, sizeof(extAddr)) == sizeof(extAddr), error = kThreadError_Parse);
|
|
otRemoveMacWhitelist(mInstance, extAddr);
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
#if OPENTHREAD_ENABLE_DIAG
|
|
void Interpreter::ProcessDiag(int argc, char *argv[])
|
|
{
|
|
// all diagnostics related features are processed within diagnostics module
|
|
sServer->OutputFormat("%s\r\n", diagProcessCmd(argc, argv));
|
|
}
|
|
#endif
|
|
|
|
void Interpreter::ProcessLine(char *aBuf, uint16_t aBufLength, Server &aServer)
|
|
{
|
|
char *argv[kMaxArgs];
|
|
char *cmd;
|
|
uint8_t argc = 0, i = 0;
|
|
|
|
sServer = &aServer;
|
|
|
|
VerifyOrExit(aBuf != NULL, ;);
|
|
|
|
for (; *aBuf == ' '; aBuf++, aBufLength--);
|
|
|
|
for (cmd = aBuf + 1; (cmd < aBuf + aBufLength) && (cmd != NULL); ++cmd)
|
|
{
|
|
VerifyOrExit(argc < kMaxArgs,
|
|
sServer->OutputFormat("Error: too many args (max %d)\r\n", kMaxArgs));
|
|
|
|
if (*cmd == ' ' || *cmd == '\r' || *cmd == '\n')
|
|
{
|
|
*cmd = '\0';
|
|
}
|
|
|
|
if (*(cmd - 1) == '\0' && *cmd != ' ')
|
|
{
|
|
argv[argc++] = cmd;
|
|
}
|
|
}
|
|
|
|
cmd = aBuf;
|
|
|
|
#if OPENTHREAD_ENABLE_DIAG
|
|
VerifyOrExit((!isDiagEnabled() || (strcmp(cmd, "diag") == 0)),
|
|
sServer->OutputFormat("under diagnostics mode, execute 'diag stop' before running any other commands.\r\n"));
|
|
#endif
|
|
|
|
for (i = 0; i < sizeof(sCommands) / sizeof(sCommands[0]); i++)
|
|
{
|
|
if (strcmp(cmd, sCommands[i].mName) == 0)
|
|
{
|
|
(this->*sCommands[i].mCommand)(argc, argv);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Error prompt for unsupported commands
|
|
if (i == sizeof(sCommands) / sizeof(sCommands[0]))
|
|
{
|
|
AppendResult(kThreadError_Parse);
|
|
}
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
void Interpreter::s_HandleNetifStateChanged(uint32_t aFlags, void *aContext)
|
|
{
|
|
static_cast<Interpreter *>(aContext)->HandleNetifStateChanged(aFlags);
|
|
}
|
|
|
|
void Interpreter::HandleNetifStateChanged(uint32_t aFlags)
|
|
{
|
|
VerifyOrExit((aFlags & OT_THREAD_NETDATA_UPDATED) != 0, ;);
|
|
|
|
otSlaacUpdate(mInstance, mSlaacAddresses, sizeof(mSlaacAddresses) / sizeof(mSlaacAddresses[0]), otCreateRandomIid,
|
|
NULL);
|
|
#if OPENTHREAD_ENABLE_DHCP6_SERVER
|
|
otDhcp6ServerUpdate(mInstance);
|
|
#endif // OPENTHREAD_ENABLE_DHCP6_SERVER
|
|
|
|
#if OPENTHREAD_ENABLE_DHCP6_CLIENT
|
|
otDhcp6ClientUpdate(mInstance, mDhcpAddresses, sizeof(mDhcpAddresses) / sizeof(mDhcpAddresses[0]), NULL);
|
|
#endif // OPENTHREAD_ENABLE_DHCP6_CLIENT
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
void Interpreter::ProcessNetworkDiagnostic(int argc, char *argv[])
|
|
{
|
|
ThreadError error = kThreadError_None;
|
|
struct otIp6Address address;
|
|
uint8_t payload[2 + OT_NETWORK_DIAGNOSTIC_TYPELIST_MAX_ENTRIES]; // TypeList Type(1B), len(1B), type list
|
|
uint8_t payloadIndex = 0;
|
|
uint8_t paramIndex = 0;
|
|
|
|
VerifyOrExit(argc > 1 + 1, error = kThreadError_Parse);
|
|
|
|
SuccessOrExit(error = otIp6AddressFromString(argv[1], &address));
|
|
|
|
payloadIndex = 2;
|
|
paramIndex = 2;
|
|
|
|
while (paramIndex < argc && payloadIndex < sizeof(payload))
|
|
{
|
|
long value;
|
|
SuccessOrExit(error = ParseLong(argv[paramIndex++], value));
|
|
payload[payloadIndex++] = static_cast<uint8_t>(value);
|
|
}
|
|
|
|
payload[0] = OT_NETWORK_DIAGNOSTIC_TYPELIST_TYPE; // TypeList TLV Type
|
|
payload[1] = payloadIndex - 2; // length
|
|
|
|
if (strcmp(argv[0], "get") == 0)
|
|
{
|
|
otSendDiagnosticGet(mInstance, &address, payload, payloadIndex);
|
|
return;
|
|
}
|
|
else if (strcmp(argv[0], "reset") == 0)
|
|
{
|
|
otSendDiagnosticReset(mInstance, &address, payload, payloadIndex);
|
|
}
|
|
|
|
exit:
|
|
AppendResult(error);
|
|
}
|
|
|
|
void Interpreter::s_HandleDiagnosticGetResponse(otMessage aMessage, const otMessageInfo *aMessageInfo,
|
|
void *aContext)
|
|
{
|
|
static_cast<Interpreter *>(aContext)->HandleDiagnosticGetResponse(*static_cast<Message *>(aMessage),
|
|
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
|
|
}
|
|
|
|
void Interpreter::HandleDiagnosticGetResponse(Message &aMessage, const Ip6::MessageInfo &)
|
|
{
|
|
uint8_t buf[16];
|
|
uint16_t bytesToPrint;
|
|
uint16_t bytesPrinted = 0;
|
|
uint16_t length = aMessage.GetLength() - aMessage.GetOffset();
|
|
|
|
sServer->OutputFormat("DIAG_GET.rsp: ");
|
|
|
|
while (length > 0)
|
|
{
|
|
bytesToPrint = (length < sizeof(buf)) ? length : sizeof(buf);
|
|
aMessage.Read(aMessage.GetOffset() + bytesPrinted, bytesToPrint, buf);
|
|
|
|
OutputBytes(buf, static_cast<uint8_t>(bytesToPrint));
|
|
|
|
length -= bytesToPrint;
|
|
bytesPrinted += bytesToPrint;
|
|
}
|
|
|
|
sServer->OutputFormat("\r\n");
|
|
}
|
|
|
|
} // namespace Cli
|
|
} // namespace Thread
|