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