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", 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", 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, ", PreferenceToString(entry.mRoutePreference));
428 }
429
430 OutputFormat("router:");
431 OutputRouterInfo(entry.mRouter, kShortVersion);
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 /**
489 * @cli br pd omrprefix
490 * @code
491 * br pd omrprefix
492 * 2001:db8:cafe:0:0/64 lifetime:1800 preferred:1800
493 * Done
494 * @endcode
495 * @par api_copy
496 * #otBorderRoutingGetPdOmrPrefix
497 */
498 else if (aArgs[0] == "omrprefix")
499 {
500 otBorderRoutingPrefixTableEntry entry;
501
502 SuccessOrExit(error = otBorderRoutingGetPdOmrPrefix(GetInstancePtr(), &entry));
503
504 OutputIp6Prefix(entry.mPrefix);
505 OutputLine(" lifetime:%lu preferred:%lu", ToUlong(entry.mValidLifetime), ToUlong(entry.mPreferredLifetime));
506 }
507 else
508 {
509 ExitNow(error = OT_ERROR_INVALID_COMMAND);
510 }
511
512 exit:
513 return error;
514 }
515 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
516
517 /**
518 * @cli br routers
519 * @code
520 * br routers
521 * ff02:0:0:0:0:0:0:1 (M:0 O:0 Stub:1) ms-since-rx:1505
522 * Done
523 * @endcode
524 * @par
525 * Get the list of discovered routers by Border Routing Manager on the infrastructure link.
526 * Info per router:
527 * - The router IPv6 address
528 * - Flags in received Router Advertisement header:
529 * - M: Managed Address Config flag
530 * - O: Other Config flag
531 * - Stub: Stub Router flag (indicates whether the router is a stub router)
532 * - Milliseconds since last received message from this router
533 * @sa otBorderRoutingGetNextRouterEntry
534 */
Process(Arg aArgs[])535 template <> otError Br::Process<Cmd("routers")>(Arg aArgs[])
536 {
537 otError error = OT_ERROR_NONE;
538 otBorderRoutingPrefixTableIterator iterator;
539 otBorderRoutingRouterEntry entry;
540
541 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
542
543 otBorderRoutingPrefixTableInitIterator(GetInstancePtr(), &iterator);
544
545 while (otBorderRoutingGetNextRouterEntry(GetInstancePtr(), &iterator, &entry) == OT_ERROR_NONE)
546 {
547 OutputRouterInfo(entry, kLongVersion);
548 }
549
550 exit:
551 return error;
552 }
553
OutputRouterInfo(const otBorderRoutingRouterEntry & aEntry,RouterOutputMode aMode)554 void Br::OutputRouterInfo(const otBorderRoutingRouterEntry &aEntry, RouterOutputMode aMode)
555 {
556 OutputIp6Address(aEntry.mAddress);
557 OutputFormat(" (M:%u O:%u Stub:%u)", aEntry.mManagedAddressConfigFlag, aEntry.mOtherConfigFlag,
558 aEntry.mStubRouterFlag);
559
560 if (aMode == kLongVersion)
561 {
562 OutputFormat(" ms-since-rx:%lu", ToUlong(aEntry.mMsecSinceLastUpdate));
563
564 if (aEntry.mIsLocalDevice)
565 {
566 OutputFormat(" (this BR)");
567 }
568 }
569
570 OutputNewLine();
571 }
572
Process(Arg aArgs[])573 template <> otError Br::Process<Cmd("raoptions")>(Arg aArgs[])
574 {
575 static constexpr uint16_t kMaxExtraOptions = 800;
576
577 otError error = OT_ERROR_NONE;
578 uint8_t options[kMaxExtraOptions];
579 uint16_t length;
580
581 /**
582 * @cli br raoptions (set,clear)
583 * @code
584 * br raoptions 0400ff00020001
585 * Done
586 * @endcode
587 * @code
588 * br raoptions clear
589 * Done
590 * @endcode
591 * @cparam br raoptions @ca{options|clear}
592 * `br raoptions clear` passes a `nullptr` to #otBorderRoutingSetExtraRouterAdvertOptions.
593 * Otherwise, you can pass the `options` byte as hex data.
594 * @par api_copy
595 * #otBorderRoutingSetExtraRouterAdvertOptions
596 */
597 if (aArgs[0] == "clear")
598 {
599 length = 0;
600 }
601 else
602 {
603 length = sizeof(options);
604 SuccessOrExit(error = aArgs[0].ParseAsHexString(length, options));
605 }
606
607 error = otBorderRoutingSetExtraRouterAdvertOptions(GetInstancePtr(), length > 0 ? options : nullptr, length);
608
609 exit:
610 return error;
611 }
612
Process(Arg aArgs[])613 template <> otError Br::Process<Cmd("rioprf")>(Arg aArgs[])
614 {
615 otError error = OT_ERROR_NONE;
616
617 /**
618 * @cli br rioprf
619 * @code
620 * br rioprf
621 * med
622 * Done
623 * @endcode
624 * @par api_copy
625 * #otBorderRoutingGetRouteInfoOptionPreference
626 */
627 if (aArgs[0].IsEmpty())
628 {
629 OutputLine("%s", PreferenceToString(otBorderRoutingGetRouteInfoOptionPreference(GetInstancePtr())));
630 }
631 /**
632 * @cli br rioprf clear
633 * @code
634 * br rioprf clear
635 * Done
636 * @endcode
637 * @par api_copy
638 * #otBorderRoutingClearRouteInfoOptionPreference
639 */
640 else if (aArgs[0] == "clear")
641 {
642 otBorderRoutingClearRouteInfoOptionPreference(GetInstancePtr());
643 }
644 /**
645 * @cli br rioprf (high,med,low)
646 * @code
647 * br rioprf low
648 * Done
649 * @endcode
650 * @cparam br rioprf [@ca{high}|@ca{med}|@ca{low}]
651 * @par api_copy
652 * #otBorderRoutingSetRouteInfoOptionPreference
653 */
654 else
655 {
656 otRoutePreference preference;
657
658 SuccessOrExit(error = Interpreter::ParsePreference(aArgs[0], preference));
659 otBorderRoutingSetRouteInfoOptionPreference(GetInstancePtr(), preference);
660 }
661
662 exit:
663 return error;
664 }
665
Process(Arg aArgs[])666 template <> otError Br::Process<Cmd("routeprf")>(Arg aArgs[])
667 {
668 otError error = OT_ERROR_NONE;
669
670 /**
671 * @cli br routeprf
672 * @code
673 * br routeprf
674 * med
675 * Done
676 * @endcode
677 * @par api_copy
678 * #otBorderRoutingGetRoutePreference
679 */
680 if (aArgs[0].IsEmpty())
681 {
682 OutputLine("%s", PreferenceToString(otBorderRoutingGetRoutePreference(GetInstancePtr())));
683 }
684 /**
685 * @cli br routeprf clear
686 * @code
687 * br routeprf clear
688 * Done
689 * @endcode
690 * @par api_copy
691 * #otBorderRoutingClearRoutePreference
692 */
693 else if (aArgs[0] == "clear")
694 {
695 otBorderRoutingClearRoutePreference(GetInstancePtr());
696 }
697 /**
698 * @cli br routeprf (high,med,low)
699 * @code
700 * br routeprf low
701 * Done
702 * @endcode
703 * @cparam br routeprf [@ca{high}|@ca{med}|@ca{low}]
704 * @par api_copy
705 * #otBorderRoutingSetRoutePreference
706 */
707 else
708 {
709 otRoutePreference preference;
710
711 SuccessOrExit(error = Interpreter::ParsePreference(aArgs[0], preference));
712 otBorderRoutingSetRoutePreference(GetInstancePtr(), preference);
713 }
714
715 exit:
716 return error;
717 }
718
719 #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
720
721 /**
722 * @cli br counters
723 * @code
724 * br counters
725 * Inbound Unicast: Packets 4 Bytes 320
726 * Inbound Multicast: Packets 0 Bytes 0
727 * Outbound Unicast: Packets 2 Bytes 160
728 * Outbound Multicast: Packets 0 Bytes 0
729 * RA Rx: 4
730 * RA TxSuccess: 2
731 * RA TxFailed: 0
732 * RS Rx: 0
733 * RS TxSuccess: 2
734 * RS TxFailed: 0
735 * Done
736 * @endcode
737 * @par api_copy
738 * #otIp6GetBorderRoutingCounters
739 */
Process(Arg aArgs[])740 template <> otError Br::Process<Cmd("counters")>(Arg aArgs[])
741 {
742 otError error = OT_ERROR_NONE;
743
744 VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
745 Interpreter::GetInterpreter().OutputBorderRouterCounters();
746
747 exit:
748 return error;
749 }
750
751 #endif // OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
752
Process(Arg aArgs[])753 otError Br::Process(Arg aArgs[])
754 {
755 #define CmdEntry(aCommandString) \
756 { \
757 aCommandString, &Br::Process<Cmd(aCommandString)> \
758 }
759
760 static constexpr Command kCommands[] = {
761 #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
762 CmdEntry("counters"),
763 #endif
764 CmdEntry("disable"),
765 CmdEntry("enable"),
766 CmdEntry("init"),
767 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
768 CmdEntry("nat64prefix"),
769 #endif
770 CmdEntry("omrprefix"),
771 CmdEntry("onlinkprefix"),
772 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
773 CmdEntry("pd"),
774 #endif
775 CmdEntry("prefixtable"),
776 CmdEntry("raoptions"),
777 CmdEntry("rioprf"),
778 CmdEntry("routeprf"),
779 CmdEntry("routers"),
780 CmdEntry("state"),
781 };
782
783 #undef CmdEntry
784
785 static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
786
787 otError error = OT_ERROR_INVALID_COMMAND;
788 const Command *command;
789
790 if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
791 {
792 OutputCommandTable(kCommands);
793 ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE);
794 }
795
796 command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
797 VerifyOrExit(command != nullptr);
798
799 error = (this->*command->mHandler)(aArgs + 1);
800
801 exit:
802 return error;
803 }
804
805 } // namespace Cli
806 } // namespace ot
807
808 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
809