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 MeshCoP Datasets manager to process commands.
32  *
33  */
34 
35 #include "dataset_manager.hpp"
36 
37 #include <stdio.h>
38 
39 #include "common/as_core_type.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/log.hpp"
42 #include "common/notifier.hpp"
43 #include "instance/instance.hpp"
44 #include "meshcop/meshcop.hpp"
45 #include "meshcop/meshcop_tlvs.hpp"
46 #include "radio/radio.hpp"
47 #include "thread/thread_netif.hpp"
48 #include "thread/thread_tlvs.hpp"
49 #include "thread/uri_paths.hpp"
50 
51 namespace ot {
52 namespace MeshCoP {
53 
54 RegisterLogModule("DatasetManager");
55 
56 //---------------------------------------------------------------------------------------------------------------------
57 // DatasetManager
58 
DatasetManager(Instance & aInstance,Type aType,Timer::Handler aTimerHandler)59 DatasetManager::DatasetManager(Instance &aInstance, Type aType, Timer::Handler aTimerHandler)
60     : InstanceLocator(aInstance)
61     , mType(aType)
62     , mLocalSaved(false)
63     , mMgmtPending(false)
64     , mLocalUpdateTime(0)
65     , mTimer(aInstance, aTimerHandler)
66 {
67     mLocalTimestamp.SetToInvalid();
68     mNetworkTimestamp.SetToInvalid();
69 }
70 
Restore(void)71 Error DatasetManager::Restore(void)
72 {
73     Error   error;
74     Dataset dataset;
75 
76     // If `Read()` fails, `dataset` will remain empty. We still call
77     // `Restore(dataset)` to stop timer and clear the timestamp
78     // flags.
79 
80     error = Read(dataset);
81     Restore(dataset);
82 
83     return error;
84 }
85 
Restore(const Dataset & aDataset)86 void DatasetManager::Restore(const Dataset &aDataset)
87 {
88     mTimer.Stop();
89 
90     mNetworkTimestamp.SetToInvalid();
91     mLocalTimestamp.SetToInvalid();
92 
93     VerifyOrExit(aDataset.GetLength() != 0);
94 
95     mLocalSaved = true;
96 
97     if (aDataset.ReadTimestamp(mType, mLocalTimestamp) == kErrorNone)
98     {
99         mNetworkTimestamp = mLocalTimestamp;
100     }
101 
102     if (IsActiveDataset())
103     {
104         IgnoreError(ApplyConfiguration(aDataset));
105     }
106 
107     SignalDatasetChange();
108 
109 exit:
110     return;
111 }
112 
Read(Dataset & aDataset) const113 Error DatasetManager::Read(Dataset &aDataset) const
114 {
115     Error error;
116 
117     aDataset.Clear();
118 
119     SuccessOrExit(error = Get<Settings>().ReadOperationalDataset(mType, aDataset));
120 
121 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
122     EmplaceSecurelyStoredKeys(aDataset);
123 #endif
124 
125     if (mType == Dataset::kActive)
126     {
127         aDataset.RemoveTlv(Tlv::kPendingTimestamp);
128         aDataset.RemoveTlv(Tlv::kDelayTimer);
129     }
130     else
131     {
132         Tlv *tlv = aDataset.FindTlv(Tlv::kDelayTimer);
133 
134         VerifyOrExit(tlv != nullptr);
135         tlv->WriteValueAs<DelayTimerTlv>(DelayTimerTlv::CalculateRemainingDelay(*tlv, mLocalUpdateTime));
136     }
137 
138     aDataset.mUpdateTime = TimerMilli::GetNow();
139 
140 exit:
141     return error;
142 }
143 
Read(Dataset::Info & aDatasetInfo) const144 Error DatasetManager::Read(Dataset::Info &aDatasetInfo) const
145 {
146     Dataset dataset;
147     Error   error;
148 
149     aDatasetInfo.Clear();
150 
151     SuccessOrExit(error = Read(dataset));
152     dataset.ConvertTo(aDatasetInfo);
153 
154 exit:
155     return error;
156 }
157 
Read(Dataset::Tlvs & aDatasetTlvs) const158 Error DatasetManager::Read(Dataset::Tlvs &aDatasetTlvs) const
159 {
160     Dataset dataset;
161     Error   error;
162 
163     ClearAllBytes(aDatasetTlvs);
164 
165     SuccessOrExit(error = Read(dataset));
166     dataset.ConvertTo(aDatasetTlvs);
167 
168 exit:
169     return error;
170 }
171 
ApplyConfiguration(void) const172 Error DatasetManager::ApplyConfiguration(void) const
173 {
174     Error   error;
175     Dataset dataset;
176 
177     SuccessOrExit(error = Read(dataset));
178     error = ApplyConfiguration(dataset);
179 
180 exit:
181     return error;
182 }
183 
ApplyConfiguration(const Dataset & aDataset) const184 Error DatasetManager::ApplyConfiguration(const Dataset &aDataset) const
185 {
186     Error error = kErrorNone;
187 
188     SuccessOrExit(error = aDataset.ValidateTlvs());
189 
190     for (const Tlv *cur = aDataset.GetTlvsStart(); cur < aDataset.GetTlvsEnd(); cur = cur->GetNext())
191     {
192         switch (cur->GetType())
193         {
194         case Tlv::kChannel:
195         {
196             uint8_t channel = static_cast<uint8_t>(cur->ReadValueAs<ChannelTlv>().GetChannel());
197 
198             error = Get<Mac::Mac>().SetPanChannel(channel);
199 
200             if (error != kErrorNone)
201             {
202                 LogCrit("Failed to set channel to %u when applying dataset: %s", channel, ErrorToString(error));
203             }
204 
205             break;
206         }
207 
208         case Tlv::kPanId:
209             Get<Mac::Mac>().SetPanId(cur->ReadValueAs<PanIdTlv>());
210             break;
211 
212         case Tlv::kExtendedPanId:
213             Get<ExtendedPanIdManager>().SetExtPanId(cur->ReadValueAs<ExtendedPanIdTlv>());
214             break;
215 
216         case Tlv::kNetworkName:
217             IgnoreError(Get<NetworkNameManager>().SetNetworkName(As<NetworkNameTlv>(cur)->GetNetworkName()));
218             break;
219 
220         case Tlv::kNetworkKey:
221             Get<KeyManager>().SetNetworkKey(cur->ReadValueAs<NetworkKeyTlv>());
222             break;
223 
224 #if OPENTHREAD_FTD
225         case Tlv::kPskc:
226             Get<KeyManager>().SetPskc(cur->ReadValueAs<PskcTlv>());
227             break;
228 #endif
229 
230         case Tlv::kMeshLocalPrefix:
231             Get<Mle::MleRouter>().SetMeshLocalPrefix(cur->ReadValueAs<MeshLocalPrefixTlv>());
232             break;
233 
234         case Tlv::kSecurityPolicy:
235             Get<KeyManager>().SetSecurityPolicy(As<SecurityPolicyTlv>(cur)->GetSecurityPolicy());
236             break;
237 
238         default:
239             break;
240         }
241     }
242 
243 exit:
244     return error;
245 }
246 
Clear(void)247 void DatasetManager::Clear(void)
248 {
249     mNetworkTimestamp.SetToInvalid();
250     mLocalTimestamp.SetToInvalid();
251 
252     mLocalSaved = false;
253 
254 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
255     DestroySecurelyStoredKeys();
256 #endif
257     Get<Settings>().DeleteOperationalDataset(mType);
258 
259     mTimer.Stop();
260 
261     if (IsPendingDataset())
262     {
263         Get<PendingDatasetManager>().mDelayTimer.Stop();
264     }
265 
266     SignalDatasetChange();
267 }
268 
Save(const Dataset & aDataset,bool aAllowOlderTimestamp)269 Error DatasetManager::Save(const Dataset &aDataset, bool aAllowOlderTimestamp)
270 {
271     Error error = kErrorNone;
272     int   compare;
273 
274     if ((aDataset.ReadTimestamp(mType, mNetworkTimestamp) == kErrorNone) && IsActiveDataset())
275     {
276         SuccessOrExit(error = ApplyConfiguration(aDataset));
277     }
278 
279     compare = Timestamp::Compare(mNetworkTimestamp, mLocalTimestamp);
280 
281     if ((compare > 0) || aAllowOlderTimestamp)
282     {
283         LocalSave(aDataset);
284 
285 #if OPENTHREAD_FTD
286         Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
287 #endif
288     }
289     else if (compare < 0)
290     {
291         mTimer.Start(kSendSetDelay);
292     }
293 
294     SignalDatasetChange();
295 
296 exit:
297     return error;
298 }
299 
SaveLocal(const Dataset::Info & aDatasetInfo)300 void DatasetManager::SaveLocal(const Dataset::Info &aDatasetInfo)
301 {
302     Dataset dataset;
303 
304     dataset.SetFrom(aDatasetInfo);
305     SaveLocal(dataset);
306 }
307 
SaveLocal(const Dataset::Tlvs & aDatasetTlvs)308 Error DatasetManager::SaveLocal(const Dataset::Tlvs &aDatasetTlvs)
309 {
310     Error   error = kErrorInvalidArgs;
311     Dataset dataset;
312 
313     SuccessOrExit(dataset.SetFrom(aDatasetTlvs));
314     SuccessOrExit(dataset.ValidateTlvs());
315     SaveLocal(dataset);
316     error = kErrorNone;
317 
318 exit:
319     return error;
320 }
321 
SaveLocal(const Dataset & aDataset)322 void DatasetManager::SaveLocal(const Dataset &aDataset)
323 {
324     LocalSave(aDataset);
325 
326     switch (Get<Mle::MleRouter>().GetRole())
327     {
328     case Mle::kRoleDisabled:
329         Restore(aDataset);
330         break;
331 
332     case Mle::kRoleChild:
333         SyncLocalWithLeader(aDataset);
334         break;
335 #if OPENTHREAD_FTD
336     case Mle::kRoleRouter:
337         SyncLocalWithLeader(aDataset);
338         break;
339 
340     case Mle::kRoleLeader:
341         Restore(aDataset);
342         Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
343         break;
344 #endif
345 
346     default:
347         break;
348     }
349 
350     SignalDatasetChange();
351 }
352 
LocalSave(const Dataset & aDataset)353 void DatasetManager::LocalSave(const Dataset &aDataset)
354 {
355 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
356     DestroySecurelyStoredKeys();
357 #endif
358 
359     if (aDataset.GetLength() == 0)
360     {
361         Get<Settings>().DeleteOperationalDataset(mType);
362         mLocalSaved = false;
363         LogInfo("%s dataset deleted", Dataset::TypeToString(mType));
364     }
365     else
366     {
367 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
368         // Store the network key and PSKC in the secure storage instead of settings.
369         Dataset dataset;
370 
371         dataset.SetFrom(aDataset);
372         MoveKeysToSecureStorage(dataset);
373         Get<Settings>().SaveOperationalDataset(mType, dataset);
374 #else
375         Get<Settings>().SaveOperationalDataset(mType, aDataset);
376 #endif
377 
378         mLocalSaved = true;
379         LogInfo("%s dataset set", Dataset::TypeToString(mType));
380     }
381 
382     if (aDataset.ReadTimestamp(mType, mLocalTimestamp) != kErrorNone)
383     {
384         mLocalTimestamp.SetToInvalid();
385     }
386 
387     mLocalUpdateTime = TimerMilli::GetNow();
388 
389     if (IsPendingDataset())
390     {
391         Get<PendingDatasetManager>().StartDelayTimer(aDataset);
392     }
393 }
394 
SignalDatasetChange(void) const395 void DatasetManager::SignalDatasetChange(void) const
396 {
397     Get<Notifier>().Signal(IsActiveDataset() ? kEventActiveDatasetChanged : kEventPendingDatasetChanged);
398 }
399 
GetChannelMask(Mac::ChannelMask & aChannelMask) const400 Error DatasetManager::GetChannelMask(Mac::ChannelMask &aChannelMask) const
401 {
402     Error                 error;
403     const ChannelMaskTlv *channelMaskTlv;
404     uint32_t              mask;
405     Dataset               dataset;
406 
407     SuccessOrExit(error = Read(dataset));
408 
409     channelMaskTlv = As<ChannelMaskTlv>(dataset.FindTlv(Tlv::kChannelMask));
410     VerifyOrExit(channelMaskTlv != nullptr, error = kErrorNotFound);
411     SuccessOrExit(channelMaskTlv->ReadChannelMask(mask));
412 
413     aChannelMask.SetMask(mask & Get<Mac::Mac>().GetSupportedChannelMask().GetMask());
414 
415     VerifyOrExit(!aChannelMask.IsEmpty(), error = kErrorNotFound);
416 
417 exit:
418     return error;
419 }
420 
HandleTimer(void)421 void DatasetManager::HandleTimer(void)
422 {
423     Dataset dataset;
424 
425     SuccessOrExit(Read(dataset));
426     SyncLocalWithLeader(dataset);
427 
428 exit:
429     return;
430 }
431 
SyncLocalWithLeader(const Dataset & aDataset)432 void DatasetManager::SyncLocalWithLeader(const Dataset &aDataset)
433 {
434     // Attempts to synchronize the local Dataset with the leader by
435     // sending `MGMT_SET` command if the local Dataset's timestamp is
436     // newer.
437 
438     Error error = kErrorNone;
439 
440     VerifyOrExit(!mMgmtPending, error = kErrorBusy);
441     VerifyOrExit(Get<Mle::MleRouter>().IsChild() || Get<Mle::MleRouter>().IsRouter(), error = kErrorInvalidState);
442 
443     VerifyOrExit(mNetworkTimestamp < mLocalTimestamp, error = kErrorAlready);
444 
445     if (IsActiveDataset())
446     {
447         Dataset   pendingDataset;
448         Timestamp timestamp;
449 
450         IgnoreError(Get<PendingDatasetManager>().Read(pendingDataset));
451 
452         if ((pendingDataset.Read<ActiveTimestampTlv>(timestamp) == kErrorNone) && (timestamp == mLocalTimestamp))
453         {
454             // Stop registration attempts during dataset transition
455             ExitNow(error = kErrorInvalidState);
456         }
457     }
458 
459     error = SendSetRequest(aDataset);
460 
461 exit:
462     if (error == kErrorNoBufs)
463     {
464         mTimer.Start(kSendSetDelay);
465     }
466 
467     if (error != kErrorAlready)
468     {
469         LogWarnOnError(error, "send Dataset set to leader");
470     }
471 }
472 
SendSetRequest(const Dataset & aDataset)473 Error DatasetManager::SendSetRequest(const Dataset &aDataset)
474 {
475     Error            error   = kErrorNone;
476     Coap::Message   *message = nullptr;
477     Tmf::MessageInfo messageInfo(GetInstance());
478 
479     VerifyOrExit(!mMgmtPending, error = kErrorAlready);
480 
481     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(IsActiveDataset() ? kUriActiveSet : kUriPendingSet);
482     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
483 
484     SuccessOrExit(error = message->AppendBytes(aDataset.GetBytes(), aDataset.GetLength()));
485     messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc();
486 
487     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, HandleMgmtSetResponse, this));
488     mMgmtPending = true;
489 
490     LogInfo("Sent dataset set request to leader");
491 
492 exit:
493     FreeMessageOnError(message, error);
494     return error;
495 }
496 
HandleMgmtSetResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aError)497 void DatasetManager::HandleMgmtSetResponse(void                *aContext,
498                                            otMessage           *aMessage,
499                                            const otMessageInfo *aMessageInfo,
500                                            Error                aError)
501 {
502     static_cast<DatasetManager *>(aContext)->HandleMgmtSetResponse(AsCoapMessagePtr(aMessage),
503                                                                    AsCoreTypePtr(aMessageInfo), aError);
504 }
505 
HandleMgmtSetResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aError)506 void DatasetManager::HandleMgmtSetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aError)
507 {
508     OT_UNUSED_VARIABLE(aMessageInfo);
509 
510     Error   error;
511     uint8_t state = StateTlv::kPending;
512 
513     SuccessOrExit(error = aError);
514     VerifyOrExit(Tlv::Find<StateTlv>(*aMessage, state) == kErrorNone && state != StateTlv::kPending,
515                  error = kErrorParse);
516 
517     if (state == StateTlv::kReject)
518     {
519         error = kErrorRejected;
520     }
521 
522 exit:
523     LogInfo("MGMT_SET finished: %s", error == kErrorNone ? "Accepted" : ErrorToString(error));
524 
525     mMgmtPending = false;
526 
527     mMgmtSetCallback.InvokeAndClearIfSet(error);
528 
529     mTimer.Start(kSendSetDelay);
530 }
531 
HandleGet(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo) const532 void DatasetManager::HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const
533 {
534     Error          error    = kErrorNone;
535     Coap::Message *response = ProcessGetRequest(aMessage, kCheckSecurityPolicyFlags);
536 
537     VerifyOrExit(response != nullptr);
538     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*response, aMessageInfo));
539 
540     LogInfo("sent %s dataset get response to %s", IsActiveDataset() ? "active" : "pending",
541             aMessageInfo.GetPeerAddr().ToString().AsCString());
542 
543 exit:
544     FreeMessageOnError(response, error);
545 }
546 
ProcessGetRequest(const Coap::Message & aRequest,SecurityPolicyCheckMode aCheckMode) const547 Coap::Message *DatasetManager::ProcessGetRequest(const Coap::Message    &aRequest,
548                                                  SecurityPolicyCheckMode aCheckMode) const
549 {
550     // Processes a MGMT_ACTIVE_GET or MGMT_PENDING_GET request
551     // and prepares the response.
552 
553     Error          error    = kErrorNone;
554     Coap::Message *response = nullptr;
555     Dataset        dataset;
556     TlvList        tlvList;
557     OffsetRange    offsetRange;
558 
559     if (Tlv::FindTlvValueOffsetRange(aRequest, Tlv::kGet, offsetRange) == kErrorNone)
560     {
561         while (!offsetRange.IsEmpty())
562         {
563             uint8_t tlvType;
564 
565             IgnoreError(aRequest.Read(offsetRange, tlvType));
566             tlvList.Add(tlvType);
567             offsetRange.AdvanceOffset(sizeof(uint8_t));
568         }
569 
570         // MGMT_PENDING_GET.rsp must include Delay Timer TLV (Thread 1.1.1
571         // Section 8.7.5.4).
572 
573         if (!tlvList.IsEmpty() && IsPendingDataset())
574         {
575             tlvList.Add(Tlv::kDelayTimer);
576         }
577     }
578 
579     // Ignore `Read()` error, since even if no Dataset is saved, we should
580     // respond with an empty one.
581 
582     IgnoreError(Read(dataset));
583 
584     response = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
585     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
586 
587     for (const Tlv *tlv = dataset.GetTlvsStart(); tlv < dataset.GetTlvsEnd(); tlv = tlv->GetNext())
588     {
589         bool shouldAppend = true;
590 
591         if (!tlvList.IsEmpty())
592         {
593             shouldAppend = tlvList.Contains(tlv->GetType());
594         }
595 
596         if ((aCheckMode == kCheckSecurityPolicyFlags) && (tlv->GetType() == Tlv::kNetworkKey) &&
597             !Get<KeyManager>().GetSecurityPolicy().mObtainNetworkKeyEnabled)
598         {
599             shouldAppend = false;
600         }
601 
602         if (shouldAppend)
603         {
604             SuccessOrExit(error = tlv->AppendTo(*response));
605         }
606     }
607 
608 exit:
609     FreeAndNullMessageOnError(response, error);
610     return response;
611 }
612 
SendSetRequest(const Dataset::Info & aDatasetInfo,const uint8_t * aTlvs,uint8_t aLength,MgmtSetCallback aCallback,void * aContext)613 Error DatasetManager::SendSetRequest(const Dataset::Info &aDatasetInfo,
614                                      const uint8_t       *aTlvs,
615                                      uint8_t              aLength,
616                                      MgmtSetCallback      aCallback,
617                                      void                *aContext)
618 {
619     Error   error = kErrorNone;
620     Dataset dataset;
621 
622     dataset.SetFrom(aDatasetInfo);
623     SuccessOrExit(error = dataset.AppendTlvsFrom(aTlvs, aLength));
624 
625 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
626     if (Get<Commissioner>().IsActive() && !dataset.ContainsTlv(Tlv::kCommissionerSessionId))
627     {
628         SuccessOrExit(error = dataset.Write<CommissionerSessionIdTlv>(Get<Commissioner>().GetSessionId()));
629     }
630 #endif
631 
632     SuccessOrExit(error = SendSetRequest(dataset));
633     mMgmtSetCallback.Set(aCallback, aContext);
634 
635 exit:
636     return error;
637 }
638 
SendGetRequest(const Dataset::Components & aDatasetComponents,const uint8_t * aTlvTypes,uint8_t aLength,const otIp6Address * aAddress) const639 Error DatasetManager::SendGetRequest(const Dataset::Components &aDatasetComponents,
640                                      const uint8_t             *aTlvTypes,
641                                      uint8_t                    aLength,
642                                      const otIp6Address        *aAddress) const
643 {
644     Error            error = kErrorNone;
645     Coap::Message   *message;
646     Tmf::MessageInfo messageInfo(GetInstance());
647     TlvList          tlvList;
648 
649     if (aDatasetComponents.IsPresent<Dataset::kActiveTimestamp>())
650     {
651         tlvList.Add(Tlv::kActiveTimestamp);
652     }
653 
654     if (aDatasetComponents.IsPresent<Dataset::kPendingTimestamp>())
655     {
656         tlvList.Add(Tlv::kPendingTimestamp);
657     }
658 
659     if (aDatasetComponents.IsPresent<Dataset::kNetworkKey>())
660     {
661         tlvList.Add(Tlv::kNetworkKey);
662     }
663 
664     if (aDatasetComponents.IsPresent<Dataset::kNetworkName>())
665     {
666         tlvList.Add(Tlv::kNetworkName);
667     }
668 
669     if (aDatasetComponents.IsPresent<Dataset::kExtendedPanId>())
670     {
671         tlvList.Add(Tlv::kExtendedPanId);
672     }
673 
674     if (aDatasetComponents.IsPresent<Dataset::kMeshLocalPrefix>())
675     {
676         tlvList.Add(Tlv::kMeshLocalPrefix);
677     }
678 
679     if (aDatasetComponents.IsPresent<Dataset::kDelay>())
680     {
681         tlvList.Add(Tlv::kDelayTimer);
682     }
683 
684     if (aDatasetComponents.IsPresent<Dataset::kPanId>())
685     {
686         tlvList.Add(Tlv::kPanId);
687     }
688 
689     if (aDatasetComponents.IsPresent<Dataset::kChannel>())
690     {
691         tlvList.Add(Tlv::kChannel);
692     }
693 
694     if (aDatasetComponents.IsPresent<Dataset::kPskc>())
695     {
696         tlvList.Add(Tlv::kPskc);
697     }
698 
699     if (aDatasetComponents.IsPresent<Dataset::kSecurityPolicy>())
700     {
701         tlvList.Add(Tlv::kSecurityPolicy);
702     }
703 
704     if (aDatasetComponents.IsPresent<Dataset::kChannelMask>())
705     {
706         tlvList.Add(Tlv::kChannelMask);
707     }
708 
709     for (uint8_t index = 0; index < aLength; index++)
710     {
711         tlvList.Add(aTlvTypes[index]);
712     }
713 
714     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(IsActiveDataset() ? kUriActiveGet : kUriPendingGet);
715     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
716 
717     if (!tlvList.IsEmpty())
718     {
719         SuccessOrExit(error = Tlv::AppendTlv(*message, Tlv::kGet, tlvList.GetArrayBuffer(), tlvList.GetLength()));
720     }
721 
722     messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc();
723 
724     if (aAddress != nullptr)
725     {
726         // Use leader ALOC if `aAddress` is `nullptr`.
727         messageInfo.SetPeerAddr(AsCoreType(aAddress));
728     }
729 
730     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
731 
732     LogInfo("sent dataset get request");
733 
734 exit:
735     FreeMessageOnError(message, error);
736     return error;
737 }
738 
Add(uint8_t aTlvType)739 void DatasetManager::TlvList::Add(uint8_t aTlvType)
740 {
741     if (!Contains(aTlvType))
742     {
743         IgnoreError(PushBack(aTlvType));
744     }
745 }
746 
747 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
748 
749 const DatasetManager::SecurelyStoredTlv DatasetManager::kSecurelyStoredTlvs[] = {
750     {
751         Tlv::kNetworkKey,
752         Crypto::Storage::kActiveDatasetNetworkKeyRef,
753         Crypto::Storage::kPendingDatasetNetworkKeyRef,
754     },
755     {
756         Tlv::kPskc,
757         Crypto::Storage::kActiveDatasetPskcRef,
758         Crypto::Storage::kPendingDatasetPskcRef,
759     },
760 };
761 
DestroySecurelyStoredKeys(void) const762 void DatasetManager::DestroySecurelyStoredKeys(void) const
763 {
764     for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
765     {
766         Crypto::Storage::DestroyKey(entry.GetKeyRef(mType));
767     }
768 }
769 
MoveKeysToSecureStorage(Dataset & aDataset) const770 void DatasetManager::MoveKeysToSecureStorage(Dataset &aDataset) const
771 {
772     for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
773     {
774         SaveTlvInSecureStorageAndClearValue(aDataset, entry.mTlvType, entry.GetKeyRef(mType));
775     }
776 }
777 
EmplaceSecurelyStoredKeys(Dataset & aDataset) const778 void DatasetManager::EmplaceSecurelyStoredKeys(Dataset &aDataset) const
779 {
780     bool moveKeys = false;
781 
782     // If reading any of the TLVs fails, it indicates they are not yet
783     // stored in secure storage and are still contained in the `Dataset`
784     // read from `Settings`. In this case, we move the keys to secure
785     // storage and then clear them from 'Settings'.
786 
787     for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
788     {
789         if (ReadTlvFromSecureStorage(aDataset, entry.mTlvType, entry.GetKeyRef(mType)) != kErrorNone)
790         {
791             moveKeys = true;
792         }
793     }
794 
795     if (moveKeys)
796     {
797         Dataset dataset;
798 
799         dataset.SetFrom(aDataset);
800         MoveKeysToSecureStorage(dataset);
801         Get<Settings>().SaveOperationalDataset(mType, dataset);
802     }
803 }
804 
SaveTlvInSecureStorageAndClearValue(Dataset & aDataset,Tlv::Type aTlvType,KeyRef aKeyRef) const805 void DatasetManager::SaveTlvInSecureStorageAndClearValue(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const
806 {
807     using namespace ot::Crypto::Storage;
808 
809     Tlv *tlv = aDataset.FindTlv(aTlvType);
810 
811     VerifyOrExit(tlv != nullptr);
812     VerifyOrExit(tlv->GetLength() > 0);
813 
814     SuccessOrAssert(ImportKey(aKeyRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent, tlv->GetValue(),
815                               tlv->GetLength()));
816 
817     memset(tlv->GetValue(), 0, tlv->GetLength());
818 
819 exit:
820     return;
821 }
822 
ReadTlvFromSecureStorage(Dataset & aDataset,Tlv::Type aTlvType,KeyRef aKeyRef) const823 Error DatasetManager::ReadTlvFromSecureStorage(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const
824 {
825     using namespace ot::Crypto::Storage;
826 
827     Error  error = kErrorNone;
828     Tlv   *tlv   = aDataset.FindTlv(aTlvType);
829     size_t readLength;
830 
831     VerifyOrExit(tlv != nullptr);
832     VerifyOrExit(tlv->GetLength() > 0);
833 
834     SuccessOrExit(error = ExportKey(aKeyRef, tlv->GetValue(), tlv->GetLength(), readLength));
835     VerifyOrExit(readLength == tlv->GetLength(), error = OT_ERROR_FAILED);
836 
837 exit:
838     return error;
839 }
840 
841 #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
842 
843 //---------------------------------------------------------------------------------------------------------------------
844 // ActiveDatasetManager
845 
ActiveDatasetManager(Instance & aInstance)846 ActiveDatasetManager::ActiveDatasetManager(Instance &aInstance)
847     : DatasetManager(aInstance, Dataset::kActive, ActiveDatasetManager::HandleTimer)
848 {
849 }
850 
IsPartiallyComplete(void) const851 bool ActiveDatasetManager::IsPartiallyComplete(void) const { return mLocalSaved && !mNetworkTimestamp.IsValid(); }
852 
IsComplete(void) const853 bool ActiveDatasetManager::IsComplete(void) const { return mLocalSaved && mNetworkTimestamp.IsValid(); }
854 
IsCommissioned(void) const855 bool ActiveDatasetManager::IsCommissioned(void) const
856 {
857     static const Tlv::Type kRequiredTlvs[] = {
858         Tlv::kNetworkKey, Tlv::kNetworkName, Tlv::kExtendedPanId, Tlv::kPanId, Tlv::kChannel,
859     };
860 
861     Dataset dataset;
862     bool    isValid = false;
863 
864     SuccessOrExit(Read(dataset));
865     isValid = dataset.ContainsAllTlvs(kRequiredTlvs, sizeof(kRequiredTlvs));
866 
867 exit:
868     return isValid;
869 }
870 
871 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)872 void ActiveDatasetManager::HandleTmf<kUriActiveGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
873 {
874     DatasetManager::HandleGet(aMessage, aMessageInfo);
875 }
876 
HandleTimer(Timer & aTimer)877 void ActiveDatasetManager::HandleTimer(Timer &aTimer) { aTimer.Get<ActiveDatasetManager>().HandleTimer(); }
878 
879 //---------------------------------------------------------------------------------------------------------------------
880 // PendingDatasetManager
881 
PendingDatasetManager(Instance & aInstance)882 PendingDatasetManager::PendingDatasetManager(Instance &aInstance)
883     : DatasetManager(aInstance, Dataset::kPending, PendingDatasetManager::HandleTimer)
884     , mDelayTimer(aInstance)
885 {
886 }
887 
ReadActiveTimestamp(Timestamp & aTimestamp) const888 Error PendingDatasetManager::ReadActiveTimestamp(Timestamp &aTimestamp) const
889 {
890     Error   error = kErrorNotFound;
891     Dataset dataset;
892 
893     SuccessOrExit(Read(dataset));
894 
895     SuccessOrExit(dataset.Read<ActiveTimestampTlv>(aTimestamp));
896     error = kErrorNone;
897 
898 exit:
899     return error;
900 }
901 
ReadRemainingDelay(uint32_t & aRemainingDelay) const902 Error PendingDatasetManager::ReadRemainingDelay(uint32_t &aRemainingDelay) const
903 {
904     Error     error = kErrorNone;
905     TimeMilli now   = TimerMilli::GetNow();
906 
907     aRemainingDelay = 0;
908 
909     VerifyOrExit(mDelayTimer.IsRunning(), error = kErrorNotFound);
910     VerifyOrExit(mDelayTimer.GetFireTime() > now);
911     aRemainingDelay = mDelayTimer.GetFireTime() - now;
912 
913 exit:
914     return error;
915 }
916 
StartDelayTimer(void)917 void PendingDatasetManager::StartDelayTimer(void)
918 {
919     Dataset dataset;
920 
921     mDelayTimer.Stop();
922 
923     SuccessOrExit(Read(dataset));
924     StartDelayTimer(dataset);
925 
926 exit:
927     return;
928 }
929 
StartDelayTimer(const Dataset & aDataset)930 void PendingDatasetManager::StartDelayTimer(const Dataset &aDataset)
931 {
932     uint32_t delay;
933 
934     mDelayTimer.Stop();
935 
936     SuccessOrExit(aDataset.Read<DelayTimerTlv>(delay));
937 
938     delay = Min(delay, DelayTimerTlv::kMaxDelay);
939 
940     mDelayTimer.StartAt(aDataset.GetUpdateTime(), delay);
941     LogInfo("delay timer started %lu", ToUlong(delay));
942 
943 exit:
944     return;
945 }
946 
HandleDelayTimer(void)947 void PendingDatasetManager::HandleDelayTimer(void)
948 {
949     Dataset   dataset;
950     Timestamp activeTimestamp;
951     bool      shouldReplaceActive = false;
952 
953     SuccessOrExit(Read(dataset));
954 
955     LogInfo("Pending delay timer expired");
956 
957     // Determine whether the Pending Dataset should replace the
958     // current Active Dataset. This is allowed if the Pending
959     // Dataset's Active Timestamp is newer, or the Pending Dataset
960     // contains a different key.
961 
962     SuccessOrExit(dataset.Read<ActiveTimestampTlv>(activeTimestamp));
963 
964     if (activeTimestamp > Get<ActiveDatasetManager>().GetTimestamp())
965     {
966         shouldReplaceActive = true;
967     }
968     else
969     {
970         NetworkKey newKey;
971         NetworkKey currentKey;
972 
973         SuccessOrExit(dataset.Read<NetworkKeyTlv>(newKey));
974         Get<KeyManager>().GetNetworkKey(currentKey);
975         shouldReplaceActive = (currentKey != newKey);
976     }
977 
978     VerifyOrExit(shouldReplaceActive);
979 
980     // Convert Pending Dataset to Active by removing the Pending
981     // Timestamp and the Delay Timer TLVs.
982 
983     dataset.RemoveTlv(Tlv::kPendingTimestamp);
984     dataset.RemoveTlv(Tlv::kDelayTimer);
985 
986     IgnoreError(Get<ActiveDatasetManager>().Save(dataset, /* aAllowOlderTimestamp */ true));
987 
988 exit:
989     Clear();
990 }
991 
992 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)993 void PendingDatasetManager::HandleTmf<kUriPendingGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
994 {
995     DatasetManager::HandleGet(aMessage, aMessageInfo);
996 }
997 
HandleTimer(Timer & aTimer)998 void PendingDatasetManager::HandleTimer(Timer &aTimer) { aTimer.Get<PendingDatasetManager>().HandleTimer(); }
999 
1000 } // namespace MeshCoP
1001 } // namespace ot
1002