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 the Thread Network Data managed by the Thread Leader.
32  */
33 
34 #include "network_data_leader.hpp"
35 
36 #include "coap/coap_message.hpp"
37 #include "common/code_utils.hpp"
38 #include "common/debug.hpp"
39 #include "common/encoding.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/logging.hpp"
43 #include "common/message.hpp"
44 #include "common/random.hpp"
45 #include "common/timer.hpp"
46 #include "mac/mac_types.hpp"
47 #include "thread/lowpan.hpp"
48 #include "thread/mle_router.hpp"
49 #include "thread/thread_netif.hpp"
50 #include "thread/thread_tlvs.hpp"
51 #include "thread/uri_paths.hpp"
52 
53 namespace ot {
54 namespace NetworkData {
55 
56 RegisterLogModule("NetworkData");
57 
Reset(void)58 void LeaderBase::Reset(void)
59 {
60     mVersion       = Random::NonCrypto::GetUint8();
61     mStableVersion = Random::NonCrypto::GetUint8();
62     SetLength(0);
63     SignalNetDataChanged();
64 }
65 
GetServiceId(uint32_t aEnterpriseNumber,const ServiceData & aServiceData,bool aServerStable,uint8_t & aServiceId) const66 Error LeaderBase::GetServiceId(uint32_t           aEnterpriseNumber,
67                                const ServiceData &aServiceData,
68                                bool               aServerStable,
69                                uint8_t           &aServiceId) const
70 {
71     Error         error    = kErrorNotFound;
72     Iterator      iterator = kIteratorInit;
73     ServiceConfig serviceConfig;
74     ServiceData   serviceData;
75 
76     while (GetNextService(iterator, serviceConfig) == kErrorNone)
77     {
78         serviceConfig.GetServiceData(serviceData);
79 
80         if (aEnterpriseNumber == serviceConfig.mEnterpriseNumber && aServiceData == serviceData &&
81             aServerStable == serviceConfig.mServerConfig.mStable)
82         {
83             aServiceId = serviceConfig.mServiceId;
84             ExitNow(error = kErrorNone);
85         }
86     }
87 
88 exit:
89     return error;
90 }
91 
GetPreferredNat64Prefix(ExternalRouteConfig & aConfig) const92 Error LeaderBase::GetPreferredNat64Prefix(ExternalRouteConfig &aConfig) const
93 {
94     Error               error    = kErrorNotFound;
95     Iterator            iterator = kIteratorInit;
96     ExternalRouteConfig config;
97 
98     while (GetNextExternalRoute(iterator, config) == kErrorNone)
99     {
100         if (!config.mNat64 || !config.GetPrefix().IsValidNat64())
101         {
102             continue;
103         }
104 
105         if ((error == kErrorNotFound) || (config.mPreference > aConfig.mPreference) ||
106             (config.mPreference == aConfig.mPreference && config.GetPrefix() < aConfig.GetPrefix()))
107         {
108             aConfig = config;
109             error   = kErrorNone;
110         }
111     }
112 
113     return error;
114 }
115 
FindNextMatchingPrefixTlv(const Ip6::Address & aAddress,const PrefixTlv * aPrevTlv) const116 const PrefixTlv *LeaderBase::FindNextMatchingPrefixTlv(const Ip6::Address &aAddress, const PrefixTlv *aPrevTlv) const
117 {
118     // This method iterates over Prefix TLVs which match a given IPv6
119     // `aAddress`. If `aPrevTlv` is `nullptr` we start from the
120     // beginning. Otherwise, we search for a match after `aPrevTlv`.
121     // This method returns a pointer to the next matching Prefix TLV
122     // when found, or `nullptr` if no match is found.
123 
124     const PrefixTlv *prefixTlv;
125     TlvIterator      tlvIterator((aPrevTlv == nullptr) ? GetTlvsStart() : aPrevTlv->GetNext(), GetTlvsEnd());
126 
127     while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
128     {
129         if (aAddress.MatchesPrefix(prefixTlv->GetPrefix(), prefixTlv->GetPrefixLength()))
130         {
131             break;
132         }
133     }
134 
135     return prefixTlv;
136 }
137 
GetContext(const Ip6::Address & aAddress,Lowpan::Context & aContext) const138 Error LeaderBase::GetContext(const Ip6::Address &aAddress, Lowpan::Context &aContext) const
139 {
140     const PrefixTlv  *prefixTlv = nullptr;
141     const ContextTlv *contextTlv;
142 
143     aContext.mPrefix.SetLength(0);
144 
145     if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
146     {
147         GetContextForMeshLocalPrefix(aContext);
148     }
149 
150     while ((prefixTlv = FindNextMatchingPrefixTlv(aAddress, prefixTlv)) != nullptr)
151     {
152         contextTlv = prefixTlv->FindSubTlv<ContextTlv>();
153 
154         if (contextTlv == nullptr)
155         {
156             continue;
157         }
158 
159         if (prefixTlv->GetPrefixLength() > aContext.mPrefix.GetLength())
160         {
161             prefixTlv->CopyPrefixTo(aContext.mPrefix);
162             aContext.mContextId    = contextTlv->GetContextId();
163             aContext.mCompressFlag = contextTlv->IsCompress();
164             aContext.mIsValid      = true;
165         }
166     }
167 
168     return (aContext.mPrefix.GetLength() > 0) ? kErrorNone : kErrorNotFound;
169 }
170 
GetContext(uint8_t aContextId,Lowpan::Context & aContext) const171 Error LeaderBase::GetContext(uint8_t aContextId, Lowpan::Context &aContext) const
172 {
173     Error            error = kErrorNotFound;
174     TlvIterator      tlvIterator(GetTlvsStart(), GetTlvsEnd());
175     const PrefixTlv *prefixTlv;
176 
177     if (aContextId == Mle::kMeshLocalPrefixContextId)
178     {
179         GetContextForMeshLocalPrefix(aContext);
180         ExitNow(error = kErrorNone);
181     }
182 
183     while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
184     {
185         const ContextTlv *contextTlv = prefixTlv->FindSubTlv<ContextTlv>();
186 
187         if ((contextTlv == nullptr) || (contextTlv->GetContextId() != aContextId))
188         {
189             continue;
190         }
191 
192         prefixTlv->CopyPrefixTo(aContext.mPrefix);
193         aContext.mContextId    = contextTlv->GetContextId();
194         aContext.mCompressFlag = contextTlv->IsCompress();
195         aContext.mIsValid      = true;
196         ExitNow(error = kErrorNone);
197     }
198 
199 exit:
200     return error;
201 }
202 
GetContextForMeshLocalPrefix(Lowpan::Context & aContext) const203 void LeaderBase::GetContextForMeshLocalPrefix(Lowpan::Context &aContext) const
204 {
205     aContext.mPrefix.Set(Get<Mle::MleRouter>().GetMeshLocalPrefix());
206     aContext.mContextId    = Mle::kMeshLocalPrefixContextId;
207     aContext.mCompressFlag = true;
208     aContext.mIsValid      = true;
209 }
210 
IsOnMesh(const Ip6::Address & aAddress) const211 bool LeaderBase::IsOnMesh(const Ip6::Address &aAddress) const
212 {
213     const PrefixTlv *prefixTlv = nullptr;
214     bool             isOnMesh  = false;
215 
216     VerifyOrExit(!Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress), isOnMesh = true);
217 
218     while ((prefixTlv = FindNextMatchingPrefixTlv(aAddress, prefixTlv)) != nullptr)
219     {
220         TlvIterator            subTlvIterator(*prefixTlv);
221         const BorderRouterTlv *brTlv;
222 
223         while ((brTlv = subTlvIterator.Iterate<BorderRouterTlv>()) != nullptr)
224         {
225             for (const BorderRouterEntry *entry = brTlv->GetFirstEntry(); entry <= brTlv->GetLastEntry();
226                  entry                          = entry->GetNext())
227             {
228                 if (entry->IsOnMesh())
229                 {
230                     ExitNow(isOnMesh = true);
231                 }
232             }
233         }
234     }
235 
236 exit:
237     return isOnMesh;
238 }
239 
RouteLookup(const Ip6::Address & aSource,const Ip6::Address & aDestination,uint16_t & aRloc16) const240 Error LeaderBase::RouteLookup(const Ip6::Address &aSource, const Ip6::Address &aDestination, uint16_t &aRloc16) const
241 {
242     Error            error     = kErrorNoRoute;
243     const PrefixTlv *prefixTlv = nullptr;
244 
245     while ((prefixTlv = FindNextMatchingPrefixTlv(aSource, prefixTlv)) != nullptr)
246     {
247         if (ExternalRouteLookup(prefixTlv->GetDomainId(), aDestination, aRloc16) == kErrorNone)
248         {
249             ExitNow(error = kErrorNone);
250         }
251 
252         if (DefaultRouteLookup(*prefixTlv, aRloc16) == kErrorNone)
253         {
254             ExitNow(error = kErrorNone);
255         }
256     }
257 
258 exit:
259     return error;
260 }
261 
262 template <typename EntryType>
CompareRouteEntries(const EntryType & aFirst,const EntryType & aSecond) const263 int LeaderBase::CompareRouteEntries(const EntryType &aFirst, const EntryType &aSecond) const
264 {
265     // `EntryType` can be `HasRouteEntry` or `BorderRouterEntry`.
266 
267     return CompareRouteEntries(aFirst.GetPreference(), aFirst.GetRloc(), aSecond.GetPreference(), aSecond.GetRloc());
268 }
269 
CompareRouteEntries(int8_t aFirstPreference,uint16_t aFirstRloc,int8_t aSecondPreference,uint16_t aSecondRloc) const270 int LeaderBase::CompareRouteEntries(int8_t   aFirstPreference,
271                                     uint16_t aFirstRloc,
272                                     int8_t   aSecondPreference,
273                                     uint16_t aSecondRloc) const
274 {
275     // Performs three-way comparison between two BR entries.
276 
277     int result;
278 
279     // Prefer the entry with higher preference.
280 
281     result = ThreeWayCompare(aFirstPreference, aSecondPreference);
282     VerifyOrExit(result == 0);
283 
284 #if OPENTHREAD_MTD
285     // On MTD, prefer the BR that is this device itself. This handles
286     // the uncommon case where an MTD itself may be acting as BR.
287 
288     result = ThreeWayCompare((aFirstRloc == Get<Mle::Mle>().GetRloc16()), (aSecondRloc == Get<Mle::Mle>().GetRloc16()));
289 #endif
290 
291 #if OPENTHREAD_FTD
292     // If all the same, prefer the one with lower mesh path cost.
293     // Lower cost is preferred so we pass the second entry's cost as
294     // the first argument in the call to `ThreeWayCompare()`, i.e.,
295     // if the second entry's cost is larger, we return 1 indicating
296     // that the first entry is preferred over the second one.
297 
298     result = ThreeWayCompare(Get<RouterTable>().GetPathCost(aSecondRloc), Get<RouterTable>().GetPathCost(aFirstRloc));
299     VerifyOrExit(result == 0);
300 
301     // If all the same, prefer the BR acting as a router over an
302     // end device.
303     result = ThreeWayCompare(Mle::IsActiveRouter(aFirstRloc), Mle::IsActiveRouter(aSecondRloc));
304 #endif
305 
306 exit:
307     return result;
308 }
309 
ExternalRouteLookup(uint8_t aDomainId,const Ip6::Address & aDestination,uint16_t & aRloc16) const310 Error LeaderBase::ExternalRouteLookup(uint8_t aDomainId, const Ip6::Address &aDestination, uint16_t &aRloc16) const
311 {
312     Error                error           = kErrorNoRoute;
313     const PrefixTlv     *prefixTlv       = nullptr;
314     const HasRouteEntry *bestRouteEntry  = nullptr;
315     uint8_t              bestMatchLength = 0;
316 
317     while ((prefixTlv = FindNextMatchingPrefixTlv(aDestination, prefixTlv)) != nullptr)
318     {
319         const HasRouteTlv *hasRoute;
320         uint8_t            prefixLength = prefixTlv->GetPrefixLength();
321         TlvIterator        subTlvIterator(*prefixTlv);
322 
323         if (prefixTlv->GetDomainId() != aDomainId)
324         {
325             continue;
326         }
327 
328         if ((bestRouteEntry != nullptr) && (prefixLength <= bestMatchLength))
329         {
330             continue;
331         }
332 
333         while ((hasRoute = subTlvIterator.Iterate<HasRouteTlv>()) != nullptr)
334         {
335             for (const HasRouteEntry *entry = hasRoute->GetFirstEntry(); entry <= hasRoute->GetLastEntry();
336                  entry                      = entry->GetNext())
337             {
338                 if ((bestRouteEntry == nullptr) || (prefixLength > bestMatchLength) ||
339                     CompareRouteEntries(*entry, *bestRouteEntry) > 0)
340                 {
341                     bestRouteEntry  = entry;
342                     bestMatchLength = prefixLength;
343                 }
344             }
345         }
346     }
347 
348     if (bestRouteEntry != nullptr)
349     {
350         aRloc16 = bestRouteEntry->GetRloc();
351         error   = kErrorNone;
352     }
353 
354     return error;
355 }
356 
DefaultRouteLookup(const PrefixTlv & aPrefix,uint16_t & aRloc16) const357 Error LeaderBase::DefaultRouteLookup(const PrefixTlv &aPrefix, uint16_t &aRloc16) const
358 {
359     Error                    error = kErrorNoRoute;
360     TlvIterator              subTlvIterator(aPrefix);
361     const BorderRouterTlv   *brTlv;
362     const BorderRouterEntry *route = nullptr;
363 
364     while ((brTlv = subTlvIterator.Iterate<BorderRouterTlv>()) != nullptr)
365     {
366         for (const BorderRouterEntry *entry = brTlv->GetFirstEntry(); entry <= brTlv->GetLastEntry();
367              entry                          = entry->GetNext())
368         {
369             if (!entry->IsDefaultRoute())
370             {
371                 continue;
372             }
373 
374             if (route == nullptr || CompareRouteEntries(*entry, *route) > 0)
375             {
376                 route = entry;
377             }
378         }
379     }
380 
381     if (route != nullptr)
382     {
383         aRloc16 = route->GetRloc();
384         error   = kErrorNone;
385     }
386 
387     return error;
388 }
389 
SetNetworkData(uint8_t aVersion,uint8_t aStableVersion,Type aType,const Message & aMessage,uint16_t aOffset,uint16_t aLength)390 Error LeaderBase::SetNetworkData(uint8_t        aVersion,
391                                  uint8_t        aStableVersion,
392                                  Type           aType,
393                                  const Message &aMessage,
394                                  uint16_t       aOffset,
395                                  uint16_t       aLength)
396 {
397     Error error = kErrorNone;
398 
399     VerifyOrExit(aLength <= kMaxSize, error = kErrorParse);
400     SuccessOrExit(error = aMessage.Read(aOffset, GetBytes(), aLength));
401 
402     SetLength(static_cast<uint8_t>(aLength));
403     mVersion       = aVersion;
404     mStableVersion = aStableVersion;
405 
406     if (aType == kStableSubset)
407     {
408         RemoveTemporaryData();
409     }
410 
411 #if OPENTHREAD_FTD
412     if (Get<Mle::MleRouter>().IsLeader())
413     {
414         Get<Leader>().HandleNetworkDataRestoredAfterReset();
415     }
416 #endif
417 
418     DumpDebg("SetNetworkData", GetBytes(), GetLength());
419 
420     SignalNetDataChanged();
421 
422 exit:
423     return error;
424 }
425 
SetCommissioningData(const uint8_t * aValue,uint8_t aValueLength)426 Error LeaderBase::SetCommissioningData(const uint8_t *aValue, uint8_t aValueLength)
427 {
428     Error                 error = kErrorNone;
429     CommissioningDataTlv *commissioningDataTlv;
430 
431     RemoveCommissioningData();
432 
433     if (aValueLength > 0)
434     {
435         VerifyOrExit(aValueLength <= kMaxSize - sizeof(CommissioningDataTlv), error = kErrorNoBufs);
436         commissioningDataTlv = As<CommissioningDataTlv>(AppendTlv(sizeof(CommissioningDataTlv) + aValueLength));
437         VerifyOrExit(commissioningDataTlv != nullptr, error = kErrorNoBufs);
438 
439         commissioningDataTlv->Init();
440         commissioningDataTlv->SetLength(aValueLength);
441         memcpy(commissioningDataTlv->GetValue(), aValue, aValueLength);
442     }
443 
444     mVersion++;
445     SignalNetDataChanged();
446 
447 exit:
448     return error;
449 }
450 
GetCommissioningData(void) const451 const CommissioningDataTlv *LeaderBase::GetCommissioningData(void) const
452 {
453     return NetworkDataTlv::Find<CommissioningDataTlv>(GetTlvsStart(), GetTlvsEnd());
454 }
455 
GetCommissioningDataSubTlv(MeshCoP::Tlv::Type aType) const456 const MeshCoP::Tlv *LeaderBase::GetCommissioningDataSubTlv(MeshCoP::Tlv::Type aType) const
457 {
458     const MeshCoP::Tlv   *rval = nullptr;
459     const NetworkDataTlv *commissioningDataTlv;
460 
461     commissioningDataTlv = GetCommissioningData();
462     VerifyOrExit(commissioningDataTlv != nullptr);
463 
464     rval = MeshCoP::Tlv::FindTlv(commissioningDataTlv->GetValue(), commissioningDataTlv->GetLength(), aType);
465 
466 exit:
467     return rval;
468 }
469 
IsJoiningEnabled(void) const470 bool LeaderBase::IsJoiningEnabled(void) const
471 {
472     const MeshCoP::Tlv *steeringData;
473     bool                rval = false;
474 
475     VerifyOrExit(GetCommissioningDataSubTlv(MeshCoP::Tlv::kBorderAgentLocator) != nullptr);
476 
477     steeringData = GetCommissioningDataSubTlv(MeshCoP::Tlv::kSteeringData);
478     VerifyOrExit(steeringData != nullptr);
479 
480     for (int i = 0; i < steeringData->GetLength(); i++)
481     {
482         if (steeringData->GetValue()[i] != 0)
483         {
484             ExitNow(rval = true);
485         }
486     }
487 
488 exit:
489     return rval;
490 }
491 
RemoveCommissioningData(void)492 void LeaderBase::RemoveCommissioningData(void)
493 {
494     CommissioningDataTlv *tlv = GetCommissioningData();
495 
496     VerifyOrExit(tlv != nullptr);
497     RemoveTlv(tlv);
498 
499 exit:
500     return;
501 }
502 
SteeringDataCheck(const FilterIndexes & aFilterIndexes) const503 Error LeaderBase::SteeringDataCheck(const FilterIndexes &aFilterIndexes) const
504 {
505     Error                 error = kErrorNone;
506     const MeshCoP::Tlv   *steeringDataTlv;
507     MeshCoP::SteeringData steeringData;
508 
509     steeringDataTlv = GetCommissioningDataSubTlv(MeshCoP::Tlv::kSteeringData);
510     VerifyOrExit(steeringDataTlv != nullptr, error = kErrorInvalidState);
511 
512     As<MeshCoP::SteeringDataTlv>(steeringDataTlv)->CopyTo(steeringData);
513 
514     VerifyOrExit(steeringData.Contains(aFilterIndexes), error = kErrorNotFound);
515 
516 exit:
517     return error;
518 }
519 
SteeringDataCheckJoiner(const Mac::ExtAddress & aEui64) const520 Error LeaderBase::SteeringDataCheckJoiner(const Mac::ExtAddress &aEui64) const
521 {
522     FilterIndexes   filterIndexes;
523     Mac::ExtAddress joinerId;
524 
525     MeshCoP::ComputeJoinerId(aEui64, joinerId);
526     MeshCoP::SteeringData::CalculateHashBitIndexes(joinerId, filterIndexes);
527 
528     return SteeringDataCheck(filterIndexes);
529 }
530 
SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner & aDiscerner) const531 Error LeaderBase::SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner &aDiscerner) const
532 {
533     FilterIndexes filterIndexes;
534 
535     MeshCoP::SteeringData::CalculateHashBitIndexes(aDiscerner, filterIndexes);
536 
537     return SteeringDataCheck(filterIndexes);
538 }
539 
SignalNetDataChanged(void)540 void LeaderBase::SignalNetDataChanged(void)
541 {
542     mMaxLength = Max(mMaxLength, GetLength());
543     Get<ot::Notifier>().Signal(kEventThreadNetdataChanged);
544 }
545 
546 } // namespace NetworkData
547 } // namespace ot
548