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