• 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 "coap/coap_message.hpp"
37 #include "common/code_utils.hpp"
38 #include "common/debug.hpp"
39 #include "common/encoding.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/logging.hpp"
42 #include "common/message.hpp"
43 #include "common/random.hpp"
44 #include "common/timer.hpp"
45 #include "instance/instance.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 
Leader(Instance & aInstance)58 Leader::Leader(Instance &aInstance)
59     : MutableNetworkData(aInstance, mTlvBuffer, 0, sizeof(mTlvBuffer))
60     , mMaxLength(0)
61 #if OPENTHREAD_FTD
62 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
63     , mIsClone(false)
64 #endif
65     , mWaitingForNetDataSync(false)
66     , mContextIds(aInstance)
67     , mTimer(aInstance)
68 #endif
69 {
70     Reset();
71 }
72 
Reset(void)73 void Leader::Reset(void)
74 {
75     mVersion       = Random::NonCrypto::GetUint8();
76     mStableVersion = Random::NonCrypto::GetUint8();
77     SetLength(0);
78     SignalNetDataChanged();
79 
80 #if OPENTHREAD_FTD
81     mContextIds.Clear();
82 #endif
83 }
84 
GetServiceId(uint32_t aEnterpriseNumber,const ServiceData & aServiceData,bool aServerStable,uint8_t & aServiceId) const85 Error Leader::GetServiceId(uint32_t           aEnterpriseNumber,
86                            const ServiceData &aServiceData,
87                            bool               aServerStable,
88                            uint8_t           &aServiceId) const
89 {
90     Error         error    = kErrorNotFound;
91     Iterator      iterator = kIteratorInit;
92     ServiceConfig serviceConfig;
93     ServiceData   serviceData;
94 
95     while (GetNextService(iterator, serviceConfig) == kErrorNone)
96     {
97         serviceConfig.GetServiceData(serviceData);
98 
99         if (aEnterpriseNumber == serviceConfig.mEnterpriseNumber && aServiceData == serviceData &&
100             aServerStable == serviceConfig.mServerConfig.mStable)
101         {
102             aServiceId = serviceConfig.mServiceId;
103             ExitNow(error = kErrorNone);
104         }
105     }
106 
107 exit:
108     return error;
109 }
110 
GetPreferredNat64Prefix(ExternalRouteConfig & aConfig) const111 Error Leader::GetPreferredNat64Prefix(ExternalRouteConfig &aConfig) const
112 {
113     Error               error    = kErrorNotFound;
114     Iterator            iterator = kIteratorInit;
115     ExternalRouteConfig config;
116 
117     while (GetNextExternalRoute(iterator, config) == kErrorNone)
118     {
119         if (!config.mNat64 || !config.GetPrefix().IsValidNat64())
120         {
121             continue;
122         }
123 
124         if ((error == kErrorNotFound) || (config.mPreference > aConfig.mPreference) ||
125             (config.mPreference == aConfig.mPreference && config.GetPrefix() < aConfig.GetPrefix()))
126         {
127             aConfig = config;
128             error   = kErrorNone;
129         }
130     }
131 
132     return error;
133 }
134 
FindNextMatchingPrefixTlv(const Ip6::Address & aAddress,const PrefixTlv * aPrevTlv) const135 const PrefixTlv *Leader::FindNextMatchingPrefixTlv(const Ip6::Address &aAddress, const PrefixTlv *aPrevTlv) const
136 {
137     // This method iterates over Prefix TLVs which match a given IPv6
138     // `aAddress`. If `aPrevTlv` is `nullptr` we start from the
139     // beginning. Otherwise, we search for a match after `aPrevTlv`.
140     // This method returns a pointer to the next matching Prefix TLV
141     // when found, or `nullptr` if no match is found.
142 
143     const PrefixTlv *prefixTlv;
144     TlvIterator      tlvIterator((aPrevTlv == nullptr) ? GetTlvsStart() : aPrevTlv->GetNext(), GetTlvsEnd());
145 
146     while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
147     {
148         if (aAddress.MatchesPrefix(prefixTlv->GetPrefix(), prefixTlv->GetPrefixLength()))
149         {
150             break;
151         }
152     }
153 
154     return prefixTlv;
155 }
156 
GetContext(const Ip6::Address & aAddress,Lowpan::Context & aContext) const157 Error Leader::GetContext(const Ip6::Address &aAddress, Lowpan::Context &aContext) const
158 {
159     const PrefixTlv  *prefixTlv = nullptr;
160     const ContextTlv *contextTlv;
161 
162     aContext.mPrefix.SetLength(0);
163 
164     if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
165     {
166         GetContextForMeshLocalPrefix(aContext);
167     }
168 
169     while ((prefixTlv = FindNextMatchingPrefixTlv(aAddress, prefixTlv)) != nullptr)
170     {
171         contextTlv = prefixTlv->FindSubTlv<ContextTlv>();
172 
173         if (contextTlv == nullptr)
174         {
175             continue;
176         }
177 
178         if (prefixTlv->GetPrefixLength() > aContext.mPrefix.GetLength())
179         {
180             prefixTlv->CopyPrefixTo(aContext.mPrefix);
181             aContext.mContextId    = contextTlv->GetContextId();
182             aContext.mCompressFlag = contextTlv->IsCompress();
183             aContext.mIsValid      = true;
184         }
185     }
186 
187     return (aContext.mPrefix.GetLength() > 0) ? kErrorNone : kErrorNotFound;
188 }
189 
GetContext(uint8_t aContextId,Lowpan::Context & aContext) const190 Error Leader::GetContext(uint8_t aContextId, Lowpan::Context &aContext) const
191 {
192     Error            error = kErrorNotFound;
193     TlvIterator      tlvIterator(GetTlvsStart(), GetTlvsEnd());
194     const PrefixTlv *prefixTlv;
195 
196     if (aContextId == Mle::kMeshLocalPrefixContextId)
197     {
198         GetContextForMeshLocalPrefix(aContext);
199         ExitNow(error = kErrorNone);
200     }
201 
202     while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
203     {
204         const ContextTlv *contextTlv = prefixTlv->FindSubTlv<ContextTlv>();
205 
206         if ((contextTlv == nullptr) || (contextTlv->GetContextId() != aContextId))
207         {
208             continue;
209         }
210 
211         prefixTlv->CopyPrefixTo(aContext.mPrefix);
212         aContext.mContextId    = contextTlv->GetContextId();
213         aContext.mCompressFlag = contextTlv->IsCompress();
214         aContext.mIsValid      = true;
215         ExitNow(error = kErrorNone);
216     }
217 
218 exit:
219     return error;
220 }
221 
GetContextForMeshLocalPrefix(Lowpan::Context & aContext) const222 void Leader::GetContextForMeshLocalPrefix(Lowpan::Context &aContext) const
223 {
224     aContext.mPrefix.Set(Get<Mle::MleRouter>().GetMeshLocalPrefix());
225     aContext.mContextId    = Mle::kMeshLocalPrefixContextId;
226     aContext.mCompressFlag = true;
227     aContext.mIsValid      = true;
228 }
229 
IsOnMesh(const Ip6::Address & aAddress) const230 bool Leader::IsOnMesh(const Ip6::Address &aAddress) const
231 {
232     const PrefixTlv *prefixTlv = nullptr;
233     bool             isOnMesh  = false;
234 
235     VerifyOrExit(!Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress), isOnMesh = true);
236 
237     while ((prefixTlv = FindNextMatchingPrefixTlv(aAddress, prefixTlv)) != nullptr)
238     {
239         TlvIterator            subTlvIterator(*prefixTlv);
240         const BorderRouterTlv *brTlv;
241 
242         while ((brTlv = subTlvIterator.Iterate<BorderRouterTlv>()) != nullptr)
243         {
244             for (const BorderRouterEntry *entry = brTlv->GetFirstEntry(); entry <= brTlv->GetLastEntry();
245                  entry                          = entry->GetNext())
246             {
247                 if (entry->IsOnMesh())
248                 {
249                     ExitNow(isOnMesh = true);
250                 }
251             }
252         }
253     }
254 
255 exit:
256     return isOnMesh;
257 }
258 
RouteLookup(const Ip6::Address & aSource,const Ip6::Address & aDestination,uint16_t & aRloc16) const259 Error Leader::RouteLookup(const Ip6::Address &aSource, const Ip6::Address &aDestination, uint16_t &aRloc16) const
260 {
261     Error            error     = kErrorNoRoute;
262     const PrefixTlv *prefixTlv = nullptr;
263 
264     while ((prefixTlv = FindNextMatchingPrefixTlv(aSource, prefixTlv)) != nullptr)
265     {
266         if (prefixTlv->FindSubTlv<BorderRouterTlv>() == nullptr)
267         {
268             continue;
269         }
270 
271         if (ExternalRouteLookup(prefixTlv->GetDomainId(), aDestination, aRloc16) == kErrorNone)
272         {
273             ExitNow(error = kErrorNone);
274         }
275 
276         if (DefaultRouteLookup(*prefixTlv, aRloc16) == kErrorNone)
277         {
278             ExitNow(error = kErrorNone);
279         }
280     }
281 
282 #if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
283     {
284         // The `Slaac` module keeps track of the associated Domain IDs
285         // for deprecating SLAAC prefixes, even if the related
286         // Prefix TLV has already been removed from the Network
287         // Data.
288 
289         uint8_t domainId;
290 
291         if (Get<Utils::Slaac>().FindDomainIdFor(aSource, domainId) == kErrorNone)
292         {
293             error = ExternalRouteLookup(domainId, aDestination, aRloc16);
294         }
295     }
296 #endif
297 
298 exit:
299     return error;
300 }
301 
CompareRouteEntries(const EntryType & aFirst,const EntryType & aSecond) const302 template <typename EntryType> int Leader::CompareRouteEntries(const EntryType &aFirst, const EntryType &aSecond) const
303 {
304     // `EntryType` can be `HasRouteEntry` or `BorderRouterEntry`.
305 
306     return CompareRouteEntries(aFirst.GetPreference(), aFirst.GetRloc(), aSecond.GetPreference(), aSecond.GetRloc());
307 }
308 
CompareRouteEntries(int8_t aFirstPreference,uint16_t aFirstRloc,int8_t aSecondPreference,uint16_t aSecondRloc) const309 int Leader::CompareRouteEntries(int8_t   aFirstPreference,
310                                 uint16_t aFirstRloc,
311                                 int8_t   aSecondPreference,
312                                 uint16_t aSecondRloc) const
313 {
314     // Performs three-way comparison between two BR entries.
315 
316     int result;
317 
318     // Prefer the entry with higher preference.
319 
320     result = ThreeWayCompare(aFirstPreference, aSecondPreference);
321     VerifyOrExit(result == 0);
322 
323 #if OPENTHREAD_MTD
324     // On MTD, prefer the BR that is this device itself. This handles
325     // the uncommon case where an MTD itself may be acting as BR.
326 
327     result = ThreeWayCompare((aFirstRloc == Get<Mle::Mle>().GetRloc16()), (aSecondRloc == Get<Mle::Mle>().GetRloc16()));
328 #endif
329 
330 #if OPENTHREAD_FTD
331     // If all the same, prefer the one with lower mesh path cost.
332     // Lower cost is preferred so we pass the second entry's cost as
333     // the first argument in the call to `ThreeWayCompare()`, i.e.,
334     // if the second entry's cost is larger, we return 1 indicating
335     // that the first entry is preferred over the second one.
336 
337     result = ThreeWayCompare(Get<RouterTable>().GetPathCost(aSecondRloc), Get<RouterTable>().GetPathCost(aFirstRloc));
338     VerifyOrExit(result == 0);
339 
340     // If all the same, prefer the BR acting as a router over an
341     // end device.
342     result = ThreeWayCompare(Mle::IsActiveRouter(aFirstRloc), Mle::IsActiveRouter(aSecondRloc));
343 #endif
344 
345 exit:
346     return result;
347 }
348 
ExternalRouteLookup(uint8_t aDomainId,const Ip6::Address & aDestination,uint16_t & aRloc16) const349 Error Leader::ExternalRouteLookup(uint8_t aDomainId, const Ip6::Address &aDestination, uint16_t &aRloc16) const
350 {
351     Error                error           = kErrorNoRoute;
352     const PrefixTlv     *prefixTlv       = nullptr;
353     const HasRouteEntry *bestRouteEntry  = nullptr;
354     uint8_t              bestMatchLength = 0;
355 
356     while ((prefixTlv = FindNextMatchingPrefixTlv(aDestination, prefixTlv)) != nullptr)
357     {
358         const HasRouteTlv *hasRoute;
359         uint8_t            prefixLength = prefixTlv->GetPrefixLength();
360         TlvIterator        subTlvIterator(*prefixTlv);
361 
362         if (prefixTlv->GetDomainId() != aDomainId)
363         {
364             continue;
365         }
366 
367         if ((bestRouteEntry != nullptr) && (prefixLength <= bestMatchLength))
368         {
369             continue;
370         }
371 
372         while ((hasRoute = subTlvIterator.Iterate<HasRouteTlv>()) != nullptr)
373         {
374             for (const HasRouteEntry *entry = hasRoute->GetFirstEntry(); entry <= hasRoute->GetLastEntry();
375                  entry                      = entry->GetNext())
376             {
377                 if ((bestRouteEntry == nullptr) || (prefixLength > bestMatchLength) ||
378                     CompareRouteEntries(*entry, *bestRouteEntry) > 0)
379                 {
380                     bestRouteEntry  = entry;
381                     bestMatchLength = prefixLength;
382                 }
383             }
384         }
385     }
386 
387     if (bestRouteEntry != nullptr)
388     {
389         aRloc16 = bestRouteEntry->GetRloc();
390         error   = kErrorNone;
391     }
392 
393     return error;
394 }
395 
DefaultRouteLookup(const PrefixTlv & aPrefix,uint16_t & aRloc16) const396 Error Leader::DefaultRouteLookup(const PrefixTlv &aPrefix, uint16_t &aRloc16) const
397 {
398     Error                    error = kErrorNoRoute;
399     TlvIterator              subTlvIterator(aPrefix);
400     const BorderRouterTlv   *brTlv;
401     const BorderRouterEntry *route = nullptr;
402 
403     while ((brTlv = subTlvIterator.Iterate<BorderRouterTlv>()) != nullptr)
404     {
405         for (const BorderRouterEntry *entry = brTlv->GetFirstEntry(); entry <= brTlv->GetLastEntry();
406              entry                          = entry->GetNext())
407         {
408             if (!entry->IsDefaultRoute())
409             {
410                 continue;
411             }
412 
413             if (route == nullptr || CompareRouteEntries(*entry, *route) > 0)
414             {
415                 route = entry;
416             }
417         }
418     }
419 
420     if (route != nullptr)
421     {
422         aRloc16 = route->GetRloc();
423         error   = kErrorNone;
424     }
425 
426     return error;
427 }
428 
SetNetworkData(uint8_t aVersion,uint8_t aStableVersion,Type aType,const Message & aMessage,uint16_t aOffset,uint16_t aLength)429 Error Leader::SetNetworkData(uint8_t        aVersion,
430                              uint8_t        aStableVersion,
431                              Type           aType,
432                              const Message &aMessage,
433                              uint16_t       aOffset,
434                              uint16_t       aLength)
435 {
436     Error error = kErrorNone;
437 
438     VerifyOrExit(aLength <= kMaxSize, error = kErrorParse);
439     SuccessOrExit(error = aMessage.Read(aOffset, GetBytes(), aLength));
440 
441     SetLength(static_cast<uint8_t>(aLength));
442     mVersion       = aVersion;
443     mStableVersion = aStableVersion;
444 
445     if (aType == kStableSubset)
446     {
447         RemoveTemporaryData();
448     }
449 
450 #if OPENTHREAD_FTD
451     if (Get<Mle::MleRouter>().IsLeader())
452     {
453         Get<Leader>().HandleNetworkDataRestoredAfterReset();
454     }
455 #endif
456 
457     DumpDebg("SetNetworkData", GetBytes(), GetLength());
458 
459     SignalNetDataChanged();
460 
461 exit:
462     return error;
463 }
464 
FindCommissioningData(void) const465 const CommissioningDataTlv *Leader::FindCommissioningData(void) const
466 {
467     return NetworkDataTlv::Find<CommissioningDataTlv>(GetTlvsStart(), GetTlvsEnd());
468 }
469 
FindCommissioningDataSubTlv(uint8_t aType) const470 const MeshCoP::Tlv *Leader::FindCommissioningDataSubTlv(uint8_t aType) const
471 {
472     const MeshCoP::Tlv   *subTlv  = nullptr;
473     const NetworkDataTlv *dataTlv = FindCommissioningData();
474 
475     VerifyOrExit(dataTlv != nullptr);
476     subTlv = As<MeshCoP::Tlv>(Tlv::FindTlv(dataTlv->GetValue(), dataTlv->GetLength(), aType));
477 
478 exit:
479     return subTlv;
480 }
481 
ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::Type aType,uint16_t & aValue) const482 Error Leader::ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::Type aType, uint16_t &aValue) const
483 {
484     Error               error  = kErrorNone;
485     const MeshCoP::Tlv *subTlv = FindCommissioningDataSubTlv(aType);
486 
487     VerifyOrExit(subTlv != nullptr, error = kErrorNotFound);
488     VerifyOrExit(subTlv->GetLength() >= sizeof(uint16_t), error = kErrorParse);
489     aValue = BigEndian::ReadUint16(subTlv->GetValue());
490 
491 exit:
492     return error;
493 }
494 
GetCommissioningDataset(MeshCoP::CommissioningDataset & aDataset) const495 void Leader::GetCommissioningDataset(MeshCoP::CommissioningDataset &aDataset) const
496 {
497     const CommissioningDataTlv *dataTlv = FindCommissioningData();
498     const MeshCoP::Tlv         *subTlv;
499     const MeshCoP::Tlv         *endTlv;
500 
501     aDataset.Clear();
502 
503     VerifyOrExit(dataTlv != nullptr);
504 
505     aDataset.mIsLocatorSet       = (FindBorderAgentRloc(aDataset.mLocator) == kErrorNone);
506     aDataset.mIsSessionIdSet     = (FindCommissioningSessionId(aDataset.mSessionId) == kErrorNone);
507     aDataset.mIsJoinerUdpPortSet = (FindJoinerUdpPort(aDataset.mJoinerUdpPort) == kErrorNone);
508     aDataset.mIsSteeringDataSet  = (FindSteeringData(AsCoreType(&aDataset.mSteeringData)) == kErrorNone);
509 
510     // Determine if the Commissioning data has any extra unknown TLVs
511 
512     subTlv = reinterpret_cast<const MeshCoP::Tlv *>(dataTlv->GetValue());
513     endTlv = reinterpret_cast<const MeshCoP::Tlv *>(dataTlv->GetValue() + dataTlv->GetLength());
514 
515     for (; subTlv < endTlv; subTlv = subTlv->GetNext())
516     {
517         switch (subTlv->GetType())
518         {
519         case MeshCoP::Tlv::kBorderAgentLocator:
520         case MeshCoP::Tlv::kSteeringData:
521         case MeshCoP::Tlv::kJoinerUdpPort:
522         case MeshCoP::Tlv::kCommissionerSessionId:
523             break;
524         default:
525             ExitNow(aDataset.mHasExtraTlv = true);
526         }
527     }
528 
529 exit:
530     return;
531 }
532 
FindBorderAgentRloc(uint16_t & aRloc16) const533 Error Leader::FindBorderAgentRloc(uint16_t &aRloc16) const
534 {
535     return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kBorderAgentLocator, aRloc16);
536 }
537 
FindCommissioningSessionId(uint16_t & aSessionId) const538 Error Leader::FindCommissioningSessionId(uint16_t &aSessionId) const
539 {
540     return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kCommissionerSessionId, aSessionId);
541 }
542 
FindJoinerUdpPort(uint16_t & aPort) const543 Error Leader::FindJoinerUdpPort(uint16_t &aPort) const
544 {
545     return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kJoinerUdpPort, aPort);
546 }
547 
FindSteeringData(MeshCoP::SteeringData & aSteeringData) const548 Error Leader::FindSteeringData(MeshCoP::SteeringData &aSteeringData) const
549 {
550     Error                           error           = kErrorNone;
551     const MeshCoP::SteeringDataTlv *steeringDataTlv = FindInCommissioningData<MeshCoP::SteeringDataTlv>();
552 
553     VerifyOrExit(steeringDataTlv != nullptr, error = kErrorNotFound);
554     steeringDataTlv->CopyTo(aSteeringData);
555 
556 exit:
557     return error;
558 }
559 
IsJoiningAllowed(void) const560 bool Leader::IsJoiningAllowed(void) const
561 {
562     bool                  isAllowed = false;
563     MeshCoP::SteeringData steeringData;
564 
565     SuccessOrExit(FindSteeringData(steeringData));
566     isAllowed = !steeringData.IsEmpty();
567 
568 exit:
569     return isAllowed;
570 }
571 
SteeringDataCheck(const FilterIndexes & aFilterIndexes) const572 Error Leader::SteeringDataCheck(const FilterIndexes &aFilterIndexes) const
573 {
574     Error                 error = kErrorInvalidState;
575     MeshCoP::SteeringData steeringData;
576 
577     SuccessOrExit(FindSteeringData(steeringData));
578     error = steeringData.Contains(aFilterIndexes) ? kErrorNone : kErrorNotFound;
579 
580 exit:
581     return error;
582 }
583 
SteeringDataCheckJoiner(const Mac::ExtAddress & aEui64) const584 Error Leader::SteeringDataCheckJoiner(const Mac::ExtAddress &aEui64) const
585 {
586     FilterIndexes   filterIndexes;
587     Mac::ExtAddress joinerId;
588 
589     MeshCoP::ComputeJoinerId(aEui64, joinerId);
590     MeshCoP::SteeringData::CalculateHashBitIndexes(joinerId, filterIndexes);
591 
592     return SteeringDataCheck(filterIndexes);
593 }
594 
SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner & aDiscerner) const595 Error Leader::SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner &aDiscerner) const
596 {
597     FilterIndexes filterIndexes;
598 
599     MeshCoP::SteeringData::CalculateHashBitIndexes(aDiscerner, filterIndexes);
600 
601     return SteeringDataCheck(filterIndexes);
602 }
603 
SignalNetDataChanged(void)604 void Leader::SignalNetDataChanged(void)
605 {
606     mMaxLength = Max(mMaxLength, GetLength());
607     Get<ot::Notifier>().Signal(kEventThreadNetdataChanged);
608 }
609 
610 } // namespace NetworkData
611 } // namespace ot
612