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