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 common methods for manipulating MeshCoP Datasets.
32 *
33 */
34
35 #include "dataset.hpp"
36
37 #include <stdio.h>
38
39 #include "common/code_utils.hpp"
40 #include "common/encoding.hpp"
41 #include "common/instance.hpp"
42 #include "common/locator_getters.hpp"
43 #include "common/log.hpp"
44 #include "mac/mac_types.hpp"
45 #include "meshcop/meshcop_tlvs.hpp"
46 #include "meshcop/timestamp.hpp"
47 #include "thread/mle_tlvs.hpp"
48
49 namespace ot {
50 namespace MeshCoP {
51
52 RegisterLogModule("Dataset");
53
GenerateRandom(Instance & aInstance)54 Error Dataset::Info::GenerateRandom(Instance &aInstance)
55 {
56 Error error;
57 Mac::ChannelMask supportedChannels = aInstance.Get<Mac::Mac>().GetSupportedChannelMask();
58 Mac::ChannelMask preferredChannels(aInstance.Get<Radio>().GetPreferredChannelMask());
59
60 // If the preferred channel mask is not empty, select a random
61 // channel from it, otherwise choose one from the supported
62 // channel mask.
63
64 preferredChannels.Intersect(supportedChannels);
65
66 if (preferredChannels.IsEmpty())
67 {
68 preferredChannels = supportedChannels;
69 }
70
71 Clear();
72
73 mActiveTimestamp.mSeconds = 1;
74 mActiveTimestamp.mTicks = 0;
75 mActiveTimestamp.mAuthoritative = false;
76 mChannel = preferredChannels.ChooseRandomChannel();
77 mChannelMask = supportedChannels.GetMask();
78 mPanId = Mac::GenerateRandomPanId();
79 AsCoreType(&mSecurityPolicy).SetToDefault();
80
81 SuccessOrExit(error = AsCoreType(&mNetworkKey).GenerateRandom());
82 SuccessOrExit(error = AsCoreType(&mPskc).GenerateRandom());
83 SuccessOrExit(error = Random::Crypto::FillBuffer(mExtendedPanId.m8, sizeof(mExtendedPanId.m8)));
84 SuccessOrExit(error = AsCoreType(&mMeshLocalPrefix).GenerateRandomUla());
85
86 snprintf(mNetworkName.m8, sizeof(mNetworkName), "OpenThread-%04x", mPanId);
87
88 mComponents.mIsActiveTimestampPresent = true;
89 mComponents.mIsNetworkKeyPresent = true;
90 mComponents.mIsNetworkNamePresent = true;
91 mComponents.mIsExtendedPanIdPresent = true;
92 mComponents.mIsMeshLocalPrefixPresent = true;
93 mComponents.mIsPanIdPresent = true;
94 mComponents.mIsChannelPresent = true;
95 mComponents.mIsPskcPresent = true;
96 mComponents.mIsSecurityPolicyPresent = true;
97 mComponents.mIsChannelMaskPresent = true;
98
99 exit:
100 return error;
101 }
102
IsSubsetOf(const Info & aOther) const103 bool Dataset::Info::IsSubsetOf(const Info &aOther) const
104 {
105 bool isSubset = false;
106
107 if (IsNetworkKeyPresent())
108 {
109 VerifyOrExit(aOther.IsNetworkKeyPresent() && GetNetworkKey() == aOther.GetNetworkKey());
110 }
111
112 if (IsNetworkNamePresent())
113 {
114 VerifyOrExit(aOther.IsNetworkNamePresent() && GetNetworkName() == aOther.GetNetworkName());
115 }
116
117 if (IsExtendedPanIdPresent())
118 {
119 VerifyOrExit(aOther.IsExtendedPanIdPresent() && GetExtendedPanId() == aOther.GetExtendedPanId());
120 }
121
122 if (IsMeshLocalPrefixPresent())
123 {
124 VerifyOrExit(aOther.IsMeshLocalPrefixPresent() && GetMeshLocalPrefix() == aOther.GetMeshLocalPrefix());
125 }
126
127 if (IsPanIdPresent())
128 {
129 VerifyOrExit(aOther.IsPanIdPresent() && GetPanId() == aOther.GetPanId());
130 }
131
132 if (IsChannelPresent())
133 {
134 VerifyOrExit(aOther.IsChannelPresent() && GetChannel() == aOther.GetChannel());
135 }
136
137 if (IsPskcPresent())
138 {
139 VerifyOrExit(aOther.IsPskcPresent() && GetPskc() == aOther.GetPskc());
140 }
141
142 if (IsSecurityPolicyPresent())
143 {
144 VerifyOrExit(aOther.IsSecurityPolicyPresent() && GetSecurityPolicy() == aOther.GetSecurityPolicy());
145 }
146
147 if (IsChannelMaskPresent())
148 {
149 VerifyOrExit(aOther.IsChannelMaskPresent() && GetChannelMask() == aOther.GetChannelMask());
150 }
151
152 isSubset = true;
153
154 exit:
155 return isSubset;
156 }
157
Dataset(void)158 Dataset::Dataset(void)
159 : mUpdateTime(0)
160 , mLength(0)
161 {
162 memset(mTlvs, 0, sizeof(mTlvs));
163 }
164
Clear(void)165 void Dataset::Clear(void)
166 {
167 mLength = 0;
168 }
169
IsValid(void) const170 bool Dataset::IsValid(void) const
171 {
172 bool rval = true;
173 const Tlv *end = GetTlvsEnd();
174
175 for (const Tlv *cur = GetTlvsStart(); cur < end; cur = cur->GetNext())
176 {
177 VerifyOrExit(!cur->IsExtended() && (cur + 1) <= end && cur->GetNext() <= end && Tlv::IsValid(*cur),
178 rval = false);
179 }
180
181 exit:
182 return rval;
183 }
184
GetTlv(Tlv::Type aType) const185 const Tlv *Dataset::GetTlv(Tlv::Type aType) const
186 {
187 return Tlv::FindTlv(mTlvs, mLength, aType);
188 }
189
ConvertTo(Info & aDatasetInfo) const190 void Dataset::ConvertTo(Info &aDatasetInfo) const
191 {
192 aDatasetInfo.Clear();
193
194 for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
195 {
196 switch (cur->GetType())
197 {
198 case Tlv::kActiveTimestamp:
199 aDatasetInfo.SetActiveTimestamp(As<ActiveTimestampTlv>(cur)->GetTimestamp());
200 break;
201
202 case Tlv::kChannel:
203 aDatasetInfo.SetChannel(As<ChannelTlv>(cur)->GetChannel());
204 break;
205
206 case Tlv::kChannelMask:
207 {
208 uint32_t mask = As<ChannelMaskTlv>(cur)->GetChannelMask();
209
210 if (mask != 0)
211 {
212 aDatasetInfo.SetChannelMask(mask);
213 }
214
215 break;
216 }
217
218 case Tlv::kDelayTimer:
219 aDatasetInfo.SetDelay(As<DelayTimerTlv>(cur)->GetDelayTimer());
220 break;
221
222 case Tlv::kExtendedPanId:
223 aDatasetInfo.SetExtendedPanId(As<ExtendedPanIdTlv>(cur)->GetExtendedPanId());
224 break;
225
226 case Tlv::kMeshLocalPrefix:
227 aDatasetInfo.SetMeshLocalPrefix(As<MeshLocalPrefixTlv>(cur)->GetMeshLocalPrefix());
228 break;
229
230 case Tlv::kNetworkKey:
231 aDatasetInfo.SetNetworkKey(As<NetworkKeyTlv>(cur)->GetNetworkKey());
232 break;
233
234 case Tlv::kNetworkName:
235 aDatasetInfo.SetNetworkName(As<NetworkNameTlv>(cur)->GetNetworkName());
236 break;
237
238 case Tlv::kPanId:
239 aDatasetInfo.SetPanId(As<PanIdTlv>(cur)->GetPanId());
240 break;
241
242 case Tlv::kPendingTimestamp:
243 aDatasetInfo.SetPendingTimestamp(As<PendingTimestampTlv>(cur)->GetTimestamp());
244 break;
245
246 case Tlv::kPskc:
247 aDatasetInfo.SetPskc(As<PskcTlv>(cur)->GetPskc());
248 break;
249
250 case Tlv::kSecurityPolicy:
251 aDatasetInfo.SetSecurityPolicy(As<SecurityPolicyTlv>(cur)->GetSecurityPolicy());
252 break;
253
254 default:
255 break;
256 }
257 }
258 }
259
ConvertTo(otOperationalDatasetTlvs & aDataset) const260 void Dataset::ConvertTo(otOperationalDatasetTlvs &aDataset) const
261 {
262 memcpy(aDataset.mTlvs, mTlvs, mLength);
263 aDataset.mLength = static_cast<uint8_t>(mLength);
264 }
265
Set(Type aType,const Dataset & aDataset)266 void Dataset::Set(Type aType, const Dataset &aDataset)
267 {
268 memcpy(mTlvs, aDataset.mTlvs, aDataset.mLength);
269 mLength = aDataset.mLength;
270
271 if (aType == kActive)
272 {
273 RemoveTlv(Tlv::kPendingTimestamp);
274 RemoveTlv(Tlv::kDelayTimer);
275 }
276
277 mUpdateTime = aDataset.GetUpdateTime();
278 }
279
SetFrom(const otOperationalDatasetTlvs & aDataset)280 void Dataset::SetFrom(const otOperationalDatasetTlvs &aDataset)
281 {
282 mLength = aDataset.mLength;
283 memcpy(mTlvs, aDataset.mTlvs, mLength);
284 }
285
SetFrom(const Info & aDatasetInfo)286 Error Dataset::SetFrom(const Info &aDatasetInfo)
287 {
288 Error error = kErrorNone;
289
290 if (aDatasetInfo.IsActiveTimestampPresent())
291 {
292 Timestamp activeTimestamp;
293
294 aDatasetInfo.GetActiveTimestamp(activeTimestamp);
295 IgnoreError(SetTlv(Tlv::kActiveTimestamp, activeTimestamp));
296 }
297
298 if (aDatasetInfo.IsPendingTimestampPresent())
299 {
300 Timestamp pendingTimestamp;
301
302 aDatasetInfo.GetPendingTimestamp(pendingTimestamp);
303 IgnoreError(SetTlv(Tlv::kPendingTimestamp, pendingTimestamp));
304 }
305
306 if (aDatasetInfo.IsDelayPresent())
307 {
308 IgnoreError(SetTlv(Tlv::kDelayTimer, aDatasetInfo.GetDelay()));
309 }
310
311 if (aDatasetInfo.IsChannelPresent())
312 {
313 ChannelTlv tlv;
314 tlv.Init();
315 tlv.SetChannel(aDatasetInfo.GetChannel());
316 IgnoreError(SetTlv(tlv));
317 }
318
319 if (aDatasetInfo.IsChannelMaskPresent())
320 {
321 ChannelMaskTlv tlv;
322 tlv.Init();
323 tlv.SetChannelMask(aDatasetInfo.GetChannelMask());
324 IgnoreError(SetTlv(tlv));
325 }
326
327 if (aDatasetInfo.IsExtendedPanIdPresent())
328 {
329 IgnoreError(SetTlv(Tlv::kExtendedPanId, aDatasetInfo.GetExtendedPanId()));
330 }
331
332 if (aDatasetInfo.IsMeshLocalPrefixPresent())
333 {
334 IgnoreError(SetTlv(Tlv::kMeshLocalPrefix, aDatasetInfo.GetMeshLocalPrefix()));
335 }
336
337 if (aDatasetInfo.IsNetworkKeyPresent())
338 {
339 IgnoreError(SetTlv(Tlv::kNetworkKey, aDatasetInfo.GetNetworkKey()));
340 }
341
342 if (aDatasetInfo.IsNetworkNamePresent())
343 {
344 NameData nameData = aDatasetInfo.GetNetworkName().GetAsData();
345
346 IgnoreError(SetTlv(Tlv::kNetworkName, nameData.GetBuffer(), nameData.GetLength()));
347 }
348
349 if (aDatasetInfo.IsPanIdPresent())
350 {
351 IgnoreError(SetTlv(Tlv::kPanId, aDatasetInfo.GetPanId()));
352 }
353
354 if (aDatasetInfo.IsPskcPresent())
355 {
356 IgnoreError(SetTlv(Tlv::kPskc, aDatasetInfo.GetPskc()));
357 }
358
359 if (aDatasetInfo.IsSecurityPolicyPresent())
360 {
361 SecurityPolicyTlv tlv;
362
363 tlv.Init();
364 tlv.SetSecurityPolicy(aDatasetInfo.GetSecurityPolicy());
365 IgnoreError(SetTlv(tlv));
366 }
367
368 mUpdateTime = TimerMilli::GetNow();
369
370 return error;
371 }
372
GetTimestamp(Type aType,Timestamp & aTimestamp) const373 Error Dataset::GetTimestamp(Type aType, Timestamp &aTimestamp) const
374 {
375 Error error = kErrorNone;
376
377 if (aType == kActive)
378 {
379 const ActiveTimestampTlv *tlv = GetTlv<ActiveTimestampTlv>();
380
381 VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
382 aTimestamp = tlv->GetTimestamp();
383 }
384 else
385 {
386 const PendingTimestampTlv *tlv = GetTlv<PendingTimestampTlv>();
387
388 VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
389 aTimestamp = tlv->GetTimestamp();
390 }
391
392 exit:
393 return error;
394 }
395
SetTimestamp(Type aType,const Timestamp & aTimestamp)396 void Dataset::SetTimestamp(Type aType, const Timestamp &aTimestamp)
397 {
398 IgnoreError(SetTlv((aType == kActive) ? Tlv::kActiveTimestamp : Tlv::kPendingTimestamp, aTimestamp));
399 }
400
SetTlv(Tlv::Type aType,const void * aValue,uint8_t aLength)401 Error Dataset::SetTlv(Tlv::Type aType, const void *aValue, uint8_t aLength)
402 {
403 Error error = kErrorNone;
404 uint16_t bytesAvailable = sizeof(mTlvs) - mLength;
405 Tlv * old = GetTlv(aType);
406 Tlv tlv;
407
408 if (old != nullptr)
409 {
410 bytesAvailable += sizeof(Tlv) + old->GetLength();
411 }
412
413 VerifyOrExit(sizeof(Tlv) + aLength <= bytesAvailable, error = kErrorNoBufs);
414
415 if (old != nullptr)
416 {
417 RemoveTlv(old);
418 }
419
420 tlv.SetType(aType);
421 tlv.SetLength(aLength);
422 memcpy(mTlvs + mLength, &tlv, sizeof(Tlv));
423 mLength += sizeof(Tlv);
424
425 memcpy(mTlvs + mLength, aValue, aLength);
426 mLength += aLength;
427
428 mUpdateTime = TimerMilli::GetNow();
429
430 exit:
431 return error;
432 }
433
SetTlv(const Tlv & aTlv)434 Error Dataset::SetTlv(const Tlv &aTlv)
435 {
436 return SetTlv(aTlv.GetType(), aTlv.GetValue(), aTlv.GetLength());
437 }
438
ReadFromMessage(const Message & aMessage,uint16_t aOffset,uint8_t aLength)439 Error Dataset::ReadFromMessage(const Message &aMessage, uint16_t aOffset, uint8_t aLength)
440 {
441 Error error = kErrorParse;
442
443 SuccessOrExit(aMessage.Read(aOffset, mTlvs, aLength));
444 mLength = aLength;
445
446 VerifyOrExit(IsValid(), error = kErrorParse);
447
448 mUpdateTime = TimerMilli::GetNow();
449 error = kErrorNone;
450
451 exit:
452 return error;
453 }
454
RemoveTlv(Tlv::Type aType)455 void Dataset::RemoveTlv(Tlv::Type aType)
456 {
457 Tlv *tlv;
458
459 VerifyOrExit((tlv = GetTlv(aType)) != nullptr);
460 RemoveTlv(tlv);
461
462 exit:
463 return;
464 }
465
AppendMleDatasetTlv(Type aType,Message & aMessage) const466 Error Dataset::AppendMleDatasetTlv(Type aType, Message &aMessage) const
467 {
468 Error error = kErrorNone;
469 Mle::Tlv tlv;
470 Mle::Tlv::Type type;
471
472 VerifyOrExit(mLength > 0);
473
474 type = (aType == kActive ? Mle::Tlv::kActiveDataset : Mle::Tlv::kPendingDataset);
475
476 tlv.SetType(type);
477 tlv.SetLength(static_cast<uint8_t>(mLength) - sizeof(Tlv) - sizeof(Timestamp));
478 SuccessOrExit(error = aMessage.Append(tlv));
479
480 for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
481 {
482 if (((aType == kActive) && (cur->GetType() == Tlv::kActiveTimestamp)) ||
483 ((aType == kPending) && (cur->GetType() == Tlv::kPendingTimestamp)))
484 {
485 ; // skip Active or Pending Timestamp TLV
486 }
487 else if (cur->GetType() == Tlv::kDelayTimer)
488 {
489 uint32_t elapsed = TimerMilli::GetNow() - mUpdateTime;
490 DelayTimerTlv delayTimer = *As<DelayTimerTlv>(cur);
491
492 if (delayTimer.GetDelayTimer() > elapsed)
493 {
494 delayTimer.SetDelayTimer(delayTimer.GetDelayTimer() - elapsed);
495 }
496 else
497 {
498 delayTimer.SetDelayTimer(0);
499 }
500
501 SuccessOrExit(error = delayTimer.AppendTo(aMessage));
502 }
503 else
504 {
505 SuccessOrExit(error = cur->AppendTo(aMessage));
506 }
507 }
508
509 exit:
510 return error;
511 }
512
RemoveTlv(Tlv * aTlv)513 void Dataset::RemoveTlv(Tlv *aTlv)
514 {
515 uint8_t *start = reinterpret_cast<uint8_t *>(aTlv);
516 uint16_t length = sizeof(Tlv) + aTlv->GetLength();
517
518 memmove(start, start + length, mLength - (static_cast<uint8_t>(start - mTlvs) + length));
519 mLength -= length;
520 }
521
ApplyConfiguration(Instance & aInstance,bool * aIsNetworkKeyUpdated) const522 Error Dataset::ApplyConfiguration(Instance &aInstance, bool *aIsNetworkKeyUpdated) const
523 {
524 Mac::Mac & mac = aInstance.Get<Mac::Mac>();
525 KeyManager &keyManager = aInstance.Get<KeyManager>();
526 Error error = kErrorNone;
527
528 VerifyOrExit(IsValid(), error = kErrorParse);
529
530 if (aIsNetworkKeyUpdated)
531 {
532 *aIsNetworkKeyUpdated = false;
533 }
534
535 for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
536 {
537 switch (cur->GetType())
538 {
539 case Tlv::kChannel:
540 {
541 uint8_t channel = static_cast<uint8_t>(As<ChannelTlv>(cur)->GetChannel());
542
543 error = mac.SetPanChannel(channel);
544
545 if (error != kErrorNone)
546 {
547 LogWarn("ApplyConfiguration() Failed to set channel to %d (%s)", channel, ErrorToString(error));
548 ExitNow();
549 }
550
551 break;
552 }
553
554 case Tlv::kPanId:
555 mac.SetPanId(As<PanIdTlv>(cur)->GetPanId());
556 break;
557
558 case Tlv::kExtendedPanId:
559 aInstance.Get<ExtendedPanIdManager>().SetExtPanId(As<ExtendedPanIdTlv>(cur)->GetExtendedPanId());
560 break;
561
562 case Tlv::kNetworkName:
563 IgnoreError(aInstance.Get<NetworkNameManager>().SetNetworkName(As<NetworkNameTlv>(cur)->GetNetworkName()));
564 break;
565
566 case Tlv::kNetworkKey:
567 {
568 const NetworkKeyTlv *key = As<NetworkKeyTlv>(cur);
569 NetworkKey networkKey;
570
571 keyManager.GetNetworkKey(networkKey);
572
573 if (aIsNetworkKeyUpdated && (key->GetNetworkKey() != networkKey))
574 {
575 *aIsNetworkKeyUpdated = true;
576 }
577
578 keyManager.SetNetworkKey(key->GetNetworkKey());
579 break;
580 }
581
582 #if OPENTHREAD_FTD
583
584 case Tlv::kPskc:
585 keyManager.SetPskc(As<PskcTlv>(cur)->GetPskc());
586 break;
587
588 #endif
589
590 case Tlv::kMeshLocalPrefix:
591 aInstance.Get<Mle::MleRouter>().SetMeshLocalPrefix(As<MeshLocalPrefixTlv>(cur)->GetMeshLocalPrefix());
592 break;
593
594 case Tlv::kSecurityPolicy:
595 keyManager.SetSecurityPolicy(As<SecurityPolicyTlv>(cur)->GetSecurityPolicy());
596 break;
597
598 default:
599 break;
600 }
601 }
602
603 exit:
604 return error;
605 }
606
ConvertToActive(void)607 void Dataset::ConvertToActive(void)
608 {
609 RemoveTlv(Tlv::kPendingTimestamp);
610 RemoveTlv(Tlv::kDelayTimer);
611 }
612
TypeToString(Type aType)613 const char *Dataset::TypeToString(Type aType)
614 {
615 return (aType == kActive) ? "Active" : "Pending";
616 }
617
618 } // namespace MeshCoP
619 } // namespace ot
620