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_config.h"
65 #include "cli/cli_dataset.hpp"
66 #include "cli/cli_dns.hpp"
67 #include "cli/cli_history.hpp"
68 #include "cli/cli_joiner.hpp"
69 #include "cli/cli_link_metrics.hpp"
70 #include "cli/cli_mac_filter.hpp"
71 #include "cli/cli_mdns.hpp"
72 #include "cli/cli_network_data.hpp"
73 #include "cli/cli_ping.hpp"
74 #include "cli/cli_srp_client.hpp"
75 #include "cli/cli_srp_server.hpp"
76 #include "cli/cli_tcat.hpp"
77 #include "cli/cli_tcp.hpp"
78 #include "cli/cli_udp.hpp"
79 #include "cli/cli_utils.hpp"
80 #if OPENTHREAD_CONFIG_COAP_API_ENABLE
81 #include "cli/cli_coap.hpp"
82 #endif
83 #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
84 #include "cli/cli_coap_secure.hpp"
85 #endif
86 
87 #include "common/array.hpp"
88 #include "common/code_utils.hpp"
89 #include "common/debug.hpp"
90 #include "common/type_traits.hpp"
91 #include "instance/instance.hpp"
92 
93 namespace ot {
94 
95 /**
96  * @namespace ot::Cli
97  *
98  * @brief
99  *   This namespace contains definitions for the CLI interpreter.
100  *
101  */
102 namespace Cli {
103 
104 extern "C" void otCliPlatLogv(otLogLevel, otLogRegion, const char *, va_list);
105 extern "C" void otCliAppendResult(otError aError);
106 extern "C" void otCliOutputBytes(const uint8_t *aBytes, uint8_t aLength);
107 extern "C" void otCliOutputFormat(const char *aFmt, ...);
108 
109 /**
110  * Implements the CLI interpreter.
111  *
112  */
113 class Interpreter : public OutputImplementer, public Utils
114 {
115 #if OPENTHREAD_FTD || OPENTHREAD_MTD
116     friend class Br;
117     friend class Bbr;
118     friend class Commissioner;
119     friend class Dns;
120     friend class Joiner;
121     friend class LinkMetrics;
122     friend class Mdns;
123     friend class NetworkData;
124     friend class PingSender;
125     friend class SrpClient;
126     friend class SrpServer;
127 #endif
128     friend void otCliPlatLogv(otLogLevel, otLogRegion, const char *, va_list);
129     friend void otCliAppendResult(otError aError);
130     friend void otCliOutputBytes(const uint8_t *aBytes, uint8_t aLength);
131     friend void otCliOutputFormat(const char *aFmt, ...);
132 
133 public:
134     /**
135      * Constructor
136      *
137      * @param[in]  aInstance    The OpenThread instance structure.
138      * @param[in]  aCallback    A callback method called to process CLI output.
139      * @param[in]  aContext     A user context pointer.
140      */
141     explicit Interpreter(Instance *aInstance, otCliOutputCallback aCallback, void *aContext);
142 
143     /**
144      * Returns a reference to the interpreter object.
145      *
146      * @returns A reference to the interpreter object.
147      *
148      */
GetInterpreter(void)149     static Interpreter &GetInterpreter(void)
150     {
151         OT_ASSERT(sInterpreter != nullptr);
152 
153         return *sInterpreter;
154     }
155 
156     /**
157      * Initializes the Console interpreter.
158      *
159      * @param[in]  aInstance  The OpenThread instance structure.
160      * @param[in]  aCallback  A pointer to a callback method.
161      * @param[in]  aContext   A pointer to a user context.
162      *
163      */
164     static void Initialize(otInstance *aInstance, otCliOutputCallback aCallback, void *aContext);
165 
166     /**
167      * Returns whether the interpreter is initialized.
168      *
169      * @returns  Whether the interpreter is initialized.
170      *
171      */
IsInitialized(void)172     static bool IsInitialized(void) { return sInterpreter != nullptr; }
173 
174     /**
175      * Interprets a CLI command.
176      *
177      * @param[in]  aBuf        A pointer to a string.
178      *
179      */
180     void ProcessLine(char *aBuf);
181 
182     /**
183      * Adds commands to the user command table.
184      *
185      * @param[in]  aCommands  A pointer to an array with user commands.
186      * @param[in]  aLength    @p aUserCommands length.
187      * @param[in]  aContext   @p aUserCommands length.
188      *
189      * @retval OT_ERROR_NONE    Successfully updated command table with commands from @p aCommands.
190      * @retval OT_ERROR_FAILED  No available UserCommandsEntry to register requested user commands.
191      */
192     otError SetUserCommands(const otCliCommand *aCommands, uint8_t aLength, void *aContext);
193 
194 protected:
195     static Interpreter *sInterpreter;
196 
197 private:
198     static constexpr uint8_t  kIndentSize            = 4;
199     static constexpr uint16_t kMaxArgs               = 32;
200     static constexpr uint16_t kMaxLineLength         = OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH;
201     static constexpr uint16_t kMaxUserCommandEntries = OPENTHREAD_CONFIG_CLI_MAX_USER_CMD_ENTRIES;
202 
203     static constexpr uint32_t kNetworkDiagnosticTimeoutMsecs = 5000;
204     static constexpr uint32_t kLocateTimeoutMsecs            = 2500;
205 
206     static constexpr uint16_t kMaxTxtDataSize = OPENTHREAD_CONFIG_CLI_TXT_RECORD_MAX_SIZE;
207 
208     using Command = CommandEntry<Interpreter>;
209 
210     void OutputPrompt(void);
211     void OutputResult(otError aError);
212 
213 #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
214     void OutputBorderRouterCounters(void);
215 #endif
216 
217     otError ProcessCommand(Arg aArgs[]);
218 
219     template <CommandId kCommandId> otError Process(Arg aArgs[]);
220 
221     otError ProcessUserCommands(Arg aArgs[]);
222 
223 #if OPENTHREAD_FTD || OPENTHREAD_MTD
224 
225 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
226 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
227     otError ProcessBackboneRouterLocal(Arg aArgs[]);
228 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
229     otError ProcessBackboneRouterMgmtMlr(Arg aArgs[]);
230     void    PrintMulticastListenersTable(void);
231 #endif
232 #endif
233 #endif
234 
235 #if OPENTHREAD_FTD
236     void OutputEidCacheEntry(const otCacheEntryInfo &aEntry);
237 #endif
238 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
239     static void HandleLocateResult(void               *aContext,
240                                    otError             aError,
241                                    const otIp6Address *aMeshLocalAddress,
242                                    uint16_t            aRloc16);
243     void        HandleLocateResult(otError aError, const otIp6Address *aMeshLocalAddress, uint16_t aRloc16);
244 #endif
245 #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
246     static void HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo, void *aContext);
247     void        HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo);
248     static void HandleMeshDiagQueryChildTableResult(otError                     aError,
249                                                     const otMeshDiagChildEntry *aChildEntry,
250                                                     void                       *aContext);
251     void        HandleMeshDiagQueryChildTableResult(otError aError, const otMeshDiagChildEntry *aChildEntry);
252     static void HandleMeshDiagQueryChildIp6Addrs(otError                    aError,
253                                                  uint16_t                   aChildRloc16,
254                                                  otMeshDiagIp6AddrIterator *aIp6AddrIterator,
255                                                  void                      *aContext);
256     void        HandleMeshDiagQueryChildIp6Addrs(otError                    aError,
257                                                  uint16_t                   aChildRloc16,
258                                                  otMeshDiagIp6AddrIterator *aIp6AddrIterator);
259     static void HandleMeshDiagQueryRouterNeighborTableResult(otError                              aError,
260                                                              const otMeshDiagRouterNeighborEntry *aNeighborEntry,
261                                                              void                                *aContext);
262     void        HandleMeshDiagQueryRouterNeighborTableResult(otError                              aError,
263                                                              const otMeshDiagRouterNeighborEntry *aNeighborEntry);
264 
265 #endif
266 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
267     static void HandleMlrRegResult(void               *aContext,
268                                    otError             aError,
269                                    uint8_t             aMlrStatus,
270                                    const otIp6Address *aFailedAddresses,
271                                    uint8_t             aFailedAddressNum);
272     void        HandleMlrRegResult(otError             aError,
273                                    uint8_t             aMlrStatus,
274                                    const otIp6Address *aFailedAddresses,
275                                    uint8_t             aFailedAddressNum);
276 #endif
277 #if OPENTHREAD_CONFIG_MULTI_RADIO
278     void OutputMultiRadioInfo(const otMultiRadioNeighborInfo &aMultiRadioInfo);
279 #endif
280 
281     static void HandleActiveScanResult(otActiveScanResult *aResult, void *aContext);
282     static void HandleEnergyScanResult(otEnergyScanResult *aResult, void *aContext);
283     static void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx, void *aContext);
284 
285 #if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
286     void HandleDiagnosticGetResponse(otError aError, const otMessage *aMessage, const Ip6::MessageInfo *aMessageInfo);
287     static void HandleDiagnosticGetResponse(otError              aError,
288                                             otMessage           *aMessage,
289                                             const otMessageInfo *aMessageInfo,
290                                             void                *aContext);
291 
292     void OutputMode(uint8_t aIndentSize, const otLinkModeConfig &aMode);
293     void OutputConnectivity(uint8_t aIndentSize, const otNetworkDiagConnectivity &aConnectivity);
294     void OutputRoute(uint8_t aIndentSize, const otNetworkDiagRoute &aRoute);
295     void OutputRouteData(uint8_t aIndentSize, const otNetworkDiagRouteData &aRouteData);
296     void OutputLeaderData(uint8_t aIndentSize, const otLeaderData &aLeaderData);
297     void OutputNetworkDiagMacCounters(uint8_t aIndentSize, const otNetworkDiagMacCounters &aMacCounters);
298     void OutputNetworkDiagMleCounters(uint8_t aIndentSize, const otNetworkDiagMleCounters &aMleCounters);
299     void OutputChildTableEntry(uint8_t aIndentSize, const otNetworkDiagChildEntry &aChildEntry);
300 #endif
301 
302 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
303     void OutputTrelCounters(const otTrelCounters &aCounters);
304 #endif
305 #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
306     void OutputNat64Counters(const otNat64Counters &aCounters);
307 #endif
308 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE
309     void OutputRadioStatsTime(const char *aTimeName, uint64_t aTimeUs, uint64_t aTotalTime);
310 #endif
311 
312 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
313     static void HandleSntpResponse(void *aContext, uint64_t aTime, otError aResult);
314 #endif
315 
316     void HandleActiveScanResult(otActiveScanResult *aResult);
317     void HandleEnergyScanResult(otEnergyScanResult *aResult);
318     void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx);
319 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
320     void HandleSntpResponse(uint64_t aTime, otError aResult);
321 #endif
322 
323 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
324     static void HandleBorderAgentEphemeralKeyStateChange(void *aContext);
325     void        HandleBorderAgentEphemeralKeyStateChange(void);
326 #endif
327 
328     static void HandleDetachGracefullyResult(void *aContext);
329     void        HandleDetachGracefullyResult(void);
330 
331 #if OPENTHREAD_FTD
332     static void HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aContext);
333     void        HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo &aInfo);
334 #endif
335 
336 #if OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK
337     static void HandleIp6Receive(otMessage *aMessage, void *aContext);
338 #endif
339 
340 #endif // OPENTHREAD_FTD || OPENTHREAD_MTD
341 
342     void SetCommandTimeout(uint32_t aTimeoutMilli);
343 
344     static void HandleTimer(Timer &aTimer);
345     void        HandleTimer(void);
346 
347     struct UserCommandsEntry
348     {
349         const otCliCommand *mCommands;
350         uint8_t             mLength;
351         void               *mContext;
352     };
353 
354     UserCommandsEntry mUserCommands[kMaxUserCommandEntries];
355     bool              mCommandIsPending;
356     bool              mInternalDebugCommand;
357 
358     TimerMilliContext mTimer;
359 
360 #if OPENTHREAD_FTD || OPENTHREAD_MTD
361 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
362     bool mSntpQueryingInProgress;
363 #endif
364 
365     Dataset     mDataset;
366     NetworkData mNetworkData;
367     UdpExample  mUdp;
368 
369 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
370     MacFilter mMacFilter;
371 #endif
372 
373 #if OPENTHREAD_CLI_DNS_ENABLE
374     Dns mDns;
375 #endif
376 
377 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
378     Mdns mMdns;
379 #endif
380 
381 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
382     Bbr mBbr;
383 #endif
384 
385 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
386     Br mBr;
387 #endif
388 
389 #if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE
390     TcpExample mTcp;
391 #endif
392 
393 #if OPENTHREAD_CONFIG_COAP_API_ENABLE
394     Coap mCoap;
395 #endif
396 
397 #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
398     CoapSecure mCoapSecure;
399 #endif
400 
401 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
402     Commissioner mCommissioner;
403 #endif
404 
405 #if OPENTHREAD_CONFIG_JOINER_ENABLE
406     Joiner mJoiner;
407 #endif
408 
409 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
410     SrpClient mSrpClient;
411 #endif
412 
413 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
414     SrpServer mSrpServer;
415 #endif
416 
417 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
418     History mHistory;
419 #endif
420 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
421     LinkMetrics mLinkMetrics;
422 #endif
423 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
424     Tcat mTcat;
425 #endif
426 #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
427     PingSender mPing;
428 #endif
429 #endif // OPENTHREAD_FTD || OPENTHREAD_MTD
430 
431 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
432     bool mLocateInProgress : 1;
433 #endif
434 };
435 
436 } // namespace Cli
437 } // namespace ot
438 
439 #endif // CLI_HPP_
440