Coverage Report

Created: 2025-10-10 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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)