1 /*
2 * Copyright (c) 2023, 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 for Border Router.
32 */
33
34 #include "cli_br.hpp"
35
36 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
37
38 #include <string.h>
39
40 #include "cli/cli.hpp"
41
42 namespace ot {
43 namespace Cli {
44
45 /**
46 * @cli br init
47 * @code
48 * br init 2 1
49 * Done
50 * @endcode
51 * @cparam br init @ca{infrastructure-network-index} @ca{is-running}
52 * @par
53 * Initializes the Border Routing Manager.
54 * @sa otBorderRoutingInit
55 */
Process(Arg aArgs[])56 template <> otError Br::Process<Cmd("init")>(Arg aArgs[])
57 {
58 otError error = OT_ERROR_NONE;
59 uint32_t ifIndex;
60 bool isRunning;
61
62 SuccessOrExit(error = aArgs[0].ParseAsUint32(ifIndex));
63 SuccessOrExit(error = aArgs[1].ParseAsBool(isRunning));
64 VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
65 error = otBorderRoutingInit(GetInstancePtr(), ifIndex, isRunning);
66
67 exit:
68 return error;
69 }
70
71 /**
72 * @cli br enable
73 * @code
74 * br enable
75 * Done
76 * @endcode
77 * @par
78 * Enables the Border Routing Manager.
79 * @sa otBorderRoutingSetEnabled
80 */
Process(Arg aArgs[])81 template <> otError Br::Process<Cmd("enable")>(Arg aArgs[])
82 {
83 otError error = OT_ERROR_NONE;
84
85 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
86 error = otBorderRoutingSetEnabled(GetInstancePtr(), true);
87
88 exit:
89 return error;
90 }
91
92 /**
93 * @cli br disable
94 * @code
95 * br disable
96 * Done
97 * @endcode
98 * @par
99 * Disables the Border Routing Manager.
100 * @sa otBorderRoutingSetEnabled
101 */
Process(Arg aArgs[])102 template <> otError Br::Process<Cmd("disable")>(Arg aArgs[])
103 {
104 otError error = OT_ERROR_NONE;
105
106 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
107 error = otBorderRoutingSetEnabled(GetInstancePtr(), false);
108
109 exit:
110 return error;
111 }
112
113 /**
114 * @cli br state
115 * @code
116 * br state
117 * running
118 * @endcode
119 * @par api_copy
120 * #otBorderRoutingGetState
121 */
Process(Arg aArgs[])122 template <> otError Br::Process<Cmd("state")>(Arg aArgs[])
123 {
124 static const char *const kStateStrings[] = {
125
126 "uninitialized", // (0) OT_BORDER_ROUTING_STATE_UNINITIALIZED
127 "disabled", // (1) OT_BORDER_ROUTING_STATE_DISABLED
128 "stopped", // (2) OT_BORDER_ROUTING_STATE_STOPPED
129 "running", // (3) OT_BORDER_ROUTING_STATE_RUNNING
130 };
131
132 otError error = OT_ERROR_NONE;
133
134 static_assert(0 == OT_BORDER_ROUTING_STATE_UNINITIALIZED, "STATE_UNINITIALIZED value is incorrect");
135 static_assert(1 == OT_BORDER_ROUTING_STATE_DISABLED, "STATE_DISABLED value is incorrect");
136 static_assert(2 == OT_BORDER_ROUTING_STATE_STOPPED, "STATE_STOPPED value is incorrect");
137 static_assert(3 == OT_BORDER_ROUTING_STATE_RUNNING, "STATE_RUNNING value is incorrect");
138
139 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
140 OutputLine("%s", Stringify(otBorderRoutingGetState(GetInstancePtr()), kStateStrings));
141
142 exit:
143 return error;
144 }
145
ParsePrefixTypeArgs(Arg aArgs[],PrefixType & aFlags)146 otError Br::ParsePrefixTypeArgs(Arg aArgs[], PrefixType &aFlags)
147 {
148 otError error = OT_ERROR_NONE;
149
150 aFlags = 0;
151
152 if (aArgs[0].IsEmpty())
153 {
154 aFlags = kPrefixTypeFavored | kPrefixTypeLocal;
155 ExitNow();
156 }
157
158 if (aArgs[0] == "local")
159 {
160 aFlags = kPrefixTypeLocal;
161 }
162 else if (aArgs[0] == "favored")
163 {
164 aFlags = kPrefixTypeFavored;
165 }
166 else
167 {
168 ExitNow(error = OT_ERROR_INVALID_ARGS);
169 }
170
171 VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
172
173 exit:
174 return error;
175 }
176
177 /**
178 * @cli br omrprefix
179 * @code
180 * br omrprefix
181 * Local: fdfc:1ff5:1512:5622::/64
182 * Favored: fdfc:1ff5:1512:5622::/64 prf:low
183 * Done
184 * @endcode
185 * @par
186 * Outputs both local and favored OMR prefix.
187 * @sa otBorderRoutingGetOmrPrefix
188 * @sa otBorderRoutingGetFavoredOmrPrefix
189 */
Process(Arg aArgs[])190 template <> otError Br::Process<Cmd("omrprefix")>(Arg aArgs[])
191 {
192 otError error = OT_ERROR_NONE;
193 PrefixType outputPrefixTypes;
194
195 SuccessOrExit(error = ParsePrefixTypeArgs(aArgs, outputPrefixTypes));
196
197 /**
198 * @cli br omrprefix local
199 * @code
200 * br omrprefix local
201 * fdfc:1ff5:1512:5622::/64
202 * Done
203 * @endcode
204 * @par api_copy
205 * #otBorderRoutingGetOmrPrefix
206 */
207 if (outputPrefixTypes & kPrefixTypeLocal)
208 {
209 otIp6Prefix local;
210
211 SuccessOrExit(error = otBorderRoutingGetOmrPrefix(GetInstancePtr(), &local));
212
213 OutputFormat("%s", outputPrefixTypes == kPrefixTypeLocal ? "" : "Local: ");
214 OutputIp6PrefixLine(local);
215 }
216
217 /**
218 * @cli br omrprefix favored
219 * @code
220 * br omrprefix favored
221 * fdfc:1ff5:1512:5622::/64 prf:low
222 * Done
223 * @endcode
224 * @par api_copy
225 * #otBorderRoutingGetFavoredOmrPrefix
226 */
227 if (outputPrefixTypes & kPrefixTypeFavored)
228 {
229 otIp6Prefix favored;
230 otRoutePreference preference;
231
232 SuccessOrExit(error = otBorderRoutingGetFavoredOmrPrefix(GetInstancePtr(), &favored, &preference));
233
234 OutputFormat("%s", outputPrefixTypes == kPrefixTypeFavored ? "" : "Favored: ");
235 OutputIp6Prefix(favored);
236 OutputLine(" prf:%s", Interpreter::PreferenceToString(preference));
237 }
238
239 exit:
240 return error;
241 }
242
243 /**
244 * @cli br onlinkprefix
245 * @code
246 * br onlinkprefix
247 * Local: fd41:2650:a6f5:0::/64
248 * Favored: 2600::0:1234:da12::/64
249 * Done
250 * @endcode
251 * @par
252 * Outputs both local and favored on-link prefixes.
253 * @sa otBorderRoutingGetOnLinkPrefix
254 * @sa otBorderRoutingGetFavoredOnLinkPrefix
255 */
Process(Arg aArgs[])256 template <> otError Br::Process<Cmd("onlinkprefix")>(Arg aArgs[])
257 {
258 otError error = OT_ERROR_NONE;
259 PrefixType outputPrefixTypes;
260
261 SuccessOrExit(error = ParsePrefixTypeArgs(aArgs, outputPrefixTypes));
262
263 /**
264 * @cli br onlinkprefix local
265 * @code
266 * br onlinkprefix local
267 * fd41:2650:a6f5:0::/64
268 * Done
269 * @endcode
270 * @par api_copy
271 * #otBorderRoutingGetOnLinkPrefix
272 */
273 if (outputPrefixTypes & kPrefixTypeLocal)
274 {
275 otIp6Prefix local;
276
277 SuccessOrExit(error = otBorderRoutingGetOnLinkPrefix(GetInstancePtr(), &local));
278
279 OutputFormat("%s", outputPrefixTypes == kPrefixTypeLocal ? "" : "Local: ");
280 OutputIp6PrefixLine(local);
281 }
282
283 /**
284 * @cli br onlinkprefix favored
285 * @code
286 * br onlinkprefix favored
287 * 2600::0:1234:da12::/64
288 * Done
289 * @endcode
290 * @par api_copy
291 * #otBorderRoutingGetFavoredOnLinkPrefix
292 */
293 if (outputPrefixTypes & kPrefixTypeFavored)
294 {
295 otIp6Prefix favored;
296
297 SuccessOrExit(error = otBorderRoutingGetFavoredOnLinkPrefix(GetInstancePtr(), &favored));
298
299 OutputFormat("%s", outputPrefixTypes == kPrefixTypeFavored ? "" : "Favored: ");
300 OutputIp6PrefixLine(favored);
301 }
302
303 exit:
304 return error;
305 }
306
307 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
308
309 /**
310 * @cli br nat64prefix
311 * @code
312 * br nat64prefix
313 * Local: fd14:1078:b3d5:b0b0:0:0::/96
314 * Favored: fd14:1078:b3d5:b0b0:0:0::/96 prf:low
315 * Done
316 * @endcode
317 * @par
318 * Outputs both local and favored NAT64 prefixes.
319 * @sa otBorderRoutingGetNat64Prefix
320 * @sa otBorderRoutingGetFavoredNat64Prefix
321 */
Process(Arg aArgs[])322 template <> otError Br::Process<Cmd("nat64prefix")>(Arg aArgs[])
323 {
324 otError error = OT_ERROR_NONE;
325 PrefixType outputPrefixTypes;
326
327 SuccessOrExit(error = ParsePrefixTypeArgs(aArgs, outputPrefixTypes));
328
329 /**
330 * @cli br nat64prefix local
331 * @code
332 * br nat64prefix local
333 * fd14:1078:b3d5:b0b0:0:0::/96
334 * Done
335 * @endcode
336 * @par api_copy
337 * #otBorderRoutingGetNat64Prefix
338 */
339 if (outputPrefixTypes & kPrefixTypeLocal)
340 {
341 otIp6Prefix local;
342
343 SuccessOrExit(error = otBorderRoutingGetNat64Prefix(GetInstancePtr(), &local));
344
345 OutputFormat("%s", outputPrefixTypes == kPrefixTypeLocal ? "" : "Local: ");
346 OutputIp6PrefixLine(local);
347 }
348
349 /**
350 * @cli br nat64prefix favored
351 * @code
352 * br nat64prefix favored
353 * fd14:1078:b3d5:b0b0:0:0::/96 prf:low
354 * Done
355 * @endcode
356 * @par api_copy
357 * #otBorderRoutingGetFavoredNat64Prefix
358 */
359 if (outputPrefixTypes & kPrefixTypeFavored)
360 {
361 otIp6Prefix favored;
362 otRoutePreference preference;
363
364 SuccessOrExit(error = otBorderRoutingGetFavoredNat64Prefix(GetInstancePtr(), &favored, &preference));
365
366 OutputFormat("%s", outputPrefixTypes == kPrefixTypeFavored ? "" : "Favored: ");
367 OutputIp6Prefix(favored);
368 OutputLine(" prf:%s", Interpreter::PreferenceToString(preference));
369 }
370
371 exit:
372 return error;
373 }
374
375 #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
376
377 /**
378 * @cli br prefixtable
379 * @code
380 * br prefixtable
381 * prefix:fd00:1234:5678:0::/64, on-link:no, ms-since-rx:29526, lifetime:1800, route-prf:med,
382 * router:ff02:0:0:0:0:0:0:1 (M:0 O:0 Stub:1)
383 * prefix:1200:abba:baba:0::/64, on-link:yes, ms-since-rx:29527, lifetime:1800, preferred:1800,
384 * router:ff02:0:0:0:0:0:0:1 (M:0 O:0 Stub:1)
385 * Done
386 * @endcode
387 * @par
388 * Get the discovered prefixes by Border Routing Manager on the infrastructure link.
389 * Info per prefix entry:
390 * - The prefix
391 * - Whether the prefix is on-link or route
392 * - Milliseconds since last received Router Advertisement containing this prefix
393 * - Prefix lifetime in seconds
394 * - Preferred lifetime in seconds only if prefix is on-link
395 * - Route preference (low, med, high) only if prefix is route (not on-link)
396 * - The router IPv6 address which advertising this prefix
397 * - Flags in received Router Advertisement header:
398 * - M: Managed Address Config flag
399 * - O: Other Config flag
400 * - Stub: Stub Router flag (indicates whether the router is a stub router)
401 * @sa otBorderRoutingGetNextPrefixTableEntry
402 */
Process(Arg aArgs[])403 template <> otError Br::Process<Cmd("prefixtable")>(Arg aArgs[])
404 {
405 otError error = OT_ERROR_NONE;
406 otBorderRoutingPrefixTableIterator iterator;
407 otBorderRoutingPrefixTableEntry entry;
408
409 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
410
411 otBorderRoutingPrefixTableInitIterator(GetInstancePtr(), &iterator);
412
413 while (otBorderRoutingGetNextPrefixTableEntry(GetInstancePtr(), &iterator, &entry) == OT_ERROR_NONE)
414 {
415 char string[OT_IP6_PREFIX_STRING_SIZE];
416
417 otIp6PrefixToString(&entry.mPrefix, string, sizeof(string));
418 OutputFormat("prefix:%s, on-link:%s, ms-since-rx:%lu, lifetime:%lu, ", string, entry.mIsOnLink ? "yes" : "no",
419 ToUlong(entry.mMsecSinceLastUpdate), ToUlong(entry.mValidLifetime));
420
421 if (entry.mIsOnLink)
422 {
423 OutputFormat("preferred:%lu, ", ToUlong(entry.mPreferredLifetime));
424 }
425 else
426 {
427 OutputFormat("route-prf:%s, ", Interpreter::PreferenceToString(entry.mRoutePreference));
428 }
429
430 OutputFormat("router:");
431 OutputRouterInfo(entry.mRouter);
432 }
433
434 exit:
435 return error;
436 }
437
438 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
Process(Arg aArgs[])439 template <> otError Br::Process<Cmd("pd")>(Arg aArgs[])
440 {
441 otError error = OT_ERROR_NONE;
442
443 /**
444 * @cli br pd (enable,disable)
445 * @code
446 * br pd enable
447 * Done
448 * @endcode
449 * @code
450 * br pd disable
451 * Done
452 * @endcode
453 * @cparam br pd @ca{enable|disable}
454 * @par api_copy
455 * #otBorderRoutingDhcp6PdSetEnabled
456 *
457 */
458 if (ProcessEnableDisable(aArgs, otBorderRoutingDhcp6PdSetEnabled) == OT_ERROR_NONE)
459 {
460 }
461 /**
462 * @cli br pd state
463 * @code
464 * br pd state
465 * running
466 * Done
467 * @endcode
468 * @par api_copy
469 * #otBorderRoutingDhcp6PdGetState
470 */
471 else if (aArgs[0] == "state")
472 {
473 static const char *const kDhcpv6PdStateStrings[] = {
474 "disabled", // (0) OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED
475 "stopped", // (1) OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED
476 "running", // (2) OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING
477 };
478
479 static_assert(0 == OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED,
480 "OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED value is not expected!");
481 static_assert(1 == OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED,
482 "OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED value is not expected!");
483 static_assert(2 == OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING,
484 "OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING value is not expected!");
485
486 OutputLine("%s", Stringify(otBorderRoutingDhcp6PdGetState(GetInstancePtr()), kDhcpv6PdStateStrings));
487 }
488 else
489 {
490 ExitNow(error = OT_ERROR_INVALID_COMMAND);
491 }
492
493 exit:
494 return error;
495 }
496 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
497
498 /**
499 * @cli br routers
500 * @code
501 * br routers
502 * ff02:0:0:0:0:0:0:1 (M:0 O:0 Stub:1)
503 * Done
504 * @endcode
505 * @par
506 * Get the list of discovered routers by Border Routing Manager on the infrastructure link.
507 * Info per router:
508 * - The router IPv6 address
509 * - Flags in received Router Advertisement header:
510 * - M: Managed Address Config flag
511 * - O: Other Config flag
512 * - Stub: Stub Router flag (indicates whether the router is a stub router)
513 * @sa otBorderRoutingGetNextRouterEntry
514 */
Process(Arg aArgs[])515 template <> otError Br::Process<Cmd("routers")>(Arg aArgs[])
516 {
517 otError error = OT_ERROR_NONE;
518 otBorderRoutingPrefixTableIterator iterator;
519 otBorderRoutingRouterEntry entry;
520
521 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
522
523 otBorderRoutingPrefixTableInitIterator(GetInstancePtr(), &iterator);
524
525 while (otBorderRoutingGetNextRouterEntry(GetInstancePtr(), &iterator, &entry) == OT_ERROR_NONE)
526 {
527 OutputRouterInfo(entry);
528 }
529
530 exit:
531 return error;
532 }
533
OutputRouterInfo(const otBorderRoutingRouterEntry & aEntry)534 void Br::OutputRouterInfo(const otBorderRoutingRouterEntry &aEntry)
535 {
536 OutputIp6Address(aEntry.mAddress);
537 OutputLine(" (M:%u O:%u Stub:%u)", aEntry.mManagedAddressConfigFlag, aEntry.mOtherConfigFlag,
538 aEntry.mStubRouterFlag);
539 }
540
Process(Arg aArgs[])541 template <> otError Br::Process<Cmd("raoptions")>(Arg aArgs[])
542 {
543 static constexpr uint16_t kMaxExtraOptions = 800;
544
545 otError error = OT_ERROR_NONE;
546 uint8_t options[kMaxExtraOptions];
547 uint16_t length;
548
549 /**
550 * @cli br raoptions (set,clear)
551 * @code
552 * br raoptions 0400ff00020001
553 * Done
554 * @endcode
555 * @code
556 * br raoptions clear
557 * Done
558 * @endcode
559 * @cparam br raoptions @ca{options|clear}
560 * `br raoptions clear` passes a `nullptr` to #otBorderRoutingSetExtraRouterAdvertOptions.
561 * Otherwise, you can pass the `options` byte as hex data.
562 * @par api_copy
563 * #otBorderRoutingSetExtraRouterAdvertOptions
564 */
565 if (aArgs[0] == "clear")
566 {
567 length = 0;
568 }
569 else
570 {
571 length = sizeof(options);
572 SuccessOrExit(error = aArgs[0].ParseAsHexString(length, options));
573 }
574
575 error = otBorderRoutingSetExtraRouterAdvertOptions(GetInstancePtr(), length > 0 ? options : nullptr, length);
576
577 exit:
578 return error;
579 }
580
Process(Arg aArgs[])581 template <> otError Br::Process<Cmd("rioprf")>(Arg aArgs[])
582 {
583 otError error = OT_ERROR_NONE;
584
585 /**
586 * @cli br rioprf
587 * @code
588 * br rioprf
589 * med
590 * Done
591 * @endcode
592 * @par api_copy
593 * #otBorderRoutingGetRouteInfoOptionPreference
594 */
595 if (aArgs[0].IsEmpty())
596 {
597 OutputLine("%s",
598 Interpreter::PreferenceToString(otBorderRoutingGetRouteInfoOptionPreference(GetInstancePtr())));
599 }
600 /**
601 * @cli br rioprf clear
602 * @code
603 * br rioprf clear
604 * Done
605 * @endcode
606 * @par api_copy
607 * #otBorderRoutingClearRouteInfoOptionPreference
608 */
609 else if (aArgs[0] == "clear")
610 {
611 otBorderRoutingClearRouteInfoOptionPreference(GetInstancePtr());
612 }
613 /**
614 * @cli br rioprf (high,med,low)
615 * @code
616 * br rioprf low
617 * Done
618 * @endcode
619 * @cparam br rioprf [@ca{high}|@ca{med}|@ca{low}]
620 * @par api_copy
621 * #otBorderRoutingSetRouteInfoOptionPreference
622 */
623 else
624 {
625 otRoutePreference preference;
626
627 SuccessOrExit(error = Interpreter::ParsePreference(aArgs[0], preference));
628 otBorderRoutingSetRouteInfoOptionPreference(GetInstancePtr(), preference);
629 }
630
631 exit:
632 return error;
633 }
634
Process(Arg aArgs[])635 template <> otError Br::Process<Cmd("routeprf")>(Arg aArgs[])
636 {
637 otError error = OT_ERROR_NONE;
638
639 /**
640 * @cli br routeprf
641 * @code
642 * br routeprf
643 * med
644 * Done
645 * @endcode
646 * @par api_copy
647 * #otBorderRoutingGetRoutePreference
648 */
649 if (aArgs[0].IsEmpty())
650 {
651 OutputLine("%s", Interpreter::PreferenceToString(otBorderRoutingGetRoutePreference(GetInstancePtr())));
652 }
653 /**
654 * @cli br routeprf clear
655 * @code
656 * br routeprf clear
657 * Done
658 * @endcode
659 * @par api_copy
660 * #otBorderRoutingClearRoutePreference
661 */
662 else if (aArgs[0] == "clear")
663 {
664 otBorderRoutingClearRoutePreference(GetInstancePtr());
665 }
666 /**
667 * @cli br routeprf (high,med,low)
668 * @code
669 * br routeprf low
670 * Done
671 * @endcode
672 * @cparam br routeprf [@ca{high}|@ca{med}|@ca{low}]
673 * @par api_copy
674 * #otBorderRoutingSetRoutePreference
675 */
676 else
677 {
678 otRoutePreference preference;
679
680 SuccessOrExit(error = Interpreter::ParsePreference(aArgs[0], preference));
681 otBorderRoutingSetRoutePreference(GetInstancePtr(), preference);
682 }
683
684 exit:
685 return error;
686 }
687
688 #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
689
690 /**
691 * @cli br counters
692 * @code
693 * br counters
694 * Inbound Unicast: Packets 4 Bytes 320
695 * Inbound Multicast: Packets 0 Bytes 0
696 * Outbound Unicast: Packets 2 Bytes 160
697 * Outbound Multicast: Packets 0 Bytes 0
698 * RA Rx: 4
699 * RA TxSuccess: 2
700 * RA TxFailed: 0
701 * RS Rx: 0
702 * RS TxSuccess: 2
703 * RS TxFailed: 0
704 * Done
705 * @endcode
706 * @par api_copy
707 * #otIp6GetBorderRoutingCounters
708 */
Process(Arg aArgs[])709 template <> otError Br::Process<Cmd("counters")>(Arg aArgs[])
710 {
711 otError error = OT_ERROR_NONE;
712
713 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
714 Interpreter::GetInterpreter().OutputBorderRouterCounters();
715
716 exit:
717 return error;
718 }
719
720 #endif // OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
721
Process(Arg aArgs[])722 otError Br::Process(Arg aArgs[])
723 {
724 #define CmdEntry(aCommandString) \
725 { \
726 aCommandString, &Br::Process<Cmd(aCommandString)> \
727 }
728
729 static constexpr Command kCommands[] = {
730 #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
731 CmdEntry("counters"),
732 #endif
733 CmdEntry("disable"),
734 CmdEntry("enable"),
735 CmdEntry("init"),
736 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
737 CmdEntry("nat64prefix"),
738 #endif
739 CmdEntry("omrprefix"),
740 CmdEntry("onlinkprefix"),
741 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
742 CmdEntry("pd"),
743 #endif
744 CmdEntry("prefixtable"),
745 CmdEntry("raoptions"),
746 CmdEntry("rioprf"),
747 CmdEntry("routeprf"),
748 CmdEntry("routers"),
749 CmdEntry("state"),
750 };
751
752 #undef CmdEntry
753
754 static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
755
756 otError error = OT_ERROR_INVALID_COMMAND;
757 const Command *command;
758
759 if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
760 {
761 OutputCommandTable(kCommands);
762 ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE);
763 }
764
765 command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
766 VerifyOrExit(command != nullptr);
767
768 error = (this->*command->mHandler)(aArgs + 1);
769
770 exit:
771 return error;
772 }
773
774 } // namespace Cli
775 } // namespace ot
776
777 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
778