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/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/notifier.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 = dataset.GetTlv<ChannelMaskTlv>();
230     VerifyOrExit(channelMaskTlv != nullptr, error = kErrorNotFound);
231     VerifyOrExit((mask = channelMaskTlv->GetChannelMask()) != 0);
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;
316 
317     SuccessOrExit(error = aError);
318     VerifyOrExit(Tlv::Find<StateTlv>(*aMessage, state) == kErrorNone, error = kErrorParse);
319 
320     switch (state)
321     {
322     case StateTlv::kReject:
323         error = kErrorRejected;
324         break;
325     case StateTlv::kAccept:
326         error = kErrorNone;
327         break;
328     default:
329         error = kErrorParse;
330         break;
331     }
332 
333 exit:
334     LogInfo("MGMT_SET finished: %s", ErrorToString(error));
335 
336     mMgmtPending = false;
337 
338     if (mMgmtSetCallback.IsSet())
339     {
340         Callback<otDatasetMgmtSetCallback> callbackCopy = mMgmtSetCallback;
341 
342         mMgmtSetCallback.Clear();
343         callbackCopy.Invoke(error);
344     }
345 
346     mTimer.Start(kSendSetDelay);
347 }
348 
HandleGet(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo) const349 void DatasetManager::HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const
350 {
351     Tlv      tlv;
352     uint16_t offset = aMessage.GetOffset();
353     uint8_t  tlvs[Dataset::kMaxGetTypes];
354     uint8_t  length = 0;
355 
356     while (offset < aMessage.GetLength())
357     {
358         SuccessOrExit(aMessage.Read(offset, tlv));
359 
360         if (tlv.GetType() == Tlv::kGet)
361         {
362             length = tlv.GetLength();
363 
364             if (length > (sizeof(tlvs) - 1))
365             {
366                 // leave space for potential DelayTimer type below
367                 length = sizeof(tlvs) - 1;
368             }
369 
370             aMessage.ReadBytes(offset + sizeof(Tlv), tlvs, length);
371             break;
372         }
373 
374         offset += sizeof(tlv) + tlv.GetLength();
375     }
376 
377     // MGMT_PENDING_GET.rsp must include Delay Timer TLV (Thread 1.1.1 Section 8.7.5.4)
378     VerifyOrExit(length > 0 && IsPendingDataset());
379 
380     for (uint8_t i = 0; i < length; i++)
381     {
382         if (tlvs[i] == Tlv::kDelayTimer)
383         {
384             ExitNow();
385         }
386     }
387 
388     tlvs[length++] = Tlv::kDelayTimer;
389 
390 exit:
391     SendGetResponse(aMessage, aMessageInfo, tlvs, length);
392 }
393 
SendGetResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,uint8_t * aTlvs,uint8_t aLength) const394 void DatasetManager::SendGetResponse(const Coap::Message    &aRequest,
395                                      const Ip6::MessageInfo &aMessageInfo,
396                                      uint8_t                *aTlvs,
397                                      uint8_t                 aLength) const
398 {
399     Error          error = kErrorNone;
400     Coap::Message *message;
401     Dataset        dataset;
402 
403     IgnoreError(Read(dataset));
404 
405     message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
406     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
407 
408     if (aLength == 0)
409     {
410         for (const Tlv *cur = dataset.GetTlvsStart(); cur < dataset.GetTlvsEnd(); cur = cur->GetNext())
411         {
412             if (cur->GetType() != Tlv::kNetworkKey || Get<KeyManager>().GetSecurityPolicy().mObtainNetworkKeyEnabled)
413             {
414                 SuccessOrExit(error = cur->AppendTo(*message));
415             }
416         }
417     }
418     else
419     {
420         for (uint8_t index = 0; index < aLength; index++)
421         {
422             const Tlv *tlv;
423 
424             if (aTlvs[index] == Tlv::kNetworkKey && !Get<KeyManager>().GetSecurityPolicy().mObtainNetworkKeyEnabled)
425             {
426                 continue;
427             }
428 
429             if ((tlv = dataset.GetTlv(static_cast<Tlv::Type>(aTlvs[index]))) != nullptr)
430             {
431                 SuccessOrExit(error = tlv->AppendTo(*message));
432             }
433         }
434     }
435 
436     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
437 
438     LogInfo("sent %s dataset get response to %s", (GetType() == Dataset::kActive ? "active" : "pending"),
439             aMessageInfo.GetPeerAddr().ToString().AsCString());
440 
441 exit:
442     FreeMessageOnError(message, error);
443 }
444 
AppendDatasetToMessage(const Dataset::Info & aDatasetInfo,Message & aMessage) const445 Error DatasetManager::AppendDatasetToMessage(const Dataset::Info &aDatasetInfo, Message &aMessage) const
446 {
447     Error   error;
448     Dataset dataset;
449 
450     SuccessOrExit(error = dataset.SetFrom(aDatasetInfo));
451     error = aMessage.AppendBytes(dataset.GetBytes(), dataset.GetSize());
452 
453 exit:
454     return error;
455 }
456 
SendSetRequest(const Dataset::Info & aDatasetInfo,const uint8_t * aTlvs,uint8_t aLength,otDatasetMgmtSetCallback aCallback,void * aContext)457 Error DatasetManager::SendSetRequest(const Dataset::Info     &aDatasetInfo,
458                                      const uint8_t           *aTlvs,
459                                      uint8_t                  aLength,
460                                      otDatasetMgmtSetCallback aCallback,
461                                      void                    *aContext)
462 {
463     Error            error   = kErrorNone;
464     Coap::Message   *message = nullptr;
465     Tmf::MessageInfo messageInfo(GetInstance());
466 
467     VerifyOrExit(!mMgmtPending, error = kErrorBusy);
468 
469     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(IsActiveDataset() ? kUriActiveSet : kUriPendingSet);
470     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
471 
472 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
473 
474     if (Get<Commissioner>().IsActive())
475     {
476         const Tlv *end          = reinterpret_cast<const Tlv *>(aTlvs + aLength);
477         bool       hasSessionId = false;
478 
479         for (const Tlv *cur = reinterpret_cast<const Tlv *>(aTlvs); cur < end; cur = cur->GetNext())
480         {
481             VerifyOrExit((cur + 1) <= end, error = kErrorInvalidArgs);
482 
483             if (cur->GetType() == Tlv::kCommissionerSessionId)
484             {
485                 hasSessionId = true;
486                 break;
487             }
488         }
489 
490         if (!hasSessionId)
491         {
492             SuccessOrExit(error = Tlv::Append<CommissionerSessionIdTlv>(*message, Get<Commissioner>().GetSessionId()));
493         }
494     }
495 
496 #endif // OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
497 
498     SuccessOrExit(error = AppendDatasetToMessage(aDatasetInfo, *message));
499 
500     if (aLength > 0)
501     {
502         SuccessOrExit(error = message->AppendBytes(aTlvs, aLength));
503     }
504 
505     IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
506 
507     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, HandleMgmtSetResponse, this));
508     mMgmtSetCallback.Set(aCallback, aContext);
509     mMgmtPending = true;
510 
511     LogInfo("sent dataset set request to leader");
512 
513 exit:
514     FreeMessageOnError(message, error);
515     return error;
516 }
517 
SendGetRequest(const Dataset::Components & aDatasetComponents,const uint8_t * aTlvTypes,uint8_t aLength,const otIp6Address * aAddress) const518 Error DatasetManager::SendGetRequest(const Dataset::Components &aDatasetComponents,
519                                      const uint8_t             *aTlvTypes,
520                                      uint8_t                    aLength,
521                                      const otIp6Address        *aAddress) const
522 {
523     Error            error = kErrorNone;
524     Coap::Message   *message;
525     Tmf::MessageInfo messageInfo(GetInstance());
526     Tlv              tlv;
527     uint8_t          datasetTlvs[kMaxDatasetTlvs];
528     uint8_t          length;
529 
530     length = 0;
531 
532     if (aDatasetComponents.IsActiveTimestampPresent())
533     {
534         datasetTlvs[length++] = Tlv::kActiveTimestamp;
535     }
536 
537     if (aDatasetComponents.IsPendingTimestampPresent())
538     {
539         datasetTlvs[length++] = Tlv::kPendingTimestamp;
540     }
541 
542     if (aDatasetComponents.IsNetworkKeyPresent())
543     {
544         datasetTlvs[length++] = Tlv::kNetworkKey;
545     }
546 
547     if (aDatasetComponents.IsNetworkNamePresent())
548     {
549         datasetTlvs[length++] = Tlv::kNetworkName;
550     }
551 
552     if (aDatasetComponents.IsExtendedPanIdPresent())
553     {
554         datasetTlvs[length++] = Tlv::kExtendedPanId;
555     }
556 
557     if (aDatasetComponents.IsMeshLocalPrefixPresent())
558     {
559         datasetTlvs[length++] = Tlv::kMeshLocalPrefix;
560     }
561 
562     if (aDatasetComponents.IsDelayPresent())
563     {
564         datasetTlvs[length++] = Tlv::kDelayTimer;
565     }
566 
567     if (aDatasetComponents.IsPanIdPresent())
568     {
569         datasetTlvs[length++] = Tlv::kPanId;
570     }
571 
572     if (aDatasetComponents.IsChannelPresent())
573     {
574         datasetTlvs[length++] = Tlv::kChannel;
575     }
576 
577     if (aDatasetComponents.IsPskcPresent())
578     {
579         datasetTlvs[length++] = Tlv::kPskc;
580     }
581 
582     if (aDatasetComponents.IsSecurityPolicyPresent())
583     {
584         datasetTlvs[length++] = Tlv::kSecurityPolicy;
585     }
586 
587     if (aDatasetComponents.IsChannelMaskPresent())
588     {
589         datasetTlvs[length++] = Tlv::kChannelMask;
590     }
591 
592     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(IsActiveDataset() ? kUriActiveGet : kUriPendingGet);
593     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
594 
595     if (aLength + length > 0)
596     {
597         tlv.SetType(Tlv::kGet);
598         tlv.SetLength(aLength + length);
599         SuccessOrExit(error = message->Append(tlv));
600 
601         if (length > 0)
602         {
603             SuccessOrExit(error = message->AppendBytes(datasetTlvs, length));
604         }
605 
606         if (aLength > 0)
607         {
608             SuccessOrExit(error = message->AppendBytes(aTlvTypes, aLength));
609         }
610     }
611 
612     IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
613 
614     if (aAddress != nullptr)
615     {
616         // Use leader ALOC if `aAddress` is `nullptr`.
617         messageInfo.SetPeerAddr(AsCoreType(aAddress));
618     }
619 
620     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
621 
622     LogInfo("sent dataset get request");
623 
624 exit:
625     FreeMessageOnError(message, error);
626     return error;
627 }
628 
ActiveDatasetManager(Instance & aInstance)629 ActiveDatasetManager::ActiveDatasetManager(Instance &aInstance)
630     : DatasetManager(aInstance, Dataset::kActive, ActiveDatasetManager::HandleTimer)
631 {
632 }
633 
IsPartiallyComplete(void) const634 bool ActiveDatasetManager::IsPartiallyComplete(void) const { return mLocal.IsSaved() && !mTimestampValid; }
635 
IsCommissioned(void) const636 bool ActiveDatasetManager::IsCommissioned(void) const
637 {
638     Dataset::Info datasetInfo;
639     bool          isValid = false;
640 
641     SuccessOrExit(Read(datasetInfo));
642 
643     isValid = (datasetInfo.IsNetworkKeyPresent() && datasetInfo.IsNetworkNamePresent() &&
644                datasetInfo.IsExtendedPanIdPresent() && datasetInfo.IsPanIdPresent() && datasetInfo.IsChannelPresent());
645 
646 exit:
647     return isValid;
648 }
649 
Save(const Timestamp & aTimestamp,const Message & aMessage,uint16_t aOffset,uint16_t aLength)650 Error ActiveDatasetManager::Save(const Timestamp &aTimestamp,
651                                  const Message   &aMessage,
652                                  uint16_t         aOffset,
653                                  uint16_t         aLength)
654 {
655     Error   error = kErrorNone;
656     Dataset dataset;
657 
658     SuccessOrExit(error = dataset.ReadFromMessage(aMessage, aOffset, aLength));
659     dataset.SetTimestamp(Dataset::kActive, aTimestamp);
660     error = DatasetManager::Save(dataset);
661 
662 exit:
663     return error;
664 }
665 
666 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)667 void ActiveDatasetManager::HandleTmf<kUriActiveGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
668 {
669     DatasetManager::HandleGet(aMessage, aMessageInfo);
670 }
671 
HandleTimer(Timer & aTimer)672 void ActiveDatasetManager::HandleTimer(Timer &aTimer) { aTimer.Get<ActiveDatasetManager>().HandleTimer(); }
673 
PendingDatasetManager(Instance & aInstance)674 PendingDatasetManager::PendingDatasetManager(Instance &aInstance)
675     : DatasetManager(aInstance, Dataset::kPending, PendingDatasetManager::HandleTimer)
676     , mDelayTimer(aInstance)
677 {
678 }
679 
Clear(void)680 void PendingDatasetManager::Clear(void)
681 {
682     DatasetManager::Clear();
683     mDelayTimer.Stop();
684 }
685 
ClearNetwork(void)686 void PendingDatasetManager::ClearNetwork(void)
687 {
688     Dataset dataset;
689 
690     mTimestamp.Clear();
691     mTimestampValid = false;
692     IgnoreError(DatasetManager::Save(dataset));
693 }
694 
Save(const Dataset::Info & aDatasetInfo)695 Error PendingDatasetManager::Save(const Dataset::Info &aDatasetInfo)
696 {
697     Error error;
698 
699     SuccessOrExit(error = DatasetManager::Save(aDatasetInfo));
700     StartDelayTimer();
701 
702 exit:
703     return error;
704 }
705 
Save(const otOperationalDatasetTlvs & aDataset)706 Error PendingDatasetManager::Save(const otOperationalDatasetTlvs &aDataset)
707 {
708     Error error;
709 
710     SuccessOrExit(error = DatasetManager::Save(aDataset));
711     StartDelayTimer();
712 
713 exit:
714     return error;
715 }
716 
Save(const Dataset & aDataset)717 Error PendingDatasetManager::Save(const Dataset &aDataset)
718 {
719     Error error;
720 
721     SuccessOrExit(error = DatasetManager::SaveLocal(aDataset));
722     StartDelayTimer();
723 
724 exit:
725     return error;
726 }
727 
Save(const Timestamp & aTimestamp,const Message & aMessage,uint16_t aOffset,uint16_t aLength)728 Error PendingDatasetManager::Save(const Timestamp &aTimestamp,
729                                   const Message   &aMessage,
730                                   uint16_t         aOffset,
731                                   uint16_t         aLength)
732 {
733     Error   error = kErrorNone;
734     Dataset dataset;
735 
736     SuccessOrExit(error = dataset.ReadFromMessage(aMessage, aOffset, aLength));
737     dataset.SetTimestamp(Dataset::kPending, aTimestamp);
738     SuccessOrExit(error = DatasetManager::Save(dataset));
739     StartDelayTimer();
740 
741 exit:
742     return error;
743 }
744 
StartDelayTimer(void)745 void PendingDatasetManager::StartDelayTimer(void)
746 {
747     DelayTimerTlv *delayTimer;
748     Dataset        dataset;
749 
750     IgnoreError(Read(dataset));
751 
752     mDelayTimer.Stop();
753 
754     if ((delayTimer = dataset.GetTlv<DelayTimerTlv>()) != nullptr)
755     {
756         uint32_t delay = delayTimer->GetDelayTimer();
757 
758         // the Timer implementation does not support the full 32 bit range
759         if (delay > Timer::kMaxDelay)
760         {
761             delay = Timer::kMaxDelay;
762         }
763 
764         mDelayTimer.StartAt(dataset.GetUpdateTime(), delay);
765         LogInfo("delay timer started %lu", ToUlong(delay));
766     }
767 }
768 
HandleDelayTimer(void)769 void PendingDatasetManager::HandleDelayTimer(void)
770 {
771     DelayTimerTlv *delayTimer;
772     Dataset        dataset;
773 
774     IgnoreError(Read(dataset));
775 
776     // if the Delay Timer value is larger than what our Timer implementation can handle, we have to compute
777     // the remainder and wait some more.
778     if ((delayTimer = dataset.GetTlv<DelayTimerTlv>()) != nullptr)
779     {
780         uint32_t elapsed = mDelayTimer.GetFireTime() - dataset.GetUpdateTime();
781         uint32_t delay   = delayTimer->GetDelayTimer();
782 
783         if (elapsed < delay)
784         {
785             mDelayTimer.StartAt(mDelayTimer.GetFireTime(), delay - elapsed);
786             ExitNow();
787         }
788     }
789 
790     LogInfo("pending delay timer expired");
791 
792     dataset.ConvertToActive();
793 
794     Get<ActiveDatasetManager>().Save(dataset);
795 
796     Clear();
797 
798 exit:
799     return;
800 }
801 
802 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)803 void PendingDatasetManager::HandleTmf<kUriPendingGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
804 {
805     DatasetManager::HandleGet(aMessage, aMessageInfo);
806 }
807 
HandleTimer(Timer & aTimer)808 void PendingDatasetManager::HandleTimer(Timer &aTimer) { aTimer.Get<PendingDatasetManager>().HandleTimer(); }
809 
810 } // namespace MeshCoP
811 } // namespace ot
812