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