• 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 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