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