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