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