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 
DatasetManager(Instance & aInstance,Dataset::Type aType,Timer::Handler aTimerHandler)56 DatasetManager::DatasetManager(Instance &aInstance, Dataset::Type aType, Timer::Handler aTimerHandler)
57     : InstanceLocator(aInstance)
58     , mLocal(aInstance, aType)
59     , mTimestampValid(false)
60     , mMgmtPending(false)
61     , mTimer(aInstance, aTimerHandler)
62 {
63     mTimestamp.Clear();
64 }
65 
GetTimestamp(void) const66 const Timestamp *DatasetManager::GetTimestamp(void) const { return mTimestampValid ? &mTimestamp : nullptr; }
67 
Restore(void)68 Error DatasetManager::Restore(void)
69 {
70     Error   error;
71     Dataset dataset;
72 
73     mTimer.Stop();
74 
75     mTimestampValid = false;
76 
77     SuccessOrExit(error = mLocal.Restore(dataset));
78 
79     mTimestampValid = (dataset.GetTimestamp(GetType(), mTimestamp) == kErrorNone);
80 
81     if (IsActiveDataset())
82     {
83         IgnoreError(dataset.ApplyConfiguration(GetInstance()));
84     }
85 
86     SignalDatasetChange();
87 
88 exit:
89     return error;
90 }
91 
ApplyConfiguration(void) const92 Error DatasetManager::ApplyConfiguration(void) const
93 {
94     Error   error;
95     Dataset dataset;
96 
97     SuccessOrExit(error = Read(dataset));
98     SuccessOrExit(error = dataset.ApplyConfiguration(GetInstance()));
99 
100 exit:
101     return error;
102 }
103 
Clear(void)104 void DatasetManager::Clear(void)
105 {
106     mTimestamp.Clear();
107     mTimestampValid = false;
108     mLocal.Clear();
109     mTimer.Stop();
110     SignalDatasetChange();
111 }
112 
HandleDetach(void)113 void DatasetManager::HandleDetach(void) { IgnoreError(Restore()); }
114 
Save(const Dataset & aDataset)115 Error DatasetManager::Save(const Dataset &aDataset)
116 {
117     Error error = kErrorNone;
118     int   compare;
119     bool  isNetworkKeyUpdated = false;
120 
121     if (aDataset.GetTimestamp(GetType(), mTimestamp) == kErrorNone)
122     {
123         mTimestampValid = true;
124 
125         if (IsActiveDataset())
126         {
127             SuccessOrExit(error = aDataset.ApplyConfiguration(GetInstance(), &isNetworkKeyUpdated));
128         }
129     }
130 
131     compare = Timestamp::Compare(mTimestampValid ? &mTimestamp : nullptr, mLocal.GetTimestamp());
132 
133     if (isNetworkKeyUpdated || compare > 0)
134     {
135         SuccessOrExit(error = mLocal.Save(aDataset));
136 
137 #if OPENTHREAD_FTD
138         Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
139 #endif
140     }
141     else if (compare < 0)
142     {
143         mTimer.Start(kSendSetDelay);
144     }
145 
146     SignalDatasetChange();
147 
148 exit:
149     return error;
150 }
151 
Save(const Dataset::Info & aDatasetInfo)152 Error DatasetManager::Save(const Dataset::Info &aDatasetInfo)
153 {
154     Error error;
155 
156     SuccessOrExit(error = mLocal.Save(aDatasetInfo));
157     HandleDatasetUpdated();
158 
159 exit:
160     return error;
161 }
162 
Save(const otOperationalDatasetTlvs & aDataset)163 Error DatasetManager::Save(const otOperationalDatasetTlvs &aDataset)
164 {
165     Error error;
166 
167     SuccessOrExit(error = mLocal.Save(aDataset));
168     HandleDatasetUpdated();
169 
170 exit:
171     return error;
172 }
173 
SaveLocal(const Dataset & aDataset)174 Error DatasetManager::SaveLocal(const Dataset &aDataset)
175 {
176     Error error;
177 
178     SuccessOrExit(error = mLocal.Save(aDataset));
179     HandleDatasetUpdated();
180 
181 exit:
182     return error;
183 }
184 
HandleDatasetUpdated(void)185 void DatasetManager::HandleDatasetUpdated(void)
186 {
187     switch (Get<Mle::MleRouter>().GetRole())
188     {
189     case Mle::kRoleDisabled:
190         IgnoreError(Restore());
191         break;
192 
193     case Mle::kRoleChild:
194         SendSet();
195         break;
196 #if OPENTHREAD_FTD
197     case Mle::kRoleRouter:
198         SendSet();
199         break;
200 
201     case Mle::kRoleLeader:
202         IgnoreError(Restore());
203         Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
204         break;
205 #endif
206 
207     default:
208         break;
209     }
210 
211     SignalDatasetChange();
212 }
213 
SignalDatasetChange(void) const214 void DatasetManager::SignalDatasetChange(void) const
215 {
216     Get<Notifier>().Signal(mLocal.GetType() == Dataset::kActive ? kEventActiveDatasetChanged
217                                                                 : kEventPendingDatasetChanged);
218 }
219 
GetChannelMask(Mac::ChannelMask & aChannelMask) const220 Error DatasetManager::GetChannelMask(Mac::ChannelMask &aChannelMask) const
221 {
222     Error                 error;
223     const ChannelMaskTlv *channelMaskTlv;
224     uint32_t              mask;
225     Dataset               dataset;
226 
227     SuccessOrExit(error = Read(dataset));
228 
229     channelMaskTlv = As<ChannelMaskTlv>(dataset.FindTlv(Tlv::kChannelMask));
230     VerifyOrExit(channelMaskTlv != nullptr, error = kErrorNotFound);
231     SuccessOrExit(channelMaskTlv->ReadChannelMask(mask));
232 
233     aChannelMask.SetMask(mask & Get<Mac::Mac>().GetSupportedChannelMask().GetMask());
234 
235     VerifyOrExit(!aChannelMask.IsEmpty(), error = kErrorNotFound);
236 
237 exit:
238     return error;
239 }
240 
HandleTimer(void)241 void DatasetManager::HandleTimer(void) { SendSet(); }
242 
SendSet(void)243 void DatasetManager::SendSet(void)
244 {
245     Error            error;
246     Coap::Message   *message = nullptr;
247     Tmf::MessageInfo messageInfo(GetInstance());
248     Dataset          dataset;
249 
250     VerifyOrExit(!mMgmtPending, error = kErrorBusy);
251     VerifyOrExit(Get<Mle::MleRouter>().IsChild() || Get<Mle::MleRouter>().IsRouter(), error = kErrorInvalidState);
252 
253     VerifyOrExit(Timestamp::Compare(GetTimestamp(), mLocal.GetTimestamp()) < 0, error = kErrorAlready);
254 
255     if (IsActiveDataset())
256     {
257         Dataset   pendingDataset;
258         Timestamp timestamp;
259 
260         IgnoreError(Get<PendingDatasetManager>().Read(pendingDataset));
261 
262         if ((pendingDataset.GetTimestamp(Dataset::kActive, timestamp) == kErrorNone) &&
263             (Timestamp::Compare(&timestamp, mLocal.GetTimestamp()) == 0))
264         {
265             // stop registration attempts during dataset transition
266             ExitNow(error = kErrorInvalidState);
267         }
268     }
269 
270     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(IsActiveDataset() ? kUriActiveSet : kUriPendingSet);
271     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
272 
273     IgnoreError(Read(dataset));
274     SuccessOrExit(error = message->AppendBytes(dataset.GetBytes(), dataset.GetSize()));
275 
276     IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
277     SuccessOrExit(
278         error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, &DatasetManager::HandleMgmtSetResponse, this));
279 
280     LogInfo("Sent %s set to leader", Dataset::TypeToString(GetType()));
281 
282 exit:
283 
284     switch (error)
285     {
286     case kErrorNone:
287         mMgmtPending = true;
288         break;
289 
290     case kErrorNoBufs:
291         mTimer.Start(kSendSetDelay);
292         OT_FALL_THROUGH;
293 
294     default:
295         LogError("send Dataset set to leader", error);
296         FreeMessage(message);
297         break;
298     }
299 }
300 
HandleMgmtSetResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aError)301 void DatasetManager::HandleMgmtSetResponse(void                *aContext,
302                                            otMessage           *aMessage,
303                                            const otMessageInfo *aMessageInfo,
304                                            Error                aError)
305 {
306     static_cast<DatasetManager *>(aContext)->HandleMgmtSetResponse(AsCoapMessagePtr(aMessage),
307                                                                    AsCoreTypePtr(aMessageInfo), aError);
308 }
309 
HandleMgmtSetResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aError)310 void DatasetManager::HandleMgmtSetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aError)
311 {
312     OT_UNUSED_VARIABLE(aMessageInfo);
313 
314     Error   error;
315     uint8_t state = StateTlv::kPending;
316 
317     SuccessOrExit(error = aError);
318     VerifyOrExit(Tlv::Find<StateTlv>(*aMessage, state) == kErrorNone && state != StateTlv::kPending,
319                  error = kErrorParse);
320     if (state == StateTlv::kReject)
321     {
322         error = kErrorRejected;
323     }
324 
325 exit:
326     LogInfo("MGMT_SET finished: %s", error == kErrorNone ? "Accepted" : ErrorToString(error));
327 
328     mMgmtPending = false;
329 
330     if (mMgmtSetCallback.IsSet())
331     {
332         Callback<otDatasetMgmtSetCallback> callbackCopy = mMgmtSetCallback;
333 
334         mMgmtSetCallback.Clear();
335         callbackCopy.Invoke(error);
336     }
337 
338     mTimer.Start(kSendSetDelay);
339 }
340 
HandleGet(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo) const341 void DatasetManager::HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const
342 {
343     Tlv      tlv;
344     uint16_t offset = aMessage.GetOffset();
345     uint8_t  tlvs[Dataset::kMaxGetTypes];
346     uint8_t  length = 0;
347 
348     while (offset < aMessage.GetLength())
349     {
350         SuccessOrExit(aMessage.Read(offset, tlv));
351 
352         if (tlv.GetType() == Tlv::kGet)
353         {
354             length = tlv.GetLength();
355 
356             if (length > (sizeof(tlvs) - 1))
357             {
358                 // leave space for potential DelayTimer type below
359                 length = sizeof(tlvs) - 1;
360             }
361 
362             aMessage.ReadBytes(offset + sizeof(Tlv), tlvs, length);
363             break;
364         }
365 
366         offset += sizeof(tlv) + tlv.GetLength();
367     }
368 
369     // MGMT_PENDING_GET.rsp must include Delay Timer TLV (Thread 1.1.1 Section 8.7.5.4)
370     VerifyOrExit(length > 0 && IsPendingDataset());
371 
372     for (uint8_t i = 0; i < length; i++)
373     {
374         if (tlvs[i] == Tlv::kDelayTimer)
375         {
376             ExitNow();
377         }
378     }
379 
380     tlvs[length++] = Tlv::kDelayTimer;
381 
382 exit:
383     SendGetResponse(aMessage, aMessageInfo, tlvs, length);
384 }
385 
SendGetResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,uint8_t * aTlvs,uint8_t aLength) const386 void DatasetManager::SendGetResponse(const Coap::Message    &aRequest,
387                                      const Ip6::MessageInfo &aMessageInfo,
388                                      uint8_t                *aTlvs,
389                                      uint8_t                 aLength) const
390 {
391     Error          error = kErrorNone;
392     Coap::Message *message;
393     Dataset        dataset;
394 
395     IgnoreError(Read(dataset));
396 
397     message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
398     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
399 
400     if (aLength == 0)
401     {
402         for (const Tlv *cur = dataset.GetTlvsStart(); cur < dataset.GetTlvsEnd(); cur = cur->GetNext())
403         {
404             if (cur->GetType() != Tlv::kNetworkKey || Get<KeyManager>().GetSecurityPolicy().mObtainNetworkKeyEnabled)
405             {
406                 SuccessOrExit(error = cur->AppendTo(*message));
407             }
408         }
409     }
410     else
411     {
412         for (uint8_t index = 0; index < aLength; index++)
413         {
414             const Tlv *tlv;
415 
416             if (aTlvs[index] == Tlv::kNetworkKey && !Get<KeyManager>().GetSecurityPolicy().mObtainNetworkKeyEnabled)
417             {
418                 continue;
419             }
420 
421             if ((tlv = dataset.FindTlv(static_cast<Tlv::Type>(aTlvs[index]))) != nullptr)
422             {
423                 SuccessOrExit(error = tlv->AppendTo(*message));
424             }
425         }
426     }
427 
428     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
429 
430     LogInfo("sent %s dataset get response to %s", (GetType() == Dataset::kActive ? "active" : "pending"),
431             aMessageInfo.GetPeerAddr().ToString().AsCString());
432 
433 exit:
434     FreeMessageOnError(message, error);
435 }
436 
AppendDatasetToMessage(const Dataset::Info & aDatasetInfo,Message & aMessage) const437 Error DatasetManager::AppendDatasetToMessage(const Dataset::Info &aDatasetInfo, Message &aMessage) const
438 {
439     Error   error;
440     Dataset dataset;
441 
442     SuccessOrExit(error = dataset.SetFrom(aDatasetInfo));
443     error = aMessage.AppendBytes(dataset.GetBytes(), dataset.GetSize());
444 
445 exit:
446     return error;
447 }
448 
SendSetRequest(const Dataset::Info & aDatasetInfo,const uint8_t * aTlvs,uint8_t aLength,otDatasetMgmtSetCallback aCallback,void * aContext)449 Error DatasetManager::SendSetRequest(const Dataset::Info     &aDatasetInfo,
450                                      const uint8_t           *aTlvs,
451                                      uint8_t                  aLength,
452                                      otDatasetMgmtSetCallback aCallback,
453                                      void                    *aContext)
454 {
455     Error            error   = kErrorNone;
456     Coap::Message   *message = nullptr;
457     Tmf::MessageInfo messageInfo(GetInstance());
458 
459     VerifyOrExit(!mMgmtPending, error = kErrorBusy);
460 
461     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(IsActiveDataset() ? kUriActiveSet : kUriPendingSet);
462     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
463 
464 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
465 
466     if (Get<Commissioner>().IsActive())
467     {
468         const Tlv *end          = reinterpret_cast<const Tlv *>(aTlvs + aLength);
469         bool       hasSessionId = false;
470 
471         for (const Tlv *cur = reinterpret_cast<const Tlv *>(aTlvs); cur < end; cur = cur->GetNext())
472         {
473             VerifyOrExit((cur + 1) <= end, error = kErrorInvalidArgs);
474 
475             if (cur->GetType() == Tlv::kCommissionerSessionId)
476             {
477                 hasSessionId = true;
478                 break;
479             }
480         }
481 
482         if (!hasSessionId)
483         {
484             SuccessOrExit(error = Tlv::Append<CommissionerSessionIdTlv>(*message, Get<Commissioner>().GetSessionId()));
485         }
486     }
487 
488 #endif // OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
489 
490     SuccessOrExit(error = AppendDatasetToMessage(aDatasetInfo, *message));
491 
492     if (aLength > 0)
493     {
494         SuccessOrExit(error = message->AppendBytes(aTlvs, aLength));
495     }
496 
497     IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
498 
499     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, HandleMgmtSetResponse, this));
500     mMgmtSetCallback.Set(aCallback, aContext);
501     mMgmtPending = true;
502 
503     LogInfo("sent dataset set request to leader");
504 
505 exit:
506     FreeMessageOnError(message, error);
507     return error;
508 }
509 
SendGetRequest(const Dataset::Components & aDatasetComponents,const uint8_t * aTlvTypes,uint8_t aLength,const otIp6Address * aAddress) const510 Error DatasetManager::SendGetRequest(const Dataset::Components &aDatasetComponents,
511                                      const uint8_t             *aTlvTypes,
512                                      uint8_t                    aLength,
513                                      const otIp6Address        *aAddress) const
514 {
515     Error            error = kErrorNone;
516     Coap::Message   *message;
517     Tmf::MessageInfo messageInfo(GetInstance());
518     Tlv              tlv;
519     uint8_t          datasetTlvs[kMaxDatasetTlvs];
520     uint8_t          length;
521 
522     length = 0;
523 
524     if (aDatasetComponents.IsActiveTimestampPresent())
525     {
526         datasetTlvs[length++] = Tlv::kActiveTimestamp;
527     }
528 
529     if (aDatasetComponents.IsPendingTimestampPresent())
530     {
531         datasetTlvs[length++] = Tlv::kPendingTimestamp;
532     }
533 
534     if (aDatasetComponents.IsNetworkKeyPresent())
535     {
536         datasetTlvs[length++] = Tlv::kNetworkKey;
537     }
538 
539     if (aDatasetComponents.IsNetworkNamePresent())
540     {
541         datasetTlvs[length++] = Tlv::kNetworkName;
542     }
543 
544     if (aDatasetComponents.IsExtendedPanIdPresent())
545     {
546         datasetTlvs[length++] = Tlv::kExtendedPanId;
547     }
548 
549     if (aDatasetComponents.IsMeshLocalPrefixPresent())
550     {
551         datasetTlvs[length++] = Tlv::kMeshLocalPrefix;
552     }
553 
554     if (aDatasetComponents.IsDelayPresent())
555     {
556         datasetTlvs[length++] = Tlv::kDelayTimer;
557     }
558 
559     if (aDatasetComponents.IsPanIdPresent())
560     {
561         datasetTlvs[length++] = Tlv::kPanId;
562     }
563 
564     if (aDatasetComponents.IsChannelPresent())
565     {
566         datasetTlvs[length++] = Tlv::kChannel;
567     }
568 
569     if (aDatasetComponents.IsPskcPresent())
570     {
571         datasetTlvs[length++] = Tlv::kPskc;
572     }
573 
574     if (aDatasetComponents.IsSecurityPolicyPresent())
575     {
576         datasetTlvs[length++] = Tlv::kSecurityPolicy;
577     }
578 
579     if (aDatasetComponents.IsChannelMaskPresent())
580     {
581         datasetTlvs[length++] = Tlv::kChannelMask;
582     }
583 
584     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(IsActiveDataset() ? kUriActiveGet : kUriPendingGet);
585     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
586 
587     if (aLength + length > 0)
588     {
589         tlv.SetType(Tlv::kGet);
590         tlv.SetLength(aLength + length);
591         SuccessOrExit(error = message->Append(tlv));
592 
593         if (length > 0)
594         {
595             SuccessOrExit(error = message->AppendBytes(datasetTlvs, length));
596         }
597 
598         if (aLength > 0)
599         {
600             SuccessOrExit(error = message->AppendBytes(aTlvTypes, aLength));
601         }
602     }
603 
604     IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
605 
606     if (aAddress != nullptr)
607     {
608         // Use leader ALOC if `aAddress` is `nullptr`.
609         messageInfo.SetPeerAddr(AsCoreType(aAddress));
610     }
611 
612     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
613 
614     LogInfo("sent dataset get request");
615 
616 exit:
617     FreeMessageOnError(message, error);
618     return error;
619 }
620 
ActiveDatasetManager(Instance & aInstance)621 ActiveDatasetManager::ActiveDatasetManager(Instance &aInstance)
622     : DatasetManager(aInstance, Dataset::kActive, ActiveDatasetManager::HandleTimer)
623 {
624 }
625 
IsPartiallyComplete(void) const626 bool ActiveDatasetManager::IsPartiallyComplete(void) const { return mLocal.IsSaved() && !mTimestampValid; }
627 
IsComplete(void) const628 bool ActiveDatasetManager::IsComplete(void) const { return mLocal.IsSaved() && mTimestampValid; }
629 
IsCommissioned(void) const630 bool ActiveDatasetManager::IsCommissioned(void) const
631 {
632     Dataset::Info datasetInfo;
633     bool          isValid = false;
634 
635     SuccessOrExit(Read(datasetInfo));
636 
637     isValid = (datasetInfo.IsNetworkKeyPresent() && datasetInfo.IsNetworkNamePresent() &&
638                datasetInfo.IsExtendedPanIdPresent() && datasetInfo.IsPanIdPresent() && datasetInfo.IsChannelPresent());
639 
640 exit:
641     return isValid;
642 }
643 
Save(const Timestamp & aTimestamp,const Message & aMessage,uint16_t aOffset,uint16_t aLength)644 Error ActiveDatasetManager::Save(const Timestamp &aTimestamp,
645                                  const Message   &aMessage,
646                                  uint16_t         aOffset,
647                                  uint16_t         aLength)
648 {
649     Error   error = kErrorNone;
650     Dataset dataset;
651 
652     SuccessOrExit(error = dataset.ReadFromMessage(aMessage, aOffset, aLength));
653     dataset.SetTimestamp(Dataset::kActive, aTimestamp);
654     error = DatasetManager::Save(dataset);
655 
656 exit:
657     return error;
658 }
659 
660 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)661 void ActiveDatasetManager::HandleTmf<kUriActiveGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
662 {
663     DatasetManager::HandleGet(aMessage, aMessageInfo);
664 }
665 
HandleTimer(Timer & aTimer)666 void ActiveDatasetManager::HandleTimer(Timer &aTimer) { aTimer.Get<ActiveDatasetManager>().HandleTimer(); }
667 
PendingDatasetManager(Instance & aInstance)668 PendingDatasetManager::PendingDatasetManager(Instance &aInstance)
669     : DatasetManager(aInstance, Dataset::kPending, PendingDatasetManager::HandleTimer)
670     , mDelayTimer(aInstance)
671 {
672 }
673 
Clear(void)674 void PendingDatasetManager::Clear(void)
675 {
676     DatasetManager::Clear();
677     mDelayTimer.Stop();
678 }
679 
ClearNetwork(void)680 void PendingDatasetManager::ClearNetwork(void)
681 {
682     Dataset dataset;
683 
684     mTimestamp.Clear();
685     mTimestampValid = false;
686     IgnoreError(DatasetManager::Save(dataset));
687 }
688 
Save(const Dataset::Info & aDatasetInfo)689 Error PendingDatasetManager::Save(const Dataset::Info &aDatasetInfo)
690 {
691     Error error;
692 
693     SuccessOrExit(error = DatasetManager::Save(aDatasetInfo));
694     StartDelayTimer();
695 
696 exit:
697     return error;
698 }
699 
Save(const otOperationalDatasetTlvs & aDataset)700 Error PendingDatasetManager::Save(const otOperationalDatasetTlvs &aDataset)
701 {
702     Error error;
703 
704     SuccessOrExit(error = DatasetManager::Save(aDataset));
705     StartDelayTimer();
706 
707 exit:
708     return error;
709 }
710 
Save(const Dataset & aDataset)711 Error PendingDatasetManager::Save(const Dataset &aDataset)
712 {
713     Error error;
714 
715     SuccessOrExit(error = DatasetManager::SaveLocal(aDataset));
716     StartDelayTimer();
717 
718 exit:
719     return error;
720 }
721 
Save(const Timestamp & aTimestamp,const Message & aMessage,uint16_t aOffset,uint16_t aLength)722 Error PendingDatasetManager::Save(const Timestamp &aTimestamp,
723                                   const Message   &aMessage,
724                                   uint16_t         aOffset,
725                                   uint16_t         aLength)
726 {
727     Error   error = kErrorNone;
728     Dataset dataset;
729 
730     SuccessOrExit(error = dataset.ReadFromMessage(aMessage, aOffset, aLength));
731     dataset.SetTimestamp(Dataset::kPending, aTimestamp);
732     SuccessOrExit(error = DatasetManager::Save(dataset));
733     StartDelayTimer();
734 
735 exit:
736     return error;
737 }
738 
StartDelayTimer(void)739 void PendingDatasetManager::StartDelayTimer(void)
740 {
741     Tlv     *tlv;
742     uint32_t delay;
743     Dataset  dataset;
744 
745     IgnoreError(Read(dataset));
746 
747     mDelayTimer.Stop();
748 
749     tlv = dataset.FindTlv(Tlv::kDelayTimer);
750     VerifyOrExit(tlv != nullptr);
751 
752     delay = tlv->ReadValueAs<DelayTimerTlv>();
753 
754     // the Timer implementation does not support the full 32 bit range
755     delay = Min(delay, Timer::kMaxDelay);
756 
757     mDelayTimer.StartAt(dataset.GetUpdateTime(), delay);
758     LogInfo("delay timer started %lu", ToUlong(delay));
759 
760 exit:
761     return;
762 }
763 
HandleDelayTimer(void)764 void PendingDatasetManager::HandleDelayTimer(void)
765 {
766     Tlv    *tlv;
767     Dataset dataset;
768 
769     IgnoreError(Read(dataset));
770 
771     // if the Delay Timer value is larger than what our Timer implementation can handle, we have to compute
772     // the remainder and wait some more.
773     if ((tlv = dataset.FindTlv(Tlv::kDelayTimer)) != nullptr)
774     {
775         uint32_t elapsed = mDelayTimer.GetFireTime() - dataset.GetUpdateTime();
776         uint32_t delay   = tlv->ReadValueAs<DelayTimerTlv>();
777 
778         if (elapsed < delay)
779         {
780             mDelayTimer.StartAt(mDelayTimer.GetFireTime(), delay - elapsed);
781             ExitNow();
782         }
783     }
784 
785     LogInfo("pending delay timer expired");
786 
787     dataset.ConvertToActive();
788 
789     Get<ActiveDatasetManager>().Save(dataset);
790 
791     Clear();
792 
793 exit:
794     return;
795 }
796 
797 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)798 void PendingDatasetManager::HandleTmf<kUriPendingGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
799 {
800     DatasetManager::HandleGet(aMessage, aMessageInfo);
801 }
802 
HandleTimer(Timer & aTimer)803 void PendingDatasetManager::HandleTimer(Timer &aTimer) { aTimer.Get<PendingDatasetManager>().HandleTimer(); }
804 
805 } // namespace MeshCoP
806 } // namespace ot
807