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 "instance/instance.hpp"
37
38 namespace ot {
39 namespace NetworkData {
40
41 RegisterLogModule("NetworkData");
42
Leader(Instance & aInstance)43 Leader::Leader(Instance &aInstance)
44 : MutableNetworkData(aInstance, mTlvBuffer, 0, sizeof(mTlvBuffer))
45 , mMaxLength(0)
46 #if OPENTHREAD_FTD
47 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
48 , mIsClone(false)
49 #endif
50 , mWaitingForNetDataSync(false)
51 , mContextIds(aInstance)
52 , mTimer(aInstance)
53 #endif
54 {
55 Reset();
56 }
57
Reset(void)58 void Leader::Reset(void)
59 {
60 mVersion = Random::NonCrypto::GetUint8();
61 mStableVersion = Random::NonCrypto::GetUint8();
62 SetLength(0);
63 SignalNetDataChanged();
64
65 #if OPENTHREAD_FTD
66 mContextIds.Clear();
67 #endif
68 }
69
GetServiceId(uint32_t aEnterpriseNumber,const ServiceData & aServiceData,bool aServerStable,uint8_t & aServiceId) const70 Error Leader::GetServiceId(uint32_t aEnterpriseNumber,
71 const ServiceData &aServiceData,
72 bool aServerStable,
73 uint8_t &aServiceId) const
74 {
75 Error error = kErrorNotFound;
76 Iterator iterator = kIteratorInit;
77 ServiceConfig serviceConfig;
78 ServiceData serviceData;
79
80 while (GetNextService(iterator, serviceConfig) == kErrorNone)
81 {
82 serviceConfig.GetServiceData(serviceData);
83
84 if (aEnterpriseNumber == serviceConfig.mEnterpriseNumber && aServiceData == serviceData &&
85 aServerStable == serviceConfig.mServerConfig.mStable)
86 {
87 aServiceId = serviceConfig.mServiceId;
88 ExitNow(error = kErrorNone);
89 }
90 }
91
92 exit:
93 return error;
94 }
95
GetPreferredNat64Prefix(ExternalRouteConfig & aConfig) const96 Error Leader::GetPreferredNat64Prefix(ExternalRouteConfig &aConfig) const
97 {
98 Error error = kErrorNotFound;
99 Iterator iterator = kIteratorInit;
100 ExternalRouteConfig config;
101
102 while (GetNextExternalRoute(iterator, config) == kErrorNone)
103 {
104 if (!config.mNat64 || !config.GetPrefix().IsValidNat64())
105 {
106 continue;
107 }
108
109 if ((error == kErrorNotFound) || (config.mPreference > aConfig.mPreference) ||
110 (config.mPreference == aConfig.mPreference && config.GetPrefix() < aConfig.GetPrefix()))
111 {
112 aConfig = config;
113 error = kErrorNone;
114 }
115 }
116
117 return error;
118 }
119
IsNat64(const Ip6::Address & aAddress) const120 bool Leader::IsNat64(const Ip6::Address &aAddress) const
121 {
122 bool isNat64 = false;
123 Iterator iterator = kIteratorInit;
124 ExternalRouteConfig config;
125
126 while (GetNextExternalRoute(iterator, config) == kErrorNone)
127 {
128 if (config.mNat64 && config.GetPrefix().IsValidNat64() && aAddress.MatchesPrefix(config.GetPrefix()))
129 {
130 isNat64 = true;
131 break;
132 }
133 }
134
135 return isNat64;
136 }
137
FindNextMatchingPrefixTlv(const Ip6::Address & aAddress,const PrefixTlv * aPrevTlv) const138 const PrefixTlv *Leader::FindNextMatchingPrefixTlv(const Ip6::Address &aAddress, const PrefixTlv *aPrevTlv) const
139 {
140 // This method iterates over Prefix TLVs which match a given IPv6
141 // `aAddress`. If `aPrevTlv` is `nullptr` we start from the
142 // beginning. Otherwise, we search for a match after `aPrevTlv`.
143 // This method returns a pointer to the next matching Prefix TLV
144 // when found, or `nullptr` if no match is found.
145
146 const PrefixTlv *prefixTlv;
147 TlvIterator tlvIterator((aPrevTlv == nullptr) ? GetTlvsStart() : aPrevTlv->GetNext(), GetTlvsEnd());
148
149 while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
150 {
151 if (aAddress.MatchesPrefix(prefixTlv->GetPrefix(), prefixTlv->GetPrefixLength()))
152 {
153 break;
154 }
155 }
156
157 return prefixTlv;
158 }
159
GetContext(const Ip6::Address & aAddress,Lowpan::Context & aContext) const160 Error Leader::GetContext(const Ip6::Address &aAddress, Lowpan::Context &aContext) const
161 {
162 const PrefixTlv *prefixTlv = nullptr;
163 const ContextTlv *contextTlv;
164
165 aContext.mPrefix.SetLength(0);
166
167 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
168 {
169 GetContextForMeshLocalPrefix(aContext);
170 }
171
172 while ((prefixTlv = FindNextMatchingPrefixTlv(aAddress, prefixTlv)) != nullptr)
173 {
174 contextTlv = prefixTlv->FindSubTlv<ContextTlv>();
175
176 if (contextTlv == nullptr)
177 {
178 continue;
179 }
180
181 if (prefixTlv->GetPrefixLength() > aContext.mPrefix.GetLength())
182 {
183 prefixTlv->CopyPrefixTo(aContext.mPrefix);
184 aContext.mContextId = contextTlv->GetContextId();
185 aContext.mCompressFlag = contextTlv->IsCompress();
186 aContext.mIsValid = true;
187 }
188 }
189
190 return (aContext.mPrefix.GetLength() > 0) ? kErrorNone : kErrorNotFound;
191 }
192
FindPrefixTlvForContextId(uint8_t aContextId,const ContextTlv * & aContextTlv) const193 const PrefixTlv *Leader::FindPrefixTlvForContextId(uint8_t aContextId, const ContextTlv *&aContextTlv) const
194 {
195 TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd());
196 const PrefixTlv *prefixTlv;
197
198 while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
199 {
200 const ContextTlv *contextTlv = prefixTlv->FindSubTlv<ContextTlv>();
201
202 if ((contextTlv != nullptr) && (contextTlv->GetContextId() == aContextId))
203 {
204 aContextTlv = contextTlv;
205 break;
206 }
207 }
208
209 return prefixTlv;
210 }
211
GetContext(uint8_t aContextId,Lowpan::Context & aContext) const212 Error Leader::GetContext(uint8_t aContextId, Lowpan::Context &aContext) const
213 {
214 Error error = kErrorNone;
215 TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd());
216 const PrefixTlv *prefixTlv;
217 const ContextTlv *contextTlv;
218
219 if (aContextId == Mle::kMeshLocalPrefixContextId)
220 {
221 GetContextForMeshLocalPrefix(aContext);
222 ExitNow();
223 }
224
225 prefixTlv = FindPrefixTlvForContextId(aContextId, contextTlv);
226 VerifyOrExit(prefixTlv != nullptr, error = kErrorNotFound);
227
228 prefixTlv->CopyPrefixTo(aContext.mPrefix);
229 aContext.mContextId = contextTlv->GetContextId();
230 aContext.mCompressFlag = contextTlv->IsCompress();
231 aContext.mIsValid = true;
232
233 exit:
234 return error;
235 }
236
GetContextForMeshLocalPrefix(Lowpan::Context & aContext) const237 void Leader::GetContextForMeshLocalPrefix(Lowpan::Context &aContext) const
238 {
239 aContext.mPrefix.Set(Get<Mle::MleRouter>().GetMeshLocalPrefix());
240 aContext.mContextId = Mle::kMeshLocalPrefixContextId;
241 aContext.mCompressFlag = true;
242 aContext.mIsValid = true;
243 }
244
IsOnMesh(const Ip6::Address & aAddress) const245 bool Leader::IsOnMesh(const Ip6::Address &aAddress) const
246 {
247 const PrefixTlv *prefixTlv = nullptr;
248 bool isOnMesh = false;
249
250 VerifyOrExit(!Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress), isOnMesh = true);
251
252 while ((prefixTlv = FindNextMatchingPrefixTlv(aAddress, prefixTlv)) != nullptr)
253 {
254 TlvIterator subTlvIterator(*prefixTlv);
255 const BorderRouterTlv *brTlv;
256
257 while ((brTlv = subTlvIterator.Iterate<BorderRouterTlv>()) != nullptr)
258 {
259 for (const BorderRouterEntry *entry = brTlv->GetFirstEntry(); entry <= brTlv->GetLastEntry();
260 entry = entry->GetNext())
261 {
262 if (entry->IsOnMesh())
263 {
264 ExitNow(isOnMesh = true);
265 }
266 }
267 }
268 }
269
270 exit:
271 return isOnMesh;
272 }
273
RouteLookup(const Ip6::Address & aSource,const Ip6::Address & aDestination,uint16_t & aRloc16) const274 Error Leader::RouteLookup(const Ip6::Address &aSource, const Ip6::Address &aDestination, uint16_t &aRloc16) const
275 {
276 Error error = kErrorNoRoute;
277 const PrefixTlv *prefixTlv = nullptr;
278
279 while ((prefixTlv = FindNextMatchingPrefixTlv(aSource, prefixTlv)) != nullptr)
280 {
281 if (prefixTlv->FindSubTlv<BorderRouterTlv>() == nullptr)
282 {
283 continue;
284 }
285
286 if (ExternalRouteLookup(prefixTlv->GetDomainId(), aDestination, aRloc16) == kErrorNone)
287 {
288 ExitNow(error = kErrorNone);
289 }
290
291 if (DefaultRouteLookup(*prefixTlv, aRloc16) == kErrorNone)
292 {
293 ExitNow(error = kErrorNone);
294 }
295 }
296
297 #if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
298 {
299 // The `Slaac` module keeps track of the associated Domain IDs
300 // for deprecating SLAAC prefixes, even if the related
301 // Prefix TLV has already been removed from the Network
302 // Data.
303
304 uint8_t domainId;
305
306 if (Get<Utils::Slaac>().FindDomainIdFor(aSource, domainId) == kErrorNone)
307 {
308 error = ExternalRouteLookup(domainId, aDestination, aRloc16);
309 }
310 }
311 #endif
312
313 exit:
314 return error;
315 }
316
CompareRouteEntries(const BorderRouterEntry & aFirst,const BorderRouterEntry & aSecond) const317 int Leader::CompareRouteEntries(const BorderRouterEntry &aFirst, const BorderRouterEntry &aSecond) const
318 {
319 return CompareRouteEntries(aFirst.GetPreference(), aFirst.GetRloc(), aSecond.GetPreference(), aSecond.GetRloc());
320 }
321
CompareRouteEntries(const HasRouteEntry & aFirst,const HasRouteEntry & aSecond) const322 int Leader::CompareRouteEntries(const HasRouteEntry &aFirst, const HasRouteEntry &aSecond) const
323 {
324 return CompareRouteEntries(aFirst.GetPreference(), aFirst.GetRloc(), aSecond.GetPreference(), aSecond.GetRloc());
325 }
326
CompareRouteEntries(const ServerTlv & aFirst,const ServerTlv & aSecond) const327 int Leader::CompareRouteEntries(const ServerTlv &aFirst, const ServerTlv &aSecond) const
328 {
329 return CompareRouteEntries(/* aFirstPreference */ 0, aFirst.GetServer16(), /* aSecondPreference */ 0,
330 aSecond.GetServer16());
331 }
332
CompareRouteEntries(int8_t aFirstPreference,uint16_t aFirstRloc,int8_t aSecondPreference,uint16_t aSecondRloc) const333 int Leader::CompareRouteEntries(int8_t aFirstPreference,
334 uint16_t aFirstRloc,
335 int8_t aSecondPreference,
336 uint16_t aSecondRloc) const
337 {
338 // Performs three-way comparison between two BR entries.
339
340 int result;
341
342 // Prefer the entry with higher preference.
343
344 result = ThreeWayCompare(aFirstPreference, aSecondPreference);
345 VerifyOrExit(result == 0);
346
347 #if OPENTHREAD_MTD
348 // On MTD, prefer the BR that is this device itself. This handles
349 // the uncommon case where an MTD itself may be acting as BR.
350
351 result = ThreeWayCompare((Get<Mle::Mle>().HasRloc16(aFirstRloc)), Get<Mle::Mle>().HasRloc16(aSecondRloc));
352 #endif
353
354 #if OPENTHREAD_FTD
355 // If all the same, prefer the one with lower mesh path cost.
356 // Lower cost is preferred so we pass the second entry's cost as
357 // the first argument in the call to `ThreeWayCompare()`, i.e.,
358 // if the second entry's cost is larger, we return 1 indicating
359 // that the first entry is preferred over the second one.
360
361 result = ThreeWayCompare(Get<RouterTable>().GetPathCost(aSecondRloc), Get<RouterTable>().GetPathCost(aFirstRloc));
362 VerifyOrExit(result == 0);
363
364 // If all the same, prefer the BR acting as a router over an
365 // end device.
366 result = ThreeWayCompare(Mle::IsRouterRloc16(aFirstRloc), Mle::IsRouterRloc16(aSecondRloc));
367 #endif
368
369 exit:
370 return result;
371 }
372
ExternalRouteLookup(uint8_t aDomainId,const Ip6::Address & aDestination,uint16_t & aRloc16) const373 Error Leader::ExternalRouteLookup(uint8_t aDomainId, const Ip6::Address &aDestination, uint16_t &aRloc16) const
374 {
375 Error error = kErrorNoRoute;
376 const PrefixTlv *prefixTlv = nullptr;
377 const HasRouteEntry *bestRouteEntry = nullptr;
378 uint8_t bestMatchLength = 0;
379
380 while ((prefixTlv = FindNextMatchingPrefixTlv(aDestination, prefixTlv)) != nullptr)
381 {
382 const HasRouteTlv *hasRoute;
383 uint8_t prefixLength = prefixTlv->GetPrefixLength();
384 TlvIterator subTlvIterator(*prefixTlv);
385
386 if (prefixTlv->GetDomainId() != aDomainId)
387 {
388 continue;
389 }
390
391 if ((bestRouteEntry != nullptr) && (prefixLength <= bestMatchLength))
392 {
393 continue;
394 }
395
396 while ((hasRoute = subTlvIterator.Iterate<HasRouteTlv>()) != nullptr)
397 {
398 for (const HasRouteEntry *entry = hasRoute->GetFirstEntry(); entry <= hasRoute->GetLastEntry();
399 entry = entry->GetNext())
400 {
401 if ((bestRouteEntry == nullptr) || (prefixLength > bestMatchLength) ||
402 CompareRouteEntries(*entry, *bestRouteEntry) > 0)
403 {
404 bestRouteEntry = entry;
405 bestMatchLength = prefixLength;
406 }
407 }
408 }
409 }
410
411 if (bestRouteEntry != nullptr)
412 {
413 aRloc16 = bestRouteEntry->GetRloc();
414 error = kErrorNone;
415 }
416
417 return error;
418 }
419
LookupRouteIn(const PrefixTlv & aPrefixTlv,EntryChecker aEntryChecker,uint16_t & aRloc16) const420 Error Leader::LookupRouteIn(const PrefixTlv &aPrefixTlv, EntryChecker aEntryChecker, uint16_t &aRloc16) const
421 {
422 // Iterates over all `BorderRouterEntry` associated with
423 // `aPrefixTlv` which also match `aEntryChecker` and determine the
424 // best route. For example, this is used from `DefaultRouteLookup()`
425 // to look up best default route.
426
427 Error error = kErrorNoRoute;
428 TlvIterator subTlvIterator(aPrefixTlv);
429 const BorderRouterTlv *brTlv;
430 const BorderRouterEntry *bestEntry = nullptr;
431
432 while ((brTlv = subTlvIterator.Iterate<BorderRouterTlv>()) != nullptr)
433 {
434 for (const BorderRouterEntry *entry = brTlv->GetFirstEntry(); entry <= brTlv->GetLastEntry();
435 entry = entry->GetNext())
436 {
437 if (!aEntryChecker(*entry))
438 {
439 continue;
440 }
441
442 if ((bestEntry == nullptr) || CompareRouteEntries(*entry, *bestEntry) > 0)
443 {
444 bestEntry = entry;
445 }
446 }
447 }
448
449 if (bestEntry != nullptr)
450 {
451 aRloc16 = bestEntry->GetRloc();
452 error = kErrorNone;
453 }
454
455 return error;
456 }
457
IsEntryDefaultRoute(const BorderRouterEntry & aEntry)458 bool Leader::IsEntryDefaultRoute(const BorderRouterEntry &aEntry) { return aEntry.IsDefaultRoute(); }
459
DefaultRouteLookup(const PrefixTlv & aPrefix,uint16_t & aRloc16) const460 Error Leader::DefaultRouteLookup(const PrefixTlv &aPrefix, uint16_t &aRloc16) const
461 {
462 return LookupRouteIn(aPrefix, IsEntryDefaultRoute, aRloc16);
463 }
464
SetNetworkData(uint8_t aVersion,uint8_t aStableVersion,Type aType,const Message & aMessage,const OffsetRange & aOffsetRange)465 Error Leader::SetNetworkData(uint8_t aVersion,
466 uint8_t aStableVersion,
467 Type aType,
468 const Message &aMessage,
469 const OffsetRange &aOffsetRange)
470 {
471 Error error = kErrorNone;
472 uint16_t length = aOffsetRange.GetLength();
473
474 VerifyOrExit(length <= kMaxSize, error = kErrorParse);
475 SuccessOrExit(error = aMessage.Read(aOffsetRange.GetOffset(), GetBytes(), length));
476
477 SetLength(static_cast<uint8_t>(length));
478 mVersion = aVersion;
479 mStableVersion = aStableVersion;
480
481 if (aType == kStableSubset)
482 {
483 RemoveTemporaryData();
484 }
485
486 #if OPENTHREAD_FTD
487 if (Get<Mle::MleRouter>().IsLeader())
488 {
489 Get<Leader>().HandleNetworkDataRestoredAfterReset();
490 }
491 #endif
492
493 DumpDebg("SetNetworkData", GetBytes(), GetLength());
494
495 SignalNetDataChanged();
496
497 exit:
498 return error;
499 }
500
FindCommissioningData(void) const501 const CommissioningDataTlv *Leader::FindCommissioningData(void) const
502 {
503 return NetworkDataTlv::Find<CommissioningDataTlv>(GetTlvsStart(), GetTlvsEnd());
504 }
505
FindCommissioningDataSubTlv(uint8_t aType) const506 const MeshCoP::Tlv *Leader::FindCommissioningDataSubTlv(uint8_t aType) const
507 {
508 const MeshCoP::Tlv *subTlv = nullptr;
509 const NetworkDataTlv *dataTlv = FindCommissioningData();
510
511 VerifyOrExit(dataTlv != nullptr);
512 subTlv = As<MeshCoP::Tlv>(Tlv::FindTlv(dataTlv->GetValue(), dataTlv->GetLength(), aType));
513
514 exit:
515 return subTlv;
516 }
517
ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::Type aType,uint16_t & aValue) const518 Error Leader::ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::Type aType, uint16_t &aValue) const
519 {
520 Error error = kErrorNone;
521 const MeshCoP::Tlv *subTlv = FindCommissioningDataSubTlv(aType);
522
523 VerifyOrExit(subTlv != nullptr, error = kErrorNotFound);
524 VerifyOrExit(subTlv->GetLength() >= sizeof(uint16_t), error = kErrorParse);
525 aValue = BigEndian::ReadUint16(subTlv->GetValue());
526
527 exit:
528 return error;
529 }
530
GetCommissioningDataset(MeshCoP::CommissioningDataset & aDataset) const531 void Leader::GetCommissioningDataset(MeshCoP::CommissioningDataset &aDataset) const
532 {
533 const CommissioningDataTlv *dataTlv = FindCommissioningData();
534 const MeshCoP::Tlv *subTlv;
535 const MeshCoP::Tlv *endTlv;
536
537 aDataset.Clear();
538
539 VerifyOrExit(dataTlv != nullptr);
540
541 aDataset.mIsLocatorSet = (FindBorderAgentRloc(aDataset.mLocator) == kErrorNone);
542 aDataset.mIsSessionIdSet = (FindCommissioningSessionId(aDataset.mSessionId) == kErrorNone);
543 aDataset.mIsJoinerUdpPortSet = (FindJoinerUdpPort(aDataset.mJoinerUdpPort) == kErrorNone);
544 aDataset.mIsSteeringDataSet = (FindSteeringData(AsCoreType(&aDataset.mSteeringData)) == kErrorNone);
545
546 // Determine if the Commissioning data has any extra unknown TLVs
547
548 subTlv = reinterpret_cast<const MeshCoP::Tlv *>(dataTlv->GetValue());
549 endTlv = reinterpret_cast<const MeshCoP::Tlv *>(dataTlv->GetValue() + dataTlv->GetLength());
550
551 for (; subTlv < endTlv; subTlv = subTlv->GetNext())
552 {
553 switch (subTlv->GetType())
554 {
555 case MeshCoP::Tlv::kBorderAgentLocator:
556 case MeshCoP::Tlv::kSteeringData:
557 case MeshCoP::Tlv::kJoinerUdpPort:
558 case MeshCoP::Tlv::kCommissionerSessionId:
559 break;
560 default:
561 ExitNow(aDataset.mHasExtraTlv = true);
562 }
563 }
564
565 exit:
566 return;
567 }
568
ProcessCommissionerGetRequest(const Coap::Message & aMessage) const569 Coap::Message *Leader::ProcessCommissionerGetRequest(const Coap::Message &aMessage) const
570 {
571 Error error = kErrorNone;
572 Coap::Message *response = nullptr;
573 OffsetRange offsetRange;
574
575 response = Get<Tmf::Agent>().NewPriorityResponseMessage(aMessage);
576 VerifyOrExit(response != nullptr, error = kErrorNoBufs);
577
578 if (Tlv::FindTlvValueOffsetRange(aMessage, MeshCoP::Tlv::kGet, offsetRange) == kErrorNone)
579 {
580 // Append the requested sub-TLV types given in Get TLV.
581
582 while (!offsetRange.IsEmpty())
583 {
584 uint8_t type;
585 const MeshCoP::Tlv *subTlv;
586
587 IgnoreError(aMessage.Read(offsetRange, type));
588 offsetRange.AdvanceOffset(sizeof(type));
589
590 subTlv = FindCommissioningDataSubTlv(type);
591
592 if (subTlv != nullptr)
593 {
594 SuccessOrExit(error = subTlv->AppendTo(*response));
595 }
596 }
597 }
598 else
599 {
600 // Append all sub-TLVs in the Commissioning Data.
601
602 const CommissioningDataTlv *dataTlv = FindCommissioningData();
603
604 if (dataTlv != nullptr)
605 {
606 SuccessOrExit(error = response->AppendBytes(dataTlv->GetValue(), dataTlv->GetLength()));
607 }
608 }
609
610 exit:
611 FreeAndNullMessageOnError(response, error);
612 return response;
613 }
614
FindBorderAgentRloc(uint16_t & aRloc16) const615 Error Leader::FindBorderAgentRloc(uint16_t &aRloc16) const
616 {
617 return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kBorderAgentLocator, aRloc16);
618 }
619
FindCommissioningSessionId(uint16_t & aSessionId) const620 Error Leader::FindCommissioningSessionId(uint16_t &aSessionId) const
621 {
622 return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kCommissionerSessionId, aSessionId);
623 }
624
FindJoinerUdpPort(uint16_t & aPort) const625 Error Leader::FindJoinerUdpPort(uint16_t &aPort) const
626 {
627 return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kJoinerUdpPort, aPort);
628 }
629
FindSteeringData(MeshCoP::SteeringData & aSteeringData) const630 Error Leader::FindSteeringData(MeshCoP::SteeringData &aSteeringData) const
631 {
632 Error error = kErrorNone;
633 const MeshCoP::SteeringDataTlv *steeringDataTlv = FindInCommissioningData<MeshCoP::SteeringDataTlv>();
634
635 VerifyOrExit(steeringDataTlv != nullptr, error = kErrorNotFound);
636 steeringDataTlv->CopyTo(aSteeringData);
637
638 exit:
639 return error;
640 }
641
IsJoiningAllowed(void) const642 bool Leader::IsJoiningAllowed(void) const
643 {
644 bool isAllowed = false;
645 MeshCoP::SteeringData steeringData;
646
647 SuccessOrExit(FindSteeringData(steeringData));
648 isAllowed = !steeringData.IsEmpty();
649
650 exit:
651 return isAllowed;
652 }
653
SteeringDataCheck(const FilterIndexes & aFilterIndexes) const654 Error Leader::SteeringDataCheck(const FilterIndexes &aFilterIndexes) const
655 {
656 Error error = kErrorInvalidState;
657 MeshCoP::SteeringData steeringData;
658
659 SuccessOrExit(FindSteeringData(steeringData));
660 error = steeringData.Contains(aFilterIndexes) ? kErrorNone : kErrorNotFound;
661
662 exit:
663 return error;
664 }
665
SteeringDataCheckJoiner(const Mac::ExtAddress & aEui64) const666 Error Leader::SteeringDataCheckJoiner(const Mac::ExtAddress &aEui64) const
667 {
668 FilterIndexes filterIndexes;
669 Mac::ExtAddress joinerId;
670
671 MeshCoP::ComputeJoinerId(aEui64, joinerId);
672 MeshCoP::SteeringData::CalculateHashBitIndexes(joinerId, filterIndexes);
673
674 return SteeringDataCheck(filterIndexes);
675 }
676
SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner & aDiscerner) const677 Error Leader::SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner &aDiscerner) const
678 {
679 FilterIndexes filterIndexes;
680
681 MeshCoP::SteeringData::CalculateHashBitIndexes(aDiscerner, filterIndexes);
682
683 return SteeringDataCheck(filterIndexes);
684 }
685
SignalNetDataChanged(void)686 void Leader::SignalNetDataChanged(void)
687 {
688 mMaxLength = Max(mMaxLength, GetLength());
689 Get<ot::Notifier>().Signal(kEventThreadNetdataChanged);
690 }
691
692 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
693
ContainsOmrPrefix(const Ip6::Prefix & aPrefix) const694 bool Leader::ContainsOmrPrefix(const Ip6::Prefix &aPrefix) const
695 {
696 bool contains = false;
697 const PrefixTlv *prefixTlv;
698 const BorderRouterTlv *brSubTlv;
699
700 VerifyOrExit(BorderRouter::RoutingManager::IsValidOmrPrefix(aPrefix));
701
702 prefixTlv = FindPrefix(aPrefix);
703 VerifyOrExit(prefixTlv != nullptr);
704
705 brSubTlv = prefixTlv->FindSubTlv<BorderRouterTlv>(/* aStable */ true);
706
707 VerifyOrExit(brSubTlv != nullptr);
708
709 for (const BorderRouterEntry *entry = brSubTlv->GetFirstEntry(); entry <= brSubTlv->GetLastEntry(); entry++)
710 {
711 OnMeshPrefixConfig config;
712
713 config.SetFrom(*prefixTlv, *brSubTlv, *entry);
714
715 if (BorderRouter::RoutingManager::IsValidOmrPrefix(config))
716 {
717 ExitNow(contains = true);
718 }
719 }
720
721 exit:
722 return contains;
723 }
724
725 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
726
727 } // namespace NetworkData
728 } // namespace ot
729