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