Coverage Report

Created: 2025-11-12 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openthread/src/cli/cli_dataset.cpp
Line
Count
Source
1
/*
2
 *  Copyright (c) 2016, 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 the CLI interpreter.
32
 */
33
34
#include "cli_dataset.hpp"
35
36
#include <stdio.h>
37
#include <stdlib.h>
38
39
#include <openthread/dataset.h>
40
#include <openthread/dataset_ftd.h>
41
#include <openthread/dataset_updater.h>
42
43
#include "cli/cli.hpp"
44
45
namespace ot {
46
namespace Cli {
47
48
otOperationalDatasetTlvs Dataset::sDatasetTlvs;
49
50
const Dataset::ComponentMapper *Dataset::LookupMapper(const char *aName) const
51
951
{
52
951
    static constexpr ComponentMapper kMappers[] = {
53
951
        {
54
951
            "activetimestamp",
55
951
            &Components::mIsActiveTimestampPresent,
56
951
            &Dataset::OutputActiveTimestamp,
57
951
            &Dataset::ParseActiveTimestamp,
58
951
        },
59
951
        {
60
951
            "channel",
61
951
            &Components::mIsChannelPresent,
62
951
            &Dataset::OutputChannel,
63
951
            &Dataset::ParseChannel,
64
951
        },
65
951
        {
66
951
            "channelmask",
67
951
            &Components::mIsChannelMaskPresent,
68
951
            &Dataset::OutputChannelMask,
69
951
            &Dataset::ParseChannelMask,
70
951
        },
71
951
        {
72
951
            "delay",
73
951
            &Components::mIsDelayPresent,
74
951
            &Dataset::OutputDelay,
75
951
            &Dataset::ParseDelay,
76
951
        },
77
951
        {
78
951
            "delaytimer", // Alias for "delay "to ensure backward compatibility for "mgmtsetcommand" command
79
951
            &Components::mIsDelayPresent,
80
951
            &Dataset::OutputDelay,
81
951
            &Dataset::ParseDelay,
82
951
        },
83
951
        {
84
951
            "extpanid",
85
951
            &Components::mIsExtendedPanIdPresent,
86
951
            &Dataset::OutputExtendedPanId,
87
951
            &Dataset::ParseExtendedPanId,
88
951
        },
89
951
        {
90
951
            "localprefix", // Alias for "meshlocalprefix" to ensure backward compatibility in "mgmtsetcommand" command
91
951
            &Components::mIsMeshLocalPrefixPresent,
92
951
            &Dataset::OutputMeshLocalPrefix,
93
951
            &Dataset::ParseMeshLocalPrefix,
94
951
        },
95
951
        {
96
951
            "meshlocalprefix",
97
951
            &Components::mIsMeshLocalPrefixPresent,
98
951
            &Dataset::OutputMeshLocalPrefix,
99
951
            &Dataset::ParseMeshLocalPrefix,
100
951
        },
101
951
        {
102
951
            "networkkey",
103
951
            &Components::mIsNetworkKeyPresent,
104
951
            &Dataset::OutputNetworkKey,
105
951
            &Dataset::ParseNetworkKey,
106
951
        },
107
951
        {
108
951
            "networkname",
109
951
            &Components::mIsNetworkNamePresent,
110
951
            &Dataset::OutputNetworkName,
111
951
            &Dataset::ParseNetworkName,
112
951
        },
113
951
        {
114
951
            "panid",
115
951
            &Components::mIsPanIdPresent,
116
951
            &Dataset::OutputPanId,
117
951
            &Dataset::ParsePanId,
118
951
        },
119
951
        {
120
951
            "pendingtimestamp",
121
951
            &Components::mIsPendingTimestampPresent,
122
951
            &Dataset::OutputPendingTimestamp,
123
951
            &Dataset::ParsePendingTimestamp,
124
951
        },
125
951
        {
126
951
            "pskc",
127
951
            &Components::mIsPskcPresent,
128
951
            &Dataset::OutputPskc,
129
951
            &Dataset::ParsePskc,
130
951
        },
131
951
        {
132
951
            "securitypolicy",
133
951
            &Components::mIsSecurityPolicyPresent,
134
951
            &Dataset::OutputSecurityPolicy,
135
951
            &Dataset::ParseSecurityPolicy,
136
951
        },
137
951
        {
138
951
            "wakeupchannel",
139
951
            &Components::mIsWakeupChannelPresent,
140
951
            &Dataset::OutputWakeupChannel,
141
951
            &Dataset::ParseWakeupChannel,
142
951
        },
143
951
    };
144
145
951
    static_assert(BinarySearch::IsSorted(kMappers), "kMappers is not sorted");
146
147
951
    return BinarySearch::Find(aName, kMappers);
148
951
}
149
150
//---------------------------------------------------------------------------------------------------------------------
151
152
/**
153
 * @cli dataset activetimestamp (get, set)
154
 * @code
155
 * dataset activetimestamp
156
 * 123456789
157
 * Done
158
 * @endcode
159
 * @code
160
 * dataset activetimestamp 123456789
161
 * Done
162
 * @endcode
163
 * @cparam dataset activetimestamp [@ca{timestamp}]
164
 * Pass the optional `timestamp` argument to set the active timestamp.
165
 * @par
166
 * Gets or sets #otOperationalDataset::mActiveTimestamp.
167
 */
168
void Dataset::OutputActiveTimestamp(const otOperationalDataset &aDataset)
169
2
{
170
2
    OutputUint64Line(aDataset.mActiveTimestamp.mSeconds);
171
2
}
172
173
/**
174
 * @cli dataset channel (get,set)
175
 * @code
176
 * dataset channel
177
 * 12
178
 * Done
179
 * @endcode
180
 * @code
181
 * dataset channel 12
182
 * Done
183
 * @endcode
184
 * @cparam dataset channel [@ca{channel-num}]
185
 * Use the optional `channel-num` argument to set the channel.
186
 * @par
187
 * Gets or sets #otOperationalDataset::mChannel.
188
 */
189
2
void Dataset::OutputChannel(const otOperationalDataset &aDataset) { OutputLine("%u", aDataset.mChannel); }
190
191
/**
192
 * @cli dataset wakeupchannel (get,set)
193
 * @code
194
 * dataset wakeupchannel
195
 * 13
196
 * Done
197
 * @endcode
198
 * @code
199
 * dataset wakeupchannel 13
200
 * Done
201
 * @endcode
202
 * @cparam dataset wakeupchannel [@ca{channel-num}]
203
 * Use the optional `channel-num` argument to set the wake-up channel.
204
 * @par
205
 * Gets or sets #otOperationalDataset::mWakeupChannel.
206
 */
207
2
void Dataset::OutputWakeupChannel(const otOperationalDataset &aDataset) { OutputLine("%u", aDataset.mWakeupChannel); }
208
209
/**
210
 * @cli dataset channelmask (get,set)
211
 * @code
212
 * dataset channelmask
213
 * 0x07fff800
214
 * Done
215
 * @endcode
216
 * @code
217
 * dataset channelmask 0x07fff800
218
 * Done
219
 * @endcode
220
 * @cparam dataset channelmask [@ca{channel-mask}]
221
 * Use the optional `channel-mask` argument to set the channel mask.
222
 * @par
223
 * Gets or sets #otOperationalDataset::mChannelMask
224
 */
225
void Dataset::OutputChannelMask(const otOperationalDataset &aDataset)
226
2
{
227
2
    OutputLine("0x%08lx", ToUlong(aDataset.mChannelMask));
228
2
}
229
230
/**
231
 * @cli dataset delay (get,set)
232
 * @code
233
 * dataset delay
234
 * 1000
235
 * Done
236
 * @endcode
237
 * @code
238
 * dataset delay 1000
239
 * Done
240
 * @endcode
241
 * @cparam dataset delay [@ca{delay}]
242
 * Use the optional `delay` argument to set the delay timer value.
243
 * @par
244
 * Gets or sets #otOperationalDataset::mDelay.
245
 * @sa otDatasetSetDelayTimerMinimal
246
 */
247
1
void Dataset::OutputDelay(const otOperationalDataset &aDataset) { OutputLine("%lu", ToUlong(aDataset.mDelay)); }
248
249
/**
250
 * @cli dataset extpanid (get,set)
251
 * @code
252
 * dataset extpanid
253
 * 000db80123456789
254
 * Done
255
 * @endcode
256
 * @code
257
 * dataset extpanid 000db80123456789
258
 * Done
259
 * @endcode
260
 * @cparam dataset extpanid [@ca{extpanid}]
261
 * Use the optional `extpanid` argument to set the Extended Personal Area Network ID.
262
 * @par
263
 * Gets or sets #otOperationalDataset::mExtendedPanId.
264
 * @note The commissioning credential in the dataset buffer becomes stale after changing
265
 * this value. Use `dataset pskc` to reset.
266
 * @csa{dataset pskc (get,set)}
267
 */
268
2
void Dataset::OutputExtendedPanId(const otOperationalDataset &aDataset) { OutputBytesLine(aDataset.mExtendedPanId.m8); }
269
270
/**
271
 * @cli dataset meshlocalprefix (get,set)
272
 * @code
273
 * dataset meshlocalprefix
274
 * fd00:db8:0:0::/64
275
 * Done
276
 * @endcode
277
 * @code
278
 * dataset meshlocalprefix fd00:db8:0:0::
279
 * Done
280
 * @endcode
281
 * @cparam dataset meshlocalprefix [@ca{meshlocalprefix}]
282
 * Use the optional `meshlocalprefix` argument to set the Mesh-Local Prefix.
283
 * @par
284
 * Gets or sets #otOperationalDataset::mMeshLocalPrefix.
285
 */
286
void Dataset::OutputMeshLocalPrefix(const otOperationalDataset &aDataset)
287
2
{
288
2
    OutputIp6PrefixLine(aDataset.mMeshLocalPrefix);
289
2
}
290
291
/**
292
 * @cli dataset networkkey (get,set)
293
 * @code
294
 * dataset networkkey
295
 * 00112233445566778899aabbccddeeff
296
 * Done
297
 * @endcode
298
 * @code
299
 * dataset networkkey 00112233445566778899aabbccddeeff
300
 * Done
301
 * @endcode
302
 * @cparam dataset networkkey [@ca{key}]
303
 * Use the optional `key` argument to set the Network Key.
304
 * @par
305
 * Gets or sets #otOperationalDataset::mNetworkKey.
306
 */
307
2
void Dataset::OutputNetworkKey(const otOperationalDataset &aDataset) { OutputBytesLine(aDataset.mNetworkKey.m8); }
308
309
/**
310
 * @cli dataset networkname (get,set)
311
 * @code
312
 * dataset networkname
313
 * OpenThread
314
 * Done
315
 * @endcode
316
 * @code
317
 * dataset networkname OpenThread
318
 * Done
319
 * @endcode
320
 * @cparam dataset networkname [@ca{name}]
321
 * Use the optional `name` argument to set the Network Name.
322
 * @par
323
 * Gets or sets #otOperationalDataset::mNetworkName.
324
 * @note The Commissioning Credential in the dataset buffer becomes stale after changing this value.
325
 * Use `dataset pskc` to reset.
326
 * @csa{dataset pskc (get,set)}
327
 */
328
2
void Dataset::OutputNetworkName(const otOperationalDataset &aDataset) { OutputLine("%s", aDataset.mNetworkName.m8); }
329
330
/**
331
 * @cli dataset panid (get,set)
332
 * @code
333
 * dataset panid
334
 * 0x1234
335
 * Done
336
 * @endcode
337
 * @code
338
 * dataset panid 0x1234
339
 * Done
340
 * @endcode
341
 * @cparam dataset panid [@ca{panid}]
342
 * Use the optional `panid` argument to set the PAN ID.
343
 * @par
344
 * Gets or sets #otOperationalDataset::mPanId.
345
 */
346
4
void Dataset::OutputPanId(const otOperationalDataset &aDataset) { OutputLine("0x%04x", aDataset.mPanId); }
347
348
/**
349
 * @cli dataset pendingtimestamp (get,set)
350
 * @code
351
 * dataset pendingtimestamp
352
 * 123456789
353
 * Done
354
 * @endcode
355
 * @code
356
 * dataset pendingtimestamp 123456789
357
 * Done
358
 * @endcode
359
 * @cparam dataset pendingtimestamp [@ca{timestamp}]
360
 * Use the optional `timestamp` argument to set the pending timestamp seconds.
361
 * @par
362
 * Gets or sets #otOperationalDataset::mPendingTimestamp.
363
 */
364
void Dataset::OutputPendingTimestamp(const otOperationalDataset &aDataset)
365
0
{
366
0
    OutputUint64Line(aDataset.mPendingTimestamp.mSeconds);
367
0
}
368
369
/**
370
 * @cli dataset pskc (get,set)
371
 * @code
372
 * dataset pskc
373
 * 67c0c203aa0b042bfb5381c47aef4d9e
374
 * Done
375
 * @endcode
376
 * @code
377
 * dataset pskc -p 123456
378
 * Done
379
 * @endcode
380
 * @code
381
 * dataset pskc 67c0c203aa0b042bfb5381c47aef4d9e
382
 * Done
383
 * @endcode
384
 * @cparam dataset pskc [@ca{-p} @ca{passphrase}] | [@ca{key}]
385
 * For FTD only, use `-p` with the `passphrase` argument. `-p` generates a pskc from
386
 * the UTF-8 encoded `passphrase` that you provide, together with
387
 * the network name and extended PAN ID. If set, `-p` uses the dataset buffer;
388
 * otherwise, it uses the current stack.
389
 * Alternatively, you can set pskc as `key` (hex format).
390
 * @par
391
 * Gets or sets #otOperationalDataset::mPskc.
392
 */
393
2
void Dataset::OutputPskc(const otOperationalDataset &aDataset) { OutputBytesLine(aDataset.mPskc.m8); }
394
395
/**
396
 * @cli dataset securitypolicy (get,set)
397
 * @code
398
 * dataset securitypolicy
399
 * 672 onrc
400
 * Done
401
 * @endcode
402
 * @code
403
 * dataset securitypolicy 672 onrc
404
 * Done
405
 * @endcode
406
 * @cparam dataset securitypolicy [@ca{rotationtime} [@ca{onrcCepR}]]
407
 * *   Use `rotationtime` for `thrKeyRotation`, in units of hours.
408
 * *   Security Policy commands use the `onrcCepR` argument mappings to get and set
409
 * #otSecurityPolicy members, for example `o` represents
410
 * #otSecurityPolicy::mObtainNetworkKeyEnabled.
411
 * @moreinfo{@dataset}.
412
 * @par
413
 * Gets or sets the %Dataset security policy.
414
 */
415
void Dataset::OutputSecurityPolicy(const otOperationalDataset &aDataset)
416
2
{
417
2
    OutputSecurityPolicy(aDataset.mSecurityPolicy);
418
2
}
419
420
//---------------------------------------------------------------------------------------------------------------------
421
422
otError Dataset::ParseActiveTimestamp(Arg *&aArgs, otOperationalDataset &aDataset)
423
156
{
424
156
    otError error;
425
426
156
    SuccessOrExit(error = aArgs++->ParseAsUint64(aDataset.mActiveTimestamp.mSeconds));
427
48
    aDataset.mActiveTimestamp.mTicks         = 0;
428
48
    aDataset.mActiveTimestamp.mAuthoritative = false;
429
430
156
exit:
431
156
    return error;
432
48
}
433
434
otError Dataset::ParseChannel(Arg *&aArgs, otOperationalDataset &aDataset)
435
2
{
436
2
    return aArgs++->ParseAsUint16(aDataset.mChannel);
437
2
}
438
439
otError Dataset::ParseWakeupChannel(Arg *&aArgs, otOperationalDataset &aDataset)
440
1
{
441
1
    return aArgs++->ParseAsUint16(aDataset.mWakeupChannel);
442
1
}
443
444
otError Dataset::ParseChannelMask(Arg *&aArgs, otOperationalDataset &aDataset)
445
3
{
446
3
    return aArgs++->ParseAsUint32(aDataset.mChannelMask);
447
3
}
448
449
otError Dataset::ParseDelay(Arg *&aArgs, otOperationalDataset &aDataset)
450
3
{
451
3
    return aArgs++->ParseAsUint32(aDataset.mDelay);
452
3
}
453
454
otError Dataset::ParseExtendedPanId(Arg *&aArgs, otOperationalDataset &aDataset)
455
3
{
456
3
    return aArgs++->ParseAsHexString(aDataset.mExtendedPanId.m8);
457
3
}
458
459
otError Dataset::ParseMeshLocalPrefix(Arg *&aArgs, otOperationalDataset &aDataset)
460
3
{
461
3
    otError      error;
462
3
    otIp6Address prefix;
463
464
3
    SuccessOrExit(error = aArgs++->ParseAsIp6Address(prefix));
465
466
1
    memcpy(aDataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(aDataset.mMeshLocalPrefix.m8));
467
468
3
exit:
469
3
    return error;
470
1
}
471
472
otError Dataset::ParseNetworkKey(Arg *&aArgs, otOperationalDataset &aDataset)
473
2
{
474
2
    return aArgs++->ParseAsHexString(aDataset.mNetworkKey.m8);
475
2
}
476
477
otError Dataset::ParseNetworkName(Arg *&aArgs, otOperationalDataset &aDataset)
478
282
{
479
282
    otError error = OT_ERROR_NONE;
480
481
282
    VerifyOrExit(!aArgs->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
482
280
    error = otNetworkNameFromString(&aDataset.mNetworkName, aArgs++->GetCString());
483
484
282
exit:
485
282
    return error;
486
280
}
487
488
otError Dataset::ParsePanId(Arg *&aArgs, otOperationalDataset &aDataset)
489
2
{
490
2
    return aArgs++->ParseAsUint16(aDataset.mPanId);
491
2
}
492
493
otError Dataset::ParsePendingTimestamp(Arg *&aArgs, otOperationalDataset &aDataset)
494
3
{
495
3
    otError error;
496
497
3
    SuccessOrExit(error = aArgs++->ParseAsUint64(aDataset.mPendingTimestamp.mSeconds));
498
2
    aDataset.mPendingTimestamp.mTicks         = 0;
499
2
    aDataset.mPendingTimestamp.mAuthoritative = false;
500
501
3
exit:
502
3
    return error;
503
2
}
504
505
otError Dataset::ParsePskc(Arg *&aArgs, otOperationalDataset &aDataset)
506
3
{
507
3
    otError error;
508
509
3
#if OPENTHREAD_FTD
510
3
    if (*aArgs == "-p")
511
0
    {
512
0
        aArgs++;
513
0
        VerifyOrExit(!aArgs->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
514
515
0
        SuccessOrExit(error = otDatasetGeneratePskc(
516
0
                          aArgs->GetCString(),
517
0
                          (aDataset.mComponents.mIsNetworkNamePresent
518
0
                               ? &aDataset.mNetworkName
519
0
                               : reinterpret_cast<const otNetworkName *>(otThreadGetNetworkName(GetInstancePtr()))),
520
0
                          (aDataset.mComponents.mIsExtendedPanIdPresent ? &aDataset.mExtendedPanId
521
0
                                                                        : otThreadGetExtendedPanId(GetInstancePtr())),
522
0
                          &aDataset.mPskc));
523
0
        aArgs++;
524
0
    }
525
3
    else
526
3
#endif
527
3
    {
528
3
        ExitNow(error = aArgs++->ParseAsHexString(aDataset.mPskc.m8));
529
3
    }
530
531
3
exit:
532
3
    return error;
533
3
}
534
535
otError Dataset::ParseSecurityPolicy(Arg *&aArgs, otOperationalDataset &aDataset)
536
71
{
537
71
    return ParseSecurityPolicy(aDataset.mSecurityPolicy, aArgs);
538
71
}
539
540
otError Dataset::ParseTlvs(Arg &aArg, otOperationalDatasetTlvs &aDatasetTlvs)
541
183
{
542
183
    otError  error;
543
183
    uint16_t length;
544
545
183
    length = sizeof(aDatasetTlvs.mTlvs);
546
183
    SuccessOrExit(error = aArg.ParseAsHexString(length, aDatasetTlvs.mTlvs));
547
178
    aDatasetTlvs.mLength = static_cast<uint8_t>(length);
548
549
183
exit:
550
183
    return error;
551
178
}
552
553
//---------------------------------------------------------------------------------------------------------------------
554
555
otError Dataset::ProcessCommand(const ComponentMapper &aMapper, Arg aArgs[])
556
305
{
557
305
    otError              error = OT_ERROR_NONE;
558
305
    otOperationalDataset dataset;
559
560
305
    if (aArgs[0].IsEmpty())
561
7
    {
562
7
        SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset));
563
564
4
        if (dataset.mComponents.*aMapper.mIsPresentPtr)
565
1
        {
566
1
            (this->*aMapper.mOutput)(dataset);
567
1
        }
568
4
    }
569
298
    else
570
298
    {
571
298
        ClearAllBytes(dataset);
572
298
        SuccessOrExit(error = (this->*aMapper.mParse)(aArgs, dataset));
573
131
        dataset.mComponents.*aMapper.mIsPresentPtr = true;
574
131
        SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs));
575
131
    }
576
577
305
exit:
578
305
    return error;
579
305
}
580
581
otError Dataset::Print(otOperationalDatasetTlvs &aDatasetTlvs, bool aNonsensitiveOnly)
582
5
{
583
5
    struct ComponentTitle
584
5
    {
585
5
        const char *mTitle;       // Title to output.
586
5
        const char *mName;        // To use with `LookupMapper()`.
587
5
        bool        mIsSensitive; // Whether the field is sensitive.
588
5
    };
589
590
5
    static const ComponentTitle kTitles[] = {
591
5
        {"Pending Timestamp", "pendingtimestamp", false},
592
5
        {"Active Timestamp", "activetimestamp", false},
593
5
        {"Channel", "channel", false},
594
5
        {"Wake-up Channel", "wakeupchannel", false},
595
5
        {"Channel Mask", "channelmask", false},
596
5
        {"Delay", "delay", false},
597
5
        {"Ext PAN ID", "extpanid", false},
598
5
        {"Mesh Local Prefix", "meshlocalprefix", false},
599
5
        {"Network Key", "networkkey", true},
600
5
        {"Network Name", "networkname", false},
601
5
        {"PAN ID", "panid", false},
602
5
        {"PSKc", "pskc", true},
603
5
        {"Security Policy", "securitypolicy", false},
604
5
    };
605
606
5
    otError              error;
607
5
    otOperationalDataset dataset;
608
609
5
    SuccessOrExit(error = otDatasetParseTlvs(&aDatasetTlvs, &dataset));
610
611
4
    for (const ComponentTitle &title : kTitles)
612
52
    {
613
52
        const ComponentMapper *mapper;
614
615
52
        mapper = LookupMapper(title.mName);
616
617
52
        if (dataset.mComponents.*mapper->mIsPresentPtr)
618
24
        {
619
24
            OutputFormat("%s: ", title.mTitle);
620
24
            if (aNonsensitiveOnly && title.mIsSensitive)
621
0
            {
622
0
                OutputLine("[Redacted]");
623
0
            }
624
24
            else
625
24
            {
626
24
                (this->*mapper->mOutput)(dataset);
627
24
            }
628
24
        }
629
52
    }
630
631
5
exit:
632
5
    return error;
633
4
}
634
635
/**
636
 * @cli dataset init (active,new,pending,tlvs)
637
 * @code
638
 * dataset init new
639
 * Done
640
 * @endcode
641
 * @cparam dataset init {@ca{active}|@ca{new}|@ca{pending}|@ca{tlvs}} [@ca{hex-encoded-tlvs}]
642
 * Use `new` to initialize a new dataset, then enter the command `dataset commit active`.
643
 * Use `tlvs` for hex-encoded TLVs.
644
 * @par
645
 * OT CLI checks for `active`, `pending`, or `tlvs` and returns the corresponding values. Otherwise,
646
 * OT CLI creates a new, random network and returns a new dataset.
647
 * @csa{dataset commit active}
648
 * @csa{dataset active}
649
 */
650
template <> otError Dataset::Process<Cmd("init")>(Arg aArgs[])
651
2
{
652
2
    otError error = OT_ERROR_INVALID_ARGS;
653
654
2
    if (aArgs[0] == "active")
655
1
    {
656
1
        error = otDatasetGetActiveTlvs(GetInstancePtr(), &sDatasetTlvs);
657
1
    }
658
1
    else if (aArgs[0] == "pending")
659
0
    {
660
0
        error = otDatasetGetPendingTlvs(GetInstancePtr(), &sDatasetTlvs);
661
0
    }
662
1
#if OPENTHREAD_FTD
663
1
    else if (aArgs[0] == "new")
664
0
    {
665
0
        otOperationalDataset dataset;
666
667
0
        SuccessOrExit(error = otDatasetCreateNewNetwork(GetInstancePtr(), &dataset));
668
0
        otDatasetConvertToTlvs(&dataset, &sDatasetTlvs);
669
0
    }
670
1
#endif
671
1
    else if (aArgs[0] == "tlvs")
672
0
    {
673
0
        ExitNow(error = ParseTlvs(aArgs[1], sDatasetTlvs));
674
0
    }
675
676
2
exit:
677
2
    return error;
678
2
}
679
680
/**
681
 * @cli dataset active
682
 * @code
683
 * dataset active
684
 * Active Timestamp: 1
685
 * Channel: 13
686
 * Channel Mask: 0x07fff800
687
 * Ext PAN ID: d63e8e3e495ebbc3
688
 * Mesh Local Prefix: fd3d:b50b:f96d:722d::/64
689
 * Network Key: dfd34f0f05cad978ec4e32b0413038ff
690
 * Network Name: OpenThread-8f28
691
 * PAN ID: 0x8f28
692
 * PSKc: c23a76e98f1a6483639b1ac1271e2e27
693
 * Security Policy: 0, onrcb
694
 * Done
695
 * @endcode
696
 * @code
697
 * dataset active -x
698
 * 0e08000000000001000000030000103506000...3023d82c841eff0e68db86f35740c030000ff
699
 * Done
700
 * @endcode
701
 * @code
702
 * dataset active -ns
703
 * Active Timestamp: 1
704
 * Channel: 13
705
 * Channel Mask: 0x07fff800
706
 * Ext PAN ID: d63e8e3e495ebbc3
707
 * Mesh Local Prefix: fd3d:b50b:f96d:722d::/64
708
 * Network Key: [Redacted]
709
 * Network Name: OpenThread-8f28
710
 * PAN ID: 0x8f28
711
 * PSKc: [Redacted]
712
 * Security Policy: 0, onrcb
713
 * Done
714
 * @endcode
715
 * @cparam dataset active [-x|-ns]
716
 * * The optional `-x` argument prints the Active Operational Dataset values as hex-encoded TLVs.
717
 * * The optional `-ns` argument prints the Active Operational Dataset values and redact the sensitive values, including
718
 * the network key and PSKc fields.
719
 * @par api_copy
720
 * #otDatasetGetActive
721
 * @par
722
 * OT CLI uses #otOperationalDataset members to return dataset values to the console.
723
 */
724
template <> otError Dataset::Process<Cmd("active")>(Arg aArgs[])
725
2
{
726
2
    otError                  error;
727
2
    otOperationalDatasetTlvs dataset;
728
729
2
    SuccessOrExit(error = otDatasetGetActiveTlvs(GetInstancePtr(), &dataset));
730
731
2
    if (aArgs[0].IsEmpty())
732
1
    {
733
1
        error = Print(dataset, /* aNonsensitiveOnly */ false);
734
1
    }
735
1
    else if (aArgs[0] == "-x")
736
0
    {
737
0
        OutputBytesLine(dataset.mTlvs, dataset.mLength);
738
0
    }
739
1
    else if (aArgs[0] == "-ns")
740
0
    {
741
0
        error = Print(dataset, /* aNonsensitiveOnly */ true);
742
0
    }
743
1
    else
744
1
    {
745
1
        error = OT_ERROR_INVALID_ARGS;
746
1
    }
747
748
2
exit:
749
2
    return error;
750
2
}
751
752
template <> otError Dataset::Process<Cmd("pending")>(Arg aArgs[])
753
1
{
754
1
    otError                  error;
755
1
    otOperationalDatasetTlvs datasetTlvs;
756
757
1
    SuccessOrExit(error = otDatasetGetPendingTlvs(GetInstancePtr(), &datasetTlvs));
758
759
0
    if (aArgs[0].IsEmpty())
760
0
    {
761
0
        error = Print(datasetTlvs, /* aNonsensitiveOnly */ false);
762
0
    }
763
0
    else if (aArgs[0] == "-x")
764
0
    {
765
0
        OutputBytesLine(datasetTlvs.mTlvs, datasetTlvs.mLength);
766
0
    }
767
0
    else if (aArgs[0] == "-ns")
768
0
    {
769
0
        error = Print(datasetTlvs, /* aNonsensitiveOnly */ true);
770
0
    }
771
0
    else
772
0
    {
773
0
        error = OT_ERROR_INVALID_ARGS;
774
0
    }
775
776
1
exit:
777
1
    return error;
778
0
}
779
780
/**
781
 * @cli dataset clear
782
 * @code
783
 * dataset clear
784
 * Done
785
 * @endcode
786
 * @par
787
 * Reset the Operational %Dataset buffer.
788
 */
789
template <> otError Dataset::Process<Cmd("clear")>(Arg aArgs[])
790
1
{
791
1
    OT_UNUSED_VARIABLE(aArgs);
792
793
1
    ClearAllBytes(sDatasetTlvs);
794
1
    return OT_ERROR_NONE;
795
1
}
796
797
template <> otError Dataset::Process<Cmd("commit")>(Arg aArgs[])
798
1
{
799
1
    otError error = OT_ERROR_INVALID_ARGS;
800
801
    /**
802
     * @cli dataset commit active
803
     * @code
804
     * dataset commit active
805
     * Done
806
     * @endcode
807
     * @par
808
     * Commit the Operational %Dataset buffer to Active Operational %Dataset.
809
     * @csa{dataset commit pending}
810
     * @sa #otDatasetSetPending
811
     */
812
1
    if (aArgs[0] == "active")
813
0
    {
814
0
        error = otDatasetSetActiveTlvs(GetInstancePtr(), &sDatasetTlvs);
815
0
    }
816
    /**
817
     * @cli dataset commit pending
818
     * @code
819
     * dataset commit pending
820
     * Done
821
     * @endcode
822
     * @par
823
     * Commit the Operational %Dataset buffer to Pending Operational %Dataset.
824
     * @csa{dataset commit active}
825
     * @sa #otDatasetSetActive
826
     */
827
1
    else if (aArgs[0] == "pending")
828
0
    {
829
0
        error = otDatasetSetPendingTlvs(GetInstancePtr(), &sDatasetTlvs);
830
0
    }
831
832
1
    return error;
833
1
}
834
835
template <> otError Dataset::Process<Cmd("mgmtsetcommand")>(Arg aArgs[])
836
87
{
837
87
    otError                  error = OT_ERROR_NONE;
838
87
    otOperationalDataset     dataset;
839
87
    otOperationalDatasetTlvs tlvs;
840
841
87
    ClearAllBytes(dataset);
842
87
    ClearAllBytes(tlvs);
843
844
309
    for (Arg *arg = &aArgs[1]; !arg->IsEmpty();)
845
284
    {
846
284
        const ComponentMapper *mapper = LookupMapper(arg->GetCString());
847
848
284
        if (mapper != nullptr)
849
236
        {
850
236
            arg++;
851
236
            SuccessOrExit(error = (this->*mapper->mParse)(arg, dataset));
852
222
            dataset.mComponents.*mapper->mIsPresentPtr = true;
853
222
        }
854
48
        else if (*arg == "-x")
855
0
        {
856
0
            arg++;
857
0
            SuccessOrExit(error = ParseTlvs(*arg, tlvs));
858
0
            arg++;
859
0
        }
860
48
        else
861
48
        {
862
48
            ExitNow(error = OT_ERROR_INVALID_ARGS);
863
48
        }
864
284
    }
865
866
    /**
867
     * @cli dataset mgmtsetcommand active
868
     * @code
869
     * dataset mgmtsetcommand active activetimestamp 123 securitypolicy 1 onrcb
870
     * Done
871
     * @endcode
872
     * @cparam dataset mgmtsetcommand active [@ca{dataset-components}] [-x @ca{tlv-list}]
873
     * To learn more about these parameters and argument mappings, refer to @dataset.
874
     * @par
875
     * @note This command is primarily used for testing only.
876
     * @par api_copy
877
     * #otDatasetSendMgmtActiveSet
878
     * @csa{dataset mgmtgetcommand active}
879
     * @csa{dataset mgmtgetcommand pending}
880
     * @csa{dataset mgmtsetcommand pending}
881
     */
882
25
    if (aArgs[0] == "active")
883
1
    {
884
1
        error =
885
1
            otDatasetSendMgmtActiveSet(GetInstancePtr(), &dataset, tlvs.mTlvs, tlvs.mLength, /* aCallback */ nullptr,
886
1
                                       /* aContext */ nullptr);
887
1
    }
888
    /**
889
     * @cli dataset mgmtsetcommand pending
890
     * @code
891
     * dataset mgmtsetcommand pending activetimestamp 123 securitypolicy 1 onrcb
892
     * Done
893
     * @endcode
894
     * @cparam dataset mgmtsetcommand pending [@ca{dataset-components}] [-x @ca{tlv-list}]
895
     * To learn more about these parameters and argument mappings, refer to @dataset.
896
     * @par
897
     * @note This command is primarily used for testing only.
898
     * @par api_copy
899
     * #otDatasetSendMgmtPendingSet
900
     * @csa{dataset mgmtgetcommand active}
901
     * @csa{dataset mgmtgetcommand pending}
902
     * @csa{dataset mgmtsetcommand active}
903
     */
904
24
    else if (aArgs[0] == "pending")
905
0
    {
906
0
        error =
907
0
            otDatasetSendMgmtPendingSet(GetInstancePtr(), &dataset, tlvs.mTlvs, tlvs.mLength, /* aCallback */ nullptr,
908
0
                                        /* aContext */ nullptr);
909
0
    }
910
24
    else
911
24
    {
912
24
        error = OT_ERROR_INVALID_ARGS;
913
24
    }
914
915
87
exit:
916
87
    return error;
917
25
}
918
919
template <> otError Dataset::Process<Cmd("mgmtgetcommand")>(Arg aArgs[])
920
9
{
921
9
    otError                        error = OT_ERROR_NONE;
922
9
    otOperationalDatasetComponents datasetComponents;
923
9
    otOperationalDatasetTlvs       tlvs;
924
9
    bool                           destAddrSpecified = false;
925
9
    otIp6Address                   address;
926
927
9
    ClearAllBytes(datasetComponents);
928
9
    ClearAllBytes(tlvs);
929
930
24
    for (Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++)
931
18
    {
932
18
        const ComponentMapper *mapper = LookupMapper(arg->GetCString());
933
934
18
        if (mapper != nullptr)
935
15
        {
936
15
            datasetComponents.*mapper->mIsPresentPtr = true;
937
15
        }
938
3
        else if (*arg == "-x")
939
0
        {
940
0
            arg++;
941
0
            SuccessOrExit(error = ParseTlvs(*arg, tlvs));
942
0
        }
943
3
        else if (*arg == "address")
944
0
        {
945
0
            arg++;
946
0
            SuccessOrExit(error = arg->ParseAsIp6Address(address));
947
0
            destAddrSpecified = true;
948
0
        }
949
3
        else
950
3
        {
951
3
            ExitNow(error = OT_ERROR_INVALID_ARGS);
952
3
        }
953
18
    }
954
955
    /**
956
     * @cli dataset mgmtgetcommand active
957
     * @code
958
     * dataset mgmtgetcommand active address fdde:ad00:beef:0:558:f56b:d688:799 activetimestamp securitypolicy
959
     * Done
960
     * @endcode
961
     * @code
962
     * dataset mgmtgetcommand active networkname
963
     * Done
964
     * @endcode
965
     * @cparam dataset mgmtgetcommand active [address @ca{leader-address}] [@ca{dataset-components}] [-x @ca{tlv-list}]
966
     * *    Use `address` to specify the IPv6 destination; otherwise, the Leader ALOC is used as default.
967
     * *    For `dataset-components`, you can pass any combination of #otOperationalDatasetComponents, for
968
     *      example `activetimestamp`, `pendingtimestamp`, or `networkkey`.
969
     * *    The optional `-x` argument specifies raw TLVs to be requested.
970
     * @par
971
     * OT CLI sends a MGMT_ACTIVE_GET with the relevant arguments.
972
     * To learn more about these parameters and argument mappings, refer to @dataset.
973
     * @note This command is primarily used for testing only.
974
     * @par api_copy
975
     * #otDatasetSendMgmtActiveGet
976
     * @csa{dataset mgmtgetcommand pending}
977
     * @csa{dataset mgmtsetcommand active}
978
     * @csa{dataset mgmtsetcommand pending}
979
     */
980
6
    if (aArgs[0] == "active")
981
2
    {
982
2
        error = otDatasetSendMgmtActiveGet(GetInstancePtr(), &datasetComponents, tlvs.mTlvs, tlvs.mLength,
983
2
                                           destAddrSpecified ? &address : nullptr);
984
2
    }
985
    /**
986
     * @cli dataset mgmtgetcommand pending
987
     * @code
988
     * dataset mgmtgetcommand pending address fdde:ad00:beef:0:558:f56b:d688:799 activetimestamp securitypolicy
989
     * Done
990
     * @endcode
991
     * @code
992
     * dataset mgmtgetcommand pending networkname
993
     * Done
994
     * @endcode
995
     * @cparam dataset mgmtgetcommand pending [address @ca{leader-address}] [@ca{dataset-components}] [-x @ca{tlv-list}]
996
     * To learn more about these parameters and argument mappings, refer to @dataset.
997
     * @par
998
     * @note This command is primarily used for testing only.
999
     * @par api_copy
1000
     * #otDatasetSendMgmtPendingGet
1001
     * @csa{dataset mgmtgetcommand active}
1002
     * @csa{dataset mgmtsetcommand active}
1003
     * @csa{dataset mgmtsetcommand pending}
1004
     */
1005
4
    else if (aArgs[0] == "pending")
1006
0
    {
1007
0
        error = otDatasetSendMgmtPendingGet(GetInstancePtr(), &datasetComponents, tlvs.mTlvs, tlvs.mLength,
1008
0
                                            destAddrSpecified ? &address : nullptr);
1009
0
    }
1010
4
    else
1011
4
    {
1012
4
        error = OT_ERROR_INVALID_ARGS;
1013
4
    }
1014
1015
9
exit:
1016
9
    return error;
1017
6
}
1018
1019
void Dataset::OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy)
1020
2
{
1021
2
    OutputFormat("%u ", aSecurityPolicy.mRotationTime);
1022
1023
2
    if (aSecurityPolicy.mObtainNetworkKeyEnabled)
1024
2
    {
1025
2
        OutputFormat("o");
1026
2
    }
1027
1028
2
    if (aSecurityPolicy.mNativeCommissioningEnabled)
1029
2
    {
1030
2
        OutputFormat("n");
1031
2
    }
1032
1033
2
    if (aSecurityPolicy.mRoutersEnabled)
1034
2
    {
1035
2
        OutputFormat("r");
1036
2
    }
1037
1038
2
    if (aSecurityPolicy.mExternalCommissioningEnabled)
1039
2
    {
1040
2
        OutputFormat("c");
1041
2
    }
1042
1043
2
    if (aSecurityPolicy.mCommercialCommissioningEnabled)
1044
0
    {
1045
0
        OutputFormat("C");
1046
0
    }
1047
1048
2
    if (aSecurityPolicy.mAutonomousEnrollmentEnabled)
1049
0
    {
1050
0
        OutputFormat("e");
1051
0
    }
1052
1053
2
    if (aSecurityPolicy.mNetworkKeyProvisioningEnabled)
1054
0
    {
1055
0
        OutputFormat("p");
1056
0
    }
1057
1058
2
    if (aSecurityPolicy.mNonCcmRoutersEnabled)
1059
0
    {
1060
0
        OutputFormat("R");
1061
0
    }
1062
1063
2
    OutputLine(" %u", aSecurityPolicy.mVersionThresholdForRouting);
1064
2
}
1065
1066
otError Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, Arg *&aArgs)
1067
71
{
1068
71
    static constexpr uint8_t kMaxVersionThreshold = 7;
1069
1070
71
    otError          error;
1071
71
    otSecurityPolicy policy;
1072
71
    uint8_t          versionThreshold;
1073
1074
71
    ClearAllBytes(policy);
1075
1076
71
    SuccessOrExit(error = aArgs->ParseAsUint16(policy.mRotationTime));
1077
70
    aArgs++;
1078
1079
70
    VerifyOrExit(!aArgs->IsEmpty());
1080
1081
1.71k
    for (const char *flag = aArgs->GetCString(); *flag != '\0'; flag++)
1082
1.66k
    {
1083
1.66k
        switch (*flag)
1084
1.66k
        {
1085
200
        case 'o':
1086
200
            policy.mObtainNetworkKeyEnabled = true;
1087
200
            break;
1088
1089
210
        case 'n':
1090
210
            policy.mNativeCommissioningEnabled = true;
1091
210
            break;
1092
1093
212
        case 'r':
1094
212
            policy.mRoutersEnabled = true;
1095
212
            break;
1096
1097
228
        case 'c':
1098
228
            policy.mExternalCommissioningEnabled = true;
1099
228
            break;
1100
1101
194
        case 'C':
1102
194
            policy.mCommercialCommissioningEnabled = true;
1103
194
            break;
1104
1105
205
        case 'e':
1106
205
            policy.mAutonomousEnrollmentEnabled = true;
1107
205
            break;
1108
1109
199
        case 'p':
1110
199
            policy.mNetworkKeyProvisioningEnabled = true;
1111
199
            break;
1112
1113
200
        case 'R':
1114
200
            policy.mNonCcmRoutersEnabled = true;
1115
200
            break;
1116
1117
15
        default:
1118
15
            ExitNow(error = OT_ERROR_INVALID_ARGS);
1119
1.66k
        }
1120
1.66k
    }
1121
1122
54
    aArgs++;
1123
54
    VerifyOrExit(!aArgs->IsEmpty());
1124
1125
5
    SuccessOrExit(error = aArgs->ParseAsUint8(versionThreshold));
1126
4
    aArgs++;
1127
4
    VerifyOrExit(versionThreshold <= kMaxVersionThreshold, error = OT_ERROR_INVALID_ARGS);
1128
3
    policy.mVersionThresholdForRouting = versionThreshold;
1129
1130
71
exit:
1131
71
    if (error == OT_ERROR_NONE)
1132
53
    {
1133
53
        aSecurityPolicy = policy;
1134
53
    }
1135
1136
71
    return error;
1137
3
}
1138
1139
/**
1140
 * @cli dataset set (active,pending)
1141
 * @code
1142
 * dataset set active 0e08000000000001000000030000103506000...3023d82c841eff0e68db86f35740c030000ff
1143
 * Done
1144
 * @endcode
1145
 * @code
1146
 * dataset set pending 0e08000000000001000000030000103506000...3023d82c841eff0e68db86f35740c030000ff
1147
 * Done
1148
 * @endcode
1149
 * @cparam dataset set {active|pending} @ca{tlvs}
1150
 * @par
1151
 * The CLI `dataset set` command sets the Active Operational %Dataset using hex-encoded TLVs.
1152
 * @par api_copy
1153
 * #otDatasetSetActive
1154
 */
1155
template <> otError Dataset::Process<Cmd("set")>(Arg aArgs[])
1156
183
{
1157
183
    otError                  error = OT_ERROR_NONE;
1158
183
    otOperationalDatasetTlvs datasetTlvs;
1159
1160
183
    SuccessOrExit(error = ParseTlvs(aArgs[1], datasetTlvs));
1161
1162
178
    if (aArgs[0] == "active")
1163
171
    {
1164
171
        error = otDatasetSetActiveTlvs(GetInstancePtr(), &datasetTlvs);
1165
171
    }
1166
7
    else if (aArgs[0] == "pending")
1167
3
    {
1168
3
        error = otDatasetSetPendingTlvs(GetInstancePtr(), &datasetTlvs);
1169
3
    }
1170
4
    else
1171
4
    {
1172
4
        error = OT_ERROR_INVALID_ARGS;
1173
4
    }
1174
1175
183
exit:
1176
183
    return error;
1177
178
}
1178
1179
/**
1180
 * @cli dataset tlvs
1181
 * @code
1182
 * dataset tlvs
1183
 * 0e080000000000010000000300001635060004001fffe0020...f7f8
1184
 * Done
1185
 * @endcode
1186
 * @par api_copy
1187
 * #otDatasetConvertToTlvs
1188
 */
1189
template <> otError Dataset::Process<Cmd("tlvs")>(Arg aArgs[])
1190
2
{
1191
2
    otError error = OT_ERROR_NONE;
1192
1193
2
    VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
1194
1
    OutputBytesLine(sDatasetTlvs.mTlvs, sDatasetTlvs.mLength);
1195
1196
2
exit:
1197
2
    return error;
1198
1
}
1199
1200
#if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD
1201
1202
template <> otError Dataset::Process<Cmd("updater")>(Arg aArgs[])
1203
2
{
1204
2
    otError error = OT_ERROR_NONE;
1205
1206
    /**
1207
     * @cli dataset updater
1208
     * @code
1209
     * dataset updater
1210
     * Enabled
1211
     * Done
1212
     * @endcode
1213
     * @par api_copy
1214
     * #otDatasetUpdaterIsUpdateOngoing
1215
     */
1216
2
    if (aArgs[0].IsEmpty())
1217
1
    {
1218
1
        OutputEnabledDisabledStatus(otDatasetUpdaterIsUpdateOngoing(GetInstancePtr()));
1219
1
    }
1220
    /**
1221
     * @cli dataset updater start
1222
     * @code
1223
     * channel
1224
     * 19
1225
     * Done
1226
     * dataset clear
1227
     * Done
1228
     * dataset channel 15
1229
     * Done
1230
     * dataset
1231
     * Channel: 15
1232
     * Done
1233
     * dataset updater start
1234
     * Done
1235
     * dataset updater
1236
     * Enabled
1237
     * Done
1238
     * Dataset update complete: OK
1239
     * channel
1240
     * 15
1241
     * Done
1242
     * @endcode
1243
     * @par api_copy
1244
     * #otDatasetUpdaterRequestUpdate
1245
     */
1246
1
    else if (aArgs[0] == "start")
1247
0
    {
1248
0
        otOperationalDataset dataset;
1249
1250
0
        SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset));
1251
0
        SuccessOrExit(
1252
0
            error = otDatasetUpdaterRequestUpdate(GetInstancePtr(), &dataset, &Dataset::HandleDatasetUpdater, this));
1253
0
    }
1254
    /**
1255
     * @cli dataset updater cancel
1256
     * @code
1257
     * @dataset updater cancel
1258
     * Done
1259
     * @endcode
1260
     * @par api_copy
1261
     * #otDatasetUpdaterCancelUpdate
1262
     */
1263
1
    else if (aArgs[0] == "cancel")
1264
0
    {
1265
0
        otDatasetUpdaterCancelUpdate(GetInstancePtr());
1266
0
    }
1267
1
    else
1268
1
    {
1269
1
        error = OT_ERROR_INVALID_ARGS;
1270
1
    }
1271
1272
2
exit:
1273
2
    return error;
1274
2
}
1275
1276
void Dataset::HandleDatasetUpdater(otError aError, void *aContext)
1277
0
{
1278
0
    static_cast<Dataset *>(aContext)->HandleDatasetUpdater(aError);
1279
0
}
1280
1281
void Dataset::HandleDatasetUpdater(otError aError)
1282
0
{
1283
0
    OutputLine("Dataset update complete: %s", otThreadErrorToString(aError));
1284
0
}
1285
1286
#endif // OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD
1287
1288
otError Dataset::Process(Arg aArgs[])
1289
601
{
1290
6.01k
#define CmdEntry(aCommandString) {aCommandString, &Dataset::Process<Cmd(aCommandString)>}
1291
1292
601
    static constexpr Command kCommands[] = {
1293
601
        CmdEntry("active"),         CmdEntry("clear"),          CmdEntry("commit"),  CmdEntry("init"),
1294
601
        CmdEntry("mgmtgetcommand"), CmdEntry("mgmtsetcommand"), CmdEntry("pending"), CmdEntry("set"),
1295
601
        CmdEntry("tlvs"),
1296
601
#if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD
1297
601
        CmdEntry("updater"),
1298
601
#endif
1299
601
    };
1300
1301
601
#undef CmdEntry
1302
1303
601
    static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
1304
1305
601
    otError                error = OT_ERROR_INVALID_COMMAND;
1306
601
    const Command         *command;
1307
601
    const ComponentMapper *mapper;
1308
1309
601
    if (aArgs[0].IsEmpty())
1310
4
    {
1311
4
        ExitNow(error = Print(sDatasetTlvs, /* aNonsensitiveOnly */ false));
1312
4
    }
1313
1314
    /**
1315
     * @cli dataset help
1316
     * @code
1317
     * dataset help
1318
     * help
1319
     * active
1320
     * activetimestamp
1321
     * channel
1322
     * channelmask
1323
     * clear
1324
     * commit
1325
     * delay
1326
     * extpanid
1327
     * init
1328
     * meshlocalprefix
1329
     * mgmtgetcommand
1330
     * mgmtsetcommand
1331
     * networkkey
1332
     * networkname
1333
     * panid
1334
     * pending
1335
     * pendingtimestamp
1336
     * pskc
1337
     * securitypolicy
1338
     * set
1339
     * tlvs
1340
     * Done
1341
     * @endcode
1342
     * @par
1343
     * Gets a list of `dataset` CLI commands. @moreinfo{@dataset}.
1344
     */
1345
597
    if (aArgs[0] == "help")
1346
0
    {
1347
0
        OutputCommandTable(kCommands);
1348
0
        ExitNow(error = OT_ERROR_NONE);
1349
0
    }
1350
1351
597
    mapper = LookupMapper(aArgs[0].GetCString());
1352
1353
597
    if (mapper != nullptr)
1354
305
    {
1355
305
        error = ProcessCommand(*mapper, aArgs + 1);
1356
305
        ExitNow();
1357
305
    }
1358
1359
292
    command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
1360
292
    VerifyOrExit(command != nullptr);
1361
1362
290
    error = (this->*command->mHandler)(aArgs + 1);
1363
1364
601
exit:
1365
601
    return error;
1366
290
}
1367
1368
} // namespace Cli
1369
} // namespace ot