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