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(×tamp, 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