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