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