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