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_output.hpp"
72 #include "cli/cli_ping.hpp"
73 #include "cli/cli_srp_client.hpp"
74 #include "cli/cli_srp_server.hpp"
75 #include "cli/cli_tcat.hpp"
76 #include "cli/cli_tcp.hpp"
77 #include "cli/cli_udp.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 Output
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     typedef Utils::CmdLineParser::Arg Arg;
132 
133     /**
134      * Constructor
135      *
136      * @param[in]  aInstance    The OpenThread instance structure.
137      * @param[in]  aCallback    A callback method called to process CLI output.
138      * @param[in]  aContext     A user context pointer.
139      */
140     explicit Interpreter(Instance *aInstance, otCliOutputCallback aCallback, void *aContext);
141 
142     /**
143      * Returns a reference to the interpreter object.
144      *
145      * @returns A reference to the interpreter object.
146      *
147      */
GetInterpreter(void)148     static Interpreter &GetInterpreter(void)
149     {
150         OT_ASSERT(sInterpreter != nullptr);
151 
152         return *sInterpreter;
153     }
154 
155     /**
156      * Initializes the Console interpreter.
157      *
158      * @param[in]  aInstance  The OpenThread instance structure.
159      * @param[in]  aCallback  A pointer to a callback method.
160      * @param[in]  aContext   A pointer to a user context.
161      *
162      */
163     static void Initialize(otInstance *aInstance, otCliOutputCallback aCallback, void *aContext);
164 
165     /**
166      * Returns whether the interpreter is initialized.
167      *
168      * @returns  Whether the interpreter is initialized.
169      *
170      */
IsInitialized(void)171     static bool IsInitialized(void) { return sInterpreter != nullptr; }
172 
173     /**
174      * Interprets a CLI command.
175      *
176      * @param[in]  aBuf        A pointer to a string.
177      *
178      */
179     void ProcessLine(char *aBuf);
180 
181     /**
182      * Checks a given argument string against "enable" or "disable" commands.
183      *
184      * @param[in]  aArg     The argument string to parse.
185      * @param[out] aEnable  Boolean variable to return outcome on success.
186      *                      Set to TRUE for "enable" command, and FALSE for "disable" command.
187      *
188      * @retval OT_ERROR_NONE             Successfully parsed the @p aString and updated @p aEnable.
189      * @retval OT_ERROR_INVALID_COMMAND  The @p aString is not "enable" or "disable" command.
190      *
191      */
192     static otError ParseEnableOrDisable(const Arg &aArg, bool &aEnable);
193 
194     /**
195      * Adds commands to the user command table.
196      *
197      * @param[in]  aCommands  A pointer to an array with user commands.
198      * @param[in]  aLength    @p aUserCommands length.
199      * @param[in]  aContext   @p aUserCommands length.
200      *
201      * @retval OT_ERROR_NONE    Successfully updated command table with commands from @p aCommands.
202      * @retval OT_ERROR_FAILED  No available UserCommandsEntry to register requested user commands.
203      */
204     otError SetUserCommands(const otCliCommand *aCommands, uint8_t aLength, void *aContext);
205 
206     static constexpr uint8_t kLinkModeStringSize = sizeof("rdn"); ///< Size of string buffer for a MLE Link Mode.
207 
208     /**
209      * Converts a given MLE Link Mode to flag string.
210      *
211      * The characters 'r', 'd', and 'n' are respectively used for `mRxOnWhenIdle`, `mDeviceType` and `mNetworkData`
212      * flags. If all flags are `false`, then "-" is returned.
213      *
214      * @param[in]  aLinkMode       The MLE Link Mode to convert.
215      * @param[out] aStringBuffer   A reference to an string array to place the string.
216      *
217      * @returns A pointer @p aStringBuffer which contains the converted string.
218      *
219      */
220     static const char *LinkModeToString(const otLinkModeConfig &aLinkMode, char (&aStringBuffer)[kLinkModeStringSize]);
221 
222     /**
223      * Converts an IPv6 address origin `OT_ADDRESS_ORIGIN_*` value to human-readable string.
224      *
225      * @param[in] aOrigin   The IPv6 address origin to convert.
226      *
227      * @returns A human-readable string representation of @p aOrigin.
228      *
229      */
230     static const char *AddressOriginToString(uint8_t aOrigin);
231 
232     /**
233      * Parses a given argument string as a route preference comparing it against  "high", "med", or
234      * "low".
235      *
236      * @param[in]  aArg          The argument string to parse.
237      * @param[out] aPreference   Reference to a `otRoutePreference` to return the parsed preference.
238      *
239      * @retval OT_ERROR_NONE             Successfully parsed @p aArg and updated @p aPreference.
240      * @retval OT_ERROR_INVALID_ARG      @p aArg is not a valid preference string "high", "med", or "low".
241      *
242      */
243     static otError ParsePreference(const Arg &aArg, otRoutePreference &aPreference);
244 
245     /**
246      * Converts a route preference value to human-readable string.
247      *
248      * @param[in] aPreference   The preference value to convert (`OT_ROUTE_PREFERENCE_*` values).
249      *
250      * @returns A string representation @p aPreference.
251      *
252      */
253     static const char *PreferenceToString(signed int aPreference);
254 
255     /**
256      * Parses the argument as an IP address.
257      *
258      * If the argument string is an IPv4 address, this method will try to synthesize an IPv6 address using preferred
259      * NAT64 prefix in the network data.
260      *
261      * @param[in]  aInstance       A pointer to openthread instance.
262      * @param[in]  aArg            The argument string to parse.
263      * @param[out] aAddress        A reference to an `otIp6Address` to output the parsed IPv6 address.
264      * @param[out] aSynthesized    Whether @p aAddress is synthesized from an IPv4 address.
265      *
266      * @retval OT_ERROR_NONE          The argument was parsed successfully.
267      * @retval OT_ERROR_INVALID_ARGS  The argument is empty or does not contain valid IP address.
268      * @retval OT_ERROR_INVALID_STATE No valid NAT64 prefix in the network data.
269      *
270      */
271     static otError ParseToIp6Address(otInstance   *aInstance,
272                                      const Arg    &aArg,
273                                      otIp6Address &aAddress,
274                                      bool         &aSynthesized);
275 
276 protected:
277     static Interpreter *sInterpreter;
278 
279 private:
280     static constexpr uint8_t  kIndentSize            = 4;
281     static constexpr uint16_t kMaxArgs               = 32;
282     static constexpr uint16_t kMaxLineLength         = OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH;
283     static constexpr uint16_t kMaxUserCommandEntries = OPENTHREAD_CONFIG_CLI_MAX_USER_CMD_ENTRIES;
284 
285     static constexpr uint32_t kNetworkDiagnosticTimeoutMsecs = 5000;
286     static constexpr uint32_t kLocateTimeoutMsecs            = 2500;
287 
288     static constexpr uint16_t kMaxTxtDataSize = OPENTHREAD_CONFIG_CLI_TXT_RECORD_MAX_SIZE;
289 
290     using Command = CommandEntry<Interpreter>;
291 
292     template <typename ValueType> using GetHandler         = ValueType (&)(otInstance *);
293     template <typename ValueType> using SetHandler         = void (&)(otInstance *, ValueType);
294     template <typename ValueType> using SetHandlerFailable = otError (&)(otInstance *, ValueType);
295     using IsEnabledHandler                                 = bool (&)(otInstance *);
296     using SetEnabledHandler                                = void (&)(otInstance *, bool);
297     using SetEnabledHandlerFailable                        = otError (&)(otInstance *, bool);
298 
299     // Returns format string to output a `ValueType` (e.g., "%u" for `uint16_t`).
300     template <typename ValueType> static constexpr const char *FormatStringFor(void);
301 
302     // General template implementation.
303     // Specializations for `uint32_t` and `int32_t` are added at the end.
ProcessGet(Arg aArgs[],GetHandler<ValueType> aGetHandler)304     template <typename ValueType> otError ProcessGet(Arg aArgs[], GetHandler<ValueType> aGetHandler)
305     {
306         static_assert(
307             TypeTraits::IsSame<ValueType, uint8_t>::kValue || TypeTraits::IsSame<ValueType, uint16_t>::kValue ||
308                 TypeTraits::IsSame<ValueType, int8_t>::kValue || TypeTraits::IsSame<ValueType, int16_t>::kValue ||
309                 TypeTraits::IsSame<ValueType, const char *>::kValue,
310             "ValueType must be an  8, 16 `int` or `uint` type, or a `const char *`");
311 
312         otError error = OT_ERROR_NONE;
313 
314         VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
315         OutputLine(FormatStringFor<ValueType>(), aGetHandler(GetInstancePtr()));
316 
317     exit:
318         return error;
319     }
320 
ProcessSet(Arg aArgs[],SetHandler<ValueType> aSetHandler)321     template <typename ValueType> otError ProcessSet(Arg aArgs[], SetHandler<ValueType> aSetHandler)
322     {
323         otError   error;
324         ValueType value;
325 
326         SuccessOrExit(error = aArgs[0].ParseAs<ValueType>(value));
327         VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
328 
329         aSetHandler(GetInstancePtr(), value);
330 
331     exit:
332         return error;
333     }
334 
ProcessSet(Arg aArgs[],SetHandlerFailable<ValueType> aSetHandler)335     template <typename ValueType> otError ProcessSet(Arg aArgs[], SetHandlerFailable<ValueType> aSetHandler)
336     {
337         otError   error;
338         ValueType value;
339 
340         SuccessOrExit(error = aArgs[0].ParseAs<ValueType>(value));
341         VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
342 
343         error = aSetHandler(GetInstancePtr(), value);
344 
345     exit:
346         return error;
347     }
348 
349     template <typename ValueType>
ProcessGetSet(Arg aArgs[],GetHandler<ValueType> aGetHandler,SetHandler<ValueType> aSetHandler)350     otError ProcessGetSet(Arg aArgs[], GetHandler<ValueType> aGetHandler, SetHandler<ValueType> aSetHandler)
351     {
352         otError error = ProcessGet(aArgs, aGetHandler);
353 
354         VerifyOrExit(error != OT_ERROR_NONE);
355         error = ProcessSet(aArgs, aSetHandler);
356 
357     exit:
358         return error;
359     }
360 
361     template <typename ValueType>
ProcessGetSet(Arg aArgs[],GetHandler<ValueType> aGetHandler,SetHandlerFailable<ValueType> aSetHandler)362     otError ProcessGetSet(Arg aArgs[], GetHandler<ValueType> aGetHandler, SetHandlerFailable<ValueType> aSetHandler)
363     {
364         otError error = ProcessGet(aArgs, aGetHandler);
365 
366         VerifyOrExit(error != OT_ERROR_NONE);
367         error = ProcessSet(aArgs, aSetHandler);
368 
369     exit:
370         return error;
371     }
372 
373     otError ProcessEnableDisable(Arg aArgs[], SetEnabledHandler aSetEnabledHandler);
374     otError ProcessEnableDisable(Arg aArgs[], SetEnabledHandlerFailable aSetEnabledHandler);
375     otError ProcessEnableDisable(Arg aArgs[], IsEnabledHandler aIsEnabledHandler, SetEnabledHandler aSetEnabledHandler);
376     otError ProcessEnableDisable(Arg                       aArgs[],
377                                  IsEnabledHandler          aIsEnabledHandler,
378                                  SetEnabledHandlerFailable aSetEnabledHandler);
379 
380     void OutputPrompt(void);
381     void OutputResult(otError aError);
382 
383     static otError ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner);
384 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
385     static otError ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig);
386     static otError ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig);
387 #endif
388 #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
389     void OutputBorderRouterCounters(void);
390 #endif
391 
392     otError ProcessCommand(Arg aArgs[]);
393 
394     template <CommandId kCommandId> otError Process(Arg aArgs[]);
395 
396     otError ProcessUserCommands(Arg aArgs[]);
397 
398 #if OPENTHREAD_FTD || OPENTHREAD_MTD
399 
400 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
401 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
402     otError ProcessBackboneRouterLocal(Arg aArgs[]);
403 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
404     otError ProcessBackboneRouterMgmtMlr(Arg aArgs[]);
405     void    PrintMulticastListenersTable(void);
406 #endif
407 #endif
408 #endif
409 
410 #if OPENTHREAD_FTD
411     void OutputEidCacheEntry(const otCacheEntryInfo &aEntry);
412 #endif
413 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
414     static void HandleLocateResult(void               *aContext,
415                                    otError             aError,
416                                    const otIp6Address *aMeshLocalAddress,
417                                    uint16_t            aRloc16);
418     void        HandleLocateResult(otError aError, const otIp6Address *aMeshLocalAddress, uint16_t aRloc16);
419 #endif
420 #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
421     static void HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo, void *aContext);
422     void        HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo);
423     static void HandleMeshDiagQueryChildTableResult(otError                     aError,
424                                                     const otMeshDiagChildEntry *aChildEntry,
425                                                     void                       *aContext);
426     void        HandleMeshDiagQueryChildTableResult(otError aError, const otMeshDiagChildEntry *aChildEntry);
427     static void HandleMeshDiagQueryChildIp6Addrs(otError                    aError,
428                                                  uint16_t                   aChildRloc16,
429                                                  otMeshDiagIp6AddrIterator *aIp6AddrIterator,
430                                                  void                      *aContext);
431     void        HandleMeshDiagQueryChildIp6Addrs(otError                    aError,
432                                                  uint16_t                   aChildRloc16,
433                                                  otMeshDiagIp6AddrIterator *aIp6AddrIterator);
434     static void HandleMeshDiagQueryRouterNeighborTableResult(otError                              aError,
435                                                              const otMeshDiagRouterNeighborEntry *aNeighborEntry,
436                                                              void                                *aContext);
437     void        HandleMeshDiagQueryRouterNeighborTableResult(otError                              aError,
438                                                              const otMeshDiagRouterNeighborEntry *aNeighborEntry);
439 
440 #endif
441 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
442     static void HandleMlrRegResult(void               *aContext,
443                                    otError             aError,
444                                    uint8_t             aMlrStatus,
445                                    const otIp6Address *aFailedAddresses,
446                                    uint8_t             aFailedAddressNum);
447     void        HandleMlrRegResult(otError             aError,
448                                    uint8_t             aMlrStatus,
449                                    const otIp6Address *aFailedAddresses,
450                                    uint8_t             aFailedAddressNum);
451 #endif
452 #if OPENTHREAD_CONFIG_MULTI_RADIO
453     void OutputMultiRadioInfo(const otMultiRadioNeighborInfo &aMultiRadioInfo);
454 #endif
455 
456     static void HandleActiveScanResult(otActiveScanResult *aResult, void *aContext);
457     static void HandleEnergyScanResult(otEnergyScanResult *aResult, void *aContext);
458     static void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx, void *aContext);
459 
460 #if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
461     void HandleDiagnosticGetResponse(otError aError, const otMessage *aMessage, const Ip6::MessageInfo *aMessageInfo);
462     static void HandleDiagnosticGetResponse(otError              aError,
463                                             otMessage           *aMessage,
464                                             const otMessageInfo *aMessageInfo,
465                                             void                *aContext);
466 
467     void OutputMode(uint8_t aIndentSize, const otLinkModeConfig &aMode);
468     void OutputConnectivity(uint8_t aIndentSize, const otNetworkDiagConnectivity &aConnectivity);
469     void OutputRoute(uint8_t aIndentSize, const otNetworkDiagRoute &aRoute);
470     void OutputRouteData(uint8_t aIndentSize, const otNetworkDiagRouteData &aRouteData);
471     void OutputLeaderData(uint8_t aIndentSize, const otLeaderData &aLeaderData);
472     void OutputNetworkDiagMacCounters(uint8_t aIndentSize, const otNetworkDiagMacCounters &aMacCounters);
473     void OutputNetworkDiagMleCounters(uint8_t aIndentSize, const otNetworkDiagMleCounters &aMleCounters);
474     void OutputChildTableEntry(uint8_t aIndentSize, const otNetworkDiagChildEntry &aChildEntry);
475 #endif
476 
477 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
478     void OutputTrelCounters(const otTrelCounters &aCounters);
479 #endif
480 #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
481     void OutputNat64Counters(const otNat64Counters &aCounters);
482 #endif
483 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE
484     void OutputRadioStatsTime(const char *aTimeName, uint64_t aTimeUs, uint64_t aTotalTime);
485 #endif
486 
487 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
488     static void HandleSntpResponse(void *aContext, uint64_t aTime, otError aResult);
489 #endif
490 
491     void HandleActiveScanResult(otActiveScanResult *aResult);
492     void HandleEnergyScanResult(otEnergyScanResult *aResult);
493     void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx);
494 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
495     void HandleSntpResponse(uint64_t aTime, otError aResult);
496 #endif
497 
498     static void HandleDetachGracefullyResult(void *aContext);
499     void        HandleDetachGracefullyResult(void);
500 
501 #if OPENTHREAD_FTD
502     static void HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aContext);
503     void        HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo &aInfo);
504 #endif
505 
506 #if OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK
507     static void HandleIp6Receive(otMessage *aMessage, void *aContext);
508 #endif
509 
510 #endif // OPENTHREAD_FTD || OPENTHREAD_MTD
511 
512     void SetCommandTimeout(uint32_t aTimeoutMilli);
513 
514     static void HandleTimer(Timer &aTimer);
515     void        HandleTimer(void);
516 
517     struct UserCommandsEntry
518     {
519         const otCliCommand *mCommands;
520         uint8_t             mLength;
521         void               *mContext;
522     };
523 
524     UserCommandsEntry mUserCommands[kMaxUserCommandEntries];
525     bool              mCommandIsPending;
526     bool              mInternalDebugCommand;
527 
528     TimerMilliContext mTimer;
529 
530 #if OPENTHREAD_FTD || OPENTHREAD_MTD
531 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
532     bool mSntpQueryingInProgress;
533 #endif
534 
535     Dataset     mDataset;
536     NetworkData mNetworkData;
537     UdpExample  mUdp;
538 
539 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
540     MacFilter mMacFilter;
541 #endif
542 
543 #if OPENTHREAD_CLI_DNS_ENABLE
544     Dns mDns;
545 #endif
546 
547 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
548     Bbr mBbr;
549 #endif
550 
551 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
552     Br mBr;
553 #endif
554 
555 #if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE
556     TcpExample mTcp;
557 #endif
558 
559 #if OPENTHREAD_CONFIG_COAP_API_ENABLE
560     Coap mCoap;
561 #endif
562 
563 #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
564     CoapSecure mCoapSecure;
565 #endif
566 
567 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
568     Commissioner mCommissioner;
569 #endif
570 
571 #if OPENTHREAD_CONFIG_JOINER_ENABLE
572     Joiner mJoiner;
573 #endif
574 
575 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
576     SrpClient mSrpClient;
577 #endif
578 
579 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
580     SrpServer mSrpServer;
581 #endif
582 
583 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
584     History mHistory;
585 #endif
586 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
587     LinkMetrics mLinkMetrics;
588 #endif
589 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
590     Tcat mTcat;
591 #endif
592 #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
593     PingSender mPing;
594 #endif
595 #endif // OPENTHREAD_FTD || OPENTHREAD_MTD
596 
597 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
598     bool mLocateInProgress : 1;
599 #endif
600 };
601 
602 // Specializations of `FormatStringFor<ValueType>()`
603 
FormatStringFor(void)604 template <> inline constexpr const char *Interpreter::FormatStringFor<uint8_t>(void) { return "%u"; }
605 
FormatStringFor(void)606 template <> inline constexpr const char *Interpreter::FormatStringFor<uint16_t>(void) { return "%u"; }
607 
FormatStringFor(void)608 template <> inline constexpr const char *Interpreter::FormatStringFor<uint32_t>(void) { return "%lu"; }
609 
FormatStringFor(void)610 template <> inline constexpr const char *Interpreter::FormatStringFor<int8_t>(void) { return "%d"; }
611 
FormatStringFor(void)612 template <> inline constexpr const char *Interpreter::FormatStringFor<int16_t>(void) { return "%d"; }
613 
FormatStringFor(void)614 template <> inline constexpr const char *Interpreter::FormatStringFor<int32_t>(void) { return "%ld"; }
615 
FormatStringFor(void)616 template <> inline constexpr const char *Interpreter::FormatStringFor<const char *>(void) { return "%s"; }
617 
618 // Specialization of ProcessGet<> for `uint32_t` and `int32_t`
619 
ProcessGet(Arg aArgs[],GetHandler<uint32_t> aGetHandler)620 template <> inline otError Interpreter::ProcessGet<uint32_t>(Arg aArgs[], GetHandler<uint32_t> aGetHandler)
621 {
622     otError error = OT_ERROR_NONE;
623 
624     VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
625     OutputLine(FormatStringFor<uint32_t>(), ToUlong(aGetHandler(GetInstancePtr())));
626 
627 exit:
628     return error;
629 }
630 
ProcessGet(Arg aArgs[],GetHandler<int32_t> aGetHandler)631 template <> inline otError Interpreter::ProcessGet<int32_t>(Arg aArgs[], GetHandler<int32_t> aGetHandler)
632 {
633     otError error = OT_ERROR_NONE;
634 
635     VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
636     OutputLine(FormatStringFor<int32_t>(), static_cast<long int>(aGetHandler(GetInstancePtr())));
637 
638 exit:
639     return error;
640 }
641 
642 } // namespace Cli
643 } // namespace ot
644 
645 #endif // CLI_HPP_
646