/src/openthread/src/cli/cli_bbr.cpp
Line | Count | Source |
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 | | |
43 | | void Bbr::OutputConfig(const otBackboneRouterConfig &aConfig) |
44 | 1 | { |
45 | 1 | OutputLine("seqno: %u", aConfig.mSequenceNumber); |
46 | 1 | OutputLine("delay: %u secs", aConfig.mReregistrationDelay); |
47 | 1 | OutputLine("timeout: %lu secs", ToUlong(aConfig.mMlrTimeout)); |
48 | 1 | } |
49 | | |
50 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE |
51 | | |
52 | | #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE |
53 | | |
54 | | template <> otError Bbr::Process<Cmd("mlr")>(Arg aArgs[]) |
55 | 0 | { |
56 | 0 | 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 | 0 | if (aArgs[0] == "listener") |
75 | 0 | { |
76 | 0 | if (aArgs[1].IsEmpty()) |
77 | 0 | { |
78 | 0 | otBackboneRouterMulticastListenerIterator iter = OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ITERATOR_INIT; |
79 | 0 | otBackboneRouterMulticastListenerInfo listenerInfo; |
80 | |
|
81 | 0 | while (otBackboneRouterMulticastListenerGetNext(GetInstancePtr(), &iter, &listenerInfo) == OT_ERROR_NONE) |
82 | 0 | { |
83 | 0 | OutputIp6Address(listenerInfo.mAddress); |
84 | 0 | OutputLine(" %lu", ToUlong(listenerInfo.mTimeout)); |
85 | 0 | } |
86 | |
|
87 | 0 | ExitNow(error = OT_ERROR_NONE); |
88 | 0 | } |
89 | | |
90 | 0 | #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 | 0 | if (aArgs[1] == "clear") |
101 | 0 | { |
102 | 0 | otBackboneRouterMulticastListenerClear(GetInstancePtr()); |
103 | 0 | error = OT_ERROR_NONE; |
104 | 0 | } |
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 | 0 | else if (aArgs[1] == "add") |
120 | 0 | { |
121 | 0 | otIp6Address address; |
122 | 0 | uint32_t timeout = 0; |
123 | |
|
124 | 0 | SuccessOrExit(error = aArgs[2].ParseAsIp6Address(address)); |
125 | | |
126 | 0 | if (!aArgs[3].IsEmpty()) |
127 | 0 | { |
128 | 0 | SuccessOrExit(error = aArgs[3].ParseAsUint32(timeout)); |
129 | 0 | } |
130 | | |
131 | 0 | error = otBackboneRouterMulticastListenerAdd(GetInstancePtr(), &address, timeout); |
132 | 0 | } |
133 | 0 | } |
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 | 0 | else if (aArgs[0] == "response") |
152 | 0 | { |
153 | 0 | uint8_t status; |
154 | |
|
155 | 0 | SuccessOrExit(error = aArgs[1].ParseAsUint8(status)); |
156 | 0 | otBackboneRouterConfigNextMulticastListenerRegistrationResponse(GetInstancePtr(), status); |
157 | 0 | error = OT_ERROR_NONE; |
158 | |
|
159 | 0 | #endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
160 | 0 | } |
161 | | |
162 | 0 | exit: |
163 | 0 | return error; |
164 | 0 | } |
165 | | |
166 | | #endif // #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE |
167 | | |
168 | | template <> otError Bbr::Process<Cmd("mgmt")>(Arg aArgs[]) |
169 | 2 | { |
170 | 2 | otError error = OT_ERROR_INVALID_COMMAND; |
171 | | |
172 | 2 | if (aArgs[0].IsEmpty()) |
173 | 1 | { |
174 | 1 | ExitNow(error = OT_ERROR_INVALID_COMMAND); |
175 | 1 | } |
176 | | |
177 | 1 | #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 | 1 | if (aArgs[0] == "dua") |
207 | 0 | { |
208 | 0 | uint8_t status; |
209 | 0 | otIp6InterfaceIdentifier *mlIid = nullptr; |
210 | 0 | otIp6InterfaceIdentifier iid; |
211 | |
|
212 | 0 | SuccessOrExit(error = aArgs[1].ParseAsUint8(status)); |
213 | | |
214 | 0 | if (!aArgs[2].IsEmpty()) |
215 | 0 | { |
216 | 0 | SuccessOrExit(error = aArgs[2].ParseAsHexString(iid.mFields.m8)); |
217 | 0 | mlIid = &iid; |
218 | 0 | VerifyOrExit(aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
219 | 0 | } |
220 | | |
221 | 0 | otBackboneRouterConfigNextDuaRegistrationResponse(GetInstancePtr(), mlIid, status); |
222 | 0 | ExitNow(); |
223 | 0 | } |
224 | 1 | #endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
225 | | |
226 | 1 | #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE |
227 | 1 | if (aArgs[0] == "mlr") |
228 | 0 | { |
229 | 0 | error = Process<Cmd("mlr")>(aArgs + 1); |
230 | 0 | ExitNow(); |
231 | 0 | } |
232 | 1 | #endif |
233 | | |
234 | 2 | exit: |
235 | 2 | return error; |
236 | 1 | } |
237 | | |
238 | | /** |
239 | | * @cli bbr enable |
240 | | * @code |
241 | | * bbr enable |
242 | | * Done |
243 | | * @endcode |
244 | | * @par api_copy |
245 | | * #otBackboneRouterSetEnabled |
246 | | */ |
247 | | template <> otError Bbr::Process<Cmd("enable")>(Arg aArgs[]) |
248 | 17 | { |
249 | 17 | OT_UNUSED_VARIABLE(aArgs); |
250 | 17 | otBackboneRouterSetEnabled(GetInstancePtr(), true); |
251 | | |
252 | 17 | return OT_ERROR_NONE; |
253 | 17 | } |
254 | | |
255 | | /** |
256 | | * @cli bbr disable |
257 | | * @code |
258 | | * bbr disable |
259 | | * Done |
260 | | * @endcode |
261 | | * @par api_copy |
262 | | * #otBackboneRouterSetEnabled |
263 | | */ |
264 | | template <> otError Bbr::Process<Cmd("disable")>(Arg aArgs[]) |
265 | 1 | { |
266 | 1 | OT_UNUSED_VARIABLE(aArgs); |
267 | 1 | otBackboneRouterSetEnabled(GetInstancePtr(), false); |
268 | | |
269 | 1 | return OT_ERROR_NONE; |
270 | 1 | } |
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 | | */ |
291 | | template <> otError Bbr::Process<Cmd("jitter")>(Arg aArgs[]) |
292 | 4 | { |
293 | 4 | return ProcessGetSet(aArgs, otBackboneRouterGetRegistrationJitter, otBackboneRouterSetRegistrationJitter); |
294 | 4 | } |
295 | | |
296 | | /** |
297 | | * @cli bbr register |
298 | | * @code |
299 | | * bbr register |
300 | | * Done |
301 | | * @endcode |
302 | | * @par api_copy |
303 | | * #otBackboneRouterRegister |
304 | | */ |
305 | | template <> otError Bbr::Process<Cmd("register")>(Arg aArgs[]) |
306 | 0 | { |
307 | 0 | OT_UNUSED_VARIABLE(aArgs); |
308 | |
|
309 | 0 | return otBackboneRouterRegister(GetInstancePtr()); |
310 | 0 | } |
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 | | */ |
334 | | template <> otError Bbr::Process<Cmd("state")>(Arg aArgs[]) |
335 | | |
336 | 1 | { |
337 | 1 | static const char *const kStateStrings[] = { |
338 | 1 | "Disabled", // (0) OT_BACKBONE_ROUTER_STATE_DISABLED |
339 | 1 | "Secondary", // (1) OT_BACKBONE_ROUTER_STATE_SECONDARY |
340 | 1 | "Primary", // (2) OT_BACKBONE_ROUTER_STATE_PRIMARY |
341 | 1 | }; |
342 | | |
343 | 1 | static_assert(0 == OT_BACKBONE_ROUTER_STATE_DISABLED, "OT_BACKBONE_ROUTER_STATE_DISABLED value is incorrect"); |
344 | 1 | static_assert(1 == OT_BACKBONE_ROUTER_STATE_SECONDARY, "OT_BACKBONE_ROUTER_STATE_SECONDARY value is incorrect"); |
345 | 1 | static_assert(2 == OT_BACKBONE_ROUTER_STATE_PRIMARY, "OT_BACKBONE_ROUTER_STATE_PRIMARY value is incorrect"); |
346 | | |
347 | 1 | OT_UNUSED_VARIABLE(aArgs); |
348 | | |
349 | 1 | OutputLine("%s", Stringify(otBackboneRouterGetState(GetInstancePtr()), kStateStrings)); |
350 | | |
351 | 1 | return OT_ERROR_NONE; |
352 | 1 | } |
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 | | */ |
366 | | template <> otError Bbr::Process<Cmd("config")>(Arg aArgs[]) |
367 | 2 | { |
368 | 2 | otError error = OT_ERROR_NONE; |
369 | 2 | otBackboneRouterConfig config; |
370 | | |
371 | 2 | otBackboneRouterGetConfig(GetInstancePtr(), &config); |
372 | | |
373 | 2 | if (aArgs[0].IsEmpty()) |
374 | 1 | { |
375 | 1 | OutputConfig(config); |
376 | 1 | } |
377 | 1 | else |
378 | 1 | { |
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 | 1 | for (Arg *arg = &aArgs[0]; !arg->IsEmpty(); arg++) |
394 | 1 | { |
395 | 1 | if (*arg == "seqno") |
396 | 0 | { |
397 | 0 | arg++; |
398 | 0 | SuccessOrExit(error = arg->ParseAsUint8(config.mSequenceNumber)); |
399 | 0 | } |
400 | 1 | else if (*arg == "delay") |
401 | 0 | { |
402 | 0 | arg++; |
403 | 0 | SuccessOrExit(error = arg->ParseAsUint16(config.mReregistrationDelay)); |
404 | 0 | } |
405 | 1 | else if (*arg == "timeout") |
406 | 0 | { |
407 | 0 | arg++; |
408 | 0 | SuccessOrExit(error = arg->ParseAsUint32(config.mMlrTimeout)); |
409 | 0 | } |
410 | 1 | else |
411 | 1 | { |
412 | 1 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
413 | 1 | } |
414 | 1 | } |
415 | | |
416 | 0 | error = otBackboneRouterSetConfig(GetInstancePtr(), &config); |
417 | 0 | } |
418 | | |
419 | 2 | exit: |
420 | 2 | return error; |
421 | 2 | } |
422 | | |
423 | | #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE |
424 | | |
425 | | otError Bbr::Process(Arg aArgs[]) |
426 | 29 | { |
427 | 196 | #define CmdEntry(aCommandString) {aCommandString, &Bbr::Process<Cmd(aCommandString)>} |
428 | | |
429 | 29 | 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 | 29 | if (aArgs[0].IsEmpty()) |
451 | 1 | { |
452 | 1 | otBackboneRouterConfig config; |
453 | | |
454 | 1 | OutputFormat("BBR Primary:"); |
455 | | |
456 | 1 | if (otBackboneRouterGetPrimary(GetInstancePtr(), &config) == OT_ERROR_NONE) |
457 | 0 | { |
458 | 0 | OutputNewLine(); |
459 | 0 | OutputLine("server16: 0x%04X", config.mServer16); |
460 | 0 | OutputConfig(config); |
461 | 0 | } |
462 | 1 | else |
463 | 1 | { |
464 | 1 | OutputLine(" None"); |
465 | 1 | } |
466 | | |
467 | 1 | error = OT_ERROR_NONE; |
468 | 1 | ExitNow(); |
469 | 1 | } |
470 | | |
471 | 28 | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE |
472 | 28 | { |
473 | 28 | static constexpr Command kCommands[] = { |
474 | 28 | CmdEntry("config"), CmdEntry("disable"), CmdEntry("enable"), CmdEntry("jitter"), |
475 | 28 | CmdEntry("mgmt"), CmdEntry("register"), CmdEntry("state"), |
476 | 28 | }; |
477 | | |
478 | 28 | #undef CmdEntry |
479 | | |
480 | 28 | static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted"); |
481 | | |
482 | 28 | const Command *command; |
483 | | |
484 | 28 | command = BinarySearch::Find(aArgs[0].GetCString(), kCommands); |
485 | 28 | VerifyOrExit(command != nullptr); |
486 | | |
487 | 27 | error = (this->*command->mHandler)(aArgs + 1); |
488 | 27 | } |
489 | 0 | #endif // #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE |
490 | | |
491 | 29 | exit: |
492 | 29 | return error; |
493 | 27 | } |
494 | | |
495 | | } // namespace Cli |
496 | | } // namespace ot |
497 | | |
498 | | #endif // #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) |