1 /*
2 * Copyright (c) 2020, 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 implements CLI commands for Network Data.
32 */
33
34 #include "cli_network_data.hpp"
35
36 #include <openthread/border_router.h>
37 #include <openthread/netdata_publisher.h>
38 #include <openthread/server.h>
39
40 #include "cli/cli.hpp"
41 #include "common/encoding.hpp"
42
43 namespace ot {
44 namespace Cli {
45
PrefixFlagsToString(const otBorderRouterConfig & aConfig,FlagsString & aString)46 void NetworkData::PrefixFlagsToString(const otBorderRouterConfig &aConfig, FlagsString &aString)
47 {
48 char *flagsPtr = &aString[0];
49
50 if (aConfig.mPreferred)
51 {
52 *flagsPtr++ = 'p';
53 }
54
55 if (aConfig.mSlaac)
56 {
57 *flagsPtr++ = 'a';
58 }
59
60 if (aConfig.mDhcp)
61 {
62 *flagsPtr++ = 'd';
63 }
64
65 if (aConfig.mConfigure)
66 {
67 *flagsPtr++ = 'c';
68 }
69
70 if (aConfig.mDefaultRoute)
71 {
72 *flagsPtr++ = 'r';
73 }
74
75 if (aConfig.mOnMesh)
76 {
77 *flagsPtr++ = 'o';
78 }
79
80 if (aConfig.mStable)
81 {
82 *flagsPtr++ = 's';
83 }
84
85 if (aConfig.mNdDns)
86 {
87 *flagsPtr++ = 'n';
88 }
89
90 if (aConfig.mDp)
91 {
92 *flagsPtr++ = 'D';
93 }
94
95 *flagsPtr = '\0';
96 }
97
OutputPrefix(const otBorderRouterConfig & aConfig)98 void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig)
99 {
100 FlagsString flagsString;
101
102 OutputIp6Prefix(aConfig.mPrefix);
103
104 PrefixFlagsToString(aConfig, flagsString);
105
106 if (flagsString[0] != '\0')
107 {
108 OutputFormat(" %s", flagsString);
109 }
110
111 OutputLine(" %s %04x", Interpreter::PreferenceToString(aConfig.mPreference), aConfig.mRloc16);
112 }
113
RouteFlagsToString(const otExternalRouteConfig & aConfig,FlagsString & aString)114 void NetworkData::RouteFlagsToString(const otExternalRouteConfig &aConfig, FlagsString &aString)
115 {
116 char *flagsPtr = &aString[0];
117
118 if (aConfig.mStable)
119 {
120 *flagsPtr++ = 's';
121 }
122
123 if (aConfig.mNat64)
124 {
125 *flagsPtr++ = 'n';
126 }
127
128 *flagsPtr = '\0';
129 }
130
OutputRoute(const otExternalRouteConfig & aConfig)131 void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig)
132 {
133 FlagsString flagsString;
134
135 OutputIp6Prefix(aConfig.mPrefix);
136
137 RouteFlagsToString(aConfig, flagsString);
138
139 if (flagsString[0] != '\0')
140 {
141 OutputFormat(" %s", flagsString);
142 }
143
144 OutputLine(" %s %04x", Interpreter::PreferenceToString(aConfig.mPreference), aConfig.mRloc16);
145 }
146
OutputService(const otServiceConfig & aConfig)147 void NetworkData::OutputService(const otServiceConfig &aConfig)
148 {
149 OutputFormat("%lu ", ToUlong(aConfig.mEnterpriseNumber));
150 OutputBytes(aConfig.mServiceData, aConfig.mServiceDataLength);
151 OutputFormat(" ");
152 OutputBytes(aConfig.mServerConfig.mServerData, aConfig.mServerConfig.mServerDataLength);
153
154 if (aConfig.mServerConfig.mStable)
155 {
156 OutputFormat(" s");
157 }
158
159 OutputLine(" %04x", aConfig.mServerConfig.mRloc16);
160 }
161
162 /**
163 * @cli netdata length
164 * @code
165 * netdata length
166 * 23
167 * Done
168 * @endcode
169 * @par api_copy
170 * #otNetDataGetLength
171 */
Process(Arg aArgs[])172 template <> otError NetworkData::Process<Cmd("length")>(Arg aArgs[])
173 {
174 otError error = OT_ERROR_NONE;
175
176 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
177 OutputLine("%u", otNetDataGetLength(GetInstancePtr()));
178
179 exit:
180 return error;
181 }
182
Process(Arg aArgs[])183 template <> otError NetworkData::Process<Cmd("maxlength")>(Arg aArgs[])
184 {
185 otError error = OT_ERROR_NONE;
186
187 /**
188 * @cli netdata maxlength
189 * @code
190 * netdata maxlength
191 * 40
192 * Done
193 * @endcode
194 * @par api_copy
195 * #otNetDataGetMaxLength
196 */
197 if (aArgs[0].IsEmpty())
198 {
199 OutputLine("%u", otNetDataGetMaxLength(GetInstancePtr()));
200 }
201 /**
202 * @cli netdata maxlength reset
203 * @code
204 * netdata maxlength reset
205 * Done
206 * @endcode
207 * @par api_copy
208 * #otNetDataResetMaxLength
209 */
210 else if (aArgs[0] == "reset")
211 {
212 otNetDataResetMaxLength(GetInstancePtr());
213 }
214 else
215 {
216 error = OT_ERROR_INVALID_ARGS;
217 }
218
219 return error;
220 }
221
222 #if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
Process(Arg aArgs[])223 template <> otError NetworkData::Process<Cmd("publish")>(Arg aArgs[])
224 {
225 otError error = OT_ERROR_NONE;
226
227 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
228 if (aArgs[0] == "dnssrp")
229 {
230 /**
231 * @cli netdata publish dnssrp anycast
232 * @code
233 * netdata publish dnssrp anycast 1
234 * Done
235 * @endcode
236 * @cparam netdata publish dnssrp anycast @ca{seq-num}
237 * @par
238 * Publishes a DNS/SRP Service Anycast Address with a sequence number. Any current
239 * DNS/SRP Service entry being published from a previous `publish dnssrp{anycast|unicast}`
240 * command is removed and replaced with the new arguments.
241 * @par
242 * `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` must be enabled.
243 * @csa{netdata publish dnssrp unicast (addr,port)}
244 * @csa{netdata publish dnssrp unicast (mle)}
245 * @sa otNetDataPublishDnsSrpServiceAnycast
246 * @endcli
247 */
248 if (aArgs[1] == "anycast")
249 {
250 uint8_t sequenceNumber;
251
252 SuccessOrExit(error = aArgs[2].ParseAsUint8(sequenceNumber));
253 otNetDataPublishDnsSrpServiceAnycast(GetInstancePtr(), sequenceNumber);
254 ExitNow();
255 }
256
257 if (aArgs[1] == "unicast")
258 {
259 otIp6Address address;
260 uint16_t port;
261
262 /**
263 * @cli netdata publish dnssrp unicast (mle)
264 * @code
265 * netdata publish dnssrp unicast 50152
266 * Done
267 * @endcode
268 * @cparam netdata publish dnssrp unicast @ca{port}
269 * @par
270 * Publishes the device's Mesh-Local EID with a port number. MLE and port information is
271 * included in the Server TLV data. To use a different Unicast address, use the
272 * `netdata publish dnssrp unicast (addr,port)` command.
273 * @par
274 * Any current DNS/SRP Service entry being published from a previous
275 * `publish dnssrp{anycast|unicast}` command is removed and replaced with the new arguments.
276 * @par
277 * `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` must be enabled.
278 * @csa{netdata publish dnssrp unicast (addr,port)}
279 * @csa{netdata publish dnssrp anycast}
280 * @sa otNetDataPublishDnsSrpServiceUnicastMeshLocalEid
281 */
282 if (aArgs[3].IsEmpty())
283 {
284 SuccessOrExit(error = aArgs[2].ParseAsUint16(port));
285 otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(GetInstancePtr(), port);
286 ExitNow();
287 }
288
289 /**
290 * @cli netdata publish dnssrp unicast (addr,port)
291 * @code
292 * netdata publish dnssrp unicast fd00::1234 51525
293 * Done
294 * @endcode
295 * @cparam netdata publish dnssrp unicast @ca{address} @ca{port}
296 * @par
297 * Publishes a DNS/SRP Service Unicast Address with an address and port number. The address
298 * and port information is included in Service TLV data. Any current DNS/SRP Service entry being
299 * published from a previous `publish dnssrp{anycast|unicast}` command is removed and replaced
300 * with the new arguments.
301 * @par
302 * `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` must be enabled.
303 * @csa{netdata publish dnssrp unicast (mle)}
304 * @csa{netdata publish dnssrp anycast}
305 * @sa otNetDataPublishDnsSrpServiceUnicast
306 */
307 SuccessOrExit(error = aArgs[2].ParseAsIp6Address(address));
308 SuccessOrExit(error = aArgs[3].ParseAsUint16(port));
309 otNetDataPublishDnsSrpServiceUnicast(GetInstancePtr(), &address, port);
310 ExitNow();
311 }
312 }
313 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
314
315 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
316 /**
317 * @cli netdata publish prefix
318 * @code
319 * netdata publish prefix fd00:1234:5678::/64 paos med
320 * Done
321 * @endcode
322 * @cparam netdata publish prefix @ca{prefix} [@ca{padcrosnD}] [@ca{high}|@ca{med}|@ca{low}]
323 * OT CLI uses mapped arguments to configure #otBorderRouterConfig values. @moreinfo{the @overview}.
324 * @par
325 * Publish an on-mesh prefix entry. @moreinfo{@netdata}.
326 * @sa otNetDataPublishOnMeshPrefix
327 */
328 if (aArgs[0] == "prefix")
329 {
330 otBorderRouterConfig config;
331
332 SuccessOrExit(error = Interpreter::ParsePrefix(aArgs + 1, config));
333 error = otNetDataPublishOnMeshPrefix(GetInstancePtr(), &config);
334 ExitNow();
335 }
336
337 /**
338 * @cli netdata publish route
339 * @code
340 * netdata publish route fd00:1234:5678::/64 s high
341 * Done
342 * @endcode
343 * @cparam publish route @ca{prefix} [@ca{sn}] [@ca{high}|@ca{med}|@ca{low}]
344 * OT CLI uses mapped arguments to configure #otExternalRouteConfig values. @moreinfo{the @overview}.
345 * @par
346 * Publish an external route entry. @moreinfo{@netdata}.
347 * @sa otNetDataPublishExternalRoute
348 */
349 if (aArgs[0] == "route")
350 {
351 otExternalRouteConfig config;
352
353 SuccessOrExit(error = Interpreter::ParseRoute(aArgs + 1, config));
354 error = otNetDataPublishExternalRoute(GetInstancePtr(), &config);
355 ExitNow();
356 }
357
358 /**
359 * @cli netdata publish replace
360 * @code
361 * netdata publish replace ::/0 fd00:1234:5678::/64 s high
362 * Done
363 * @endcode
364 * @cparam netdata publish replace @ca{oldprefix} @ca{prefix} [@ca{sn}] [@ca{high}|@ca{med}|@ca{low}]
365 * OT CLI uses mapped arguments to configure #otExternalRouteConfig values. @moreinfo{the @overview}.
366 * @par
367 * Replaces a previously published external route entry. @moreinfo{@netdata}.
368 * @sa otNetDataReplacePublishedExternalRoute
369 */
370 if (aArgs[0] == "replace")
371 {
372 otIp6Prefix prefix;
373 otExternalRouteConfig config;
374
375 SuccessOrExit(error = aArgs[1].ParseAsIp6Prefix(prefix));
376 SuccessOrExit(error = Interpreter::ParseRoute(aArgs + 2, config));
377 error = otNetDataReplacePublishedExternalRoute(GetInstancePtr(), &prefix, &config);
378 ExitNow();
379 }
380 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
381
382 error = OT_ERROR_INVALID_ARGS;
383
384 exit:
385 return error;
386 }
387
Process(Arg aArgs[])388 template <> otError NetworkData::Process<Cmd("unpublish")>(Arg aArgs[])
389 {
390 otError error = OT_ERROR_NONE;
391
392 /**
393 * @cli netdata unpublish dnssrp
394 * @code
395 * netdata unpublish dnssrp
396 * Done
397 * @endcode
398 * @par api_copy
399 * #otNetDataUnpublishDnsSrpService
400 */
401 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
402 if (aArgs[0] == "dnssrp")
403 {
404 otNetDataUnpublishDnsSrpService(GetInstancePtr());
405 ExitNow();
406 }
407 #endif
408
409 /**
410 * @cli netdata unpublish (prefix)
411 * @code
412 * netdata unpublish fd00:1234:5678::/64
413 * Done
414 * @endcode
415 * @cparam netdata unpublish @ca{prefix}
416 * @par api_copy
417 * #otNetDataUnpublishPrefix
418 * @par
419 * @moreinfo{@netdata}.
420 */
421 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
422 {
423 otIp6Prefix prefix;
424
425 if (aArgs[0].ParseAsIp6Prefix(prefix) == OT_ERROR_NONE)
426 {
427 error = otNetDataUnpublishPrefix(GetInstancePtr(), &prefix);
428 ExitNow();
429 }
430 }
431 #endif
432
433 error = OT_ERROR_INVALID_ARGS;
434
435 exit:
436 return error;
437 }
438 #endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
439
440 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
441 /**
442 * @cli netdata register
443 * @code
444 * netdata register
445 * Done
446 * @endcode
447 * @par
448 * Register configured prefixes, routes, and services with the Leader.
449 * @par
450 * OT CLI checks for `OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE`. If OTBR is enabled, it
451 * registers local Network Data with the Leader. Otherwise, it calls the CLI function `otServerRegister`.
452 * @moreinfo{@netdata}.
453 * @csa{prefix add}
454 * @sa otBorderRouterRegister
455 * @sa otServerAddService
456 */
Process(Arg aArgs[])457 template <> otError NetworkData::Process<Cmd("register")>(Arg aArgs[])
458 {
459 OT_UNUSED_VARIABLE(aArgs);
460
461 otError error = OT_ERROR_NONE;
462
463 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
464 SuccessOrExit(error = otBorderRouterRegister(GetInstancePtr()));
465 #else
466 SuccessOrExit(error = otServerRegister(GetInstancePtr()));
467 #endif
468
469 exit:
470 return error;
471 }
472 #endif
473
Process(Arg aArgs[])474 template <> otError NetworkData::Process<Cmd("steeringdata")>(Arg aArgs[])
475 {
476 otError error;
477 otExtAddress addr;
478 otJoinerDiscerner discerner;
479
480 VerifyOrExit(aArgs[0] == "check", error = OT_ERROR_INVALID_ARGS);
481
482 error = Interpreter::ParseJoinerDiscerner(aArgs[1], discerner);
483
484 if (error == OT_ERROR_NOT_FOUND)
485 {
486 discerner.mLength = 0;
487 error = aArgs[1].ParseAsHexString(addr.m8);
488 }
489
490 SuccessOrExit(error);
491
492 /**
493 * @cli netdata steeringdata check (discerner)
494 * @code
495 * netdata steeringdata check 0xabc/12
496 * Done
497 * @endcode
498 * @code
499 * netdata steeringdata check 0xdef/12
500 * Error 23: NotFound
501 * @endcode
502 * @cparam netdata steeringdata check @ca{discerner}
503 * * `discerner`: The %Joiner discerner in format `{number}/{length}`.
504 * @par api_copy
505 * #otNetDataSteeringDataCheckJoinerWithDiscerner
506 * @csa{joiner discerner}
507 */
508 if (discerner.mLength)
509 {
510 error = otNetDataSteeringDataCheckJoinerWithDiscerner(GetInstancePtr(), &discerner);
511 }
512 /**
513 * @cli netdata steeringdata check (eui64)
514 * @code
515 * netdata steeringdata check d45e64fa83f81cf7
516 * Done
517 * @endcode
518 * @cparam netdata steeringdata check @ca{eui64}
519 * * `eui64`: The IEEE EUI-64 of the %Joiner.
520 * @par api_copy
521 * #otNetDataSteeringDataCheckJoiner
522 * @csa{eui64}
523 */
524 else
525 {
526 error = otNetDataSteeringDataCheckJoiner(GetInstancePtr(), &addr);
527 }
528
529 exit:
530 return error;
531 }
532
GetNextPrefix(otNetworkDataIterator * aIterator,otBorderRouterConfig * aConfig,bool aLocal)533 otError NetworkData::GetNextPrefix(otNetworkDataIterator *aIterator, otBorderRouterConfig *aConfig, bool aLocal)
534 {
535 otError error;
536
537 if (aLocal)
538 {
539 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
540 error = otBorderRouterGetNextOnMeshPrefix(GetInstancePtr(), aIterator, aConfig);
541 #else
542 error = OT_ERROR_NOT_FOUND;
543 #endif
544 }
545 else
546 {
547 error = otNetDataGetNextOnMeshPrefix(GetInstancePtr(), aIterator, aConfig);
548 }
549
550 return error;
551 }
552
OutputPrefixes(bool aLocal)553 void NetworkData::OutputPrefixes(bool aLocal)
554 {
555 otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
556 otBorderRouterConfig config;
557
558 OutputLine("Prefixes:");
559
560 while (GetNextPrefix(&iterator, &config, aLocal) == OT_ERROR_NONE)
561 {
562 OutputPrefix(config);
563 }
564 }
565
GetNextRoute(otNetworkDataIterator * aIterator,otExternalRouteConfig * aConfig,bool aLocal)566 otError NetworkData::GetNextRoute(otNetworkDataIterator *aIterator, otExternalRouteConfig *aConfig, bool aLocal)
567 {
568 otError error;
569
570 if (aLocal)
571 {
572 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
573 error = otBorderRouterGetNextRoute(GetInstancePtr(), aIterator, aConfig);
574 #else
575 error = OT_ERROR_NOT_FOUND;
576 #endif
577 }
578 else
579 {
580 error = otNetDataGetNextRoute(GetInstancePtr(), aIterator, aConfig);
581 }
582
583 return error;
584 }
585
OutputRoutes(bool aLocal)586 void NetworkData::OutputRoutes(bool aLocal)
587 {
588 otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
589 otExternalRouteConfig config;
590
591 OutputLine("Routes:");
592
593 while (GetNextRoute(&iterator, &config, aLocal) == OT_ERROR_NONE)
594 {
595 OutputRoute(config);
596 }
597 }
598
GetNextService(otNetworkDataIterator * aIterator,otServiceConfig * aConfig,bool aLocal)599 otError NetworkData::GetNextService(otNetworkDataIterator *aIterator, otServiceConfig *aConfig, bool aLocal)
600 {
601 otError error;
602
603 if (aLocal)
604 {
605 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
606 error = otServerGetNextService(GetInstancePtr(), aIterator, aConfig);
607 #else
608 error = OT_ERROR_NOT_FOUND;
609 #endif
610 }
611 else
612 {
613 error = otNetDataGetNextService(GetInstancePtr(), aIterator, aConfig);
614 }
615
616 return error;
617 }
618
OutputServices(bool aLocal)619 void NetworkData::OutputServices(bool aLocal)
620 {
621 otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
622 otServiceConfig config;
623
624 OutputLine("Services:");
625
626 while (GetNextService(&iterator, &config, aLocal) == OT_ERROR_NONE)
627 {
628 OutputService(config);
629 }
630 }
631
OutputLowpanContexts(bool aLocal)632 void NetworkData::OutputLowpanContexts(bool aLocal)
633 {
634 otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
635 otLowpanContextInfo info;
636
637 VerifyOrExit(!aLocal);
638
639 OutputLine("Contexts:");
640
641 while (otNetDataGetNextLowpanContextInfo(GetInstancePtr(), &iterator, &info) == OT_ERROR_NONE)
642 {
643 OutputIp6Prefix(info.mPrefix);
644 OutputLine(" %u %c", info.mContextId, info.mCompressFlag ? 'c' : '-');
645 }
646
647 exit:
648 return;
649 }
650
OutputBinary(bool aLocal)651 otError NetworkData::OutputBinary(bool aLocal)
652 {
653 otError error;
654 uint8_t data[255];
655 uint8_t len = sizeof(data);
656
657 if (aLocal)
658 {
659 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
660 error = otBorderRouterGetNetData(GetInstancePtr(), false, data, &len);
661 #else
662 error = OT_ERROR_NOT_IMPLEMENTED;
663 #endif
664 }
665 else
666 {
667 error = otNetDataGet(GetInstancePtr(), false, data, &len);
668 }
669 SuccessOrExit(error);
670
671 OutputBytesLine(data, static_cast<uint8_t>(len));
672
673 exit:
674 return error;
675 }
676
677 /**
678 * @cli netdata show
679 * @code
680 * netdata show
681 * Prefixes:
682 * fd00:dead:beef:cafe::/64 paros med dc00
683 * Routes:
684 * fd49:7770:7fc5:0::/64 s med 4000
685 * Services:
686 * 44970 5d c000 s 4000
687 * 44970 01 9a04b000000e10 s 4000
688 * Contexts:
689 * fd00:dead:beef:cafe::/64 1 c
690 * Done
691 * @endcode
692 * @code
693 * netdata show -x
694 * 08040b02174703140040fd00deadbeefcafe0504dc00330007021140
695 * Done
696 * @endcode
697 * @cparam netdata show [@ca{-x}]
698 * * The optional `-x` argument gets Network Data as hex-encoded TLVs.
699 * @par
700 * `netdata show` from OT CLI gets full Network Data received from the Leader. This command uses several
701 * API functions to combine prefixes, routes, and services, including #otNetDataGetNextOnMeshPrefix,
702 * #otNetDataGetNextRoute, #otNetDataGetNextService and #otNetDataGetNextLowpanContextInfo.
703 * @par
704 * On-mesh prefixes are listed under `Prefixes` header:
705 * * The on-mesh prefix
706 * * Flags
707 * * p: Preferred flag
708 * * a: Stateless IPv6 Address Autoconfiguration flag
709 * * d: DHCPv6 IPv6 Address Configuration flag
710 * * c: DHCPv6 Other Configuration flag
711 * * r: Default Route flag
712 * * o: On Mesh flag
713 * * s: Stable flag
714 * * n: Nd Dns flag
715 * * D: Domain Prefix flag (only available for Thread 1.2).
716 * * Preference `high`, `med`, or `low`
717 * * RLOC16 of device which added the on-mesh prefix
718 * @par
719 * External Routes are listed under `Routes` header:
720 * * The route prefix
721 * * Flags
722 * * s: Stable flag
723 * * n: NAT64 flag
724 * * Preference `high`, `med`, or `low`
725 * * RLOC16 of device which added the route prefix
726 * @par
727 * Service entries are listed under `Services` header:
728 * * Enterprise number
729 * * Service data (as hex bytes)
730 * * Server data (as hex bytes)
731 * * Flags
732 * * s: Stable flag
733 * * RLOC16 of devices which added the service entry
734 * @par
735 * 6LoWPAN Context IDs are listed under `Contexts` header:
736 * * The prefix
737 * * Context ID
738 * * Compress flag (`c` if marked or `-` otherwise).
739 * @par
740 * @moreinfo{@netdata}.
741 * @csa{br omrprefix}
742 * @csa{br onlinkprefix}
743 * @sa otBorderRouterGetNetData
744 */
Process(Arg aArgs[])745 template <> otError NetworkData::Process<Cmd("show")>(Arg aArgs[])
746 {
747 otError error = OT_ERROR_INVALID_ARGS;
748 bool local = false;
749 bool binary = false;
750
751 for (uint8_t i = 0; !aArgs[i].IsEmpty(); i++)
752 {
753 /**
754 * @cli netdata show local
755 * @code
756 * netdata show local
757 * Prefixes:
758 * fd00:dead:beef:cafe::/64 paros med dc00
759 * Routes:
760 * Services:
761 * Done
762 * @endcode
763 * @code
764 * netdata show local -x
765 * 08040b02174703140040fd00deadbeefcafe0504dc00330007021140
766 * Done
767 * @endcode
768 * @cparam netdata show local [@ca{-x}]
769 * * The optional `-x` argument gets local Network Data as hex-encoded TLVs.
770 * @par
771 * Print local Network Data to sync with the Leader.
772 * @csa{netdata show}
773 */
774 if (aArgs[i] == "local")
775 {
776 local = true;
777 }
778 else if (aArgs[i] == "-x")
779 {
780 binary = true;
781 }
782 else
783 {
784 ExitNow(error = OT_ERROR_INVALID_ARGS);
785 }
786 }
787
788 if (binary)
789 {
790 error = OutputBinary(local);
791 }
792 else
793 {
794 OutputPrefixes(local);
795 OutputRoutes(local);
796 OutputServices(local);
797 OutputLowpanContexts(local);
798 error = OT_ERROR_NONE;
799 }
800
801 exit:
802 return error;
803 }
804
Process(Arg aArgs[])805 otError NetworkData::Process(Arg aArgs[])
806 {
807 #define CmdEntry(aCommandString) \
808 { \
809 aCommandString, &NetworkData::Process<Cmd(aCommandString)> \
810 }
811
812 static constexpr Command kCommands[] = {
813 CmdEntry("length"),
814 CmdEntry("maxlength"),
815 #if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
816 CmdEntry("publish"),
817 #endif
818 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
819 CmdEntry("register"),
820 #endif
821 CmdEntry("show"),
822 CmdEntry("steeringdata"),
823 #if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
824 CmdEntry("unpublish"),
825 #endif
826 };
827
828 #undef CmdEntry
829
830 static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
831
832 otError error = OT_ERROR_INVALID_COMMAND;
833 const Command *command;
834
835 /**
836 * @cli netdata help
837 * @code
838 * netdata help
839 * length
840 * maxlength
841 * publish
842 * register
843 * show
844 * steeringdata
845 * unpublish
846 * Done
847 * @endcode
848 * @par
849 * Gets a list of `netdata` CLI commands.
850 * @sa @netdata
851 */
852 if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
853 {
854 OutputCommandTable(kCommands);
855 ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE);
856 }
857
858 command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
859 VerifyOrExit(command != nullptr);
860
861 error = (this->*command->mHandler)(aArgs + 1);
862
863 exit:
864 return error;
865 }
866
867 } // namespace Cli
868 } // namespace ot
869