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 Backbone Router.
32 */
33
34 #include "cli_bbr.hpp"
35
36 #include "cli/cli.hpp"
37
38 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
39
40 namespace ot {
41 namespace Cli {
42
OutputConfig(const otBackboneRouterConfig & aConfig)43 void Bbr::OutputConfig(const otBackboneRouterConfig &aConfig)
44 {
45 OutputLine("seqno: %u", aConfig.mSequenceNumber);
46 OutputLine("delay: %u secs", aConfig.mReregistrationDelay);
47 OutputLine("timeout: %lu secs", ToUlong(aConfig.mMlrTimeout));
48 }
49
50 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
51
52 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
53
Process(Arg aArgs[])54 template <> otError Bbr::Process<Cmd("mlr")>(Arg aArgs[])
55 {
56 otError error = OT_ERROR_INVALID_COMMAND;
57
58 /**
59 * @cli bbr mgmt mlr listener
60 * @code
61 * bbr mgmt mlr listener
62 * ff04:0:0:0:0:0:0:abcd 3534000
63 * ff04:0:0:0:0:0:0:eeee 3537610
64 * Done
65 * @endcode
66 * @par
67 * Returns the Multicast Listeners with the #otBackboneRouterMulticastListenerInfo
68 * `mTimeout` in seconds.
69 * @par
70 * Available when `OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE` and
71 * `OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE` are enabled.
72 * @sa otBackboneRouterMulticastListenerGetNext
73 */
74 if (aArgs[0] == "listener")
75 {
76 if (aArgs[1].IsEmpty())
77 {
78 otBackboneRouterMulticastListenerIterator iter = OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ITERATOR_INIT;
79 otBackboneRouterMulticastListenerInfo listenerInfo;
80
81 while (otBackboneRouterMulticastListenerGetNext(GetInstancePtr(), &iter, &listenerInfo) == OT_ERROR_NONE)
82 {
83 OutputIp6Address(listenerInfo.mAddress);
84 OutputLine(" %lu", ToUlong(listenerInfo.mTimeout));
85 }
86
87 ExitNow(error = OT_ERROR_NONE);
88 }
89
90 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
91 /**
92 * @cli bbr mgmt mlr listener clear
93 * @code
94 * bbr mgmt mlr listener clear
95 * Done
96 * @endcode
97 * @par api_copy
98 * #otBackboneRouterMulticastListenerClear
99 */
100 if (aArgs[1] == "clear")
101 {
102 otBackboneRouterMulticastListenerClear(GetInstancePtr());
103 error = OT_ERROR_NONE;
104 }
105 /**
106 * @cli bbr mgmt mlr listener add
107 * @code
108 * bbr mgmt mlr listener add ff04::1
109 * Done
110 * @endcode
111 * @code
112 * bbr mgmt mlr listener add ff04::2 300
113 * Done
114 * @endcode
115 * @cparam bbr mgmt mlr listener add @ca{ipaddress} [@ca{timeout-seconds}]
116 * @par api_copy
117 * #otBackboneRouterMulticastListenerAdd
118 */
119 else if (aArgs[1] == "add")
120 {
121 otIp6Address address;
122 uint32_t timeout = 0;
123
124 SuccessOrExit(error = aArgs[2].ParseAsIp6Address(address));
125
126 if (!aArgs[3].IsEmpty())
127 {
128 SuccessOrExit(error = aArgs[3].ParseAsUint32(timeout));
129 }
130
131 error = otBackboneRouterMulticastListenerAdd(GetInstancePtr(), &address, timeout);
132 }
133 }
134 /**
135 * @cli bbr mgmt mlr response
136 * @code
137 * bbr mgmt mlr response 2
138 * Done
139 * @endcode
140 * @cparam bbr mgmt mlr response @ca{status-code}
141 * For `status-code`, use:
142 * * 0: ST_MLR_SUCCESS
143 * * 2: ST_MLR_INVALID
144 * * 3: ST_MLR_NO_PERSISTENT
145 * * 4: ST_MLR_NO_RESOURCES
146 * * 5: ST_MLR_BBR_NOT_PRIMARY
147 * * 6: ST_MLR_GENERAL_FAILURE
148 * @par api_copy
149 * #otBackboneRouterConfigNextMulticastListenerRegistrationResponse
150 */
151 else if (aArgs[0] == "response")
152 {
153 uint8_t status;
154
155 SuccessOrExit(error = aArgs[1].ParseAsUint8(status));
156 otBackboneRouterConfigNextMulticastListenerRegistrationResponse(GetInstancePtr(), status);
157 error = OT_ERROR_NONE;
158
159 #endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
160 }
161
162 exit:
163 return error;
164 }
165
166 #endif // #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
167
Process(Arg aArgs[])168 template <> otError Bbr::Process<Cmd("mgmt")>(Arg aArgs[])
169 {
170 otError error = OT_ERROR_INVALID_COMMAND;
171
172 if (aArgs[0].IsEmpty())
173 {
174 ExitNow(error = OT_ERROR_INVALID_COMMAND);
175 }
176
177 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
178 /**
179 * @cli bbr mgmt dua
180 * @code
181 * bbr mgmt dua 1 2f7c235e5025a2fd
182 * Done
183 * @endcode
184 * @code
185 * bbr mgmt dua 160
186 * Done
187 * @endcode
188 * @cparam bbr mgmt dua @ca{status|coap-code} [@ca{meshLocalIid}]
189 * For `status` or `coap-code`, use:
190 * * 0: ST_DUA_SUCCESS
191 * * 1: ST_DUA_REREGISTER
192 * * 2: ST_DUA_INVALID
193 * * 3: ST_DUA_DUPLICATE
194 * * 4: ST_DUA_NO_RESOURCES
195 * * 5: ST_DUA_BBR_NOT_PRIMARY
196 * * 6: ST_DUA_GENERAL_FAILURE
197 * * 160: COAP code 5.00
198 * @par
199 * With the `meshLocalIid` included, this command configures the response status
200 * for the next DUA registration. Without `meshLocalIid`, respond to the next
201 * DUA.req with the specified `status` or `coap-code`.
202 * @par
203 * Available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
204 * @sa otBackboneRouterConfigNextDuaRegistrationResponse
205 */
206 if (aArgs[0] == "dua")
207 {
208 uint8_t status;
209 otIp6InterfaceIdentifier *mlIid = nullptr;
210 otIp6InterfaceIdentifier iid;
211
212 SuccessOrExit(error = aArgs[1].ParseAsUint8(status));
213
214 if (!aArgs[2].IsEmpty())
215 {
216 SuccessOrExit(error = aArgs[2].ParseAsHexString(iid.mFields.m8));
217 mlIid = &iid;
218 VerifyOrExit(aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
219 }
220
221 otBackboneRouterConfigNextDuaRegistrationResponse(GetInstancePtr(), mlIid, status);
222 ExitNow();
223 }
224 #endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
225
226 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
227 if (aArgs[0] == "mlr")
228 {
229 error = Process<Cmd("mlr")>(aArgs + 1);
230 ExitNow();
231 }
232 #endif
233
234 exit:
235 return error;
236 }
237
238 /**
239 * @cli bbr enable
240 * @code
241 * bbr enable
242 * Done
243 * @endcode
244 * @par api_copy
245 * #otBackboneRouterSetEnabled
246 */
Process(Arg aArgs[])247 template <> otError Bbr::Process<Cmd("enable")>(Arg aArgs[])
248 {
249 OT_UNUSED_VARIABLE(aArgs);
250 otBackboneRouterSetEnabled(GetInstancePtr(), true);
251
252 return OT_ERROR_NONE;
253 }
254
255 /**
256 * @cli bbr disable
257 * @code
258 * bbr disable
259 * Done
260 * @endcode
261 * @par api_copy
262 * #otBackboneRouterSetEnabled
263 */
Process(Arg aArgs[])264 template <> otError Bbr::Process<Cmd("disable")>(Arg aArgs[])
265 {
266 OT_UNUSED_VARIABLE(aArgs);
267 otBackboneRouterSetEnabled(GetInstancePtr(), false);
268
269 return OT_ERROR_NONE;
270 }
271
272 /**
273 * @cli bbr jitter (get,set)
274 * @code
275 * bbr jitter
276 * 20
277 * Done
278 * @endcode
279 * @code
280 * bbr jitter 10
281 * Done
282 * @endcode
283 * @cparam bbr jitter [@ca{jitter}]
284 * @par
285 * Gets or sets jitter (in seconds) for Backbone Router registration.
286 * @par
287 * Available when `OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE` is enabled.
288 * @sa otBackboneRouterGetRegistrationJitter
289 * @sa otBackboneRouterSetRegistrationJitter
290 */
Process(Arg aArgs[])291 template <> otError Bbr::Process<Cmd("jitter")>(Arg aArgs[])
292 {
293 return ProcessGetSet(aArgs, otBackboneRouterGetRegistrationJitter, otBackboneRouterSetRegistrationJitter);
294 }
295
296 /**
297 * @cli bbr register
298 * @code
299 * bbr register
300 * Done
301 * @endcode
302 * @par api_copy
303 * #otBackboneRouterRegister
304 */
Process(Arg aArgs[])305 template <> otError Bbr::Process<Cmd("register")>(Arg aArgs[])
306 {
307 OT_UNUSED_VARIABLE(aArgs);
308
309 return otBackboneRouterRegister(GetInstancePtr());
310 }
311
312 /**
313 * @cli bbr state
314 * @code
315 * bbr state
316 * Disabled
317 * Done
318 * @endcode
319 * @code
320 * bbr state
321 * Primary
322 * Done
323 * @endcode
324 * @code
325 * bbr state
326 * Secondary
327 * Done
328 * @endcode
329 * @par
330 * Available when `OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE` is enabled.
331 * @par api_copy
332 * #otBackboneRouterGetState
333 */
Process(Arg aArgs[])334 template <> otError Bbr::Process<Cmd("state")>(Arg aArgs[])
335
336 {
337 static const char *const kStateStrings[] = {
338 "Disabled", // (0) OT_BACKBONE_ROUTER_STATE_DISABLED
339 "Secondary", // (1) OT_BACKBONE_ROUTER_STATE_SECONDARY
340 "Primary", // (2) OT_BACKBONE_ROUTER_STATE_PRIMARY
341 };
342
343 static_assert(0 == OT_BACKBONE_ROUTER_STATE_DISABLED, "OT_BACKBONE_ROUTER_STATE_DISABLED value is incorrect");
344 static_assert(1 == OT_BACKBONE_ROUTER_STATE_SECONDARY, "OT_BACKBONE_ROUTER_STATE_SECONDARY value is incorrect");
345 static_assert(2 == OT_BACKBONE_ROUTER_STATE_PRIMARY, "OT_BACKBONE_ROUTER_STATE_PRIMARY value is incorrect");
346
347 OT_UNUSED_VARIABLE(aArgs);
348
349 OutputLine("%s", Stringify(otBackboneRouterGetState(GetInstancePtr()), kStateStrings));
350
351 return OT_ERROR_NONE;
352 }
353
354 /**
355 * @cli bbr config
356 * @code
357 * bbr config
358 * seqno: 10
359 * delay: 120 secs
360 * timeout: 300 secs
361 * Done
362 * @endcode
363 * @par api_copy
364 * #otBackboneRouterGetConfig
365 */
Process(Arg aArgs[])366 template <> otError Bbr::Process<Cmd("config")>(Arg aArgs[])
367 {
368 otError error = OT_ERROR_NONE;
369 otBackboneRouterConfig config;
370
371 otBackboneRouterGetConfig(GetInstancePtr(), &config);
372
373 if (aArgs[0].IsEmpty())
374 {
375 OutputConfig(config);
376 }
377 else
378 {
379 // Set local Backbone Router configuration.
380 /**
381 * @cli bbr config (set)
382 * @code
383 * bbr config seqno 20 delay 30
384 * Done
385 * @endcode
386 * @cparam bbr config [seqno @ca{seqno}] [delay @ca{delay}] [timeout @ca{timeout}]
387 * @par
388 * `bbr register` should be issued explicitly to register Backbone Router service to Leader
389 * for Secondary Backbone Router.
390 * @par api_copy
391 * #otBackboneRouterSetConfig
392 */
393 for (Arg *arg = &aArgs[0]; !arg->IsEmpty(); arg++)
394 {
395 if (*arg == "seqno")
396 {
397 arg++;
398 SuccessOrExit(error = arg->ParseAsUint8(config.mSequenceNumber));
399 }
400 else if (*arg == "delay")
401 {
402 arg++;
403 SuccessOrExit(error = arg->ParseAsUint16(config.mReregistrationDelay));
404 }
405 else if (*arg == "timeout")
406 {
407 arg++;
408 SuccessOrExit(error = arg->ParseAsUint32(config.mMlrTimeout));
409 }
410 else
411 {
412 ExitNow(error = OT_ERROR_INVALID_ARGS);
413 }
414 }
415
416 error = otBackboneRouterSetConfig(GetInstancePtr(), &config);
417 }
418
419 exit:
420 return error;
421 }
422
423 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
424
Process(Arg aArgs[])425 otError Bbr::Process(Arg aArgs[])
426 {
427 #define CmdEntry(aCommandString) {aCommandString, &Bbr::Process<Cmd(aCommandString)>}
428
429 otError error = OT_ERROR_INVALID_COMMAND;
430
431 /**
432 * @cli bbr
433 * @code
434 * bbr
435 * BBR Primary:
436 * server16: 0xE400
437 * seqno: 10
438 * delay: 120 secs
439 * timeout: 300 secs
440 * Done
441 * @endcode
442 * @code
443 * bbr
444 * BBR Primary: None
445 * Done
446 * @endcode
447 * @par
448 * Returns the current Primary Backbone Router information for the Thread device.
449 */
450 if (aArgs[0].IsEmpty())
451 {
452 otBackboneRouterConfig config;
453
454 OutputFormat("BBR Primary:");
455
456 if (otBackboneRouterGetPrimary(GetInstancePtr(), &config) == OT_ERROR_NONE)
457 {
458 OutputNewLine();
459 OutputLine("server16: 0x%04X", config.mServer16);
460 OutputConfig(config);
461 }
462 else
463 {
464 OutputLine(" None");
465 }
466
467 error = OT_ERROR_NONE;
468 ExitNow();
469 }
470
471 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
472 {
473 static constexpr Command kCommands[] = {
474 CmdEntry("config"), CmdEntry("disable"), CmdEntry("enable"), CmdEntry("jitter"),
475 CmdEntry("mgmt"), CmdEntry("register"), CmdEntry("state"),
476 };
477
478 #undef CmdEntry
479
480 static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
481
482 const Command *command;
483
484 command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
485 VerifyOrExit(command != nullptr);
486
487 error = (this->*command->mHandler)(aArgs + 1);
488 }
489 #endif // #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
490
491 exit:
492 return error;
493 }
494
495 } // namespace Cli
496 } // namespace ot
497
498 #endif // #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
499