1 /* 2 * Copyright (c) 2016, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file contains definitions for the CLI interpreter. 32 */ 33 34 #ifndef CLI_HPP_ 35 #define CLI_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include "cli_config.h" 40 41 #include <stdarg.h> 42 43 #include <openthread/cli.h> 44 #include <openthread/dataset.h> 45 #include <openthread/dns_client.h> 46 #include <openthread/instance.h> 47 #include <openthread/ip6.h> 48 #include <openthread/link.h> 49 #include <openthread/logging.h> 50 #include <openthread/mesh_diag.h> 51 #include <openthread/netdata.h> 52 #include <openthread/ping_sender.h> 53 #include <openthread/sntp.h> 54 #if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE 55 #include <openthread/tcp.h> 56 #endif 57 #include <openthread/thread.h> 58 #include <openthread/thread_ftd.h> 59 #include <openthread/udp.h> 60 61 #include "cli/cli_bbr.hpp" 62 #include "cli/cli_br.hpp" 63 #include "cli/cli_commissioner.hpp" 64 #include "cli/cli_dataset.hpp" 65 #include "cli/cli_dns.hpp" 66 #include "cli/cli_history.hpp" 67 #include "cli/cli_joiner.hpp" 68 #include "cli/cli_link_metrics.hpp" 69 #include "cli/cli_mac_filter.hpp" 70 #include "cli/cli_network_data.hpp" 71 #include "cli/cli_ping.hpp" 72 #include "cli/cli_srp_client.hpp" 73 #include "cli/cli_srp_server.hpp" 74 #include "cli/cli_tcat.hpp" 75 #include "cli/cli_tcp.hpp" 76 #include "cli/cli_udp.hpp" 77 #include "cli/cli_utils.hpp" 78 #if OPENTHREAD_CONFIG_COAP_API_ENABLE 79 #include "cli/cli_coap.hpp" 80 #endif 81 #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE 82 #include "cli/cli_coap_secure.hpp" 83 #endif 84 85 #include "common/array.hpp" 86 #include "common/code_utils.hpp" 87 #include "common/debug.hpp" 88 #include "common/type_traits.hpp" 89 #include "instance/instance.hpp" 90 91 namespace ot { 92 93 /** 94 * @namespace ot::Cli 95 * 96 * @brief 97 * This namespace contains definitions for the CLI interpreter. 98 * 99 */ 100 namespace Cli { 101 102 extern "C" void otCliPlatLogv(otLogLevel, otLogRegion, const char *, va_list); 103 extern "C" void otCliAppendResult(otError aError); 104 extern "C" void otCliOutputBytes(const uint8_t *aBytes, uint8_t aLength); 105 extern "C" void otCliOutputFormat(const char *aFmt, ...); 106 107 /** 108 * Implements the CLI interpreter. 109 * 110 */ 111 class Interpreter : public OutputImplementer, public Utils 112 { 113 #if OPENTHREAD_FTD || OPENTHREAD_MTD 114 friend class Br; 115 friend class Bbr; 116 friend class Commissioner; 117 friend class Dns; 118 friend class Joiner; 119 friend class LinkMetrics; 120 friend class NetworkData; 121 friend class PingSender; 122 friend class SrpClient; 123 friend class SrpServer; 124 #endif 125 friend void otCliPlatLogv(otLogLevel, otLogRegion, const char *, va_list); 126 friend void otCliAppendResult(otError aError); 127 friend void otCliOutputBytes(const uint8_t *aBytes, uint8_t aLength); 128 friend void otCliOutputFormat(const char *aFmt, ...); 129 130 public: 131 /** 132 * Constructor 133 * 134 * @param[in] aInstance The OpenThread instance structure. 135 * @param[in] aCallback A callback method called to process CLI output. 136 * @param[in] aContext A user context pointer. 137 */ 138 explicit Interpreter(Instance *aInstance, otCliOutputCallback aCallback, void *aContext); 139 140 /** 141 * Returns a reference to the interpreter object. 142 * 143 * @returns A reference to the interpreter object. 144 * 145 */ GetInterpreter(void)146 static Interpreter &GetInterpreter(void) 147 { 148 OT_ASSERT(sInterpreter != nullptr); 149 150 return *sInterpreter; 151 } 152 153 /** 154 * Initializes the Console interpreter. 155 * 156 * @param[in] aInstance The OpenThread instance structure. 157 * @param[in] aCallback A pointer to a callback method. 158 * @param[in] aContext A pointer to a user context. 159 * 160 */ 161 static void Initialize(otInstance *aInstance, otCliOutputCallback aCallback, void *aContext); 162 163 /** 164 * Returns whether the interpreter is initialized. 165 * 166 * @returns Whether the interpreter is initialized. 167 * 168 */ IsInitialized(void)169 static bool IsInitialized(void) { return sInterpreter != nullptr; } 170 171 /** 172 * Interprets a CLI command. 173 * 174 * @param[in] aBuf A pointer to a string. 175 * 176 */ 177 void ProcessLine(char *aBuf); 178 179 /** 180 * Adds commands to the user command table. 181 * 182 * @param[in] aCommands A pointer to an array with user commands. 183 * @param[in] aLength @p aUserCommands length. 184 * @param[in] aContext @p aUserCommands length. 185 * 186 * @retval OT_ERROR_NONE Successfully updated command table with commands from @p aCommands. 187 * @retval OT_ERROR_FAILED No available UserCommandsEntry to register requested user commands. 188 */ 189 otError SetUserCommands(const otCliCommand *aCommands, uint8_t aLength, void *aContext); 190 191 static constexpr uint8_t kLinkModeStringSize = sizeof("rdn"); ///< Size of string buffer for a MLE Link Mode. 192 193 /** 194 * Converts a given MLE Link Mode to flag string. 195 * 196 * The characters 'r', 'd', and 'n' are respectively used for `mRxOnWhenIdle`, `mDeviceType` and `mNetworkData` 197 * flags. If all flags are `false`, then "-" is returned. 198 * 199 * @param[in] aLinkMode The MLE Link Mode to convert. 200 * @param[out] aStringBuffer A reference to an string array to place the string. 201 * 202 * @returns A pointer @p aStringBuffer which contains the converted string. 203 * 204 */ 205 static const char *LinkModeToString(const otLinkModeConfig &aLinkMode, char (&aStringBuffer)[kLinkModeStringSize]); 206 207 /** 208 * Converts an IPv6 address origin `OT_ADDRESS_ORIGIN_*` value to human-readable string. 209 * 210 * @param[in] aOrigin The IPv6 address origin to convert. 211 * 212 * @returns A human-readable string representation of @p aOrigin. 213 * 214 */ 215 static const char *AddressOriginToString(uint8_t aOrigin); 216 217 /** 218 * Parses a given argument string as a route preference comparing it against "high", "med", or 219 * "low". 220 * 221 * @param[in] aArg The argument string to parse. 222 * @param[out] aPreference Reference to a `otRoutePreference` to return the parsed preference. 223 * 224 * @retval OT_ERROR_NONE Successfully parsed @p aArg and updated @p aPreference. 225 * @retval OT_ERROR_INVALID_ARG @p aArg is not a valid preference string "high", "med", or "low". 226 * 227 */ 228 static otError ParsePreference(const Arg &aArg, otRoutePreference &aPreference); 229 230 /** 231 * Converts a route preference value to human-readable string. 232 * 233 * @param[in] aPreference The preference value to convert (`OT_ROUTE_PREFERENCE_*` values). 234 * 235 * @returns A string representation @p aPreference. 236 * 237 */ 238 static const char *PreferenceToString(signed int aPreference); 239 240 /** 241 * Parses the argument as an IP address. 242 * 243 * If the argument string is an IPv4 address, this method will try to synthesize an IPv6 address using preferred 244 * NAT64 prefix in the network data. 245 * 246 * @param[in] aInstance A pointer to OpenThread instance. 247 * @param[in] aArg The argument string to parse. 248 * @param[out] aAddress A reference to an `otIp6Address` to output the parsed IPv6 address. 249 * @param[out] aSynthesized Whether @p aAddress is synthesized from an IPv4 address. 250 * 251 * @retval OT_ERROR_NONE The argument was parsed successfully. 252 * @retval OT_ERROR_INVALID_ARGS The argument is empty or does not contain a valid IP address. 253 * @retval OT_ERROR_INVALID_STATE No valid NAT64 prefix in the network data. 254 * 255 */ 256 static otError ParseToIp6Address(otInstance *aInstance, 257 const Arg &aArg, 258 otIp6Address &aAddress, 259 bool &aSynthesized); 260 261 protected: 262 static Interpreter *sInterpreter; 263 264 private: 265 static constexpr uint8_t kIndentSize = 4; 266 static constexpr uint16_t kMaxArgs = 32; 267 static constexpr uint16_t kMaxLineLength = OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH; 268 static constexpr uint16_t kMaxUserCommandEntries = OPENTHREAD_CONFIG_CLI_MAX_USER_CMD_ENTRIES; 269 270 static constexpr uint32_t kNetworkDiagnosticTimeoutMsecs = 5000; 271 static constexpr uint32_t kLocateTimeoutMsecs = 2500; 272 273 static constexpr uint16_t kMaxTxtDataSize = OPENTHREAD_CONFIG_CLI_TXT_RECORD_MAX_SIZE; 274 275 using Command = CommandEntry<Interpreter>; 276 277 void OutputPrompt(void); 278 void OutputResult(otError aError); 279 280 static otError ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner); 281 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 282 static otError ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig); 283 static otError ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig); 284 #endif 285 #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE 286 void OutputBorderRouterCounters(void); 287 #endif 288 289 otError ProcessCommand(Arg aArgs[]); 290 291 template <CommandId kCommandId> otError Process(Arg aArgs[]); 292 293 otError ProcessUserCommands(Arg aArgs[]); 294 295 #if OPENTHREAD_FTD || OPENTHREAD_MTD 296 297 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) 298 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE 299 otError ProcessBackboneRouterLocal(Arg aArgs[]); 300 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE 301 otError ProcessBackboneRouterMgmtMlr(Arg aArgs[]); 302 void PrintMulticastListenersTable(void); 303 #endif 304 #endif 305 #endif 306 307 #if OPENTHREAD_FTD 308 void OutputEidCacheEntry(const otCacheEntryInfo &aEntry); 309 #endif 310 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE 311 static void HandleLocateResult(void *aContext, 312 otError aError, 313 const otIp6Address *aMeshLocalAddress, 314 uint16_t aRloc16); 315 void HandleLocateResult(otError aError, const otIp6Address *aMeshLocalAddress, uint16_t aRloc16); 316 #endif 317 #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD 318 static void HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo, void *aContext); 319 void HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo); 320 static void HandleMeshDiagQueryChildTableResult(otError aError, 321 const otMeshDiagChildEntry *aChildEntry, 322 void *aContext); 323 void HandleMeshDiagQueryChildTableResult(otError aError, const otMeshDiagChildEntry *aChildEntry); 324 static void HandleMeshDiagQueryChildIp6Addrs(otError aError, 325 uint16_t aChildRloc16, 326 otMeshDiagIp6AddrIterator *aIp6AddrIterator, 327 void *aContext); 328 void HandleMeshDiagQueryChildIp6Addrs(otError aError, 329 uint16_t aChildRloc16, 330 otMeshDiagIp6AddrIterator *aIp6AddrIterator); 331 static void HandleMeshDiagQueryRouterNeighborTableResult(otError aError, 332 const otMeshDiagRouterNeighborEntry *aNeighborEntry, 333 void *aContext); 334 void HandleMeshDiagQueryRouterNeighborTableResult(otError aError, 335 const otMeshDiagRouterNeighborEntry *aNeighborEntry); 336 337 #endif 338 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 339 static void HandleMlrRegResult(void *aContext, 340 otError aError, 341 uint8_t aMlrStatus, 342 const otIp6Address *aFailedAddresses, 343 uint8_t aFailedAddressNum); 344 void HandleMlrRegResult(otError aError, 345 uint8_t aMlrStatus, 346 const otIp6Address *aFailedAddresses, 347 uint8_t aFailedAddressNum); 348 #endif 349 #if OPENTHREAD_CONFIG_MULTI_RADIO 350 void OutputMultiRadioInfo(const otMultiRadioNeighborInfo &aMultiRadioInfo); 351 #endif 352 353 static void HandleActiveScanResult(otActiveScanResult *aResult, void *aContext); 354 static void HandleEnergyScanResult(otEnergyScanResult *aResult, void *aContext); 355 static void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx, void *aContext); 356 357 #if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE 358 void HandleDiagnosticGetResponse(otError aError, const otMessage *aMessage, const Ip6::MessageInfo *aMessageInfo); 359 static void HandleDiagnosticGetResponse(otError aError, 360 otMessage *aMessage, 361 const otMessageInfo *aMessageInfo, 362 void *aContext); 363 364 void OutputMode(uint8_t aIndentSize, const otLinkModeConfig &aMode); 365 void OutputConnectivity(uint8_t aIndentSize, const otNetworkDiagConnectivity &aConnectivity); 366 void OutputRoute(uint8_t aIndentSize, const otNetworkDiagRoute &aRoute); 367 void OutputRouteData(uint8_t aIndentSize, const otNetworkDiagRouteData &aRouteData); 368 void OutputLeaderData(uint8_t aIndentSize, const otLeaderData &aLeaderData); 369 void OutputNetworkDiagMacCounters(uint8_t aIndentSize, const otNetworkDiagMacCounters &aMacCounters); 370 void OutputNetworkDiagMleCounters(uint8_t aIndentSize, const otNetworkDiagMleCounters &aMleCounters); 371 void OutputChildTableEntry(uint8_t aIndentSize, const otNetworkDiagChildEntry &aChildEntry); 372 #endif 373 374 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE 375 void OutputTrelCounters(const otTrelCounters &aCounters); 376 #endif 377 #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE 378 void OutputNat64Counters(const otNat64Counters &aCounters); 379 #endif 380 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE 381 void OutputRadioStatsTime(const char *aTimeName, uint64_t aTimeUs, uint64_t aTotalTime); 382 #endif 383 384 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 385 static void HandleSntpResponse(void *aContext, uint64_t aTime, otError aResult); 386 #endif 387 388 void HandleActiveScanResult(otActiveScanResult *aResult); 389 void HandleEnergyScanResult(otEnergyScanResult *aResult); 390 void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx); 391 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 392 void HandleSntpResponse(uint64_t aTime, otError aResult); 393 #endif 394 395 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE 396 static void HandleBorderAgentEphemeralKeyStateChange(void *aContext); 397 void HandleBorderAgentEphemeralKeyStateChange(void); 398 #endif 399 400 static void HandleDetachGracefullyResult(void *aContext); 401 void HandleDetachGracefullyResult(void); 402 403 #if OPENTHREAD_FTD 404 static void HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aContext); 405 void HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo &aInfo); 406 #endif 407 408 #if OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK 409 static void HandleIp6Receive(otMessage *aMessage, void *aContext); 410 #endif 411 412 #endif // OPENTHREAD_FTD || OPENTHREAD_MTD 413 414 void SetCommandTimeout(uint32_t aTimeoutMilli); 415 416 static void HandleTimer(Timer &aTimer); 417 void HandleTimer(void); 418 419 struct UserCommandsEntry 420 { 421 const otCliCommand *mCommands; 422 uint8_t mLength; 423 void *mContext; 424 }; 425 426 UserCommandsEntry mUserCommands[kMaxUserCommandEntries]; 427 bool mCommandIsPending; 428 bool mInternalDebugCommand; 429 430 TimerMilliContext mTimer; 431 432 #if OPENTHREAD_FTD || OPENTHREAD_MTD 433 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 434 bool mSntpQueryingInProgress; 435 #endif 436 437 Dataset mDataset; 438 NetworkData mNetworkData; 439 UdpExample mUdp; 440 441 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE 442 MacFilter mMacFilter; 443 #endif 444 445 #if OPENTHREAD_CLI_DNS_ENABLE 446 Dns mDns; 447 #endif 448 449 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) 450 Bbr mBbr; 451 #endif 452 453 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 454 Br mBr; 455 #endif 456 457 #if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE 458 TcpExample mTcp; 459 #endif 460 461 #if OPENTHREAD_CONFIG_COAP_API_ENABLE 462 Coap mCoap; 463 #endif 464 465 #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE 466 CoapSecure mCoapSecure; 467 #endif 468 469 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD 470 Commissioner mCommissioner; 471 #endif 472 473 #if OPENTHREAD_CONFIG_JOINER_ENABLE 474 Joiner mJoiner; 475 #endif 476 477 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 478 SrpClient mSrpClient; 479 #endif 480 481 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 482 SrpServer mSrpServer; 483 #endif 484 485 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE 486 History mHistory; 487 #endif 488 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 489 LinkMetrics mLinkMetrics; 490 #endif 491 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE 492 Tcat mTcat; 493 #endif 494 #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE 495 PingSender mPing; 496 #endif 497 #endif // OPENTHREAD_FTD || OPENTHREAD_MTD 498 499 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE 500 bool mLocateInProgress : 1; 501 #endif 502 }; 503 504 } // namespace Cli 505 } // namespace ot 506 507 #endif // CLI_HPP_ 508