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