• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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