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 #include "dataset_manager.hpp"
35
36 #include "instance/instance.hpp"
37
38 namespace ot {
39 namespace MeshCoP {
40
41 RegisterLogModule("DatasetManager");
42
43 //---------------------------------------------------------------------------------------------------------------------
44 // DatasetManager
45
DatasetManager(Instance & aInstance,Type aType,Timer::Handler aTimerHandler)46 DatasetManager::DatasetManager(Instance &aInstance, Type aType, Timer::Handler aTimerHandler)
47 : InstanceLocator(aInstance)
48 , mType(aType)
49 , mLocalSaved(false)
50 , mMgmtPending(false)
51 , mLocalUpdateTime(0)
52 , mTimer(aInstance, aTimerHandler)
53 {
54 mLocalTimestamp.SetToInvalid();
55 mNetworkTimestamp.SetToInvalid();
56 }
57
Restore(void)58 Error DatasetManager::Restore(void)
59 {
60 Error error;
61 Dataset dataset;
62
63 // If `Read()` fails, `dataset` will remain empty. We still call
64 // `Restore(dataset)` to stop timer and clear the timestamp
65 // flags.
66
67 error = Read(dataset);
68 Restore(dataset);
69
70 return error;
71 }
72
Restore(const Dataset & aDataset)73 void DatasetManager::Restore(const Dataset &aDataset)
74 {
75 mTimer.Stop();
76
77 mNetworkTimestamp.SetToInvalid();
78 mLocalTimestamp.SetToInvalid();
79
80 VerifyOrExit(aDataset.GetLength() != 0);
81
82 mLocalSaved = true;
83
84 if (aDataset.ReadTimestamp(mType, mLocalTimestamp) == kErrorNone)
85 {
86 mNetworkTimestamp = mLocalTimestamp;
87 }
88
89 if (IsActiveDataset())
90 {
91 IgnoreError(ApplyConfiguration(aDataset));
92 }
93
94 SignalDatasetChange();
95
96 exit:
97 return;
98 }
99
Read(Dataset & aDataset) const100 Error DatasetManager::Read(Dataset &aDataset) const
101 {
102 Error error;
103
104 aDataset.Clear();
105
106 SuccessOrExit(error = Get<Settings>().ReadOperationalDataset(mType, aDataset));
107
108 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
109 EmplaceSecurelyStoredKeys(aDataset);
110 #endif
111
112 if (mType == Dataset::kActive)
113 {
114 aDataset.RemoveTlv(Tlv::kPendingTimestamp);
115 aDataset.RemoveTlv(Tlv::kDelayTimer);
116 }
117 else
118 {
119 Tlv *tlv = aDataset.FindTlv(Tlv::kDelayTimer);
120
121 VerifyOrExit(tlv != nullptr);
122 tlv->WriteValueAs<DelayTimerTlv>(DelayTimerTlv::CalculateRemainingDelay(*tlv, mLocalUpdateTime));
123 }
124
125 aDataset.mUpdateTime = TimerMilli::GetNow();
126
127 exit:
128 return error;
129 }
130
Read(Dataset::Info & aDatasetInfo) const131 Error DatasetManager::Read(Dataset::Info &aDatasetInfo) const
132 {
133 Dataset dataset;
134 Error error;
135
136 aDatasetInfo.Clear();
137
138 SuccessOrExit(error = Read(dataset));
139 dataset.ConvertTo(aDatasetInfo);
140
141 exit:
142 return error;
143 }
144
Read(Dataset::Tlvs & aDatasetTlvs) const145 Error DatasetManager::Read(Dataset::Tlvs &aDatasetTlvs) const
146 {
147 Dataset dataset;
148 Error error;
149
150 ClearAllBytes(aDatasetTlvs);
151
152 SuccessOrExit(error = Read(dataset));
153 dataset.ConvertTo(aDatasetTlvs);
154
155 exit:
156 return error;
157 }
158
ApplyConfiguration(void) const159 Error DatasetManager::ApplyConfiguration(void) const
160 {
161 Error error;
162 Dataset dataset;
163
164 SuccessOrExit(error = Read(dataset));
165 error = ApplyConfiguration(dataset);
166
167 exit:
168 return error;
169 }
170
ApplyConfiguration(const Dataset & aDataset) const171 Error DatasetManager::ApplyConfiguration(const Dataset &aDataset) const
172 {
173 Error error = kErrorNone;
174
175 SuccessOrExit(error = aDataset.ValidateTlvs());
176
177 for (const Tlv *cur = aDataset.GetTlvsStart(); cur < aDataset.GetTlvsEnd(); cur = cur->GetNext())
178 {
179 switch (cur->GetType())
180 {
181 case Tlv::kChannel:
182 {
183 uint8_t channel = static_cast<uint8_t>(cur->ReadValueAs<ChannelTlv>().GetChannel());
184
185 error = Get<Mac::Mac>().SetPanChannel(channel);
186
187 if (error != kErrorNone)
188 {
189 LogCrit("Failed to set PAN channel to %u when applying dataset: %s", channel, ErrorToString(error));
190 }
191
192 break;
193 }
194
195 case Tlv::kWakeupChannel:
196 {
197 #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
198 uint8_t channel = static_cast<uint8_t>(cur->ReadValueAs<WakeupChannelTlv>().GetChannel());
199 error = Get<Mac::Mac>().SetWakeupChannel(channel);
200
201 if (error != kErrorNone)
202 {
203 LogCrit("Failed to set wake-up channel to %u when applying dataset: %s", channel, ErrorToString(error));
204 }
205 #endif
206 break;
207 }
208
209 case Tlv::kPanId:
210 Get<Mac::Mac>().SetPanId(cur->ReadValueAs<PanIdTlv>());
211 break;
212
213 case Tlv::kExtendedPanId:
214 Get<ExtendedPanIdManager>().SetExtPanId(cur->ReadValueAs<ExtendedPanIdTlv>());
215 break;
216
217 case Tlv::kNetworkName:
218 IgnoreError(Get<NetworkNameManager>().SetNetworkName(As<NetworkNameTlv>(cur)->GetNetworkName()));
219 break;
220
221 case Tlv::kNetworkKey:
222 Get<KeyManager>().SetNetworkKey(cur->ReadValueAs<NetworkKeyTlv>());
223 break;
224
225 #if OPENTHREAD_FTD
226 case Tlv::kPskc:
227 Get<KeyManager>().SetPskc(cur->ReadValueAs<PskcTlv>());
228 break;
229 #endif
230
231 case Tlv::kMeshLocalPrefix:
232 Get<Mle::MleRouter>().SetMeshLocalPrefix(cur->ReadValueAs<MeshLocalPrefixTlv>());
233 break;
234
235 case Tlv::kSecurityPolicy:
236 Get<KeyManager>().SetSecurityPolicy(As<SecurityPolicyTlv>(cur)->GetSecurityPolicy());
237 break;
238
239 default:
240 break;
241 }
242 }
243
244 exit:
245 return error;
246 }
247
Clear(void)248 void DatasetManager::Clear(void)
249 {
250 mNetworkTimestamp.SetToInvalid();
251 mLocalTimestamp.SetToInvalid();
252
253 mLocalSaved = false;
254
255 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
256 DestroySecurelyStoredKeys();
257 #endif
258 Get<Settings>().DeleteOperationalDataset(mType);
259
260 mTimer.Stop();
261
262 if (IsPendingDataset())
263 {
264 Get<PendingDatasetManager>().mDelayTimer.Stop();
265 }
266
267 SignalDatasetChange();
268 }
269
Save(const Dataset & aDataset,bool aAllowOlderTimestamp)270 Error DatasetManager::Save(const Dataset &aDataset, bool aAllowOlderTimestamp)
271 {
272 Error error = kErrorNone;
273 int compare;
274
275 if ((aDataset.ReadTimestamp(mType, mNetworkTimestamp) == kErrorNone) && IsActiveDataset())
276 {
277 SuccessOrExit(error = ApplyConfiguration(aDataset));
278 }
279
280 compare = Timestamp::Compare(mNetworkTimestamp, mLocalTimestamp);
281
282 if ((compare > 0) || aAllowOlderTimestamp)
283 {
284 LocalSave(aDataset);
285
286 #if OPENTHREAD_FTD
287 Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
288 #endif
289 }
290 else if (compare < 0)
291 {
292 mTimer.Start(kSendSetDelay);
293 }
294
295 SignalDatasetChange();
296
297 exit:
298 return error;
299 }
300
SaveLocal(const Dataset::Info & aDatasetInfo)301 void DatasetManager::SaveLocal(const Dataset::Info &aDatasetInfo)
302 {
303 Dataset dataset;
304
305 dataset.SetFrom(aDatasetInfo);
306 SaveLocal(dataset);
307 }
308
SaveLocal(const Dataset::Tlvs & aDatasetTlvs)309 Error DatasetManager::SaveLocal(const Dataset::Tlvs &aDatasetTlvs)
310 {
311 Error error = kErrorInvalidArgs;
312 Dataset dataset;
313
314 SuccessOrExit(dataset.SetFrom(aDatasetTlvs));
315 SuccessOrExit(dataset.ValidateTlvs());
316 SaveLocal(dataset);
317 error = kErrorNone;
318
319 exit:
320 return error;
321 }
322
SaveLocal(const Dataset & aDataset)323 void DatasetManager::SaveLocal(const Dataset &aDataset)
324 {
325 LocalSave(aDataset);
326
327 switch (Get<Mle::MleRouter>().GetRole())
328 {
329 case Mle::kRoleDisabled:
330 Restore(aDataset);
331 break;
332
333 case Mle::kRoleChild:
334 SyncLocalWithLeader(aDataset);
335 break;
336 #if OPENTHREAD_FTD
337 case Mle::kRoleRouter:
338 SyncLocalWithLeader(aDataset);
339 break;
340
341 case Mle::kRoleLeader:
342 Restore(aDataset);
343 Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
344 break;
345 #endif
346
347 default:
348 break;
349 }
350
351 SignalDatasetChange();
352 }
353
LocalSave(const Dataset & aDataset)354 void DatasetManager::LocalSave(const Dataset &aDataset)
355 {
356 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
357 DestroySecurelyStoredKeys();
358 #endif
359
360 if (aDataset.GetLength() == 0)
361 {
362 Get<Settings>().DeleteOperationalDataset(mType);
363 mLocalSaved = false;
364 LogInfo("%s dataset deleted", Dataset::TypeToString(mType));
365 }
366 else
367 {
368 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
369 // Store the network key and PSKC in the secure storage instead of settings.
370 Dataset dataset;
371
372 dataset.SetFrom(aDataset);
373 MoveKeysToSecureStorage(dataset);
374 Get<Settings>().SaveOperationalDataset(mType, dataset);
375 #else
376 Get<Settings>().SaveOperationalDataset(mType, aDataset);
377 #endif
378
379 mLocalSaved = true;
380 LogInfo("%s dataset set", Dataset::TypeToString(mType));
381 }
382
383 if (aDataset.ReadTimestamp(mType, mLocalTimestamp) != kErrorNone)
384 {
385 mLocalTimestamp.SetToInvalid();
386 }
387
388 mLocalUpdateTime = TimerMilli::GetNow();
389
390 if (IsPendingDataset())
391 {
392 Get<PendingDatasetManager>().StartDelayTimer(aDataset);
393 }
394 }
395
SignalDatasetChange(void) const396 void DatasetManager::SignalDatasetChange(void) const
397 {
398 Get<Notifier>().Signal(IsActiveDataset() ? kEventActiveDatasetChanged : kEventPendingDatasetChanged);
399 }
400
GetChannelMask(Mac::ChannelMask & aChannelMask) const401 Error DatasetManager::GetChannelMask(Mac::ChannelMask &aChannelMask) const
402 {
403 Error error;
404 const ChannelMaskTlv *channelMaskTlv;
405 uint32_t mask;
406 Dataset dataset;
407
408 SuccessOrExit(error = Read(dataset));
409
410 channelMaskTlv = As<ChannelMaskTlv>(dataset.FindTlv(Tlv::kChannelMask));
411 VerifyOrExit(channelMaskTlv != nullptr, error = kErrorNotFound);
412 SuccessOrExit(channelMaskTlv->ReadChannelMask(mask));
413
414 aChannelMask.SetMask(mask & Get<Mac::Mac>().GetSupportedChannelMask().GetMask());
415
416 VerifyOrExit(!aChannelMask.IsEmpty(), error = kErrorNotFound);
417
418 exit:
419 return error;
420 }
421
HandleTimer(void)422 void DatasetManager::HandleTimer(void)
423 {
424 Dataset dataset;
425
426 SuccessOrExit(Read(dataset));
427 SyncLocalWithLeader(dataset);
428
429 exit:
430 return;
431 }
432
SyncLocalWithLeader(const Dataset & aDataset)433 void DatasetManager::SyncLocalWithLeader(const Dataset &aDataset)
434 {
435 // Attempts to synchronize the local Dataset with the leader by
436 // sending `MGMT_SET` command if the local Dataset's timestamp is
437 // newer.
438
439 Error error = kErrorNone;
440
441 VerifyOrExit(!mMgmtPending, error = kErrorBusy);
442 VerifyOrExit(Get<Mle::MleRouter>().IsChild() || Get<Mle::MleRouter>().IsRouter(), error = kErrorInvalidState);
443
444 VerifyOrExit(mNetworkTimestamp < mLocalTimestamp, error = kErrorAlready);
445
446 if (IsActiveDataset())
447 {
448 Dataset pendingDataset;
449 Timestamp timestamp;
450
451 IgnoreError(Get<PendingDatasetManager>().Read(pendingDataset));
452
453 if ((pendingDataset.Read<ActiveTimestampTlv>(timestamp) == kErrorNone) && (timestamp == mLocalTimestamp))
454 {
455 // Stop registration attempts during dataset transition
456 ExitNow(error = kErrorInvalidState);
457 }
458 }
459
460 error = SendSetRequest(aDataset);
461
462 exit:
463 if (error == kErrorNoBufs)
464 {
465 mTimer.Start(kSendSetDelay);
466 }
467
468 if (error != kErrorAlready)
469 {
470 LogWarnOnError(error, "send Dataset set to leader");
471 }
472 }
473
SendSetRequest(const Dataset & aDataset)474 Error DatasetManager::SendSetRequest(const Dataset &aDataset)
475 {
476 Error error = kErrorNone;
477 Coap::Message *message = nullptr;
478 Tmf::MessageInfo messageInfo(GetInstance());
479
480 VerifyOrExit(!mMgmtPending, error = kErrorAlready);
481
482 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(IsActiveDataset() ? kUriActiveSet : kUriPendingSet);
483 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
484
485 SuccessOrExit(error = message->AppendBytes(aDataset.GetBytes(), aDataset.GetLength()));
486 messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc();
487
488 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, HandleMgmtSetResponse, this));
489 mMgmtPending = true;
490
491 LogInfo("Sent dataset set request to leader");
492
493 exit:
494 FreeMessageOnError(message, error);
495 return error;
496 }
497
HandleMgmtSetResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,otError aError)498 void DatasetManager::HandleMgmtSetResponse(void *aContext,
499 otMessage *aMessage,
500 const otMessageInfo *aMessageInfo,
501 otError aError)
502 {
503 static_cast<DatasetManager *>(aContext)->HandleMgmtSetResponse(AsCoapMessagePtr(aMessage),
504 AsCoreTypePtr(aMessageInfo), aError);
505 }
506
HandleMgmtSetResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aError)507 void DatasetManager::HandleMgmtSetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aError)
508 {
509 OT_UNUSED_VARIABLE(aMessageInfo);
510
511 Error error;
512 uint8_t state = StateTlv::kPending;
513
514 SuccessOrExit(error = aError);
515 VerifyOrExit(Tlv::Find<StateTlv>(*aMessage, state) == kErrorNone && state != StateTlv::kPending,
516 error = kErrorParse);
517
518 if (state == StateTlv::kReject)
519 {
520 error = kErrorRejected;
521 }
522
523 exit:
524 LogInfo("MGMT_SET finished: %s", error == kErrorNone ? "Accepted" : ErrorToString(error));
525
526 mMgmtPending = false;
527
528 mMgmtSetCallback.InvokeAndClearIfSet(error);
529
530 mTimer.Start(kSendSetDelay);
531 }
532
HandleGet(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo) const533 void DatasetManager::HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const
534 {
535 Error error = kErrorNone;
536 Coap::Message *response = ProcessGetRequest(aMessage, kCheckSecurityPolicyFlags);
537
538 VerifyOrExit(response != nullptr);
539 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*response, aMessageInfo));
540
541 LogInfo("sent %s dataset get response to %s", IsActiveDataset() ? "active" : "pending",
542 aMessageInfo.GetPeerAddr().ToString().AsCString());
543
544 exit:
545 FreeMessageOnError(response, error);
546 }
547
ProcessGetRequest(const Coap::Message & aRequest,SecurityPolicyCheckMode aCheckMode) const548 Coap::Message *DatasetManager::ProcessGetRequest(const Coap::Message &aRequest,
549 SecurityPolicyCheckMode aCheckMode) const
550 {
551 // Processes a MGMT_ACTIVE_GET or MGMT_PENDING_GET request
552 // and prepares the response.
553
554 Error error = kErrorNone;
555 Coap::Message *response = nullptr;
556 Dataset dataset;
557 TlvList tlvList;
558 OffsetRange offsetRange;
559
560 if (Tlv::FindTlvValueOffsetRange(aRequest, Tlv::kGet, offsetRange) == kErrorNone)
561 {
562 while (!offsetRange.IsEmpty())
563 {
564 uint8_t tlvType;
565
566 IgnoreError(aRequest.Read(offsetRange, tlvType));
567 tlvList.Add(tlvType);
568 offsetRange.AdvanceOffset(sizeof(uint8_t));
569 }
570
571 // MGMT_PENDING_GET.rsp must include Delay Timer TLV (Thread 1.1.1
572 // Section 8.7.5.4).
573
574 if (!tlvList.IsEmpty() && IsPendingDataset())
575 {
576 tlvList.Add(Tlv::kDelayTimer);
577 }
578 }
579
580 // Ignore `Read()` error, since even if no Dataset is saved, we should
581 // respond with an empty one.
582
583 IgnoreError(Read(dataset));
584
585 response = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
586 VerifyOrExit(response != nullptr, error = kErrorNoBufs);
587
588 for (const Tlv *tlv = dataset.GetTlvsStart(); tlv < dataset.GetTlvsEnd(); tlv = tlv->GetNext())
589 {
590 bool shouldAppend = true;
591
592 if (!tlvList.IsEmpty())
593 {
594 shouldAppend = tlvList.Contains(tlv->GetType());
595 }
596
597 if ((aCheckMode == kCheckSecurityPolicyFlags) && (tlv->GetType() == Tlv::kNetworkKey) &&
598 !Get<KeyManager>().GetSecurityPolicy().mObtainNetworkKeyEnabled)
599 {
600 shouldAppend = false;
601 }
602
603 if (shouldAppend)
604 {
605 SuccessOrExit(error = tlv->AppendTo(*response));
606 }
607 }
608
609 exit:
610 FreeAndNullMessageOnError(response, error);
611 return response;
612 }
613
SendSetRequest(const Dataset::Info & aDatasetInfo,const uint8_t * aTlvs,uint8_t aLength,MgmtSetCallback aCallback,void * aContext)614 Error DatasetManager::SendSetRequest(const Dataset::Info &aDatasetInfo,
615 const uint8_t *aTlvs,
616 uint8_t aLength,
617 MgmtSetCallback aCallback,
618 void *aContext)
619 {
620 Error error = kErrorNone;
621 Dataset dataset;
622
623 dataset.SetFrom(aDatasetInfo);
624 SuccessOrExit(error = dataset.AppendTlvsFrom(aTlvs, aLength));
625
626 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
627 if (Get<Commissioner>().IsActive() && !dataset.ContainsTlv(Tlv::kCommissionerSessionId))
628 {
629 SuccessOrExit(error = dataset.Write<CommissionerSessionIdTlv>(Get<Commissioner>().GetSessionId()));
630 }
631 #endif
632
633 SuccessOrExit(error = SendSetRequest(dataset));
634 mMgmtSetCallback.Set(aCallback, aContext);
635
636 exit:
637 return error;
638 }
639
SendGetRequest(const Dataset::Components & aDatasetComponents,const uint8_t * aTlvTypes,uint8_t aLength,const otIp6Address * aAddress) const640 Error DatasetManager::SendGetRequest(const Dataset::Components &aDatasetComponents,
641 const uint8_t *aTlvTypes,
642 uint8_t aLength,
643 const otIp6Address *aAddress) const
644 {
645 Error error = kErrorNone;
646 Coap::Message *message;
647 Tmf::MessageInfo messageInfo(GetInstance());
648 TlvList tlvList;
649
650 if (aDatasetComponents.IsPresent<Dataset::kActiveTimestamp>())
651 {
652 tlvList.Add(Tlv::kActiveTimestamp);
653 }
654
655 if (aDatasetComponents.IsPresent<Dataset::kPendingTimestamp>())
656 {
657 tlvList.Add(Tlv::kPendingTimestamp);
658 }
659
660 if (aDatasetComponents.IsPresent<Dataset::kNetworkKey>())
661 {
662 tlvList.Add(Tlv::kNetworkKey);
663 }
664
665 if (aDatasetComponents.IsPresent<Dataset::kNetworkName>())
666 {
667 tlvList.Add(Tlv::kNetworkName);
668 }
669
670 if (aDatasetComponents.IsPresent<Dataset::kExtendedPanId>())
671 {
672 tlvList.Add(Tlv::kExtendedPanId);
673 }
674
675 if (aDatasetComponents.IsPresent<Dataset::kMeshLocalPrefix>())
676 {
677 tlvList.Add(Tlv::kMeshLocalPrefix);
678 }
679
680 if (aDatasetComponents.IsPresent<Dataset::kDelay>())
681 {
682 tlvList.Add(Tlv::kDelayTimer);
683 }
684
685 if (aDatasetComponents.IsPresent<Dataset::kPanId>())
686 {
687 tlvList.Add(Tlv::kPanId);
688 }
689
690 if (aDatasetComponents.IsPresent<Dataset::kChannel>())
691 {
692 tlvList.Add(Tlv::kChannel);
693 }
694
695 if (aDatasetComponents.IsPresent<Dataset::kWakeupChannel>())
696 {
697 tlvList.Add(Tlv::kWakeupChannel);
698 }
699
700 if (aDatasetComponents.IsPresent<Dataset::kPskc>())
701 {
702 tlvList.Add(Tlv::kPskc);
703 }
704
705 if (aDatasetComponents.IsPresent<Dataset::kSecurityPolicy>())
706 {
707 tlvList.Add(Tlv::kSecurityPolicy);
708 }
709
710 if (aDatasetComponents.IsPresent<Dataset::kChannelMask>())
711 {
712 tlvList.Add(Tlv::kChannelMask);
713 }
714
715 for (uint8_t index = 0; index < aLength; index++)
716 {
717 tlvList.Add(aTlvTypes[index]);
718 }
719
720 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(IsActiveDataset() ? kUriActiveGet : kUriPendingGet);
721 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
722
723 if (!tlvList.IsEmpty())
724 {
725 SuccessOrExit(error = Tlv::AppendTlv(*message, Tlv::kGet, tlvList.GetArrayBuffer(), tlvList.GetLength()));
726 }
727
728 messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc();
729
730 if (aAddress != nullptr)
731 {
732 // Use leader ALOC if `aAddress` is `nullptr`.
733 messageInfo.SetPeerAddr(AsCoreType(aAddress));
734 }
735
736 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
737
738 LogInfo("sent dataset get request");
739
740 exit:
741 FreeMessageOnError(message, error);
742 return error;
743 }
744
Add(uint8_t aTlvType)745 void DatasetManager::TlvList::Add(uint8_t aTlvType)
746 {
747 if (!Contains(aTlvType))
748 {
749 IgnoreError(PushBack(aTlvType));
750 }
751 }
752
753 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
754
755 const DatasetManager::SecurelyStoredTlv DatasetManager::kSecurelyStoredTlvs[] = {
756 {
757 Tlv::kNetworkKey,
758 KeyRefManager::kActiveDatasetNetworkKey,
759 KeyRefManager::kPendingDatasetNetworkKey,
760 },
761 {
762 Tlv::kPskc,
763 KeyRefManager::kActiveDatasetPskc,
764 KeyRefManager::kPendingDatasetPskc,
765 },
766 };
767
DestroySecurelyStoredKeys(void) const768 void DatasetManager::DestroySecurelyStoredKeys(void) const
769 {
770 for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
771 {
772 Crypto::Storage::DestroyKey(Get<KeyRefManager>().KeyRefFor(entry.GetKeyRefType(mType)));
773 }
774 }
775
MoveKeysToSecureStorage(Dataset & aDataset) const776 void DatasetManager::MoveKeysToSecureStorage(Dataset &aDataset) const
777 {
778 for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
779 {
780 KeyRef keyRef = Get<KeyRefManager>().KeyRefFor(entry.GetKeyRefType(mType));
781
782 SaveTlvInSecureStorageAndClearValue(aDataset, entry.mTlvType, keyRef);
783 }
784 }
785
EmplaceSecurelyStoredKeys(Dataset & aDataset) const786 void DatasetManager::EmplaceSecurelyStoredKeys(Dataset &aDataset) const
787 {
788 bool moveKeys = false;
789
790 // If reading any of the TLVs fails, it indicates they are not yet
791 // stored in secure storage and are still contained in the `Dataset`
792 // read from `Settings`. In this case, we move the keys to secure
793 // storage and then clear them from 'Settings'.
794
795 for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
796 {
797 KeyRef keyRef = Get<KeyRefManager>().KeyRefFor(entry.GetKeyRefType(mType));
798
799 if (ReadTlvFromSecureStorage(aDataset, entry.mTlvType, keyRef) != kErrorNone)
800 {
801 moveKeys = true;
802 }
803 }
804
805 if (moveKeys)
806 {
807 Dataset dataset;
808
809 dataset.SetFrom(aDataset);
810 MoveKeysToSecureStorage(dataset);
811 Get<Settings>().SaveOperationalDataset(mType, dataset);
812 }
813 }
814
SaveTlvInSecureStorageAndClearValue(Dataset & aDataset,Tlv::Type aTlvType,KeyRef aKeyRef) const815 void DatasetManager::SaveTlvInSecureStorageAndClearValue(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const
816 {
817 using namespace ot::Crypto::Storage;
818
819 Tlv *tlv = aDataset.FindTlv(aTlvType);
820
821 VerifyOrExit(tlv != nullptr);
822 VerifyOrExit(tlv->GetLength() > 0);
823
824 SuccessOrAssert(ImportKey(aKeyRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent, tlv->GetValue(),
825 tlv->GetLength()));
826
827 memset(tlv->GetValue(), 0, tlv->GetLength());
828
829 exit:
830 return;
831 }
832
ReadTlvFromSecureStorage(Dataset & aDataset,Tlv::Type aTlvType,KeyRef aKeyRef) const833 Error DatasetManager::ReadTlvFromSecureStorage(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const
834 {
835 using namespace ot::Crypto::Storage;
836
837 Error error = kErrorNone;
838 Tlv *tlv = aDataset.FindTlv(aTlvType);
839 size_t readLength;
840
841 VerifyOrExit(tlv != nullptr);
842 VerifyOrExit(tlv->GetLength() > 0);
843
844 SuccessOrExit(error = ExportKey(aKeyRef, tlv->GetValue(), tlv->GetLength(), readLength));
845 VerifyOrExit(readLength == tlv->GetLength(), error = OT_ERROR_FAILED);
846
847 exit:
848 return error;
849 }
850
851 #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
852
853 //---------------------------------------------------------------------------------------------------------------------
854 // ActiveDatasetManager
855
ActiveDatasetManager(Instance & aInstance)856 ActiveDatasetManager::ActiveDatasetManager(Instance &aInstance)
857 : DatasetManager(aInstance, Dataset::kActive, ActiveDatasetManager::HandleTimer)
858 {
859 }
860
IsPartiallyComplete(void) const861 bool ActiveDatasetManager::IsPartiallyComplete(void) const { return mLocalSaved && !mNetworkTimestamp.IsValid(); }
862
IsComplete(void) const863 bool ActiveDatasetManager::IsComplete(void) const { return mLocalSaved && mNetworkTimestamp.IsValid(); }
864
IsCommissioned(void) const865 bool ActiveDatasetManager::IsCommissioned(void) const
866 {
867 static const Tlv::Type kRequiredTlvs[] = {
868 Tlv::kNetworkKey, Tlv::kNetworkName, Tlv::kExtendedPanId, Tlv::kPanId, Tlv::kChannel,
869 };
870
871 Dataset dataset;
872 bool isValid = false;
873
874 SuccessOrExit(Read(dataset));
875 isValid = dataset.ContainsAllTlvs(kRequiredTlvs, sizeof(kRequiredTlvs));
876
877 exit:
878 return isValid;
879 }
880
881 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)882 void ActiveDatasetManager::HandleTmf<kUriActiveGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
883 {
884 DatasetManager::HandleGet(aMessage, aMessageInfo);
885 }
886
HandleTimer(Timer & aTimer)887 void ActiveDatasetManager::HandleTimer(Timer &aTimer) { aTimer.Get<ActiveDatasetManager>().HandleTimer(); }
888
889 //---------------------------------------------------------------------------------------------------------------------
890 // PendingDatasetManager
891
PendingDatasetManager(Instance & aInstance)892 PendingDatasetManager::PendingDatasetManager(Instance &aInstance)
893 : DatasetManager(aInstance, Dataset::kPending, PendingDatasetManager::HandleTimer)
894 , mDelayTimer(aInstance)
895 {
896 }
897
ReadActiveTimestamp(Timestamp & aTimestamp) const898 Error PendingDatasetManager::ReadActiveTimestamp(Timestamp &aTimestamp) const
899 {
900 Error error = kErrorNotFound;
901 Dataset dataset;
902
903 SuccessOrExit(Read(dataset));
904
905 SuccessOrExit(dataset.Read<ActiveTimestampTlv>(aTimestamp));
906 error = kErrorNone;
907
908 exit:
909 return error;
910 }
911
ReadRemainingDelay(uint32_t & aRemainingDelay) const912 Error PendingDatasetManager::ReadRemainingDelay(uint32_t &aRemainingDelay) const
913 {
914 Error error = kErrorNone;
915 TimeMilli now = TimerMilli::GetNow();
916
917 aRemainingDelay = 0;
918
919 VerifyOrExit(mDelayTimer.IsRunning(), error = kErrorNotFound);
920 VerifyOrExit(mDelayTimer.GetFireTime() > now);
921 aRemainingDelay = mDelayTimer.GetFireTime() - now;
922
923 exit:
924 return error;
925 }
926
StartDelayTimer(void)927 void PendingDatasetManager::StartDelayTimer(void)
928 {
929 Dataset dataset;
930
931 mDelayTimer.Stop();
932
933 SuccessOrExit(Read(dataset));
934 StartDelayTimer(dataset);
935
936 exit:
937 return;
938 }
939
StartDelayTimer(const Dataset & aDataset)940 void PendingDatasetManager::StartDelayTimer(const Dataset &aDataset)
941 {
942 uint32_t delay;
943
944 mDelayTimer.Stop();
945
946 SuccessOrExit(aDataset.Read<DelayTimerTlv>(delay));
947
948 delay = Min(delay, DelayTimerTlv::kMaxDelay);
949
950 mDelayTimer.StartAt(aDataset.GetUpdateTime(), delay);
951 LogInfo("delay timer started %lu", ToUlong(delay));
952
953 exit:
954 return;
955 }
956
HandleDelayTimer(void)957 void PendingDatasetManager::HandleDelayTimer(void)
958 {
959 Dataset dataset;
960 Timestamp activeTimestamp;
961 bool shouldReplaceActive = false;
962
963 SuccessOrExit(Read(dataset));
964
965 LogInfo("Pending delay timer expired");
966
967 // Determine whether the Pending Dataset should replace the
968 // current Active Dataset. This is allowed if the Pending
969 // Dataset's Active Timestamp is newer, or the Pending Dataset
970 // contains a different key.
971
972 SuccessOrExit(dataset.Read<ActiveTimestampTlv>(activeTimestamp));
973
974 if (activeTimestamp > Get<ActiveDatasetManager>().GetTimestamp())
975 {
976 shouldReplaceActive = true;
977 }
978 else
979 {
980 NetworkKey newKey;
981 NetworkKey currentKey;
982
983 SuccessOrExit(dataset.Read<NetworkKeyTlv>(newKey));
984 Get<KeyManager>().GetNetworkKey(currentKey);
985 shouldReplaceActive = (currentKey != newKey);
986 }
987
988 VerifyOrExit(shouldReplaceActive);
989
990 // Convert Pending Dataset to Active by removing the Pending
991 // Timestamp and the Delay Timer TLVs.
992
993 dataset.RemoveTlv(Tlv::kPendingTimestamp);
994 dataset.RemoveTlv(Tlv::kDelayTimer);
995
996 IgnoreError(Get<ActiveDatasetManager>().Save(dataset, /* aAllowOlderTimestamp */ true));
997
998 exit:
999 Clear();
1000 }
1001
1002 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1003 void PendingDatasetManager::HandleTmf<kUriPendingGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1004 {
1005 DatasetManager::HandleGet(aMessage, aMessageInfo);
1006 }
1007
HandleTimer(Timer & aTimer)1008 void PendingDatasetManager::HandleTimer(Timer &aTimer) { aTimer.Get<PendingDatasetManager>().HandleTimer(); }
1009
1010 } // namespace MeshCoP
1011 } // namespace ot
1012