• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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