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 #include "dataset.hpp"
35
36 #include "instance/instance.hpp"
37
38 namespace ot {
39 namespace MeshCoP {
40
41 RegisterLogModule("Dataset");
42
GenerateRandom(Instance & aInstance)43 Error Dataset::Info::GenerateRandom(Instance &aInstance)
44 {
45 Error error;
46 Mac::ChannelMask supportedChannels = aInstance.Get<Mac::Mac>().GetSupportedChannelMask();
47 Mac::ChannelMask preferredChannels(aInstance.Get<Radio>().GetPreferredChannelMask());
48 StringWriter nameWriter(mNetworkName.m8, sizeof(mNetworkName));
49
50 // If the preferred channel mask is not empty, select a random
51 // channel from it, otherwise choose one from the supported
52 // channel mask.
53
54 preferredChannels.Intersect(supportedChannels);
55
56 if (preferredChannels.IsEmpty())
57 {
58 preferredChannels = supportedChannels;
59 }
60
61 Clear();
62
63 mActiveTimestamp.mSeconds = 1;
64 mActiveTimestamp.mTicks = 0;
65 mActiveTimestamp.mAuthoritative = false;
66 mChannel = preferredChannels.ChooseRandomChannel();
67 mChannelMask = supportedChannels.GetMask();
68 mWakeupChannel = supportedChannels.ChooseRandomChannel();
69 mPanId = Mac::GenerateRandomPanId();
70 AsCoreType(&mSecurityPolicy).SetToDefault();
71
72 SuccessOrExit(error = AsCoreType(&mNetworkKey).GenerateRandom());
73 SuccessOrExit(error = AsCoreType(&mPskc).GenerateRandom());
74 SuccessOrExit(error = Random::Crypto::Fill(mExtendedPanId));
75 SuccessOrExit(error = AsCoreType(&mMeshLocalPrefix).GenerateRandomUla());
76
77 nameWriter.Append("%s-%04x", NetworkName::kNetworkNameInit, mPanId);
78
79 mComponents.mIsActiveTimestampPresent = true;
80 mComponents.mIsNetworkKeyPresent = true;
81 mComponents.mIsNetworkNamePresent = true;
82 mComponents.mIsExtendedPanIdPresent = true;
83 mComponents.mIsMeshLocalPrefixPresent = true;
84 mComponents.mIsPanIdPresent = true;
85 mComponents.mIsChannelPresent = true;
86 mComponents.mIsWakeupChannelPresent = true;
87 mComponents.mIsPskcPresent = true;
88 mComponents.mIsSecurityPolicyPresent = true;
89 mComponents.mIsChannelMaskPresent = true;
90
91 exit:
92 return error;
93 }
94
Dataset(void)95 Dataset::Dataset(void)
96 : mLength(0)
97 , mUpdateTime(0)
98 {
99 ClearAllBytes(mTlvs);
100 }
101
ValidateTlvs(void) const102 Error Dataset::ValidateTlvs(void) const
103 {
104 Error error = kErrorParse;
105 const Tlv *end = GetTlvsEnd();
106 uint16_t validatedLength;
107
108 VerifyOrExit(mLength <= kMaxLength);
109
110 for (const Tlv *tlv = GetTlvsStart(); tlv < end; tlv = tlv->GetNext())
111 {
112 VerifyOrExit(!tlv->IsExtended() && ((tlv + 1) <= end) && (tlv->GetNext() <= end));
113 VerifyOrExit(IsTlvValid(*tlv));
114
115 // Ensure there are no duplicate TLVs.
116 validatedLength = static_cast<uint16_t>(reinterpret_cast<const uint8_t *>(tlv) - mTlvs);
117 VerifyOrExit(Tlv::FindTlv(mTlvs, validatedLength, tlv->GetType()) == nullptr);
118 }
119
120 error = kErrorNone;
121
122 exit:
123 return error;
124 }
125
IsTlvValid(const Tlv & aTlv)126 bool Dataset::IsTlvValid(const Tlv &aTlv)
127 {
128 bool isValid = true;
129 uint8_t minLength = 0;
130
131 switch (aTlv.GetType())
132 {
133 case Tlv::kActiveTimestamp:
134 minLength = sizeof(ActiveTimestampTlv::ValueType);
135 break;
136 case Tlv::kPendingTimestamp:
137 minLength = sizeof(PendingTimestampTlv::ValueType);
138 break;
139 case Tlv::kDelayTimer:
140 minLength = sizeof(DelayTimerTlv::UintValueType);
141 break;
142 case Tlv::kPanId:
143 minLength = sizeof(PanIdTlv::UintValueType);
144 break;
145 case Tlv::kExtendedPanId:
146 minLength = sizeof(ExtendedPanIdTlv::ValueType);
147 break;
148 case Tlv::kPskc:
149 minLength = sizeof(PskcTlv::ValueType);
150 break;
151 case Tlv::kNetworkKey:
152 minLength = sizeof(NetworkKeyTlv::ValueType);
153 break;
154 case Tlv::kMeshLocalPrefix:
155 minLength = sizeof(MeshLocalPrefixTlv::ValueType);
156 break;
157 case Tlv::kChannel:
158 VerifyOrExit(aTlv.GetLength() >= sizeof(ChannelTlvValue), isValid = false);
159 isValid = aTlv.ReadValueAs<ChannelTlv>().IsValid();
160 break;
161 case Tlv::kWakeupChannel:
162 VerifyOrExit(aTlv.GetLength() >= sizeof(ChannelTlvValue), isValid = false);
163 isValid = aTlv.ReadValueAs<WakeupChannelTlv>().IsValid();
164 break;
165 case Tlv::kNetworkName:
166 isValid = As<NetworkNameTlv>(aTlv).IsValid();
167 break;
168
169 case Tlv::kSecurityPolicy:
170 isValid = As<SecurityPolicyTlv>(aTlv).IsValid();
171 break;
172
173 case Tlv::kChannelMask:
174 isValid = As<ChannelMaskTlv>(aTlv).IsValid();
175 break;
176
177 default:
178 break;
179 }
180
181 if (minLength > 0)
182 {
183 isValid = (aTlv.GetLength() >= minLength);
184 }
185
186 exit:
187 return isValid;
188 }
189
ContainsAllTlvs(const Tlv::Type aTlvTypes[],uint8_t aLength) const190 bool Dataset::ContainsAllTlvs(const Tlv::Type aTlvTypes[], uint8_t aLength) const
191 {
192 bool containsAll = true;
193
194 for (uint8_t index = 0; index < aLength; index++)
195 {
196 if (!ContainsTlv(aTlvTypes[index]))
197 {
198 containsAll = false;
199 break;
200 }
201 }
202
203 return containsAll;
204 }
205
ContainsAllRequiredTlvsFor(Type aType) const206 bool Dataset::ContainsAllRequiredTlvsFor(Type aType) const
207 {
208 static const Tlv::Type kDatasetTlvs[] = {
209 Tlv::kActiveTimestamp,
210 Tlv::kChannel,
211 Tlv::kChannelMask,
212 Tlv::kExtendedPanId,
213 Tlv::kMeshLocalPrefix,
214 Tlv::kNetworkKey,
215 Tlv::kNetworkName,
216 Tlv::kPanId,
217 Tlv::kPskc,
218 Tlv::kSecurityPolicy,
219 // The last two TLVs are for Pending Dataset
220 Tlv::kPendingTimestamp,
221 Tlv::kDelayTimer,
222 };
223
224 uint8_t length = sizeof(kDatasetTlvs);
225
226 if (aType == kActive)
227 {
228 length -= 2;
229 }
230
231 return ContainsAllTlvs(kDatasetTlvs, length);
232 }
233
FindTlv(Tlv::Type aType) const234 const Tlv *Dataset::FindTlv(Tlv::Type aType) const { return As<Tlv>(Tlv::FindTlv(mTlvs, mLength, aType)); }
235
ConvertTo(Info & aDatasetInfo) const236 void Dataset::ConvertTo(Info &aDatasetInfo) const
237 {
238 aDatasetInfo.Clear();
239
240 for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
241 {
242 switch (cur->GetType())
243 {
244 case Tlv::kActiveTimestamp:
245 aDatasetInfo.Set<kActiveTimestamp>(cur->ReadValueAs<ActiveTimestampTlv>());
246 break;
247
248 case Tlv::kChannel:
249 aDatasetInfo.Set<kChannel>(cur->ReadValueAs<ChannelTlv>().GetChannel());
250 break;
251
252 case Tlv::kWakeupChannel:
253 aDatasetInfo.Set<kWakeupChannel>(cur->ReadValueAs<WakeupChannelTlv>().GetChannel());
254 break;
255
256 case Tlv::kChannelMask:
257 {
258 uint32_t mask;
259
260 if (As<ChannelMaskTlv>(cur)->ReadChannelMask(mask) == kErrorNone)
261 {
262 aDatasetInfo.Set<kChannelMask>(mask);
263 }
264
265 break;
266 }
267
268 case Tlv::kDelayTimer:
269 aDatasetInfo.Set<kDelay>(cur->ReadValueAs<DelayTimerTlv>());
270 break;
271
272 case Tlv::kExtendedPanId:
273 aDatasetInfo.Set<kExtendedPanId>(cur->ReadValueAs<ExtendedPanIdTlv>());
274 break;
275
276 case Tlv::kMeshLocalPrefix:
277 aDatasetInfo.Set<kMeshLocalPrefix>(cur->ReadValueAs<MeshLocalPrefixTlv>());
278 break;
279
280 case Tlv::kNetworkKey:
281 aDatasetInfo.Set<kNetworkKey>(cur->ReadValueAs<NetworkKeyTlv>());
282 break;
283
284 case Tlv::kNetworkName:
285 IgnoreError(aDatasetInfo.Update<kNetworkName>().Set(As<NetworkNameTlv>(cur)->GetNetworkName()));
286 break;
287
288 case Tlv::kPanId:
289 aDatasetInfo.Set<kPanId>(cur->ReadValueAs<PanIdTlv>());
290 break;
291
292 case Tlv::kPendingTimestamp:
293 aDatasetInfo.Set<kPendingTimestamp>(cur->ReadValueAs<PendingTimestampTlv>());
294 break;
295
296 case Tlv::kPskc:
297 aDatasetInfo.Set<kPskc>(cur->ReadValueAs<PskcTlv>());
298 break;
299
300 case Tlv::kSecurityPolicy:
301 aDatasetInfo.Set<kSecurityPolicy>(As<SecurityPolicyTlv>(cur)->GetSecurityPolicy());
302 break;
303
304 default:
305 break;
306 }
307 }
308 }
309
ConvertTo(Tlvs & aTlvs) const310 void Dataset::ConvertTo(Tlvs &aTlvs) const
311 {
312 memcpy(aTlvs.mTlvs, mTlvs, mLength);
313 aTlvs.mLength = static_cast<uint8_t>(mLength);
314 }
315
SetFrom(const Dataset & aDataset)316 void Dataset::SetFrom(const Dataset &aDataset)
317 {
318 memcpy(mTlvs, aDataset.mTlvs, aDataset.mLength);
319 mLength = aDataset.mLength;
320 mUpdateTime = aDataset.GetUpdateTime();
321 }
322
SetFrom(const Tlvs & aTlvs)323 Error Dataset::SetFrom(const Tlvs &aTlvs) { return SetFrom(aTlvs.mTlvs, aTlvs.mLength); }
324
SetFrom(const uint8_t * aTlvs,uint8_t aLength)325 Error Dataset::SetFrom(const uint8_t *aTlvs, uint8_t aLength)
326 {
327 Error error = kErrorNone;
328
329 VerifyOrExit(aLength <= kMaxLength, error = kErrorInvalidArgs);
330
331 mLength = aLength;
332 memcpy(mTlvs, aTlvs, mLength);
333
334 mUpdateTime = TimerMilli::GetNow();
335
336 exit:
337 return error;
338 }
339
SetFrom(const Info & aDatasetInfo)340 void Dataset::SetFrom(const Info &aDatasetInfo)
341 {
342 Clear();
343 IgnoreError(WriteTlvsFrom(aDatasetInfo));
344
345 // `mUpdateTime` is already set by `WriteTlvsFrom()`.
346 }
347
SetFrom(const Message & aMessage,const OffsetRange & aOffsetRange)348 Error Dataset::SetFrom(const Message &aMessage, const OffsetRange &aOffsetRange)
349 {
350 Error error = kErrorNone;
351
352 VerifyOrExit(aOffsetRange.GetLength() <= kMaxLength, error = kErrorInvalidArgs);
353
354 SuccessOrExit(error = aMessage.Read(aOffsetRange, mTlvs, aOffsetRange.GetLength()));
355 mLength = static_cast<uint8_t>(aOffsetRange.GetLength());
356
357 mUpdateTime = TimerMilli::GetNow();
358
359 exit:
360 return error;
361 }
362
WriteTlv(Tlv::Type aType,const void * aValue,uint8_t aLength)363 Error Dataset::WriteTlv(Tlv::Type aType, const void *aValue, uint8_t aLength)
364 {
365 Error error = kErrorNone;
366 uint16_t bytesAvailable = sizeof(mTlvs) - mLength;
367 Tlv *oldTlv = FindTlv(aType);
368 Tlv *newTlv;
369
370 if (oldTlv != nullptr)
371 {
372 bytesAvailable += sizeof(Tlv) + oldTlv->GetLength();
373 }
374
375 VerifyOrExit(sizeof(Tlv) + aLength <= bytesAvailable, error = kErrorNoBufs);
376
377 RemoveTlv(oldTlv);
378
379 newTlv = GetTlvsEnd();
380 mLength += sizeof(Tlv) + aLength;
381
382 newTlv->SetType(aType);
383 newTlv->SetLength(aLength);
384 memcpy(newTlv->GetValue(), aValue, aLength);
385
386 mUpdateTime = TimerMilli::GetNow();
387
388 exit:
389 return error;
390 }
391
WriteTlv(const Tlv & aTlv)392 Error Dataset::WriteTlv(const Tlv &aTlv) { return WriteTlv(aTlv.GetType(), aTlv.GetValue(), aTlv.GetLength()); }
393
WriteTlvsFrom(const Dataset & aDataset)394 Error Dataset::WriteTlvsFrom(const Dataset &aDataset)
395 {
396 Error error;
397
398 SuccessOrExit(error = aDataset.ValidateTlvs());
399
400 for (const Tlv *tlv = aDataset.GetTlvsStart(); tlv < aDataset.GetTlvsEnd(); tlv = tlv->GetNext())
401 {
402 SuccessOrExit(error = WriteTlv(*tlv));
403 }
404
405 exit:
406 return error;
407 }
408
WriteTlvsFrom(const uint8_t * aTlvs,uint8_t aLength)409 Error Dataset::WriteTlvsFrom(const uint8_t *aTlvs, uint8_t aLength)
410 {
411 Error error;
412 Dataset dataset;
413
414 SuccessOrExit(error = dataset.SetFrom(aTlvs, aLength));
415 error = WriteTlvsFrom(dataset);
416
417 exit:
418 return error;
419 }
420
WriteTlvsFrom(const Dataset::Info & aDatasetInfo)421 Error Dataset::WriteTlvsFrom(const Dataset::Info &aDatasetInfo)
422 {
423 Error error = kErrorNone;
424
425 if (aDatasetInfo.IsPresent<kActiveTimestamp>())
426 {
427 Timestamp activeTimestamp;
428
429 aDatasetInfo.Get<kActiveTimestamp>(activeTimestamp);
430 SuccessOrExit(error = Write<ActiveTimestampTlv>(activeTimestamp));
431 }
432
433 if (aDatasetInfo.IsPresent<kPendingTimestamp>())
434 {
435 Timestamp pendingTimestamp;
436
437 aDatasetInfo.Get<kPendingTimestamp>(pendingTimestamp);
438 SuccessOrExit(error = Write<PendingTimestampTlv>(pendingTimestamp));
439 }
440
441 if (aDatasetInfo.IsPresent<kDelay>())
442 {
443 SuccessOrExit(error = Write<DelayTimerTlv>(aDatasetInfo.Get<kDelay>()));
444 }
445
446 if (aDatasetInfo.IsPresent<kChannel>())
447 {
448 ChannelTlvValue channelValue;
449
450 channelValue.SetChannelAndPage(aDatasetInfo.Get<kChannel>());
451 SuccessOrExit(error = Write<ChannelTlv>(channelValue));
452 }
453
454 if (aDatasetInfo.IsPresent<kWakeupChannel>())
455 {
456 ChannelTlvValue channelValue;
457
458 channelValue.SetChannelAndPage(aDatasetInfo.Get<kWakeupChannel>());
459 SuccessOrExit(error = Write<WakeupChannelTlv>(channelValue));
460 }
461
462 if (aDatasetInfo.IsPresent<kChannelMask>())
463 {
464 ChannelMaskTlv::Value value;
465
466 ChannelMaskTlv::PrepareValue(value, aDatasetInfo.Get<kChannelMask>());
467 SuccessOrExit(error = WriteTlv(Tlv::kChannelMask, value.mData, value.mLength));
468 }
469
470 if (aDatasetInfo.IsPresent<kExtendedPanId>())
471 {
472 SuccessOrExit(error = Write<ExtendedPanIdTlv>(aDatasetInfo.Get<kExtendedPanId>()));
473 }
474
475 if (aDatasetInfo.IsPresent<kMeshLocalPrefix>())
476 {
477 SuccessOrExit(error = Write<MeshLocalPrefixTlv>(aDatasetInfo.Get<kMeshLocalPrefix>()));
478 }
479
480 if (aDatasetInfo.IsPresent<kNetworkKey>())
481 {
482 SuccessOrExit(error = Write<NetworkKeyTlv>(aDatasetInfo.Get<kNetworkKey>()));
483 }
484
485 if (aDatasetInfo.IsPresent<kNetworkName>())
486 {
487 NameData nameData = aDatasetInfo.Get<kNetworkName>().GetAsData();
488
489 SuccessOrExit(error = WriteTlv(Tlv::kNetworkName, nameData.GetBuffer(), nameData.GetLength()));
490 }
491
492 if (aDatasetInfo.IsPresent<kPanId>())
493 {
494 SuccessOrExit(error = Write<PanIdTlv>(aDatasetInfo.Get<kPanId>()));
495 }
496
497 if (aDatasetInfo.IsPresent<kPskc>())
498 {
499 SuccessOrExit(error = Write<PskcTlv>(aDatasetInfo.Get<kPskc>()));
500 }
501
502 if (aDatasetInfo.IsPresent<kSecurityPolicy>())
503 {
504 SecurityPolicyTlv tlv;
505
506 tlv.Init();
507 tlv.SetSecurityPolicy(aDatasetInfo.Get<kSecurityPolicy>());
508 SuccessOrExit(error = WriteTlv(tlv));
509 }
510
511 exit:
512 return error;
513 }
514
AppendTlvsFrom(const uint8_t * aTlvs,uint8_t aLength)515 Error Dataset::AppendTlvsFrom(const uint8_t *aTlvs, uint8_t aLength)
516 {
517 Error error = kErrorNone;
518 uint16_t newLength = mLength;
519
520 newLength += aLength;
521 VerifyOrExit(newLength <= kMaxLength, error = kErrorNoBufs);
522
523 memcpy(mTlvs + mLength, aTlvs, aLength);
524 mLength += aLength;
525
526 exit:
527 return error;
528 }
529
RemoveTlv(Tlv::Type aType)530 void Dataset::RemoveTlv(Tlv::Type aType) { RemoveTlv(FindTlv(aType)); }
531
RemoveTlv(Tlv * aTlv)532 void Dataset::RemoveTlv(Tlv *aTlv)
533 {
534 if (aTlv != nullptr)
535 {
536 uint8_t *start = reinterpret_cast<uint8_t *>(aTlv);
537 uint16_t length = sizeof(Tlv) + aTlv->GetLength();
538
539 memmove(start, start + length, mLength - (static_cast<uint8_t>(start - mTlvs) + length));
540 mLength -= length;
541 }
542 }
543
ReadTimestamp(Type aType,Timestamp & aTimestamp) const544 Error Dataset::ReadTimestamp(Type aType, Timestamp &aTimestamp) const
545 {
546 Error error = kErrorNone;
547 const Tlv *tlv = FindTlv(TimestampTlvFor(aType));
548
549 VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
550
551 // Since both `ActiveTimestampTlv` and `PendingTimestampTlv` use
552 // `Timestamp` as their TLV value format, we can safely use
553 // `ReadValueAs<ActiveTimestampTlv>()` for both.
554
555 aTimestamp = tlv->ReadValueAs<ActiveTimestampTlv>();
556
557 exit:
558 return error;
559 }
560
WriteTimestamp(Type aType,const Timestamp & aTimestamp)561 Error Dataset::WriteTimestamp(Type aType, const Timestamp &aTimestamp)
562 {
563 return WriteTlv(TimestampTlvFor(aType), &aTimestamp, sizeof(Timestamp));
564 }
565
RemoveTimestamp(Type aType)566 void Dataset::RemoveTimestamp(Type aType) { RemoveTlv(TimestampTlvFor(aType)); }
567
IsSubsetOf(const Dataset & aOther) const568 bool Dataset::IsSubsetOf(const Dataset &aOther) const
569 {
570 bool isSubset = false;
571
572 for (const Tlv *tlv = GetTlvsStart(); tlv < GetTlvsEnd(); tlv = tlv->GetNext())
573 {
574 const Tlv *otherTlv;
575
576 if ((tlv->GetType() == Tlv::kActiveTimestamp) || (tlv->GetType() == Tlv::kPendingTimestamp) ||
577 (tlv->GetType() == Tlv::kDelayTimer))
578 {
579 continue;
580 }
581
582 otherTlv = aOther.FindTlv(tlv->GetType());
583 VerifyOrExit(otherTlv != nullptr);
584 VerifyOrExit(memcmp(tlv, otherTlv, tlv->GetSize()) == 0);
585 }
586
587 isSubset = true;
588
589 exit:
590 return isSubset;
591 }
592
TypeToString(Type aType)593 const char *Dataset::TypeToString(Type aType) { return (aType == kActive) ? "Active" : "Pending"; }
594
595 } // namespace MeshCoP
596 } // namespace ot
597