diff --git a/Android.mk b/Android.mk index ee8c0a5de..264ff2e80 100644 --- a/Android.mk +++ b/Android.mk @@ -310,6 +310,7 @@ LOCAL_LDLIBS := \ LOCAL_SRC_FILES := \ src/cli/cli.cpp \ src/cli/cli_coap.cpp \ + src/cli/cli_commissioner.cpp \ src/cli/cli_console.cpp \ src/cli/cli_dataset.cpp \ src/cli/cli_joiner.cpp \ diff --git a/etc/visual-studio/libopenthread-cli-windows.vcxproj b/etc/visual-studio/libopenthread-cli-windows.vcxproj index bec386723..e62e29f13 100644 --- a/etc/visual-studio/libopenthread-cli-windows.vcxproj +++ b/etc/visual-studio/libopenthread-cli-windows.vcxproj @@ -58,6 +58,7 @@ + diff --git a/etc/visual-studio/libopenthread-cli-windows.vcxproj.filters b/etc/visual-studio/libopenthread-cli-windows.vcxproj.filters index 24477b720..7832b5237 100644 --- a/etc/visual-studio/libopenthread-cli-windows.vcxproj.filters +++ b/etc/visual-studio/libopenthread-cli-windows.vcxproj.filters @@ -10,6 +10,9 @@ Source Files + + Source Files + Source Files diff --git a/etc/visual-studio/libopenthread-cli.vcxproj b/etc/visual-studio/libopenthread-cli.vcxproj index 4add881b5..4fd882d4d 100644 --- a/etc/visual-studio/libopenthread-cli.vcxproj +++ b/etc/visual-studio/libopenthread-cli.vcxproj @@ -57,6 +57,7 @@ + diff --git a/etc/visual-studio/libopenthread-cli.vcxproj.filters b/etc/visual-studio/libopenthread-cli.vcxproj.filters index b28bcd5c1..687e25b6f 100644 --- a/etc/visual-studio/libopenthread-cli.vcxproj.filters +++ b/etc/visual-studio/libopenthread-cli.vcxproj.filters @@ -10,6 +10,9 @@ Source Files + + Source Files + Source Files diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am index a0e32ee2a..ee3d799af 100644 --- a/src/cli/Makefile.am +++ b/src/cli/Makefile.am @@ -145,6 +145,7 @@ SOURCES_COMMON = \ cli.cpp \ cli_coap.cpp \ cli_coap_secure.cpp \ + cli_commissioner.cpp \ cli_console.cpp \ cli_dataset.cpp \ cli_joiner.cpp \ @@ -165,6 +166,7 @@ noinst_HEADERS = \ cli.hpp \ cli_coap.hpp \ cli_coap_secure.hpp \ + cli_commissioner.hpp \ cli_console.hpp \ cli_dataset.hpp \ cli_joiner.hpp \ diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 4c8c9d03d..1d875dc6e 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -43,7 +43,6 @@ #include "utils/parse_cmdline.hpp" #include "utils/wrap_string.h" -#include #include #include #include @@ -304,6 +303,9 @@ Interpreter::Interpreter(Instance *aInstance) #if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE , mCoapSecure(*this) #endif +#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD + , mCommissioner(*this) +#endif #if OPENTHREAD_ENABLE_JOINER , mJoiner(*this) #endif @@ -3178,285 +3180,12 @@ void Interpreter::ProcessVersion(int argc, char *argv[]) void Interpreter::ProcessCommissioner(int argc, char *argv[]) { - otError error = OT_ERROR_NONE; - - VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS); - - 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 = OT_ERROR_INVALID_ARGS); - - if (strcmp(argv[2], "*") == 0) - { - addrPtr = NULL; - } - else - { - VerifyOrExit(Hex2Bin(argv[2], addr.m8, sizeof(addr)) == sizeof(addr), error = OT_ERROR_PARSE); - addrPtr = &addr; - } - - if (strcmp(argv[1], "add") == 0) - { - VerifyOrExit(argc > 3, error = OT_ERROR_INVALID_ARGS); - // Timeout parameter is optional - if not specified, use default value. - unsigned long timeout = kDefaultJoinerTimeout; - - if (argc > 4) - { - SuccessOrExit(error = ParseUnsignedLong(argv[4], timeout)); - } - - SuccessOrExit(error = otCommissionerAddJoiner(mInstance, addrPtr, argv[3], static_cast(timeout))); - } - 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 = OT_ERROR_INVALID_ARGS); - - // 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(mask), - static_cast(count), static_cast(period), - &address)); - } - else if (strcmp(argv[0], "energy") == 0) - { - long mask; - long count; - long period; - long scanDuration; - otIp6Address address; - - VerifyOrExit(argc > 5, error = OT_ERROR_INVALID_ARGS); - - // 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(mask), static_cast(count), - static_cast(period), static_cast(scanDuration), - &address, Interpreter::s_HandleEnergyReport, this)); - } - else if (strcmp(argv[0], "panid") == 0) - { - long panid; - long mask; - otIp6Address address; - - VerifyOrExit(argc > 3, error = OT_ERROR_INVALID_ARGS); - - // 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(panid), static_cast(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(length) < sizeof(tlvs), error = OT_ERROR_NO_BUFS); - - 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 = OT_ERROR_INVALID_ARGS); - value = static_cast(strlen(argv[index]) + 1) / 2; - VerifyOrExit(static_cast(value) <= (sizeof(tlvs) - static_cast(length)), - error = OT_ERROR_NO_BUFS); - VerifyOrExit(Interpreter::Hex2Bin(argv[index], tlvs + length, static_cast(value)) >= 0, - error = OT_ERROR_PARSE); - length += value; - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - - SuccessOrExit(error = otCommissionerSendMgmtGet(mInstance, tlvs, static_cast(length))); - } - else if (strcmp(argv[0], "mgmtset") == 0) - { - otCommissioningDataset dataset; - uint8_t tlvs[32]; - long value; - int length = 0; - - VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS); - - memset(&dataset, 0, sizeof(dataset)); - - for (uint8_t index = 1; index < argc; index++) - { - VerifyOrExit(static_cast(length) < sizeof(tlvs), error = OT_ERROR_NO_BUFS); - - if (strcmp(argv[index], "locator") == 0) - { - VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); - dataset.mIsLocatorSet = true; - SuccessOrExit(error = Interpreter::ParseLong(argv[index], value)); - dataset.mLocator = static_cast(value); - } - else if (strcmp(argv[index], "sessionid") == 0) - { - VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); - dataset.mIsSessionIdSet = true; - SuccessOrExit(error = Interpreter::ParseLong(argv[index], value)); - dataset.mSessionId = static_cast(value); - } - else if (strcmp(argv[index], "steeringdata") == 0) - { - VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); - dataset.mIsSteeringDataSet = true; - length = static_cast((strlen(argv[index]) + 1) / 2); - VerifyOrExit(static_cast(length) <= OT_STEERING_DATA_MAX_LENGTH, error = OT_ERROR_NO_BUFS); - VerifyOrExit( - Interpreter::Hex2Bin(argv[index], dataset.mSteeringData.m8, static_cast(length)) >= 0, - error = OT_ERROR_PARSE); - dataset.mSteeringData.mLength = static_cast(length); - length = 0; - } - else if (strcmp(argv[index], "joinerudpport") == 0) - { - VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); - dataset.mIsJoinerUdpPortSet = true; - SuccessOrExit(error = Interpreter::ParseLong(argv[index], value)); - dataset.mJoinerUdpPort = static_cast(value); - } - else if (strcmp(argv[index], "binary") == 0) - { - VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); - length = static_cast((strlen(argv[index]) + 1) / 2); - VerifyOrExit(static_cast(length) <= sizeof(tlvs), error = OT_ERROR_NO_BUFS); - VerifyOrExit(Interpreter::Hex2Bin(argv[index], tlvs, static_cast(length)) >= 0, - error = OT_ERROR_PARSE); - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - - SuccessOrExit(error = otCommissionerSendMgmtSet(mInstance, &dataset, tlvs, static_cast(length))); - } - else if (strcmp(argv[0], "sessionid") == 0) - { - mServer->OutputFormat("%d\r\n", otCommissionerGetSessionId(mInstance)); - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - -exit: + otError error; + error = mCommissioner.Process(argc, argv); AppendResult(error); } -void OTCALL Interpreter::s_HandleEnergyReport(uint32_t aChannelMask, - const uint8_t *aEnergyList, - uint8_t aEnergyListLength, - void * aContext) -{ - static_cast(aContext)->HandleEnergyReport(aChannelMask, aEnergyList, aEnergyListLength); -} - -void Interpreter::HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength) -{ - mServer->OutputFormat("Energy: %08x ", aChannelMask); - - for (uint8_t i = 0; i < aEnergyListLength; i++) - { - mServer->OutputFormat("%d ", static_cast(aEnergyList[i])); - } - - mServer->OutputFormat("\r\n"); -} - -void OTCALL Interpreter::s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext) -{ - static_cast(aContext)->HandlePanIdConflict(aPanId, aChannelMask); -} - -void Interpreter::HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask) -{ - mServer->OutputFormat("Conflict: %04x, %08x\r\n", aPanId, aChannelMask); -} - -#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD +#endif #if OPENTHREAD_ENABLE_JOINER diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index bca954be6..f1fbb1adf 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -42,6 +42,7 @@ #include #include +#include "cli/cli_commissioner.hpp" #include "cli/cli_dataset.hpp" #include "cli/cli_joiner.hpp" #include "cli/cli_udp.hpp" @@ -102,6 +103,7 @@ class Interpreter { friend class Coap; friend class CoapSecure; + friend class Commissioner; friend class Dataset; friend class Joiner; friend class UdpExample; @@ -192,9 +194,8 @@ public: private: enum { - kMaxArgs = 32, - kMaxAutoAddresses = 8, - kDefaultJoinerTimeout = 120, ///< Default timeout for Joiners, in seconds. + kMaxArgs = 32, + kMaxAutoAddresses = 8, }; otError ParsePingInterval(const char *aString, uint32_t &aInterval); @@ -216,7 +217,7 @@ private: #endif // OPENTHREAD_ENABLE_APPLICATION_COAP #if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD void ProcessCommissioner(int argc, char *argv[]); -#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD +#endif #if OPENTHREAD_FTD void ProcessContextIdReuseDelay(int argc, char *argv[]); #endif @@ -360,11 +361,6 @@ private: #ifndef OTDLL static void s_HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx, void *aContext); #endif - static void OTCALL s_HandleEnergyReport(uint32_t aChannelMask, - const uint8_t *aEnergyList, - uint8_t aEnergyListLength, - void * aContext); - static void OTCALL s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext); #ifndef OTDLL static void OTCALL s_HandleDiagnosticGetResponse(otMessage * aMessage, const otMessageInfo *aMessageInfo, @@ -392,8 +388,6 @@ private: #ifndef OTDLL void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx); #endif - void HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength); - void HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask); #ifndef OTDLL void HandleDiagnosticGetResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); #endif @@ -459,6 +453,10 @@ private: CoapSecure mCoapSecure; #endif +#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD + Commissioner mCommissioner; +#endif + #if OPENTHREAD_ENABLE_JOINER Joiner mJoiner; #endif diff --git a/src/cli/cli_commissioner.cpp b/src/cli/cli_commissioner.cpp new file mode 100644 index 000000000..2a556925a --- /dev/null +++ b/src/cli/cli_commissioner.cpp @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2019, 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 a simple CLI for the Commissioner role. + */ + +#include "cli_commissioner.hpp" + +#include "cli/cli.hpp" +#include "cli/cli_server.hpp" + +#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD + +namespace ot { +namespace Cli { + +const struct Commissioner::Command Commissioner::sCommands[] = { + {"help", &Commissioner::ProcessHelp}, {"announce", &Commissioner::ProcessAnnounce}, + {"energy", &Commissioner::ProcessEnergy}, {"joiner", &Commissioner::ProcessJoiner}, + {"mgmtget", &Commissioner::ProcessMgmtGet}, {"mgmtset", &Commissioner::ProcessMgmtSet}, + {"panid", &Commissioner::ProcessPanId}, {"provisioningurl", &Commissioner::ProcessProvisioningUrl}, + {"sessionid", &Commissioner::ProcessSessionId}, {"start", &Commissioner::ProcessStart}, + {"stop", &Commissioner::ProcessStop}, +}; + +otError Commissioner::ProcessHelp(int argc, char *argv[]) +{ + OT_UNUSED_VARIABLE(argc); + OT_UNUSED_VARIABLE(argv); + + for (size_t i = 0; i < OT_ARRAY_LENGTH(sCommands); i++) + { + mInterpreter.mServer->OutputFormat("%s\r\n", sCommands[i].mName); + } + + return OT_ERROR_NONE; +} + +otError Commissioner::ProcessAnnounce(int argc, char *argv[]) +{ + otError error; + long mask; + long count; + long period; + otIp6Address address; + + VerifyOrExit(argc > 4, error = OT_ERROR_INVALID_ARGS); + + SuccessOrExit(error = Interpreter::ParseLong(argv[1], mask)); + SuccessOrExit(error = Interpreter::ParseLong(argv[2], count)); + SuccessOrExit(error = Interpreter::ParseLong(argv[3], period)); + SuccessOrExit(error = otIp6AddressFromString(argv[4], &address)); + + SuccessOrExit(error = otCommissionerAnnounceBegin(mInterpreter.mInstance, static_cast(mask), + static_cast(count), static_cast(period), + &address)); + +exit: + return error; +} + +otError Commissioner::ProcessEnergy(int argc, char *argv[]) +{ + otError error; + long mask; + long count; + long period; + long scanDuration; + otIp6Address address; + + VerifyOrExit(argc > 5, error = OT_ERROR_INVALID_ARGS); + + SuccessOrExit(error = Interpreter::ParseLong(argv[1], mask)); + SuccessOrExit(error = Interpreter::ParseLong(argv[2], count)); + SuccessOrExit(error = Interpreter::ParseLong(argv[3], period)); + SuccessOrExit(error = Interpreter::ParseLong(argv[4], scanDuration)); + SuccessOrExit(error = otIp6AddressFromString(argv[5], &address)); + + SuccessOrExit(error = otCommissionerEnergyScan(mInterpreter.mInstance, static_cast(mask), + static_cast(count), static_cast(period), + static_cast(scanDuration), &address, + &Commissioner::HandleEnergyReport, this)); + +exit: + return error; +} + +otError Commissioner::ProcessJoiner(int argc, char *argv[]) +{ + otError error; + otExtAddress addr; + const otExtAddress *addrPtr; + + VerifyOrExit(argc > 2, error = OT_ERROR_INVALID_ARGS); + + if (strcmp(argv[2], "*") == 0) + { + addrPtr = NULL; + } + else + { + VerifyOrExit(Interpreter::Hex2Bin(argv[2], addr.m8, sizeof(addr)) == sizeof(addr), error = OT_ERROR_PARSE); + addrPtr = &addr; + } + + if (strcmp(argv[1], "add") == 0) + { + VerifyOrExit(argc > 3, error = OT_ERROR_INVALID_ARGS); + // Timeout parameter is optional - if not specified, use default value. + unsigned long timeout = kDefaultJoinerTimeout; + + if (argc > 4) + { + SuccessOrExit(error = Interpreter::ParseUnsignedLong(argv[4], timeout)); + } + + SuccessOrExit( + error = otCommissionerAddJoiner(mInterpreter.mInstance, addrPtr, argv[3], static_cast(timeout))); + } + else if (strcmp(argv[1], "remove") == 0) + { + SuccessOrExit(error = otCommissionerRemoveJoiner(mInterpreter.mInstance, addrPtr)); + } + else + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + +exit: + return error; +} + +otError Commissioner::ProcessMgmtGet(int argc, char *argv[]) +{ + otError error; + uint8_t tlvs[32]; + long value; + int length = 0; + + for (uint8_t index = 1; index < argc; index++) + { + VerifyOrExit(static_cast(length) < sizeof(tlvs), error = OT_ERROR_NO_BUFS); + + 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 = OT_ERROR_INVALID_ARGS); + value = static_cast(strlen(argv[index]) + 1) / 2; + VerifyOrExit(static_cast(value) <= (sizeof(tlvs) - static_cast(length)), + error = OT_ERROR_NO_BUFS); + VerifyOrExit(Interpreter::Hex2Bin(argv[index], tlvs + length, static_cast(value)) >= 0, + error = OT_ERROR_PARSE); + length += value; + } + else + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + } + + SuccessOrExit(error = otCommissionerSendMgmtGet(mInterpreter.mInstance, tlvs, static_cast(length))); + +exit: + return error; +} + +otError Commissioner::ProcessMgmtSet(int argc, char *argv[]) +{ + otError error; + otCommissioningDataset dataset; + uint8_t tlvs[32]; + long value; + int length = 0; + + VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS); + + memset(&dataset, 0, sizeof(dataset)); + + for (uint8_t index = 1; index < argc; index++) + { + VerifyOrExit(static_cast(length) < sizeof(tlvs), error = OT_ERROR_NO_BUFS); + + if (strcmp(argv[index], "locator") == 0) + { + VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); + dataset.mIsLocatorSet = true; + SuccessOrExit(error = Interpreter::Interpreter::ParseLong(argv[index], value)); + dataset.mLocator = static_cast(value); + } + else if (strcmp(argv[index], "sessionid") == 0) + { + VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); + dataset.mIsSessionIdSet = true; + SuccessOrExit(error = Interpreter::Interpreter::ParseLong(argv[index], value)); + dataset.mSessionId = static_cast(value); + } + else if (strcmp(argv[index], "steeringdata") == 0) + { + VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); + dataset.mIsSteeringDataSet = true; + length = static_cast((strlen(argv[index]) + 1) / 2); + VerifyOrExit(static_cast(length) <= OT_STEERING_DATA_MAX_LENGTH, error = OT_ERROR_NO_BUFS); + VerifyOrExit(Interpreter::Hex2Bin(argv[index], dataset.mSteeringData.m8, static_cast(length)) >= + 0, + error = OT_ERROR_PARSE); + dataset.mSteeringData.mLength = static_cast(length); + length = 0; + } + else if (strcmp(argv[index], "joinerudpport") == 0) + { + VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); + dataset.mIsJoinerUdpPortSet = true; + SuccessOrExit(error = Interpreter::Interpreter::ParseLong(argv[index], value)); + dataset.mJoinerUdpPort = static_cast(value); + } + else if (strcmp(argv[index], "binary") == 0) + { + VerifyOrExit(++index < argc, error = OT_ERROR_INVALID_ARGS); + length = static_cast((strlen(argv[index]) + 1) / 2); + VerifyOrExit(static_cast(length) <= sizeof(tlvs), error = OT_ERROR_NO_BUFS); + VerifyOrExit(Interpreter::Hex2Bin(argv[index], tlvs, static_cast(length)) >= 0, + error = OT_ERROR_PARSE); + } + else + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + } + + SuccessOrExit(error = + otCommissionerSendMgmtSet(mInterpreter.mInstance, &dataset, tlvs, static_cast(length))); + +exit: + return error; +} + +otError Commissioner::ProcessPanId(int argc, char *argv[]) +{ + otError error; + long panid; + long mask; + otIp6Address address; + + VerifyOrExit(argc > 3, error = OT_ERROR_INVALID_ARGS); + + SuccessOrExit(error = Interpreter::ParseLong(argv[1], panid)); + SuccessOrExit(error = Interpreter::ParseLong(argv[2], mask)); + SuccessOrExit(error = otIp6AddressFromString(argv[3], &address)); + + SuccessOrExit(error = otCommissionerPanIdQuery(mInterpreter.mInstance, static_cast(panid), + static_cast(mask), &address, + &Commissioner::HandlePanIdConflict, this)); + +exit: + return error; +} + +otError Commissioner::ProcessProvisioningUrl(int argc, char *argv[]) +{ + return otCommissionerSetProvisioningUrl(mInterpreter.mInstance, (argc > 1) ? argv[1] : NULL); +} + +otError Commissioner::ProcessSessionId(int argc, char *argv[]) +{ + OT_UNUSED_VARIABLE(argc); + OT_UNUSED_VARIABLE(argv); + + mInterpreter.mServer->OutputFormat("%d\r\n", otCommissionerGetSessionId(mInterpreter.mInstance)); + + return OT_ERROR_NONE; +} + +otError Commissioner::ProcessStart(int argc, char *argv[]) +{ + OT_UNUSED_VARIABLE(argc); + OT_UNUSED_VARIABLE(argv); + + return otCommissionerStart(mInterpreter.mInstance); +} + +otError Commissioner::ProcessStop(int argc, char *argv[]) +{ + OT_UNUSED_VARIABLE(argc); + OT_UNUSED_VARIABLE(argv); + + return otCommissionerStop(mInterpreter.mInstance); +} + +otError Commissioner::Process(int argc, char *argv[]) +{ + otError error = OT_ERROR_INVALID_ARGS; + + if (argc < 1) + { + ProcessHelp(0, NULL); + } + else + { + for (size_t i = 0; i < OT_ARRAY_LENGTH(sCommands); i++) + { + if (strcmp(argv[0], sCommands[i].mName) == 0) + { + error = (this->*sCommands[i].mCommand)(argc, argv); + break; + } + } + } + + return error; +} + +void OTCALL Commissioner::HandleEnergyReport(uint32_t aChannelMask, + const uint8_t *aEnergyList, + uint8_t aEnergyListLength, + void * aContext) +{ + static_cast(aContext)->HandleEnergyReport(aChannelMask, aEnergyList, aEnergyListLength); +} + +void Commissioner::HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength) +{ + mInterpreter.mServer->OutputFormat("Energy: %08x ", aChannelMask); + + for (uint8_t i = 0; i < aEnergyListLength; i++) + { + mInterpreter.mServer->OutputFormat("%d ", static_cast(aEnergyList[i])); + } + + mInterpreter.mServer->OutputFormat("\r\n"); +} + +void OTCALL Commissioner::HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext) +{ + static_cast(aContext)->HandlePanIdConflict(aPanId, aChannelMask); +} + +void Commissioner::HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask) +{ + mInterpreter.mServer->OutputFormat("Conflict: %04x, %08x\r\n", aPanId, aChannelMask); +} + +} // namespace Cli +} // namespace ot + +#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD diff --git a/src/cli/cli_commissioner.hpp b/src/cli/cli_commissioner.hpp new file mode 100644 index 000000000..ef51f0f40 --- /dev/null +++ b/src/cli/cli_commissioner.hpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2019, 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 contains definitions for a simple CLI to control the Commissioner role. + */ + +#ifndef CLI_COMMISSIONER_HPP_ +#define CLI_COMMISSIONER_HPP_ + +#include "openthread-core-config.h" + +#include + +#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD + +namespace ot { +namespace Cli { + +class Interpreter; + +/** + * This class implements the CLI CoAP Secure server and client. + * + */ +class Commissioner +{ +public: + /** + * Constructor + * + * @param[in] aInterpreter The CLI interpreter. + * + */ + explicit Commissioner(Interpreter &aInterpreter) + : mInterpreter(aInterpreter) + { + } + + /** + * This method interprets a list of CLI arguments. + * + * @param[in] argc The number of elements in argv. + * @param[in] argv A pointer to an array of command line arguments. + * + */ + otError Process(int argc, char *argv[]); + +private: + enum + { + kDefaultJoinerTimeout = 120, ///< Default timeout for Joiners, in seconds. + }; + + struct Command + { + const char *mName; + otError (Commissioner::*mCommand)(int argc, char *argv[]); + }; + + otError ProcessHelp(int argc, char *argv[]); + otError ProcessAnnounce(int argc, char *argv[]); + otError ProcessEnergy(int argc, char *argv[]); + otError ProcessJoiner(int argc, char *argv[]); + otError ProcessMgmtGet(int argc, char *argv[]); + otError ProcessMgmtSet(int argc, char *argv[]); + otError ProcessPanId(int argc, char *argv[]); + otError ProcessProvisioningUrl(int argc, char *argv[]); + otError ProcessSessionId(int argc, char *argv[]); + otError ProcessStart(int argc, char *argv[]); + otError ProcessStop(int argc, char *argv[]); + + static void OTCALL HandleEnergyReport(uint32_t aChannelMask, + const uint8_t *aEnergyList, + uint8_t aEnergyListLength, + void * aContext); + void HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength); + + static void OTCALL HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext); + void HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask); + + static const Command sCommands[]; + Interpreter & mInterpreter; +}; + +} // namespace Cli +} // namespace ot + +#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD + +#endif // CLI_COMMISSIONER_HPP_