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 constexpr Dataset::Command Dataset::sCommands[];
49 otOperationalDataset Dataset::sDataset;
50
Print(otOperationalDataset & aDataset)51 otError Dataset::Print(otOperationalDataset &aDataset)
52 {
53 if (aDataset.mComponents.mIsPendingTimestampPresent)
54 {
55 mInterpreter.OutputLine("Pending Timestamp: %lu", aDataset.mPendingTimestamp);
56 }
57
58 if (aDataset.mComponents.mIsActiveTimestampPresent)
59 {
60 mInterpreter.OutputLine("Active Timestamp: %lu", aDataset.mActiveTimestamp);
61 }
62
63 if (aDataset.mComponents.mIsChannelPresent)
64 {
65 mInterpreter.OutputLine("Channel: %d", aDataset.mChannel);
66 }
67
68 if (aDataset.mComponents.mIsChannelMaskPresent)
69 {
70 mInterpreter.OutputLine("Channel Mask: 0x%08x", aDataset.mChannelMask);
71 }
72
73 if (aDataset.mComponents.mIsDelayPresent)
74 {
75 mInterpreter.OutputLine("Delay: %d", aDataset.mDelay);
76 }
77
78 if (aDataset.mComponents.mIsExtendedPanIdPresent)
79 {
80 mInterpreter.OutputFormat("Ext PAN ID: ");
81 mInterpreter.OutputBytes(aDataset.mExtendedPanId.m8);
82 mInterpreter.OutputLine("");
83 }
84
85 if (aDataset.mComponents.mIsMeshLocalPrefixPresent)
86 {
87 mInterpreter.OutputFormat("Mesh Local Prefix: ");
88 mInterpreter.OutputPrefix(aDataset.mMeshLocalPrefix);
89 mInterpreter.OutputLine("");
90 }
91
92 if (aDataset.mComponents.mIsNetworkKeyPresent)
93 {
94 mInterpreter.OutputFormat("Network Key: ");
95 mInterpreter.OutputBytes(aDataset.mNetworkKey.m8);
96 mInterpreter.OutputLine("");
97 }
98
99 if (aDataset.mComponents.mIsNetworkNamePresent)
100 {
101 mInterpreter.OutputFormat("Network Name: ");
102 mInterpreter.OutputLine("%s", aDataset.mNetworkName.m8);
103 }
104
105 if (aDataset.mComponents.mIsPanIdPresent)
106 {
107 mInterpreter.OutputLine("PAN ID: 0x%04x", aDataset.mPanId);
108 }
109
110 if (aDataset.mComponents.mIsPskcPresent)
111 {
112 mInterpreter.OutputFormat("PSKc: ");
113 mInterpreter.OutputBytes(aDataset.mPskc.m8);
114 mInterpreter.OutputLine("");
115 }
116
117 if (aDataset.mComponents.mIsSecurityPolicyPresent)
118 {
119 mInterpreter.OutputFormat("Security Policy: ");
120 OutputSecurityPolicy(aDataset.mSecurityPolicy);
121 mInterpreter.OutputLine("");
122 }
123
124 return OT_ERROR_NONE;
125 }
126
Process(Arg aArgs[])127 otError Dataset::Process(Arg aArgs[])
128 {
129 otError error = OT_ERROR_INVALID_COMMAND;
130 const Command *command;
131
132 if (aArgs[0].IsEmpty())
133 {
134 ExitNow(error = Print(sDataset));
135 }
136
137 command = Utils::LookupTable::Find(aArgs[0].GetCString(), sCommands);
138 VerifyOrExit(command != nullptr);
139
140 error = (this->*command->mHandler)(aArgs + 1);
141
142 exit:
143 return error;
144 }
145
ProcessHelp(Arg aArgs[])146 otError Dataset::ProcessHelp(Arg aArgs[])
147 {
148 OT_UNUSED_VARIABLE(aArgs);
149
150 for (const Command &command : sCommands)
151 {
152 mInterpreter.OutputLine(command.mName);
153 }
154
155 return OT_ERROR_NONE;
156 }
157
ProcessInit(Arg aArgs[])158 otError Dataset::ProcessInit(Arg aArgs[])
159 {
160 otError error = OT_ERROR_INVALID_ARGS;
161
162 if (aArgs[0] == "active")
163 {
164 error = otDatasetGetActive(mInterpreter.mInstance, &sDataset);
165 }
166 else if (aArgs[0] == "pending")
167 {
168 error = otDatasetGetPending(mInterpreter.mInstance, &sDataset);
169 }
170 #if OPENTHREAD_FTD
171 else if (aArgs[0] == "new")
172 {
173 error = otDatasetCreateNewNetwork(mInterpreter.mInstance, &sDataset);
174 }
175 #endif
176 else if (aArgs[0] == "tlvs")
177 {
178 otOperationalDatasetTlvs datasetTlvs;
179 uint16_t size = sizeof(datasetTlvs.mTlvs);
180
181 SuccessOrExit(error = aArgs[1].ParseAsHexString(size, datasetTlvs.mTlvs));
182 datasetTlvs.mLength = static_cast<uint8_t>(size);
183
184 SuccessOrExit(error = otDatasetParseTlvs(&datasetTlvs, &sDataset));
185 }
186
187 exit:
188 return error;
189 }
190
ProcessActive(Arg aArgs[])191 otError Dataset::ProcessActive(Arg aArgs[])
192 {
193 otError error = OT_ERROR_INVALID_ARGS;
194
195 if (aArgs[0].IsEmpty())
196 {
197 otOperationalDataset dataset;
198
199 SuccessOrExit(error = otDatasetGetActive(mInterpreter.mInstance, &dataset));
200 error = Print(dataset);
201 }
202 else if (aArgs[0] == "-x")
203 {
204 otOperationalDatasetTlvs dataset;
205
206 SuccessOrExit(error = otDatasetGetActiveTlvs(mInterpreter.mInstance, &dataset));
207 mInterpreter.OutputBytes(dataset.mTlvs, dataset.mLength);
208 mInterpreter.OutputLine("");
209 }
210
211 exit:
212 return error;
213 }
214
ProcessPending(Arg aArgs[])215 otError Dataset::ProcessPending(Arg aArgs[])
216 {
217 otError error = OT_ERROR_INVALID_ARGS;
218
219 if (aArgs[0].IsEmpty())
220 {
221 otOperationalDataset dataset;
222
223 SuccessOrExit(error = otDatasetGetPending(mInterpreter.mInstance, &dataset));
224 error = Print(dataset);
225 }
226 else if (aArgs[0] == "-x")
227 {
228 otOperationalDatasetTlvs dataset;
229
230 SuccessOrExit(error = otDatasetGetPendingTlvs(mInterpreter.mInstance, &dataset));
231 mInterpreter.OutputBytes(dataset.mTlvs, dataset.mLength);
232 mInterpreter.OutputLine("");
233 }
234
235 exit:
236 return error;
237 }
238
ProcessActiveTimestamp(Arg aArgs[])239 otError Dataset::ProcessActiveTimestamp(Arg aArgs[])
240 {
241 otError error = OT_ERROR_NONE;
242
243 if (aArgs[0].IsEmpty())
244 {
245 if (sDataset.mComponents.mIsActiveTimestampPresent)
246 {
247 mInterpreter.OutputLine("%lu", sDataset.mActiveTimestamp);
248 }
249 }
250 else
251 {
252 SuccessOrExit(error = aArgs[0].ParseAsUint64(sDataset.mActiveTimestamp));
253 sDataset.mComponents.mIsActiveTimestampPresent = true;
254 }
255
256 exit:
257 return error;
258 }
259
ProcessChannel(Arg aArgs[])260 otError Dataset::ProcessChannel(Arg aArgs[])
261 {
262 otError error = OT_ERROR_NONE;
263
264 if (aArgs[0].IsEmpty())
265 {
266 if (sDataset.mComponents.mIsChannelPresent)
267 {
268 mInterpreter.OutputLine("%d", sDataset.mChannel);
269 }
270 }
271 else
272 {
273 SuccessOrExit(error = aArgs[0].ParseAsUint16(sDataset.mChannel));
274 sDataset.mComponents.mIsChannelPresent = true;
275 }
276
277 exit:
278 return error;
279 }
280
ProcessChannelMask(Arg aArgs[])281 otError Dataset::ProcessChannelMask(Arg aArgs[])
282 {
283 otError error = OT_ERROR_NONE;
284
285 if (aArgs[0].IsEmpty())
286 {
287 if (sDataset.mComponents.mIsChannelMaskPresent)
288 {
289 mInterpreter.OutputLine("0x%08x", sDataset.mChannelMask);
290 }
291 }
292 else
293 {
294 SuccessOrExit(error = aArgs[0].ParseAsUint32(sDataset.mChannelMask));
295 sDataset.mComponents.mIsChannelMaskPresent = true;
296 }
297
298 exit:
299 return error;
300 }
301
ProcessClear(Arg aArgs[])302 otError Dataset::ProcessClear(Arg aArgs[])
303 {
304 OT_UNUSED_VARIABLE(aArgs);
305
306 memset(&sDataset, 0, sizeof(sDataset));
307 return OT_ERROR_NONE;
308 }
309
ProcessCommit(Arg aArgs[])310 otError Dataset::ProcessCommit(Arg aArgs[])
311 {
312 otError error = OT_ERROR_INVALID_ARGS;
313
314 if (aArgs[0] == "active")
315 {
316 error = otDatasetSetActive(mInterpreter.mInstance, &sDataset);
317 }
318 else if (aArgs[0] == "pending")
319 {
320 error = otDatasetSetPending(mInterpreter.mInstance, &sDataset);
321 }
322
323 return error;
324 }
325
ProcessDelay(Arg aArgs[])326 otError Dataset::ProcessDelay(Arg aArgs[])
327 {
328 otError error = OT_ERROR_NONE;
329
330 if (aArgs[0].IsEmpty())
331 {
332 if (sDataset.mComponents.mIsDelayPresent)
333 {
334 mInterpreter.OutputLine("%d", sDataset.mDelay);
335 }
336 }
337 else
338 {
339 SuccessOrExit(error = aArgs[0].ParseAsUint32(sDataset.mDelay));
340 sDataset.mComponents.mIsDelayPresent = true;
341 }
342
343 exit:
344 return error;
345 }
346
ProcessExtPanId(Arg aArgs[])347 otError Dataset::ProcessExtPanId(Arg aArgs[])
348 {
349 otError error = OT_ERROR_NONE;
350
351 if (aArgs[0].IsEmpty())
352 {
353 if (sDataset.mComponents.mIsExtendedPanIdPresent)
354 {
355 mInterpreter.OutputBytes(sDataset.mExtendedPanId.m8);
356 mInterpreter.OutputLine("");
357 }
358 }
359 else
360 {
361 SuccessOrExit(error = aArgs[0].ParseAsHexString(sDataset.mExtendedPanId.m8));
362 sDataset.mComponents.mIsExtendedPanIdPresent = true;
363 }
364
365 exit:
366 return error;
367 }
368
ProcessMeshLocalPrefix(Arg aArgs[])369 otError Dataset::ProcessMeshLocalPrefix(Arg aArgs[])
370 {
371 otError error = OT_ERROR_NONE;
372
373 if (aArgs[0].IsEmpty())
374 {
375 if (sDataset.mComponents.mIsMeshLocalPrefixPresent)
376 {
377 mInterpreter.OutputFormat("Mesh Local Prefix: ");
378 mInterpreter.OutputPrefix(sDataset.mMeshLocalPrefix);
379 mInterpreter.OutputLine("");
380 }
381 }
382 else
383 {
384 otIp6Address prefix;
385
386 SuccessOrExit(error = aArgs[0].ParseAsIp6Address(prefix));
387
388 memcpy(sDataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(sDataset.mMeshLocalPrefix.m8));
389 sDataset.mComponents.mIsMeshLocalPrefixPresent = true;
390 }
391
392 exit:
393 return error;
394 }
395
ProcessNetworkKey(Arg aArgs[])396 otError Dataset::ProcessNetworkKey(Arg aArgs[])
397 {
398 otError error = OT_ERROR_NONE;
399
400 if (aArgs[0].IsEmpty())
401 {
402 if (sDataset.mComponents.mIsNetworkKeyPresent)
403 {
404 mInterpreter.OutputBytes(sDataset.mNetworkKey.m8);
405 mInterpreter.OutputLine("");
406 }
407 }
408 else
409 {
410 SuccessOrExit(error = aArgs[0].ParseAsHexString(sDataset.mNetworkKey.m8));
411 sDataset.mComponents.mIsNetworkKeyPresent = true;
412 }
413
414 exit:
415 return error;
416 }
417
ProcessNetworkName(Arg aArgs[])418 otError Dataset::ProcessNetworkName(Arg aArgs[])
419 {
420 otError error = OT_ERROR_NONE;
421
422 if (aArgs[0].IsEmpty())
423 {
424 if (sDataset.mComponents.mIsNetworkNamePresent)
425 {
426 mInterpreter.OutputLine("%s", sDataset.mNetworkName.m8);
427 }
428 }
429 else
430 {
431 SuccessOrExit(error = otNetworkNameFromString(&sDataset.mNetworkName, aArgs[0].GetCString()));
432 sDataset.mComponents.mIsNetworkNamePresent = true;
433 }
434
435 exit:
436 return error;
437 }
438
ProcessPanId(Arg aArgs[])439 otError Dataset::ProcessPanId(Arg aArgs[])
440 {
441 otError error = OT_ERROR_NONE;
442
443 if (aArgs[0].IsEmpty())
444 {
445 if (sDataset.mComponents.mIsPanIdPresent)
446 {
447 mInterpreter.OutputLine("0x%04x", sDataset.mPanId);
448 }
449 }
450 else
451 {
452 SuccessOrExit(error = aArgs[0].ParseAsUint16(sDataset.mPanId));
453 sDataset.mComponents.mIsPanIdPresent = true;
454 }
455
456 exit:
457 return error;
458 }
459
ProcessPendingTimestamp(Arg aArgs[])460 otError Dataset::ProcessPendingTimestamp(Arg aArgs[])
461 {
462 otError error = OT_ERROR_NONE;
463
464 if (aArgs[0].IsEmpty())
465 {
466 if (sDataset.mComponents.mIsPendingTimestampPresent)
467 {
468 mInterpreter.OutputLine("%lu", sDataset.mPendingTimestamp);
469 }
470 }
471 else
472 {
473 SuccessOrExit(error = aArgs[0].ParseAsUint64(sDataset.mPendingTimestamp));
474 sDataset.mComponents.mIsPendingTimestampPresent = true;
475 }
476
477 exit:
478 return error;
479 }
480
ProcessMgmtSetCommand(Arg aArgs[])481 otError Dataset::ProcessMgmtSetCommand(Arg aArgs[])
482 {
483 otError error = OT_ERROR_NONE;
484 otOperationalDataset dataset;
485 uint8_t tlvs[128];
486 uint8_t tlvsLength = 0;
487
488 memset(&dataset, 0, sizeof(dataset));
489
490 for (Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++)
491 {
492 if (*arg == "activetimestamp")
493 {
494 arg++;
495 dataset.mComponents.mIsActiveTimestampPresent = true;
496 SuccessOrExit(error = arg->ParseAsUint64(dataset.mActiveTimestamp));
497 }
498 else if (*arg == "pendingtimestamp")
499 {
500 arg++;
501 dataset.mComponents.mIsPendingTimestampPresent = true;
502 SuccessOrExit(error = arg->ParseAsUint64(dataset.mPendingTimestamp));
503 }
504 else if (*arg == "networkkey")
505 {
506 arg++;
507 dataset.mComponents.mIsNetworkKeyPresent = true;
508 SuccessOrExit(error = arg->ParseAsHexString(dataset.mNetworkKey.m8));
509 }
510 else if (*arg == "networkname")
511 {
512 arg++;
513 dataset.mComponents.mIsNetworkNamePresent = true;
514 VerifyOrExit(!arg->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
515 SuccessOrExit(error = otNetworkNameFromString(&dataset.mNetworkName, arg->GetCString()));
516 }
517 else if (*arg == "extpanid")
518 {
519 arg++;
520 dataset.mComponents.mIsExtendedPanIdPresent = true;
521 SuccessOrExit(error = arg->ParseAsHexString(dataset.mExtendedPanId.m8));
522 }
523 else if (*arg == "localprefix")
524 {
525 otIp6Address prefix;
526
527 arg++;
528 dataset.mComponents.mIsMeshLocalPrefixPresent = true;
529 SuccessOrExit(error = arg->ParseAsIp6Address(prefix));
530 memcpy(dataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(dataset.mMeshLocalPrefix.m8));
531 }
532 else if (*arg == "delaytimer")
533 {
534 arg++;
535 dataset.mComponents.mIsDelayPresent = true;
536 SuccessOrExit(error = arg->ParseAsUint32(dataset.mDelay));
537 }
538 else if (*arg == "panid")
539 {
540 arg++;
541 dataset.mComponents.mIsPanIdPresent = true;
542 SuccessOrExit(error = arg->ParseAsUint16(dataset.mPanId));
543 }
544 else if (*arg == "channel")
545 {
546 arg++;
547 dataset.mComponents.mIsChannelPresent = true;
548 SuccessOrExit(error = arg->ParseAsUint16(dataset.mChannel));
549 }
550 else if (*arg == "channelmask")
551 {
552 arg++;
553 dataset.mComponents.mIsChannelMaskPresent = true;
554 SuccessOrExit(error = arg->ParseAsUint32(dataset.mChannelMask));
555 }
556 else if (*arg == "securitypolicy")
557 {
558 arg++;
559 SuccessOrExit(error = ParseSecurityPolicy(dataset.mSecurityPolicy, arg));
560 dataset.mComponents.mIsSecurityPolicyPresent = true;
561 }
562 else if (*arg == "-x")
563 {
564 uint16_t length;
565
566 arg++;
567 length = sizeof(tlvs);
568 SuccessOrExit(error = arg->ParseAsHexString(length, tlvs));
569 tlvsLength = static_cast<uint8_t>(length);
570 }
571 else
572 {
573 ExitNow(error = OT_ERROR_INVALID_ARGS);
574 }
575 }
576
577 if (aArgs[0] == "active")
578 {
579 error = otDatasetSendMgmtActiveSet(mInterpreter.mInstance, &dataset, tlvs, tlvsLength, /* aCallback */ nullptr,
580 /* aContext */ nullptr);
581 }
582 else if (aArgs[0] == "pending")
583 {
584 error = otDatasetSendMgmtPendingSet(mInterpreter.mInstance, &dataset, tlvs, tlvsLength, /* aCallback */ nullptr,
585 /* aContext */ nullptr);
586 }
587 else
588 {
589 error = OT_ERROR_INVALID_ARGS;
590 }
591
592 exit:
593 return error;
594 }
595
ProcessMgmtGetCommand(Arg aArgs[])596 otError Dataset::ProcessMgmtGetCommand(Arg aArgs[])
597 {
598 otError error = OT_ERROR_NONE;
599 otOperationalDatasetComponents datasetComponents;
600 uint8_t tlvs[32];
601 uint8_t tlvsLength = 0;
602 bool destAddrSpecified = false;
603 otIp6Address address;
604
605 memset(&datasetComponents, 0, sizeof(datasetComponents));
606
607 for (Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++)
608 {
609 if (*arg == "activetimestamp")
610 {
611 datasetComponents.mIsActiveTimestampPresent = true;
612 }
613 else if (*arg == "pendingtimestamp")
614 {
615 datasetComponents.mIsPendingTimestampPresent = true;
616 }
617 else if (*arg == "networkkey")
618 {
619 datasetComponents.mIsNetworkKeyPresent = true;
620 }
621 else if (*arg == "networkname")
622 {
623 datasetComponents.mIsNetworkNamePresent = true;
624 }
625 else if (*arg == "extpanid")
626 {
627 datasetComponents.mIsExtendedPanIdPresent = true;
628 }
629 else if (*arg == "localprefix")
630 {
631 datasetComponents.mIsMeshLocalPrefixPresent = true;
632 }
633 else if (*arg == "delaytimer")
634 {
635 datasetComponents.mIsDelayPresent = true;
636 }
637 else if (*arg == "panid")
638 {
639 datasetComponents.mIsPanIdPresent = true;
640 }
641 else if (*arg == "channel")
642 {
643 datasetComponents.mIsChannelPresent = true;
644 }
645 else if (*arg == "securitypolicy")
646 {
647 datasetComponents.mIsSecurityPolicyPresent = true;
648 }
649 else if (*arg == "-x")
650 {
651 uint16_t length;
652
653 arg++;
654 length = sizeof(tlvs);
655 SuccessOrExit(error = arg->ParseAsHexString(length, tlvs));
656 tlvsLength = static_cast<uint8_t>(length);
657 }
658 else if (*arg == "address")
659 {
660 arg++;
661 SuccessOrExit(error = arg->ParseAsIp6Address(address));
662 destAddrSpecified = true;
663 }
664 else
665 {
666 ExitNow(error = OT_ERROR_INVALID_ARGS);
667 }
668 }
669
670 if (aArgs[0] == "active")
671 {
672 error = otDatasetSendMgmtActiveGet(mInterpreter.mInstance, &datasetComponents, tlvs, tlvsLength,
673 destAddrSpecified ? &address : nullptr);
674 }
675 else if (aArgs[0] == "pending")
676 {
677 error = otDatasetSendMgmtPendingGet(mInterpreter.mInstance, &datasetComponents, tlvs, tlvsLength,
678 destAddrSpecified ? &address : nullptr);
679 }
680 else
681 {
682 error = OT_ERROR_INVALID_ARGS;
683 }
684
685 exit:
686 return error;
687 }
688
ProcessPskc(Arg aArgs[])689 otError Dataset::ProcessPskc(Arg aArgs[])
690 {
691 otError error = OT_ERROR_NONE;
692
693 if (aArgs[0].IsEmpty())
694 {
695 if (sDataset.mComponents.mIsPskcPresent)
696 {
697 mInterpreter.OutputBytes(sDataset.mPskc.m8);
698 mInterpreter.OutputLine("");
699 }
700 }
701 else
702 {
703 #if OPENTHREAD_FTD
704 if (aArgs[0] == "-p")
705 {
706 VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
707
708 SuccessOrExit(
709 error = otDatasetGeneratePskc(
710 aArgs[1].GetCString(),
711 (sDataset.mComponents.mIsNetworkNamePresent
712 ? &sDataset.mNetworkName
713 : reinterpret_cast<const otNetworkName *>(otThreadGetNetworkName(mInterpreter.mInstance))),
714 (sDataset.mComponents.mIsExtendedPanIdPresent ? &sDataset.mExtendedPanId
715 : otThreadGetExtendedPanId(mInterpreter.mInstance)),
716 &sDataset.mPskc));
717 }
718 else
719 #endif
720 {
721 SuccessOrExit(error = aArgs[0].ParseAsHexString(sDataset.mPskc.m8));
722 }
723
724 sDataset.mComponents.mIsPskcPresent = true;
725 }
726
727 exit:
728 return error;
729 }
730
OutputSecurityPolicy(const otSecurityPolicy & aSecurityPolicy)731 void Dataset::OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy)
732 {
733 mInterpreter.OutputFormat("%d ", aSecurityPolicy.mRotationTime);
734
735 if (aSecurityPolicy.mObtainNetworkKeyEnabled)
736 {
737 mInterpreter.OutputFormat("o");
738 }
739
740 if (aSecurityPolicy.mNativeCommissioningEnabled)
741 {
742 mInterpreter.OutputFormat("n");
743 }
744
745 if (aSecurityPolicy.mRoutersEnabled)
746 {
747 mInterpreter.OutputFormat("r");
748 }
749
750 if (aSecurityPolicy.mExternalCommissioningEnabled)
751 {
752 mInterpreter.OutputFormat("c");
753 }
754
755 if (aSecurityPolicy.mBeaconsEnabled)
756 {
757 mInterpreter.OutputFormat("b");
758 }
759
760 if (aSecurityPolicy.mCommercialCommissioningEnabled)
761 {
762 mInterpreter.OutputFormat("C");
763 }
764
765 if (aSecurityPolicy.mAutonomousEnrollmentEnabled)
766 {
767 mInterpreter.OutputFormat("e");
768 }
769
770 if (aSecurityPolicy.mNetworkKeyProvisioningEnabled)
771 {
772 mInterpreter.OutputFormat("p");
773 }
774
775 if (aSecurityPolicy.mNonCcmRoutersEnabled)
776 {
777 mInterpreter.OutputFormat("R");
778 }
779 }
780
ParseSecurityPolicy(otSecurityPolicy & aSecurityPolicy,Arg * & aArgs)781 otError Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, Arg *&aArgs)
782 {
783 otError error;
784 otSecurityPolicy policy;
785
786 memset(&policy, 0, sizeof(policy));
787
788 SuccessOrExit(error = aArgs->ParseAsUint16(policy.mRotationTime));
789 aArgs++;
790
791 VerifyOrExit(!aArgs->IsEmpty());
792
793 for (const char *flag = aArgs->GetCString(); *flag != '\0'; flag++)
794 {
795 switch (*flag)
796 {
797 case 'o':
798 policy.mObtainNetworkKeyEnabled = true;
799 break;
800
801 case 'n':
802 policy.mNativeCommissioningEnabled = true;
803 break;
804
805 case 'r':
806 policy.mRoutersEnabled = true;
807 break;
808
809 case 'c':
810 policy.mExternalCommissioningEnabled = true;
811 break;
812
813 case 'b':
814 policy.mBeaconsEnabled = true;
815 break;
816
817 case 'C':
818 policy.mCommercialCommissioningEnabled = true;
819 break;
820
821 case 'e':
822 policy.mAutonomousEnrollmentEnabled = true;
823 break;
824
825 case 'p':
826 policy.mNetworkKeyProvisioningEnabled = true;
827 break;
828
829 case 'R':
830 policy.mNonCcmRoutersEnabled = true;
831 break;
832
833 default:
834 ExitNow(error = OT_ERROR_INVALID_ARGS);
835 }
836 }
837
838 aArgs++;
839
840 exit:
841 if (error == OT_ERROR_NONE)
842 {
843 aSecurityPolicy = policy;
844 }
845
846 return error;
847 }
848
ProcessSecurityPolicy(Arg aArgs[])849 otError Dataset::ProcessSecurityPolicy(Arg aArgs[])
850 {
851 otError error = OT_ERROR_NONE;
852
853 if (aArgs[0].IsEmpty())
854 {
855 if (sDataset.mComponents.mIsSecurityPolicyPresent)
856 {
857 OutputSecurityPolicy(sDataset.mSecurityPolicy);
858 mInterpreter.OutputLine("");
859 }
860 }
861 else
862 {
863 Arg *arg = &aArgs[0];
864
865 SuccessOrExit(error = ParseSecurityPolicy(sDataset.mSecurityPolicy, arg));
866 sDataset.mComponents.mIsSecurityPolicyPresent = true;
867 }
868
869 exit:
870 return error;
871 }
872
ProcessSet(Arg aArgs[])873 otError Dataset::ProcessSet(Arg aArgs[])
874 {
875 otError error = OT_ERROR_NONE;
876 MeshCoP::Dataset::Type datasetType;
877
878 if (aArgs[0] == "active")
879 {
880 datasetType = MeshCoP::Dataset::Type::kActive;
881 }
882 else if (aArgs[0] == "pending")
883 {
884 datasetType = MeshCoP::Dataset::Type::kPending;
885 }
886 else
887 {
888 ExitNow(error = OT_ERROR_INVALID_ARGS);
889 }
890
891 {
892 MeshCoP::Dataset dataset;
893 MeshCoP::Dataset::Info datasetInfo;
894 uint16_t tlvsLength = MeshCoP::Dataset::kMaxSize;
895
896 SuccessOrExit(error = aArgs[1].ParseAsHexString(tlvsLength, dataset.GetBytes()));
897 dataset.SetSize(tlvsLength);
898 VerifyOrExit(dataset.IsValid(), error = OT_ERROR_INVALID_ARGS);
899 dataset.ConvertTo(datasetInfo);
900
901 switch (datasetType)
902 {
903 case MeshCoP::Dataset::Type::kActive:
904 SuccessOrExit(error = otDatasetSetActive(mInterpreter.mInstance, &datasetInfo));
905 break;
906 case MeshCoP::Dataset::Type::kPending:
907 SuccessOrExit(error = otDatasetSetPending(mInterpreter.mInstance, &datasetInfo));
908 break;
909 }
910 }
911
912 exit:
913 return error;
914 }
915
916 #if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD
917
ProcessUpdater(Arg aArgs[])918 otError Dataset::ProcessUpdater(Arg aArgs[])
919 {
920 otError error = OT_ERROR_NONE;
921
922 if (aArgs[0].IsEmpty())
923 {
924 mInterpreter.OutputEnabledDisabledStatus(otDatasetUpdaterIsUpdateOngoing(mInterpreter.mInstance));
925 }
926 else if (aArgs[0] == "start")
927 {
928 error = otDatasetUpdaterRequestUpdate(mInterpreter.mInstance, &sDataset, &Dataset::HandleDatasetUpdater, this);
929 }
930 else if (aArgs[0] == "cancel")
931 {
932 otDatasetUpdaterCancelUpdate(mInterpreter.mInstance);
933 }
934 else
935 {
936 error = OT_ERROR_INVALID_ARGS;
937 }
938
939 return error;
940 }
941
HandleDatasetUpdater(otError aError,void * aContext)942 void Dataset::HandleDatasetUpdater(otError aError, void *aContext)
943 {
944 static_cast<Dataset *>(aContext)->HandleDatasetUpdater(aError);
945 }
946
HandleDatasetUpdater(otError aError)947 void Dataset::HandleDatasetUpdater(otError aError)
948 {
949 mInterpreter.OutputLine("Dataset update complete: %s", otThreadErrorToString(aError));
950 }
951
952 #endif // OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD
953
954 } // namespace Cli
955 } // namespace ot
956