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::Fill(mExtendedPanId));
84 SuccessOrExit(error = AsCoreType(&mMeshLocalPrefix).GenerateRandomUla());
85
86 snprintf(mNetworkName.m8, sizeof(mNetworkName), "%s-%04x", NetworkName::kNetworkNameInit, 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) { mLength = 0; }
166
IsValid(void) const167 bool Dataset::IsValid(void) const
168 {
169 bool rval = true;
170 const Tlv *end = GetTlvsEnd();
171
172 for (const Tlv *cur = GetTlvsStart(); cur < end; cur = cur->GetNext())
173 {
174 VerifyOrExit(!cur->IsExtended() && (cur + 1) <= end && cur->GetNext() <= end && Tlv::IsValid(*cur),
175 rval = false);
176 }
177
178 exit:
179 return rval;
180 }
181
GetTlv(Tlv::Type aType) const182 const Tlv *Dataset::GetTlv(Tlv::Type aType) const { return Tlv::FindTlv(mTlvs, mLength, aType); }
183
ConvertTo(Info & aDatasetInfo) const184 void Dataset::ConvertTo(Info &aDatasetInfo) const
185 {
186 aDatasetInfo.Clear();
187
188 for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
189 {
190 switch (cur->GetType())
191 {
192 case Tlv::kActiveTimestamp:
193 aDatasetInfo.SetActiveTimestamp(As<ActiveTimestampTlv>(cur)->GetTimestamp());
194 break;
195
196 case Tlv::kChannel:
197 aDatasetInfo.SetChannel(As<ChannelTlv>(cur)->GetChannel());
198 break;
199
200 case Tlv::kChannelMask:
201 {
202 uint32_t mask = As<ChannelMaskTlv>(cur)->GetChannelMask();
203
204 if (mask != 0)
205 {
206 aDatasetInfo.SetChannelMask(mask);
207 }
208
209 break;
210 }
211
212 case Tlv::kDelayTimer:
213 aDatasetInfo.SetDelay(As<DelayTimerTlv>(cur)->GetDelayTimer());
214 break;
215
216 case Tlv::kExtendedPanId:
217 aDatasetInfo.SetExtendedPanId(As<ExtendedPanIdTlv>(cur)->GetExtendedPanId());
218 break;
219
220 case Tlv::kMeshLocalPrefix:
221 aDatasetInfo.SetMeshLocalPrefix(As<MeshLocalPrefixTlv>(cur)->GetMeshLocalPrefix());
222 break;
223
224 case Tlv::kNetworkKey:
225 aDatasetInfo.SetNetworkKey(As<NetworkKeyTlv>(cur)->GetNetworkKey());
226 break;
227
228 case Tlv::kNetworkName:
229 aDatasetInfo.SetNetworkName(As<NetworkNameTlv>(cur)->GetNetworkName());
230 break;
231
232 case Tlv::kPanId:
233 aDatasetInfo.SetPanId(As<PanIdTlv>(cur)->GetPanId());
234 break;
235
236 case Tlv::kPendingTimestamp:
237 aDatasetInfo.SetPendingTimestamp(As<PendingTimestampTlv>(cur)->GetTimestamp());
238 break;
239
240 case Tlv::kPskc:
241 aDatasetInfo.SetPskc(As<PskcTlv>(cur)->GetPskc());
242 break;
243
244 case Tlv::kSecurityPolicy:
245 aDatasetInfo.SetSecurityPolicy(As<SecurityPolicyTlv>(cur)->GetSecurityPolicy());
246 break;
247
248 default:
249 break;
250 }
251 }
252 }
253
ConvertTo(otOperationalDatasetTlvs & aDataset) const254 void Dataset::ConvertTo(otOperationalDatasetTlvs &aDataset) const
255 {
256 memcpy(aDataset.mTlvs, mTlvs, mLength);
257 aDataset.mLength = static_cast<uint8_t>(mLength);
258 }
259
Set(Type aType,const Dataset & aDataset)260 void Dataset::Set(Type aType, const Dataset &aDataset)
261 {
262 memcpy(mTlvs, aDataset.mTlvs, aDataset.mLength);
263 mLength = aDataset.mLength;
264
265 if (aType == kActive)
266 {
267 RemoveTlv(Tlv::kPendingTimestamp);
268 RemoveTlv(Tlv::kDelayTimer);
269 }
270
271 mUpdateTime = aDataset.GetUpdateTime();
272 }
273
SetFrom(const otOperationalDatasetTlvs & aDataset)274 void Dataset::SetFrom(const otOperationalDatasetTlvs &aDataset)
275 {
276 mLength = aDataset.mLength;
277 memcpy(mTlvs, aDataset.mTlvs, mLength);
278 }
279
SetFrom(const Info & aDatasetInfo)280 Error Dataset::SetFrom(const Info &aDatasetInfo)
281 {
282 Error error = kErrorNone;
283
284 if (aDatasetInfo.IsActiveTimestampPresent())
285 {
286 Timestamp activeTimestamp;
287
288 aDatasetInfo.GetActiveTimestamp(activeTimestamp);
289 IgnoreError(SetTlv(Tlv::kActiveTimestamp, activeTimestamp));
290 }
291
292 if (aDatasetInfo.IsPendingTimestampPresent())
293 {
294 Timestamp pendingTimestamp;
295
296 aDatasetInfo.GetPendingTimestamp(pendingTimestamp);
297 IgnoreError(SetTlv(Tlv::kPendingTimestamp, pendingTimestamp));
298 }
299
300 if (aDatasetInfo.IsDelayPresent())
301 {
302 IgnoreError(SetTlv(Tlv::kDelayTimer, aDatasetInfo.GetDelay()));
303 }
304
305 if (aDatasetInfo.IsChannelPresent())
306 {
307 ChannelTlv tlv;
308 tlv.Init();
309 tlv.SetChannel(aDatasetInfo.GetChannel());
310 IgnoreError(SetTlv(tlv));
311 }
312
313 if (aDatasetInfo.IsChannelMaskPresent())
314 {
315 ChannelMaskTlv tlv;
316 tlv.Init();
317 tlv.SetChannelMask(aDatasetInfo.GetChannelMask());
318 IgnoreError(SetTlv(tlv));
319 }
320
321 if (aDatasetInfo.IsExtendedPanIdPresent())
322 {
323 IgnoreError(SetTlv(Tlv::kExtendedPanId, aDatasetInfo.GetExtendedPanId()));
324 }
325
326 if (aDatasetInfo.IsMeshLocalPrefixPresent())
327 {
328 IgnoreError(SetTlv(Tlv::kMeshLocalPrefix, aDatasetInfo.GetMeshLocalPrefix()));
329 }
330
331 if (aDatasetInfo.IsNetworkKeyPresent())
332 {
333 IgnoreError(SetTlv(Tlv::kNetworkKey, aDatasetInfo.GetNetworkKey()));
334 }
335
336 if (aDatasetInfo.IsNetworkNamePresent())
337 {
338 NameData nameData = aDatasetInfo.GetNetworkName().GetAsData();
339
340 IgnoreError(SetTlv(Tlv::kNetworkName, nameData.GetBuffer(), nameData.GetLength()));
341 }
342
343 if (aDatasetInfo.IsPanIdPresent())
344 {
345 IgnoreError(SetTlv(Tlv::kPanId, aDatasetInfo.GetPanId()));
346 }
347
348 if (aDatasetInfo.IsPskcPresent())
349 {
350 IgnoreError(SetTlv(Tlv::kPskc, aDatasetInfo.GetPskc()));
351 }
352
353 if (aDatasetInfo.IsSecurityPolicyPresent())
354 {
355 SecurityPolicyTlv tlv;
356
357 tlv.Init();
358 tlv.SetSecurityPolicy(aDatasetInfo.GetSecurityPolicy());
359 IgnoreError(SetTlv(tlv));
360 }
361
362 mUpdateTime = TimerMilli::GetNow();
363
364 return error;
365 }
366
GetTimestamp(Type aType,Timestamp & aTimestamp) const367 Error Dataset::GetTimestamp(Type aType, Timestamp &aTimestamp) const
368 {
369 Error error = kErrorNone;
370
371 if (aType == kActive)
372 {
373 const ActiveTimestampTlv *tlv = GetTlv<ActiveTimestampTlv>();
374
375 VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
376 aTimestamp = tlv->GetTimestamp();
377 }
378 else
379 {
380 const PendingTimestampTlv *tlv = GetTlv<PendingTimestampTlv>();
381
382 VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
383 aTimestamp = tlv->GetTimestamp();
384 }
385
386 exit:
387 return error;
388 }
389
SetTimestamp(Type aType,const Timestamp & aTimestamp)390 void Dataset::SetTimestamp(Type aType, const Timestamp &aTimestamp)
391 {
392 IgnoreError(SetTlv((aType == kActive) ? Tlv::kActiveTimestamp : Tlv::kPendingTimestamp, aTimestamp));
393 }
394
SetTlv(Tlv::Type aType,const void * aValue,uint8_t aLength)395 Error Dataset::SetTlv(Tlv::Type aType, const void *aValue, uint8_t aLength)
396 {
397 Error error = kErrorNone;
398 uint16_t bytesAvailable = sizeof(mTlvs) - mLength;
399 Tlv *old = GetTlv(aType);
400 Tlv tlv;
401
402 if (old != nullptr)
403 {
404 bytesAvailable += sizeof(Tlv) + old->GetLength();
405 }
406
407 VerifyOrExit(sizeof(Tlv) + aLength <= bytesAvailable, error = kErrorNoBufs);
408
409 if (old != nullptr)
410 {
411 RemoveTlv(old);
412 }
413
414 tlv.SetType(aType);
415 tlv.SetLength(aLength);
416 memcpy(mTlvs + mLength, &tlv, sizeof(Tlv));
417 mLength += sizeof(Tlv);
418
419 memcpy(mTlvs + mLength, aValue, aLength);
420 mLength += aLength;
421
422 mUpdateTime = TimerMilli::GetNow();
423
424 exit:
425 return error;
426 }
427
SetTlv(const Tlv & aTlv)428 Error Dataset::SetTlv(const Tlv &aTlv) { return SetTlv(aTlv.GetType(), aTlv.GetValue(), aTlv.GetLength()); }
429
ReadFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)430 Error Dataset::ReadFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
431 {
432 Error error = kErrorParse;
433
434 VerifyOrExit(aLength <= kMaxSize);
435
436 SuccessOrExit(aMessage.Read(aOffset, mTlvs, aLength));
437 mLength = aLength;
438
439 VerifyOrExit(IsValid(), error = kErrorParse);
440
441 mUpdateTime = TimerMilli::GetNow();
442 error = kErrorNone;
443
444 exit:
445 return error;
446 }
447
RemoveTlv(Tlv::Type aType)448 void Dataset::RemoveTlv(Tlv::Type aType)
449 {
450 Tlv *tlv;
451
452 VerifyOrExit((tlv = GetTlv(aType)) != nullptr);
453 RemoveTlv(tlv);
454
455 exit:
456 return;
457 }
458
AppendMleDatasetTlv(Type aType,Message & aMessage) const459 Error Dataset::AppendMleDatasetTlv(Type aType, Message &aMessage) const
460 {
461 Error error = kErrorNone;
462 Mle::Tlv tlv;
463 Mle::Tlv::Type type;
464
465 VerifyOrExit(mLength > 0);
466
467 type = (aType == kActive ? Mle::Tlv::kActiveDataset : Mle::Tlv::kPendingDataset);
468
469 tlv.SetType(type);
470 tlv.SetLength(static_cast<uint8_t>(mLength) - sizeof(Tlv) - sizeof(Timestamp));
471 SuccessOrExit(error = aMessage.Append(tlv));
472
473 for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
474 {
475 if (((aType == kActive) && (cur->GetType() == Tlv::kActiveTimestamp)) ||
476 ((aType == kPending) && (cur->GetType() == Tlv::kPendingTimestamp)))
477 {
478 ; // skip Active or Pending Timestamp TLV
479 }
480 else if (cur->GetType() == Tlv::kDelayTimer)
481 {
482 uint32_t elapsed = TimerMilli::GetNow() - mUpdateTime;
483 DelayTimerTlv delayTimer = *As<DelayTimerTlv>(cur);
484
485 if (delayTimer.GetDelayTimer() > elapsed)
486 {
487 delayTimer.SetDelayTimer(delayTimer.GetDelayTimer() - elapsed);
488 }
489 else
490 {
491 delayTimer.SetDelayTimer(0);
492 }
493
494 SuccessOrExit(error = delayTimer.AppendTo(aMessage));
495 }
496 else
497 {
498 SuccessOrExit(error = cur->AppendTo(aMessage));
499 }
500 }
501
502 exit:
503 return error;
504 }
505
RemoveTlv(Tlv * aTlv)506 void Dataset::RemoveTlv(Tlv *aTlv)
507 {
508 uint8_t *start = reinterpret_cast<uint8_t *>(aTlv);
509 uint16_t length = sizeof(Tlv) + aTlv->GetLength();
510
511 memmove(start, start + length, mLength - (static_cast<uint8_t>(start - mTlvs) + length));
512 mLength -= length;
513 }
514
ApplyConfiguration(Instance & aInstance,bool * aIsNetworkKeyUpdated) const515 Error Dataset::ApplyConfiguration(Instance &aInstance, bool *aIsNetworkKeyUpdated) const
516 {
517 Mac::Mac &mac = aInstance.Get<Mac::Mac>();
518 KeyManager &keyManager = aInstance.Get<KeyManager>();
519 Error error = kErrorNone;
520
521 VerifyOrExit(IsValid(), error = kErrorParse);
522
523 if (aIsNetworkKeyUpdated)
524 {
525 *aIsNetworkKeyUpdated = false;
526 }
527
528 for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
529 {
530 switch (cur->GetType())
531 {
532 case Tlv::kChannel:
533 {
534 uint8_t channel = static_cast<uint8_t>(As<ChannelTlv>(cur)->GetChannel());
535
536 error = mac.SetPanChannel(channel);
537
538 if (error != kErrorNone)
539 {
540 LogWarn("ApplyConfiguration() Failed to set channel to %d (%s)", channel, ErrorToString(error));
541 ExitNow();
542 }
543
544 break;
545 }
546
547 case Tlv::kPanId:
548 mac.SetPanId(As<PanIdTlv>(cur)->GetPanId());
549 break;
550
551 case Tlv::kExtendedPanId:
552 aInstance.Get<ExtendedPanIdManager>().SetExtPanId(As<ExtendedPanIdTlv>(cur)->GetExtendedPanId());
553 break;
554
555 case Tlv::kNetworkName:
556 IgnoreError(aInstance.Get<NetworkNameManager>().SetNetworkName(As<NetworkNameTlv>(cur)->GetNetworkName()));
557 break;
558
559 case Tlv::kNetworkKey:
560 {
561 const NetworkKeyTlv *key = As<NetworkKeyTlv>(cur);
562 NetworkKey networkKey;
563
564 keyManager.GetNetworkKey(networkKey);
565
566 if (aIsNetworkKeyUpdated && (key->GetNetworkKey() != networkKey))
567 {
568 *aIsNetworkKeyUpdated = true;
569 }
570
571 keyManager.SetNetworkKey(key->GetNetworkKey());
572 break;
573 }
574
575 #if OPENTHREAD_FTD
576
577 case Tlv::kPskc:
578 keyManager.SetPskc(As<PskcTlv>(cur)->GetPskc());
579 break;
580
581 #endif
582
583 case Tlv::kMeshLocalPrefix:
584 aInstance.Get<Mle::MleRouter>().SetMeshLocalPrefix(As<MeshLocalPrefixTlv>(cur)->GetMeshLocalPrefix());
585 break;
586
587 case Tlv::kSecurityPolicy:
588 keyManager.SetSecurityPolicy(As<SecurityPolicyTlv>(cur)->GetSecurityPolicy());
589 break;
590
591 default:
592 break;
593 }
594 }
595
596 exit:
597 return error;
598 }
599
ConvertToActive(void)600 void Dataset::ConvertToActive(void)
601 {
602 RemoveTlv(Tlv::kPendingTimestamp);
603 RemoveTlv(Tlv::kDelayTimer);
604 }
605
TypeToString(Type aType)606 const char *Dataset::TypeToString(Type aType) { return (aType == kActive) ? "Active" : "Pending"; }
607
608 } // namespace MeshCoP
609 } // namespace ot
610