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