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 
IsNat64(const Ip6::Address & aAddress) const135 bool Leader::IsNat64(const Ip6::Address &aAddress) const
136 {
137     bool                isNat64  = false;
138     Iterator            iterator = kIteratorInit;
139     ExternalRouteConfig config;
140 
141     while (GetNextExternalRoute(iterator, config) == kErrorNone)
142     {
143         if (config.mNat64 && config.GetPrefix().IsValidNat64() && aAddress.MatchesPrefix(config.GetPrefix()))
144         {
145             isNat64 = true;
146             break;
147         }
148     }
149 
150     return isNat64;
151 }
152 
FindNextMatchingPrefixTlv(const Ip6::Address & aAddress,const PrefixTlv * aPrevTlv) const153 const PrefixTlv *Leader::FindNextMatchingPrefixTlv(const Ip6::Address &aAddress, const PrefixTlv *aPrevTlv) const
154 {
155     // This method iterates over Prefix TLVs which match a given IPv6
156     // `aAddress`. If `aPrevTlv` is `nullptr` we start from the
157     // beginning. Otherwise, we search for a match after `aPrevTlv`.
158     // This method returns a pointer to the next matching Prefix TLV
159     // when found, or `nullptr` if no match is found.
160 
161     const PrefixTlv *prefixTlv;
162     TlvIterator      tlvIterator((aPrevTlv == nullptr) ? GetTlvsStart() : aPrevTlv->GetNext(), GetTlvsEnd());
163 
164     while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
165     {
166         if (aAddress.MatchesPrefix(prefixTlv->GetPrefix(), prefixTlv->GetPrefixLength()))
167         {
168             break;
169         }
170     }
171 
172     return prefixTlv;
173 }
174 
GetContext(const Ip6::Address & aAddress,Lowpan::Context & aContext) const175 Error Leader::GetContext(const Ip6::Address &aAddress, Lowpan::Context &aContext) const
176 {
177     const PrefixTlv  *prefixTlv = nullptr;
178     const ContextTlv *contextTlv;
179 
180     aContext.mPrefix.SetLength(0);
181 
182     if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
183     {
184         GetContextForMeshLocalPrefix(aContext);
185     }
186 
187     while ((prefixTlv = FindNextMatchingPrefixTlv(aAddress, prefixTlv)) != nullptr)
188     {
189         contextTlv = prefixTlv->FindSubTlv<ContextTlv>();
190 
191         if (contextTlv == nullptr)
192         {
193             continue;
194         }
195 
196         if (prefixTlv->GetPrefixLength() > aContext.mPrefix.GetLength())
197         {
198             prefixTlv->CopyPrefixTo(aContext.mPrefix);
199             aContext.mContextId    = contextTlv->GetContextId();
200             aContext.mCompressFlag = contextTlv->IsCompress();
201             aContext.mIsValid      = true;
202         }
203     }
204 
205     return (aContext.mPrefix.GetLength() > 0) ? kErrorNone : kErrorNotFound;
206 }
207 
FindPrefixTlvForContextId(uint8_t aContextId,const ContextTlv * & aContextTlv) const208 const PrefixTlv *Leader::FindPrefixTlvForContextId(uint8_t aContextId, const ContextTlv *&aContextTlv) const
209 {
210     TlvIterator      tlvIterator(GetTlvsStart(), GetTlvsEnd());
211     const PrefixTlv *prefixTlv;
212 
213     while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
214     {
215         const ContextTlv *contextTlv = prefixTlv->FindSubTlv<ContextTlv>();
216 
217         if ((contextTlv != nullptr) && (contextTlv->GetContextId() == aContextId))
218         {
219             aContextTlv = contextTlv;
220             break;
221         }
222     }
223 
224     return prefixTlv;
225 }
226 
GetContext(uint8_t aContextId,Lowpan::Context & aContext) const227 Error Leader::GetContext(uint8_t aContextId, Lowpan::Context &aContext) const
228 {
229     Error             error = kErrorNone;
230     TlvIterator       tlvIterator(GetTlvsStart(), GetTlvsEnd());
231     const PrefixTlv  *prefixTlv;
232     const ContextTlv *contextTlv;
233 
234     if (aContextId == Mle::kMeshLocalPrefixContextId)
235     {
236         GetContextForMeshLocalPrefix(aContext);
237         ExitNow();
238     }
239 
240     prefixTlv = FindPrefixTlvForContextId(aContextId, contextTlv);
241     VerifyOrExit(prefixTlv != nullptr, error = kErrorNotFound);
242 
243     prefixTlv->CopyPrefixTo(aContext.mPrefix);
244     aContext.mContextId    = contextTlv->GetContextId();
245     aContext.mCompressFlag = contextTlv->IsCompress();
246     aContext.mIsValid      = true;
247 
248 exit:
249     return error;
250 }
251 
GetContextForMeshLocalPrefix(Lowpan::Context & aContext) const252 void Leader::GetContextForMeshLocalPrefix(Lowpan::Context &aContext) const
253 {
254     aContext.mPrefix.Set(Get<Mle::MleRouter>().GetMeshLocalPrefix());
255     aContext.mContextId    = Mle::kMeshLocalPrefixContextId;
256     aContext.mCompressFlag = true;
257     aContext.mIsValid      = true;
258 }
259 
IsOnMesh(const Ip6::Address & aAddress) const260 bool Leader::IsOnMesh(const Ip6::Address &aAddress) const
261 {
262     const PrefixTlv *prefixTlv = nullptr;
263     bool             isOnMesh  = false;
264 
265     VerifyOrExit(!Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress), isOnMesh = true);
266 
267     while ((prefixTlv = FindNextMatchingPrefixTlv(aAddress, prefixTlv)) != nullptr)
268     {
269         TlvIterator            subTlvIterator(*prefixTlv);
270         const BorderRouterTlv *brTlv;
271 
272         while ((brTlv = subTlvIterator.Iterate<BorderRouterTlv>()) != nullptr)
273         {
274             for (const BorderRouterEntry *entry = brTlv->GetFirstEntry(); entry <= brTlv->GetLastEntry();
275                  entry                          = entry->GetNext())
276             {
277                 if (entry->IsOnMesh())
278                 {
279                     ExitNow(isOnMesh = true);
280                 }
281             }
282         }
283     }
284 
285 exit:
286     return isOnMesh;
287 }
288 
RouteLookup(const Ip6::Address & aSource,const Ip6::Address & aDestination,uint16_t & aRloc16) const289 Error Leader::RouteLookup(const Ip6::Address &aSource, const Ip6::Address &aDestination, uint16_t &aRloc16) const
290 {
291     Error            error     = kErrorNoRoute;
292     const PrefixTlv *prefixTlv = nullptr;
293 
294     while ((prefixTlv = FindNextMatchingPrefixTlv(aSource, prefixTlv)) != nullptr)
295     {
296         if (prefixTlv->FindSubTlv<BorderRouterTlv>() == nullptr)
297         {
298             continue;
299         }
300 
301         if (ExternalRouteLookup(prefixTlv->GetDomainId(), aDestination, aRloc16) == kErrorNone)
302         {
303             ExitNow(error = kErrorNone);
304         }
305 
306         if (DefaultRouteLookup(*prefixTlv, aRloc16) == kErrorNone)
307         {
308             ExitNow(error = kErrorNone);
309         }
310     }
311 
312 #if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
313     {
314         // The `Slaac` module keeps track of the associated Domain IDs
315         // for deprecating SLAAC prefixes, even if the related
316         // Prefix TLV has already been removed from the Network
317         // Data.
318 
319         uint8_t domainId;
320 
321         if (Get<Utils::Slaac>().FindDomainIdFor(aSource, domainId) == kErrorNone)
322         {
323             error = ExternalRouteLookup(domainId, aDestination, aRloc16);
324         }
325     }
326 #endif
327 
328 exit:
329     return error;
330 }
331 
CompareRouteEntries(const BorderRouterEntry & aFirst,const BorderRouterEntry & aSecond) const332 int Leader::CompareRouteEntries(const BorderRouterEntry &aFirst, const BorderRouterEntry &aSecond) const
333 {
334     return CompareRouteEntries(aFirst.GetPreference(), aFirst.GetRloc(), aSecond.GetPreference(), aSecond.GetRloc());
335 }
336 
CompareRouteEntries(const HasRouteEntry & aFirst,const HasRouteEntry & aSecond) const337 int Leader::CompareRouteEntries(const HasRouteEntry &aFirst, const HasRouteEntry &aSecond) const
338 {
339     return CompareRouteEntries(aFirst.GetPreference(), aFirst.GetRloc(), aSecond.GetPreference(), aSecond.GetRloc());
340 }
341 
CompareRouteEntries(const ServerTlv & aFirst,const ServerTlv & aSecond) const342 int Leader::CompareRouteEntries(const ServerTlv &aFirst, const ServerTlv &aSecond) const
343 {
344     return CompareRouteEntries(/* aFirstPreference */ 0, aFirst.GetServer16(), /* aSecondPreference */ 0,
345                                aSecond.GetServer16());
346 }
347 
CompareRouteEntries(int8_t aFirstPreference,uint16_t aFirstRloc,int8_t aSecondPreference,uint16_t aSecondRloc) const348 int Leader::CompareRouteEntries(int8_t   aFirstPreference,
349                                 uint16_t aFirstRloc,
350                                 int8_t   aSecondPreference,
351                                 uint16_t aSecondRloc) const
352 {
353     // Performs three-way comparison between two BR entries.
354 
355     int result;
356 
357     // Prefer the entry with higher preference.
358 
359     result = ThreeWayCompare(aFirstPreference, aSecondPreference);
360     VerifyOrExit(result == 0);
361 
362 #if OPENTHREAD_MTD
363     // On MTD, prefer the BR that is this device itself. This handles
364     // the uncommon case where an MTD itself may be acting as BR.
365 
366     result = ThreeWayCompare((Get<Mle::Mle>().HasRloc16(aFirstRloc)), Get<Mle::Mle>().HasRloc16(aSecondRloc));
367 #endif
368 
369 #if OPENTHREAD_FTD
370     // If all the same, prefer the one with lower mesh path cost.
371     // Lower cost is preferred so we pass the second entry's cost as
372     // the first argument in the call to `ThreeWayCompare()`, i.e.,
373     // if the second entry's cost is larger, we return 1 indicating
374     // that the first entry is preferred over the second one.
375 
376     result = ThreeWayCompare(Get<RouterTable>().GetPathCost(aSecondRloc), Get<RouterTable>().GetPathCost(aFirstRloc));
377     VerifyOrExit(result == 0);
378 
379     // If all the same, prefer the BR acting as a router over an
380     // end device.
381     result = ThreeWayCompare(Mle::IsRouterRloc16(aFirstRloc), Mle::IsRouterRloc16(aSecondRloc));
382 #endif
383 
384 exit:
385     return result;
386 }
387 
ExternalRouteLookup(uint8_t aDomainId,const Ip6::Address & aDestination,uint16_t & aRloc16) const388 Error Leader::ExternalRouteLookup(uint8_t aDomainId, const Ip6::Address &aDestination, uint16_t &aRloc16) const
389 {
390     Error                error           = kErrorNoRoute;
391     const PrefixTlv     *prefixTlv       = nullptr;
392     const HasRouteEntry *bestRouteEntry  = nullptr;
393     uint8_t              bestMatchLength = 0;
394 
395     while ((prefixTlv = FindNextMatchingPrefixTlv(aDestination, prefixTlv)) != nullptr)
396     {
397         const HasRouteTlv *hasRoute;
398         uint8_t            prefixLength = prefixTlv->GetPrefixLength();
399         TlvIterator        subTlvIterator(*prefixTlv);
400 
401         if (prefixTlv->GetDomainId() != aDomainId)
402         {
403             continue;
404         }
405 
406         if ((bestRouteEntry != nullptr) && (prefixLength <= bestMatchLength))
407         {
408             continue;
409         }
410 
411         while ((hasRoute = subTlvIterator.Iterate<HasRouteTlv>()) != nullptr)
412         {
413             for (const HasRouteEntry *entry = hasRoute->GetFirstEntry(); entry <= hasRoute->GetLastEntry();
414                  entry                      = entry->GetNext())
415             {
416                 if ((bestRouteEntry == nullptr) || (prefixLength > bestMatchLength) ||
417                     CompareRouteEntries(*entry, *bestRouteEntry) > 0)
418                 {
419                     bestRouteEntry  = entry;
420                     bestMatchLength = prefixLength;
421                 }
422             }
423         }
424     }
425 
426     if (bestRouteEntry != nullptr)
427     {
428         aRloc16 = bestRouteEntry->GetRloc();
429         error   = kErrorNone;
430     }
431 
432     return error;
433 }
434 
LookupRouteIn(const PrefixTlv & aPrefixTlv,EntryChecker aEntryChecker,uint16_t & aRloc16) const435 Error Leader::LookupRouteIn(const PrefixTlv &aPrefixTlv, EntryChecker aEntryChecker, uint16_t &aRloc16) const
436 {
437     // Iterates over all `BorderRouterEntry` associated with
438     // `aPrefixTlv` which also match `aEntryChecker` and determine the
439     // best route. For example, this is used from `DefaultRouteLookup()`
440     // to look up best default route.
441 
442     Error                    error = kErrorNoRoute;
443     TlvIterator              subTlvIterator(aPrefixTlv);
444     const BorderRouterTlv   *brTlv;
445     const BorderRouterEntry *bestEntry = nullptr;
446 
447     while ((brTlv = subTlvIterator.Iterate<BorderRouterTlv>()) != nullptr)
448     {
449         for (const BorderRouterEntry *entry = brTlv->GetFirstEntry(); entry <= brTlv->GetLastEntry();
450              entry                          = entry->GetNext())
451         {
452             if (!aEntryChecker(*entry))
453             {
454                 continue;
455             }
456 
457             if ((bestEntry == nullptr) || CompareRouteEntries(*entry, *bestEntry) > 0)
458             {
459                 bestEntry = entry;
460             }
461         }
462     }
463 
464     if (bestEntry != nullptr)
465     {
466         aRloc16 = bestEntry->GetRloc();
467         error   = kErrorNone;
468     }
469 
470     return error;
471 }
472 
IsEntryDefaultRoute(const BorderRouterEntry & aEntry)473 bool Leader::IsEntryDefaultRoute(const BorderRouterEntry &aEntry) { return aEntry.IsDefaultRoute(); }
474 
DefaultRouteLookup(const PrefixTlv & aPrefix,uint16_t & aRloc16) const475 Error Leader::DefaultRouteLookup(const PrefixTlv &aPrefix, uint16_t &aRloc16) const
476 {
477     return LookupRouteIn(aPrefix, IsEntryDefaultRoute, aRloc16);
478 }
479 
SetNetworkData(uint8_t aVersion,uint8_t aStableVersion,Type aType,const Message & aMessage,const OffsetRange & aOffsetRange)480 Error Leader::SetNetworkData(uint8_t            aVersion,
481                              uint8_t            aStableVersion,
482                              Type               aType,
483                              const Message     &aMessage,
484                              const OffsetRange &aOffsetRange)
485 {
486     Error    error  = kErrorNone;
487     uint16_t length = aOffsetRange.GetLength();
488 
489     VerifyOrExit(length <= kMaxSize, error = kErrorParse);
490     SuccessOrExit(error = aMessage.Read(aOffsetRange.GetOffset(), GetBytes(), length));
491 
492     SetLength(static_cast<uint8_t>(length));
493     mVersion       = aVersion;
494     mStableVersion = aStableVersion;
495 
496     if (aType == kStableSubset)
497     {
498         RemoveTemporaryData();
499     }
500 
501 #if OPENTHREAD_FTD
502     if (Get<Mle::MleRouter>().IsLeader())
503     {
504         Get<Leader>().HandleNetworkDataRestoredAfterReset();
505     }
506 #endif
507 
508     DumpDebg("SetNetworkData", GetBytes(), GetLength());
509 
510     SignalNetDataChanged();
511 
512 exit:
513     return error;
514 }
515 
FindCommissioningData(void) const516 const CommissioningDataTlv *Leader::FindCommissioningData(void) const
517 {
518     return NetworkDataTlv::Find<CommissioningDataTlv>(GetTlvsStart(), GetTlvsEnd());
519 }
520 
FindCommissioningDataSubTlv(uint8_t aType) const521 const MeshCoP::Tlv *Leader::FindCommissioningDataSubTlv(uint8_t aType) const
522 {
523     const MeshCoP::Tlv   *subTlv  = nullptr;
524     const NetworkDataTlv *dataTlv = FindCommissioningData();
525 
526     VerifyOrExit(dataTlv != nullptr);
527     subTlv = As<MeshCoP::Tlv>(Tlv::FindTlv(dataTlv->GetValue(), dataTlv->GetLength(), aType));
528 
529 exit:
530     return subTlv;
531 }
532 
ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::Type aType,uint16_t & aValue) const533 Error Leader::ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::Type aType, uint16_t &aValue) const
534 {
535     Error               error  = kErrorNone;
536     const MeshCoP::Tlv *subTlv = FindCommissioningDataSubTlv(aType);
537 
538     VerifyOrExit(subTlv != nullptr, error = kErrorNotFound);
539     VerifyOrExit(subTlv->GetLength() >= sizeof(uint16_t), error = kErrorParse);
540     aValue = BigEndian::ReadUint16(subTlv->GetValue());
541 
542 exit:
543     return error;
544 }
545 
GetCommissioningDataset(MeshCoP::CommissioningDataset & aDataset) const546 void Leader::GetCommissioningDataset(MeshCoP::CommissioningDataset &aDataset) const
547 {
548     const CommissioningDataTlv *dataTlv = FindCommissioningData();
549     const MeshCoP::Tlv         *subTlv;
550     const MeshCoP::Tlv         *endTlv;
551 
552     aDataset.Clear();
553 
554     VerifyOrExit(dataTlv != nullptr);
555 
556     aDataset.mIsLocatorSet       = (FindBorderAgentRloc(aDataset.mLocator) == kErrorNone);
557     aDataset.mIsSessionIdSet     = (FindCommissioningSessionId(aDataset.mSessionId) == kErrorNone);
558     aDataset.mIsJoinerUdpPortSet = (FindJoinerUdpPort(aDataset.mJoinerUdpPort) == kErrorNone);
559     aDataset.mIsSteeringDataSet  = (FindSteeringData(AsCoreType(&aDataset.mSteeringData)) == kErrorNone);
560 
561     // Determine if the Commissioning data has any extra unknown TLVs
562 
563     subTlv = reinterpret_cast<const MeshCoP::Tlv *>(dataTlv->GetValue());
564     endTlv = reinterpret_cast<const MeshCoP::Tlv *>(dataTlv->GetValue() + dataTlv->GetLength());
565 
566     for (; subTlv < endTlv; subTlv = subTlv->GetNext())
567     {
568         switch (subTlv->GetType())
569         {
570         case MeshCoP::Tlv::kBorderAgentLocator:
571         case MeshCoP::Tlv::kSteeringData:
572         case MeshCoP::Tlv::kJoinerUdpPort:
573         case MeshCoP::Tlv::kCommissionerSessionId:
574             break;
575         default:
576             ExitNow(aDataset.mHasExtraTlv = true);
577         }
578     }
579 
580 exit:
581     return;
582 }
583 
ProcessCommissionerGetRequest(const Coap::Message & aMessage) const584 Coap::Message *Leader::ProcessCommissionerGetRequest(const Coap::Message &aMessage) const
585 {
586     Error          error    = kErrorNone;
587     Coap::Message *response = nullptr;
588     OffsetRange    offsetRange;
589 
590     response = Get<Tmf::Agent>().NewPriorityResponseMessage(aMessage);
591     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
592 
593     if (Tlv::FindTlvValueOffsetRange(aMessage, MeshCoP::Tlv::kGet, offsetRange) == kErrorNone)
594     {
595         // Append the requested sub-TLV types given in Get TLV.
596 
597         while (!offsetRange.IsEmpty())
598         {
599             uint8_t             type;
600             const MeshCoP::Tlv *subTlv;
601 
602             IgnoreError(aMessage.Read(offsetRange, type));
603             offsetRange.AdvanceOffset(sizeof(type));
604 
605             subTlv = FindCommissioningDataSubTlv(type);
606 
607             if (subTlv != nullptr)
608             {
609                 SuccessOrExit(error = subTlv->AppendTo(*response));
610             }
611         }
612     }
613     else
614     {
615         // Append all sub-TLVs in the Commissioning Data.
616 
617         const CommissioningDataTlv *dataTlv = FindCommissioningData();
618 
619         if (dataTlv != nullptr)
620         {
621             SuccessOrExit(error = response->AppendBytes(dataTlv->GetValue(), dataTlv->GetLength()));
622         }
623     }
624 
625 exit:
626     FreeAndNullMessageOnError(response, error);
627     return response;
628 }
629 
FindBorderAgentRloc(uint16_t & aRloc16) const630 Error Leader::FindBorderAgentRloc(uint16_t &aRloc16) const
631 {
632     return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kBorderAgentLocator, aRloc16);
633 }
634 
FindCommissioningSessionId(uint16_t & aSessionId) const635 Error Leader::FindCommissioningSessionId(uint16_t &aSessionId) const
636 {
637     return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kCommissionerSessionId, aSessionId);
638 }
639 
FindJoinerUdpPort(uint16_t & aPort) const640 Error Leader::FindJoinerUdpPort(uint16_t &aPort) const
641 {
642     return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kJoinerUdpPort, aPort);
643 }
644 
FindSteeringData(MeshCoP::SteeringData & aSteeringData) const645 Error Leader::FindSteeringData(MeshCoP::SteeringData &aSteeringData) const
646 {
647     Error                           error           = kErrorNone;
648     const MeshCoP::SteeringDataTlv *steeringDataTlv = FindInCommissioningData<MeshCoP::SteeringDataTlv>();
649 
650     VerifyOrExit(steeringDataTlv != nullptr, error = kErrorNotFound);
651     steeringDataTlv->CopyTo(aSteeringData);
652 
653 exit:
654     return error;
655 }
656 
IsJoiningAllowed(void) const657 bool Leader::IsJoiningAllowed(void) const
658 {
659     bool                  isAllowed = false;
660     MeshCoP::SteeringData steeringData;
661 
662     SuccessOrExit(FindSteeringData(steeringData));
663     isAllowed = !steeringData.IsEmpty();
664 
665 exit:
666     return isAllowed;
667 }
668 
SteeringDataCheck(const FilterIndexes & aFilterIndexes) const669 Error Leader::SteeringDataCheck(const FilterIndexes &aFilterIndexes) const
670 {
671     Error                 error = kErrorInvalidState;
672     MeshCoP::SteeringData steeringData;
673 
674     SuccessOrExit(FindSteeringData(steeringData));
675     error = steeringData.Contains(aFilterIndexes) ? kErrorNone : kErrorNotFound;
676 
677 exit:
678     return error;
679 }
680 
SteeringDataCheckJoiner(const Mac::ExtAddress & aEui64) const681 Error Leader::SteeringDataCheckJoiner(const Mac::ExtAddress &aEui64) const
682 {
683     FilterIndexes   filterIndexes;
684     Mac::ExtAddress joinerId;
685 
686     MeshCoP::ComputeJoinerId(aEui64, joinerId);
687     MeshCoP::SteeringData::CalculateHashBitIndexes(joinerId, filterIndexes);
688 
689     return SteeringDataCheck(filterIndexes);
690 }
691 
SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner & aDiscerner) const692 Error Leader::SteeringDataCheckJoiner(const MeshCoP::JoinerDiscerner &aDiscerner) const
693 {
694     FilterIndexes filterIndexes;
695 
696     MeshCoP::SteeringData::CalculateHashBitIndexes(aDiscerner, filterIndexes);
697 
698     return SteeringDataCheck(filterIndexes);
699 }
700 
SignalNetDataChanged(void)701 void Leader::SignalNetDataChanged(void)
702 {
703     mMaxLength = Max(mMaxLength, GetLength());
704     Get<ot::Notifier>().Signal(kEventThreadNetdataChanged);
705 }
706 
707 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
708 
ContainsOmrPrefix(const Ip6::Prefix & aPrefix) const709 bool Leader::ContainsOmrPrefix(const Ip6::Prefix &aPrefix) const
710 {
711     bool                   contains = false;
712     const PrefixTlv       *prefixTlv;
713     const BorderRouterTlv *brSubTlv;
714 
715     VerifyOrExit(BorderRouter::RoutingManager::IsValidOmrPrefix(aPrefix));
716 
717     prefixTlv = FindPrefix(aPrefix);
718     VerifyOrExit(prefixTlv != nullptr);
719 
720     brSubTlv = prefixTlv->FindSubTlv<BorderRouterTlv>(/* aStable */ true);
721 
722     VerifyOrExit(brSubTlv != nullptr);
723 
724     for (const BorderRouterEntry *entry = brSubTlv->GetFirstEntry(); entry <= brSubTlv->GetLastEntry(); entry++)
725     {
726         OnMeshPrefixConfig config;
727 
728         config.SetFrom(*prefixTlv, *brSubTlv, *entry);
729 
730         if (BorderRouter::RoutingManager::IsValidOmrPrefix(config))
731         {
732             ExitNow(contains = true);
733         }
734     }
735 
736 exit:
737     return contains;
738 }
739 
740 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
741 
742 } // namespace NetworkData
743 } // namespace ot
744