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 #if OPENTHREAD_FTD
37
38 #include "instance/instance.hpp"
39
40 namespace ot {
41 namespace NetworkData {
42
43 RegisterLogModule("NetworkData");
44
Start(Mle::LeaderStartMode aStartMode)45 void Leader::Start(Mle::LeaderStartMode aStartMode)
46 {
47 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
48 OT_ASSERT(!mIsClone);
49 #endif
50
51 mWaitingForNetDataSync = (aStartMode == Mle::kRestoringLeaderRoleAfterReset);
52
53 if (mWaitingForNetDataSync)
54 {
55 mTimer.Start(kMaxNetDataSyncWait);
56 }
57 }
58
IncrementVersion(void)59 void Leader::IncrementVersion(void)
60 {
61 if (Get<Mle::MleRouter>().IsLeader())
62 {
63 IncrementVersions(/* aIncludeStable */ false);
64 }
65 }
66
IncrementVersionAndStableVersion(void)67 void Leader::IncrementVersionAndStableVersion(void)
68 {
69 if (Get<Mle::MleRouter>().IsLeader())
70 {
71 IncrementVersions(/* aIncludeStable */ true);
72 }
73 }
74
IncrementVersions(const ChangedFlags & aFlags)75 void Leader::IncrementVersions(const ChangedFlags &aFlags)
76 {
77 if (aFlags.DidChange())
78 {
79 IncrementVersions(aFlags.DidStableChange());
80 }
81 }
82
IncrementVersions(bool aIncludeStable)83 void Leader::IncrementVersions(bool aIncludeStable)
84 {
85 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
86 VerifyOrExit(!mIsClone);
87 #endif
88
89 if (aIncludeStable)
90 {
91 mStableVersion++;
92 }
93
94 mVersion++;
95 SignalNetDataChanged();
96 ExitNow();
97
98 exit:
99 return;
100 }
101
AnycastLookup(uint16_t aAloc16,uint16_t & aRloc16) const102 Error Leader::AnycastLookup(uint16_t aAloc16, uint16_t &aRloc16) const
103 {
104 Error error = kErrorNone;
105
106 aRloc16 = Mle::kInvalidRloc16;
107
108 if (aAloc16 == Mle::kAloc16Leader)
109 {
110 aRloc16 = Get<Mle::Mle>().GetLeaderRloc16();
111 }
112 else if (IsValueInRange(aAloc16, Mle::kAloc16DhcpAgentStart, Mle::kAloc16DhcpAgentEnd))
113 {
114 uint8_t contextId = static_cast<uint8_t>(aAloc16 - Mle::kAloc16DhcpAgentStart + 1);
115
116 error = LookupRouteForAgentAloc(contextId, IsEntryForDhcp6Agent, aRloc16);
117 }
118 else if (IsValueInRange(aAloc16, Mle::kAloc16ServiceStart, Mle::kAloc16ServiceEnd))
119 {
120 error = LookupRouteForServiceAloc(aAloc16, aRloc16);
121 }
122 else if (IsValueInRange(aAloc16, Mle::kAloc16CommissionerStart, Mle::kAloc16CommissionerEnd))
123 {
124 error = FindBorderAgentRloc(aRloc16);
125 }
126 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
127 else if (aAloc16 == Mle::kAloc16BackboneRouterPrimary)
128 {
129 VerifyOrExit(Get<BackboneRouter::Leader>().HasPrimary(), error = kErrorDrop);
130 aRloc16 = Get<BackboneRouter::Leader>().GetServer16();
131 }
132 #endif
133 else if (IsValueInRange(aAloc16, Mle::kAloc16NeighborDiscoveryAgentStart, Mle::kAloc16NeighborDiscoveryAgentEnd))
134 {
135 uint8_t contextId = static_cast<uint8_t>(aAloc16 - Mle::kAloc16NeighborDiscoveryAgentStart + 1);
136
137 error = LookupRouteForAgentAloc(contextId, IsEntryForNdAgent, aRloc16);
138 }
139 else
140 {
141 error = kErrorDrop;
142 }
143
144 SuccessOrExit(error);
145 VerifyOrExit(aRloc16 != Mle::kInvalidRloc16, error = kErrorNoRoute);
146
147 if (Mle::IsChildRloc16(aRloc16))
148 {
149 // If the selected destination is a child, we use its parent
150 // as the destination unless the device itself is the
151 // parent of the `aRloc16`.
152
153 uint16_t parentRloc16 = Mle::ParentRloc16ForRloc16(aRloc16);
154
155 if (!Get<Mle::Mle>().HasRloc16(parentRloc16))
156 {
157 aRloc16 = parentRloc16;
158 }
159 }
160
161 exit:
162 return error;
163 }
164
LookupRouteForServiceAloc(uint16_t aAloc16,uint16_t & aRloc16) const165 Error Leader::LookupRouteForServiceAloc(uint16_t aAloc16, uint16_t &aRloc16) const
166 {
167 Error error = kErrorNoRoute;
168 const ServiceTlv *serviceTlv = FindServiceById(Mle::ServiceIdFromAloc(aAloc16));
169
170 if (serviceTlv != nullptr)
171 {
172 TlvIterator subTlvIterator(*serviceTlv);
173 const ServerTlv *bestServerTlv = nullptr;
174 const ServerTlv *serverTlv;
175
176 while ((serverTlv = subTlvIterator.Iterate<ServerTlv>()) != nullptr)
177 {
178 if ((bestServerTlv == nullptr) || CompareRouteEntries(*serverTlv, *bestServerTlv) > 0)
179 {
180 bestServerTlv = serverTlv;
181 }
182 }
183
184 if (bestServerTlv != nullptr)
185 {
186 aRloc16 = bestServerTlv->GetServer16();
187 error = kErrorNone;
188 }
189 }
190
191 return error;
192 }
193
IsEntryForDhcp6Agent(const BorderRouterEntry & aEntry)194 bool Leader::IsEntryForDhcp6Agent(const BorderRouterEntry &aEntry) { return aEntry.IsDhcp() || aEntry.IsConfigure(); }
195
IsEntryForNdAgent(const BorderRouterEntry & aEntry)196 bool Leader::IsEntryForNdAgent(const BorderRouterEntry &aEntry) { return aEntry.IsNdDns(); }
197
LookupRouteForAgentAloc(uint8_t aContextId,EntryChecker aEntryChecker,uint16_t & aRloc16) const198 Error Leader::LookupRouteForAgentAloc(uint8_t aContextId, EntryChecker aEntryChecker, uint16_t &aRloc16) const
199 {
200 Error error = kErrorNoRoute;
201 const PrefixTlv *prefixTlv;
202 const ContextTlv *contextTlv;
203
204 prefixTlv = FindPrefixTlvForContextId(aContextId, contextTlv);
205 VerifyOrExit(prefixTlv != nullptr);
206
207 error = LookupRouteIn(*prefixTlv, aEntryChecker, aRloc16);
208
209 exit:
210 return error;
211 }
212
RemoveBorderRouter(uint16_t aRloc16,MatchMode aMatchMode)213 void Leader::RemoveBorderRouter(uint16_t aRloc16, MatchMode aMatchMode)
214 {
215 ChangedFlags flags;
216
217 RemoveRloc(aRloc16, aMatchMode, flags);
218
219 IncrementVersions(flags);
220 }
221
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)222 template <> void Leader::HandleTmf<kUriServerData>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
223 {
224 ThreadNetworkDataTlv networkDataTlv;
225 uint16_t rloc16;
226
227 VerifyOrExit(Get<Mle::Mle>().IsLeader() && !mWaitingForNetDataSync);
228
229 LogInfo("Received %s", UriToString<kUriServerData>());
230
231 VerifyOrExit(aMessageInfo.GetPeerAddr().GetIid().IsRoutingLocator());
232
233 switch (Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16))
234 {
235 case kErrorNone:
236 RemoveBorderRouter(rloc16, kMatchModeRloc16);
237 break;
238 case kErrorNotFound:
239 break;
240 default:
241 ExitNow();
242 }
243
244 if (Tlv::FindTlv(aMessage, networkDataTlv) == kErrorNone)
245 {
246 VerifyOrExit(networkDataTlv.IsValid());
247
248 {
249 NetworkData networkData(GetInstance(), networkDataTlv.GetTlvs(), networkDataTlv.GetLength());
250
251 RegisterNetworkData(aMessageInfo.GetPeerAddr().GetIid().GetLocator(), networkData);
252 }
253 }
254
255 SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo));
256
257 LogInfo("Sent %s ack", UriToString<kUriServerData>());
258
259 exit:
260 return;
261 }
262
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)263 template <> void Leader::HandleTmf<kUriCommissionerSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
264 {
265 MeshCoP::StateTlv::State state = MeshCoP::StateTlv::kReject;
266 uint16_t borderAgentRloc;
267 uint16_t sessionId;
268 uint16_t localSessionId;
269
270 VerifyOrExit(Get<Mle::Mle>().IsLeader() && !mWaitingForNetDataSync);
271
272 // Validate that there is no Border Agent Locator TLV. This also
273 // validates that all included TLVs are properly formatted.
274
275 VerifyOrExit(Tlv::Find<MeshCoP::BorderAgentLocatorTlv>(aMessage, borderAgentRloc) == kErrorNotFound);
276
277 SuccessOrExit(Tlv::Find<MeshCoP::CommissionerSessionIdTlv>(aMessage, sessionId));
278
279 if (FindCommissioningSessionId(localSessionId) == kErrorNone)
280 {
281 VerifyOrExit(sessionId == localSessionId);
282 }
283
284 // Add the Border Agent RLOC TLV from Network Data.
285
286 if (FindBorderAgentRloc(borderAgentRloc) == kErrorNone)
287 {
288 SuccessOrExit(Tlv::Append<MeshCoP::BorderAgentLocatorTlv>(aMessage, borderAgentRloc));
289 }
290
291 SuccessOrExit(SetCommissioningData(aMessage));
292
293 state = MeshCoP::StateTlv::kAccept;
294
295 exit:
296 if (Get<Mle::MleRouter>().IsLeader())
297 {
298 SendCommissioningSetResponse(aMessage, aMessageInfo, state);
299 }
300 }
301
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)302 template <> void Leader::HandleTmf<kUriCommissionerGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
303 {
304 Error error = kErrorNone;
305 Coap::Message *response = nullptr;
306
307 VerifyOrExit(Get<Mle::Mle>().IsLeader() && !mWaitingForNetDataSync, error = kErrorInvalidState);
308
309 response = ProcessCommissionerGetRequest(aMessage);
310 VerifyOrExit(response != nullptr, error = kErrorParse);
311 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*response, aMessageInfo));
312
313 LogInfo("Sent %s response to %s", UriToString<kUriCommissionerGet>(),
314 aMessageInfo.GetPeerAddr().ToString().AsCString());
315
316 exit:
317 LogWarnOnError(error, "send CommissionerGet response");
318 FreeMessageOnError(response, error);
319 }
320
SendCommissioningSetResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,MeshCoP::StateTlv::State aState)321 void Leader::SendCommissioningSetResponse(const Coap::Message &aRequest,
322 const Ip6::MessageInfo &aMessageInfo,
323 MeshCoP::StateTlv::State aState)
324 {
325 Coap::Message *message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
326
327 VerifyOrExit(message != nullptr);
328 SuccessOrExit(Tlv::Append<MeshCoP::StateTlv>(*message, aState));
329
330 SuccessOrExit(Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
331 message = nullptr; // `SendMessage` takes ownership on success
332
333 LogInfo("Sent %s response", UriToString<kUriCommissionerSet>());
334
335 exit:
336 FreeMessage(message);
337 }
338
RlocMatch(uint16_t aFirstRloc16,uint16_t aSecondRloc16,MatchMode aMatchMode)339 bool Leader::RlocMatch(uint16_t aFirstRloc16, uint16_t aSecondRloc16, MatchMode aMatchMode)
340 {
341 bool matched = false;
342
343 switch (aMatchMode)
344 {
345 case kMatchModeRloc16:
346 matched = (aFirstRloc16 == aSecondRloc16);
347 break;
348
349 case kMatchModeRouterId:
350 matched = Mle::RouterIdMatch(aFirstRloc16, aSecondRloc16);
351 break;
352 }
353
354 return matched;
355 }
356
Validate(const NetworkData & aNetworkData,uint16_t aRloc16)357 Error Leader::Validate(const NetworkData &aNetworkData, uint16_t aRloc16)
358 {
359 // Validate that the `aTlvs` contains well-formed TLVs, sub-TLVs,
360 // and entries all matching `aRloc16` (no other entry for other
361 // RLOCs and no duplicates TLVs).
362
363 Error error = kErrorNone;
364 const NetworkDataTlv *end = aNetworkData.GetTlvsEnd();
365
366 for (const NetworkDataTlv *cur = aNetworkData.GetTlvsStart(); cur < end; cur = cur->GetNext())
367 {
368 NetworkData validatedSegment(aNetworkData.GetInstance(), aNetworkData.GetTlvsStart(), cur);
369
370 VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end, error = kErrorParse);
371
372 switch (cur->GetType())
373 {
374 case NetworkDataTlv::kTypePrefix:
375 {
376 const PrefixTlv *prefix = As<PrefixTlv>(cur);
377
378 VerifyOrExit(prefix->IsValid(), error = kErrorParse);
379
380 // Ensure there is no duplicate Prefix TLVs with same prefix.
381 VerifyOrExit(validatedSegment.FindPrefix(prefix->GetPrefix(), prefix->GetPrefixLength()) == nullptr,
382 error = kErrorParse);
383
384 SuccessOrExit(error = ValidatePrefix(*prefix, aRloc16));
385 break;
386 }
387
388 case NetworkDataTlv::kTypeService:
389 {
390 const ServiceTlv *service = As<ServiceTlv>(cur);
391 ServiceData serviceData;
392
393 VerifyOrExit(service->IsValid(), error = kErrorParse);
394
395 service->GetServiceData(serviceData);
396
397 // Ensure there is no duplicate Service TLV with same
398 // Enterprise Number and Service Data.
399 VerifyOrExit(validatedSegment.FindService(service->GetEnterpriseNumber(), serviceData,
400 kServiceExactMatch) == nullptr,
401 error = kErrorParse);
402
403 SuccessOrExit(error = ValidateService(*service, aRloc16));
404 break;
405 }
406
407 default:
408 break;
409 }
410 }
411
412 exit:
413 return error;
414 }
415
ValidatePrefix(const PrefixTlv & aPrefix,uint16_t aRloc16)416 Error Leader::ValidatePrefix(const PrefixTlv &aPrefix, uint16_t aRloc16)
417 {
418 // Validate that `aPrefix` TLV contains well-formed sub-TLVs and
419 // and entries all matching `aRloc16` (no other entry for other
420 // RLOCs).
421
422 Error error = kErrorParse;
423 const NetworkDataTlv *subEnd = aPrefix.GetNext();
424 bool foundTempHasRoute = false;
425 bool foundStableHasRoute = false;
426 bool foundTempBorderRouter = false;
427 bool foundStableBorderRouter = false;
428
429 for (const NetworkDataTlv *subCur = aPrefix.GetSubTlvs(); subCur < subEnd; subCur = subCur->GetNext())
430 {
431 VerifyOrExit((subCur + 1) <= subEnd && subCur->GetNext() <= subEnd);
432
433 switch (subCur->GetType())
434 {
435 case NetworkDataTlv::kTypeBorderRouter:
436 {
437 const BorderRouterTlv *borderRouter = As<BorderRouterTlv>(subCur);
438
439 // Ensure Prefix TLV contains at most one stable and one
440 // temporary Border Router sub-TLV and the sub-TLVs have
441 // a single entry.
442
443 if (borderRouter->IsStable())
444 {
445 VerifyOrExit(!foundStableBorderRouter);
446 foundStableBorderRouter = true;
447 }
448 else
449 {
450 VerifyOrExit(!foundTempBorderRouter);
451 foundTempBorderRouter = true;
452 }
453
454 VerifyOrExit(borderRouter->GetFirstEntry() == borderRouter->GetLastEntry());
455 VerifyOrExit(borderRouter->GetFirstEntry()->GetRloc() == aRloc16);
456 break;
457 }
458
459 case NetworkDataTlv::kTypeHasRoute:
460 {
461 const HasRouteTlv *hasRoute = As<HasRouteTlv>(subCur);
462
463 // Ensure Prefix TLV contains at most one stable and one
464 // temporary Has Route sub-TLV and the sub-TLVs have a
465 // single entry.
466
467 if (hasRoute->IsStable())
468 {
469 VerifyOrExit(!foundStableHasRoute);
470 foundStableHasRoute = true;
471 }
472 else
473 {
474 VerifyOrExit(!foundTempHasRoute);
475 foundTempHasRoute = true;
476 }
477
478 VerifyOrExit(hasRoute->GetFirstEntry() == hasRoute->GetLastEntry());
479 VerifyOrExit(hasRoute->GetFirstEntry()->GetRloc() == aRloc16);
480 break;
481 }
482
483 default:
484 break;
485 }
486 }
487
488 if (foundStableBorderRouter || foundTempBorderRouter || foundStableHasRoute || foundTempHasRoute)
489 {
490 error = kErrorNone;
491 }
492
493 exit:
494 return error;
495 }
496
ValidateService(const ServiceTlv & aService,uint16_t aRloc16)497 Error Leader::ValidateService(const ServiceTlv &aService, uint16_t aRloc16)
498 {
499 // Validate that `aService` TLV contains a single well-formed
500 // Server sub-TLV associated with `aRloc16`.
501
502 Error error = kErrorParse;
503 const NetworkDataTlv *subEnd = aService.GetNext();
504 bool foundServer = false;
505
506 for (const NetworkDataTlv *subCur = aService.GetSubTlvs(); subCur < subEnd; subCur = subCur->GetNext())
507 {
508 VerifyOrExit((subCur + 1) <= subEnd && subCur->GetNext() <= subEnd);
509
510 switch (subCur->GetType())
511 {
512 case NetworkDataTlv::kTypeServer:
513 {
514 const ServerTlv *server = As<ServerTlv>(subCur);
515
516 VerifyOrExit(!foundServer);
517 foundServer = true;
518
519 VerifyOrExit(server->IsValid() && server->GetServer16() == aRloc16);
520 break;
521 }
522
523 default:
524 break;
525 }
526 }
527
528 if (foundServer)
529 {
530 error = kErrorNone;
531 }
532
533 exit:
534 return error;
535 }
536
ContainsMatchingEntry(const PrefixTlv * aPrefix,bool aStable,const HasRouteEntry & aEntry)537 bool Leader::ContainsMatchingEntry(const PrefixTlv *aPrefix, bool aStable, const HasRouteEntry &aEntry)
538 {
539 // Check whether `aPrefix` has a Has Route sub-TLV with stable
540 // flag `aStable` containing a matching entry to `aEntry`.
541
542 return (aPrefix == nullptr) ? false : ContainsMatchingEntry(aPrefix->FindSubTlv<HasRouteTlv>(aStable), aEntry);
543 }
544
ContainsMatchingEntry(const HasRouteTlv * aHasRoute,const HasRouteEntry & aEntry)545 bool Leader::ContainsMatchingEntry(const HasRouteTlv *aHasRoute, const HasRouteEntry &aEntry)
546 {
547 // Check whether `aHasRoute` has a matching entry to `aEntry`.
548
549 bool contains = false;
550
551 VerifyOrExit(aHasRoute != nullptr);
552
553 for (const HasRouteEntry *entry = aHasRoute->GetFirstEntry(); entry <= aHasRoute->GetLastEntry(); entry++)
554 {
555 if (*entry == aEntry)
556 {
557 contains = true;
558 break;
559 }
560 }
561
562 exit:
563 return contains;
564 }
565
ContainsMatchingEntry(const PrefixTlv * aPrefix,bool aStable,const BorderRouterEntry & aEntry)566 bool Leader::ContainsMatchingEntry(const PrefixTlv *aPrefix, bool aStable, const BorderRouterEntry &aEntry)
567 {
568 // Check whether `aPrefix` has a Border Router sub-TLV with stable
569 // flag `aStable` containing a matching entry to `aEntry`.
570
571 return (aPrefix == nullptr) ? false : ContainsMatchingEntry(aPrefix->FindSubTlv<BorderRouterTlv>(aStable), aEntry);
572 }
573
ContainsMatchingEntry(const BorderRouterTlv * aBorderRouter,const BorderRouterEntry & aEntry)574 bool Leader::ContainsMatchingEntry(const BorderRouterTlv *aBorderRouter, const BorderRouterEntry &aEntry)
575 {
576 // Check whether `aBorderRouter` has a matching entry to `aEntry`.
577
578 bool contains = false;
579
580 VerifyOrExit(aBorderRouter != nullptr);
581
582 for (const BorderRouterEntry *entry = aBorderRouter->GetFirstEntry(); entry <= aBorderRouter->GetLastEntry();
583 entry++)
584 {
585 if (*entry == aEntry)
586 {
587 contains = true;
588 break;
589 }
590 }
591
592 exit:
593 return contains;
594 }
595
ContainsMatchingServer(const ServiceTlv * aService,const ServerTlv & aServer)596 bool Leader::ContainsMatchingServer(const ServiceTlv *aService, const ServerTlv &aServer)
597 {
598 // Check whether the `aService` has a matching Server sub-TLV
599 // same as `aServer`.
600
601 bool contains = false;
602
603 if (aService != nullptr)
604 {
605 const ServerTlv *server;
606 TlvIterator subTlvIterator(*aService);
607
608 while ((server = subTlvIterator.Iterate<ServerTlv>(aServer.IsStable())) != nullptr)
609 {
610 if (*server == aServer)
611 {
612 contains = true;
613 break;
614 }
615 }
616 }
617
618 return contains;
619 }
620
UpdatePrefix(PrefixTlv & aPrefix)621 Leader::UpdateStatus Leader::UpdatePrefix(PrefixTlv &aPrefix) { return UpdateTlv(aPrefix, aPrefix.GetSubTlvs()); }
622
UpdateService(ServiceTlv & aService)623 Leader::UpdateStatus Leader::UpdateService(ServiceTlv &aService) { return UpdateTlv(aService, aService.GetSubTlvs()); }
624
UpdateTlv(NetworkDataTlv & aTlv,const NetworkDataTlv * aSubTlvs)625 Leader::UpdateStatus Leader::UpdateTlv(NetworkDataTlv &aTlv, const NetworkDataTlv *aSubTlvs)
626 {
627 // If `aTlv` contains no sub-TLVs, remove it from Network Data,
628 // otherwise update its stable flag based on its sub-TLVs.
629
630 UpdateStatus status = kTlvUpdated;
631
632 if (aSubTlvs == aTlv.GetNext())
633 {
634 RemoveTlv(&aTlv);
635 ExitNow(status = kTlvRemoved);
636 }
637
638 for (const NetworkDataTlv *subCur = aSubTlvs; subCur < aTlv.GetNext(); subCur = subCur->GetNext())
639 {
640 if (subCur->IsStable())
641 {
642 aTlv.SetStable();
643 ExitNow();
644 }
645 }
646
647 aTlv.ClearStable();
648
649 exit:
650 return status;
651 }
652
653 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
654
CheckForNetDataGettingFull(const NetworkData & aNetworkData,uint16_t aOldRloc16)655 void Leader::CheckForNetDataGettingFull(const NetworkData &aNetworkData, uint16_t aOldRloc16)
656 {
657 // Determines whether there is still room in Network Data to register
658 // `aNetworkData` entries. The `aNetworkData` MUST follow the format of
659 // local Network Data (e.g., all entries associated with the RLOC16 of
660 // this device). Network data getting full is signaled by invoking the
661 // `Get<Notifier>().SignalNetworkDataFull()` method.
662 //
663 // Input `aOldRloc16` can be used to indicate the old RLOC16 of the
664 // device. If provided, then entries matching old RLOC16 are first
665 // removed, before checking if new entries from @p aNetworkData can fit.
666
667 if (!Get<Mle::MleRouter>().IsLeader())
668 {
669 // Create a clone of the leader's network data, and try to register
670 // `aNetworkData` into the copy (as if this device itself is the
671 // leader). `mIsClone` flag is used to mark the clone and ensure
672 // that the cloned instance does interact with other OT modules,
673 // e.g., does not start timer, or does not signal version change
674 // using `Get<ot::Notifier>().Signal()`, or allocate service or
675 // context ID.
676
677 Leader leaderClone(GetInstance());
678
679 leaderClone.MarkAsClone();
680 SuccessOrAssert(CopyNetworkData(kFullSet, leaderClone));
681
682 if (aOldRloc16 != Mle::kInvalidRloc16)
683 {
684 leaderClone.RemoveBorderRouter(aOldRloc16, kMatchModeRloc16);
685 }
686
687 leaderClone.RegisterNetworkData(Get<Mle::Mle>().GetRloc16(), aNetworkData);
688 }
689 }
690
MarkAsClone(void)691 void Leader::MarkAsClone(void)
692 {
693 mIsClone = true;
694 mContextIds.MarkAsClone();
695 }
696
697 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
698
RegisterNetworkData(uint16_t aRloc16,const NetworkData & aNetworkData)699 void Leader::RegisterNetworkData(uint16_t aRloc16, const NetworkData &aNetworkData)
700 {
701 Error error = kErrorNone;
702 ChangedFlags flags;
703
704 VerifyOrExit(Get<RouterTable>().IsAllocated(Mle::RouterIdFromRloc16(aRloc16)), error = kErrorNoRoute);
705
706 // Validate that the `aNetworkData` contains well-formed TLVs, sub-TLVs,
707 // and entries all matching `aRloc16` (no other RLOCs).
708 SuccessOrExit(error = Validate(aNetworkData, aRloc16));
709
710 // Remove all entries matching `aRloc16` excluding entries that are
711 // present in `aNetworkData`
712 RemoveRloc(aRloc16, kMatchModeRloc16, aNetworkData, flags);
713
714 // Now add all new entries in `aTlvs` to Network Data.
715 for (const NetworkDataTlv *cur = aNetworkData.GetTlvsStart(); cur < aNetworkData.GetTlvsEnd(); cur = cur->GetNext())
716 {
717 switch (cur->GetType())
718 {
719 case NetworkDataTlv::kTypePrefix:
720 SuccessOrExit(error = AddPrefix(*As<PrefixTlv>(cur), flags));
721 break;
722
723 case NetworkDataTlv::kTypeService:
724 SuccessOrExit(error = AddService(*As<ServiceTlv>(cur), flags));
725 break;
726
727 default:
728 break;
729 }
730 }
731
732 DumpDebg("Register", GetBytes(), GetLength());
733
734 exit:
735 IncrementVersions(flags);
736
737 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
738 if (error == kErrorNoBufs)
739 {
740 Get<Notifier>().SignalNetworkDataFull();
741 }
742
743 if (!mIsClone)
744 #endif
745 {
746 LogWarnOnError(error, "register network data");
747 }
748 }
749
AddPrefix(const PrefixTlv & aPrefix,ChangedFlags & aChangedFlags)750 Error Leader::AddPrefix(const PrefixTlv &aPrefix, ChangedFlags &aChangedFlags)
751 {
752 Error error = kErrorNone;
753 PrefixTlv *dstPrefix = FindPrefix(aPrefix.GetPrefix(), aPrefix.GetPrefixLength());
754
755 if (dstPrefix == nullptr)
756 {
757 dstPrefix = As<PrefixTlv>(AppendTlv(PrefixTlv::CalculateSize(aPrefix.GetPrefixLength())));
758 VerifyOrExit(dstPrefix != nullptr, error = kErrorNoBufs);
759
760 dstPrefix->Init(aPrefix.GetDomainId(), aPrefix.GetPrefixLength(), aPrefix.GetPrefix());
761 }
762
763 for (const NetworkDataTlv *subCur = aPrefix.GetSubTlvs(); subCur < aPrefix.GetNext(); subCur = subCur->GetNext())
764 {
765 switch (subCur->GetType())
766 {
767 case NetworkDataTlv::kTypeHasRoute:
768 SuccessOrExit(error = AddHasRoute(*As<HasRouteTlv>(subCur), *dstPrefix, aChangedFlags));
769 break;
770
771 case NetworkDataTlv::kTypeBorderRouter:
772 SuccessOrExit(error = AddBorderRouter(*As<BorderRouterTlv>(subCur), *dstPrefix, aChangedFlags));
773 break;
774
775 default:
776 break;
777 }
778 }
779
780 exit:
781 if (dstPrefix != nullptr)
782 {
783 // `UpdatePrefix()` updates the TLV's stable flag based on
784 // its sub-TLVs, or removes the TLV if it contains no sub-TLV.
785 // This is called at `exit` to ensure that if appending
786 // sub-TLVs fail (e.g., out of space in network data), we
787 // remove an empty Prefix TLV.
788
789 IgnoreReturnValue(UpdatePrefix(*dstPrefix));
790 }
791
792 return error;
793 }
794
AddService(const ServiceTlv & aService,ChangedFlags & aChangedFlags)795 Error Leader::AddService(const ServiceTlv &aService, ChangedFlags &aChangedFlags)
796 {
797 Error error = kErrorNone;
798 ServiceTlv *dstService;
799 ServiceData serviceData;
800 const ServerTlv *server;
801
802 aService.GetServiceData(serviceData);
803 dstService = FindService(aService.GetEnterpriseNumber(), serviceData, kServiceExactMatch);
804
805 if (dstService == nullptr)
806 {
807 uint8_t serviceId;
808
809 SuccessOrExit(error = AllocateServiceId(serviceId));
810
811 dstService = As<ServiceTlv>(
812 AppendTlv(ServiceTlv::CalculateSize(aService.GetEnterpriseNumber(), serviceData.GetLength())));
813 VerifyOrExit(dstService != nullptr, error = kErrorNoBufs);
814
815 dstService->Init(serviceId, aService.GetEnterpriseNumber(), serviceData);
816 }
817
818 server = NetworkDataTlv::Find<ServerTlv>(aService.GetSubTlvs(), aService.GetNext());
819 OT_ASSERT(server != nullptr);
820
821 SuccessOrExit(error = AddServer(*server, *dstService, aChangedFlags));
822
823 exit:
824 if (dstService != nullptr)
825 {
826 // `UpdateService()` updates the TLV's stable flag based on
827 // its sub-TLVs, or removes the TLV if it contains no sub-TLV.
828 // This is called at `exit` to ensure that if appending
829 // sub-TLVs fail (e.g., out of space in network data), we
830 // remove an empty Service TLV.
831
832 IgnoreReturnValue(UpdateService(*dstService));
833 }
834
835 return error;
836 }
837
AddHasRoute(const HasRouteTlv & aHasRoute,PrefixTlv & aDstPrefix,ChangedFlags & aChangedFlags)838 Error Leader::AddHasRoute(const HasRouteTlv &aHasRoute, PrefixTlv &aDstPrefix, ChangedFlags &aChangedFlags)
839 {
840 Error error = kErrorNone;
841 HasRouteTlv *dstHasRoute = aDstPrefix.FindSubTlv<HasRouteTlv>(aHasRoute.IsStable());
842 const HasRouteEntry *entry = aHasRoute.GetFirstEntry();
843
844 if (dstHasRoute == nullptr)
845 {
846 // Ensure there is space for `HasRouteTlv` and a single entry.
847 VerifyOrExit(CanInsert(sizeof(HasRouteTlv) + sizeof(HasRouteEntry)), error = kErrorNoBufs);
848
849 dstHasRoute = As<HasRouteTlv>(aDstPrefix.GetNext());
850 Insert(dstHasRoute, sizeof(HasRouteTlv));
851 aDstPrefix.IncreaseLength(sizeof(HasRouteTlv));
852 dstHasRoute->Init();
853
854 if (aHasRoute.IsStable())
855 {
856 dstHasRoute->SetStable();
857 }
858 }
859
860 VerifyOrExit(!ContainsMatchingEntry(dstHasRoute, *entry));
861
862 VerifyOrExit(CanInsert(sizeof(HasRouteEntry)), error = kErrorNoBufs);
863
864 Insert(dstHasRoute->GetNext(), sizeof(HasRouteEntry));
865 dstHasRoute->IncreaseLength(sizeof(HasRouteEntry));
866 aDstPrefix.IncreaseLength(sizeof(HasRouteEntry));
867
868 *dstHasRoute->GetLastEntry() = *entry;
869 aChangedFlags.Update(*dstHasRoute);
870
871 exit:
872 return error;
873 }
874
AddBorderRouter(const BorderRouterTlv & aBorderRouter,PrefixTlv & aDstPrefix,ChangedFlags & aChangedFlags)875 Error Leader::AddBorderRouter(const BorderRouterTlv &aBorderRouter, PrefixTlv &aDstPrefix, ChangedFlags &aChangedFlags)
876 {
877 Error error = kErrorNone;
878 BorderRouterTlv *dstBorderRouter = aDstPrefix.FindSubTlv<BorderRouterTlv>(aBorderRouter.IsStable());
879 ContextTlv *dstContext = aDstPrefix.FindSubTlv<ContextTlv>();
880 uint8_t contextId = 0;
881 const BorderRouterEntry *entry = aBorderRouter.GetFirstEntry();
882
883 if (dstContext == nullptr)
884 {
885 // Get a new Context ID first. This ensure that if we cannot
886 // get new Context ID, we fail and exit before potentially
887 // inserting a Border Router sub-TLV.
888 SuccessOrExit(error = mContextIds.GetUnallocatedId(contextId));
889 }
890
891 if (dstBorderRouter == nullptr)
892 {
893 // Ensure there is space for `BorderRouterTlv` with a single entry
894 // and a `ContextTlv` (if not already present).
895 VerifyOrExit(CanInsert(sizeof(BorderRouterTlv) + sizeof(BorderRouterEntry) +
896 ((dstContext == nullptr) ? sizeof(ContextTlv) : 0)),
897 error = kErrorNoBufs);
898
899 dstBorderRouter = As<BorderRouterTlv>(aDstPrefix.GetNext());
900 Insert(dstBorderRouter, sizeof(BorderRouterTlv));
901 aDstPrefix.IncreaseLength(sizeof(BorderRouterTlv));
902 dstBorderRouter->Init();
903
904 if (aBorderRouter.IsStable())
905 {
906 dstBorderRouter->SetStable();
907 }
908 }
909
910 if (dstContext == nullptr)
911 {
912 // Ensure there is space for a `ContextTlv` and a single entry.
913 VerifyOrExit(CanInsert(sizeof(BorderRouterEntry) + sizeof(ContextTlv)), error = kErrorNoBufs);
914
915 dstContext = As<ContextTlv>(aDstPrefix.GetNext());
916 Insert(dstContext, sizeof(ContextTlv));
917 aDstPrefix.IncreaseLength(sizeof(ContextTlv));
918 dstContext->Init(static_cast<uint8_t>(contextId), aDstPrefix.GetPrefixLength());
919 }
920
921 if (aBorderRouter.IsStable())
922 {
923 dstContext->SetStable();
924 }
925
926 dstContext->SetCompress();
927 mContextIds.MarkAsInUse(dstContext->GetContextId());
928
929 VerifyOrExit(!ContainsMatchingEntry(dstBorderRouter, *entry));
930
931 VerifyOrExit(CanInsert(sizeof(BorderRouterEntry)), error = kErrorNoBufs);
932
933 Insert(dstBorderRouter->GetNext(), sizeof(BorderRouterEntry));
934 dstBorderRouter->IncreaseLength(sizeof(BorderRouterEntry));
935 aDstPrefix.IncreaseLength(sizeof(BorderRouterEntry));
936 *dstBorderRouter->GetLastEntry() = *entry;
937 aChangedFlags.Update(*dstBorderRouter);
938
939 exit:
940 return error;
941 }
942
AddServer(const ServerTlv & aServer,ServiceTlv & aDstService,ChangedFlags & aChangedFlags)943 Error Leader::AddServer(const ServerTlv &aServer, ServiceTlv &aDstService, ChangedFlags &aChangedFlags)
944 {
945 Error error = kErrorNone;
946 ServerTlv *dstServer;
947 ServerData serverData;
948 uint8_t tlvSize = aServer.GetSize();
949
950 VerifyOrExit(!ContainsMatchingServer(&aDstService, aServer));
951
952 VerifyOrExit(CanInsert(tlvSize), error = kErrorNoBufs);
953
954 aServer.GetServerData(serverData);
955
956 dstServer = As<ServerTlv>(aDstService.GetNext());
957 Insert(dstServer, tlvSize);
958 dstServer->Init(aServer.GetServer16(), serverData);
959
960 if (aServer.IsStable())
961 {
962 dstServer->SetStable();
963 }
964
965 aDstService.IncreaseLength(tlvSize);
966 aChangedFlags.Update(*dstServer);
967
968 exit:
969 return error;
970 }
971
AllocateServiceId(uint8_t & aServiceId) const972 Error Leader::AllocateServiceId(uint8_t &aServiceId) const
973 {
974 Error error = kErrorNotFound;
975 uint8_t serviceId;
976
977 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
978 if (mIsClone)
979 {
980 aServiceId = kMinServiceId;
981 error = kErrorNone;
982 ExitNow();
983 }
984 #endif
985
986 for (serviceId = kMinServiceId; serviceId <= kMaxServiceId; serviceId++)
987 {
988 if (FindServiceById(serviceId) == nullptr)
989 {
990 aServiceId = serviceId;
991 error = kErrorNone;
992 LogInfo("Allocated Service ID = %d", serviceId);
993 ExitNow();
994 }
995 }
996
997 exit:
998 return error;
999 }
1000
FindServiceById(uint8_t aServiceId) const1001 const ServiceTlv *Leader::FindServiceById(uint8_t aServiceId) const
1002 {
1003 const ServiceTlv *service;
1004 TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd());
1005
1006 while ((service = tlvIterator.Iterate<ServiceTlv>()) != nullptr)
1007 {
1008 if (service->GetServiceId() == aServiceId)
1009 {
1010 break;
1011 }
1012 }
1013
1014 return service;
1015 }
1016
RemoveRloc(uint16_t aRloc16,MatchMode aMatchMode,ChangedFlags & aChangedFlags)1017 void Leader::RemoveRloc(uint16_t aRloc16, MatchMode aMatchMode, ChangedFlags &aChangedFlags)
1018 {
1019 NetworkData excludeNetworkData(GetInstance()); // Empty network data.
1020
1021 RemoveRloc(aRloc16, aMatchMode, excludeNetworkData, aChangedFlags);
1022 }
1023
RemoveRloc(uint16_t aRloc16,MatchMode aMatchMode,const NetworkData & aExcludeNetworkData,ChangedFlags & aChangedFlags)1024 void Leader::RemoveRloc(uint16_t aRloc16,
1025 MatchMode aMatchMode,
1026 const NetworkData &aExcludeNetworkData,
1027 ChangedFlags &aChangedFlags)
1028 {
1029 // Remove entries from Network Data matching `aRloc16` (using
1030 // `aMatchMode` to determine the match) but exclude any entries
1031 // that are present in `aExcludeNetworkData`. As entries are
1032 // removed update `aChangedFlags` to indicate if Network Data
1033 // (stable or not) got changed.
1034
1035 NetworkDataTlv *cur = GetTlvsStart();
1036
1037 while (cur < GetTlvsEnd())
1038 {
1039 switch (cur->GetType())
1040 {
1041 case NetworkDataTlv::kTypePrefix:
1042 {
1043 PrefixTlv *prefix = As<PrefixTlv>(cur);
1044 const PrefixTlv *excludePrefix =
1045 aExcludeNetworkData.FindPrefix(prefix->GetPrefix(), prefix->GetPrefixLength());
1046
1047 RemoveRlocInPrefix(*prefix, aRloc16, aMatchMode, excludePrefix, aChangedFlags);
1048
1049 if (UpdatePrefix(*prefix) == kTlvRemoved)
1050 {
1051 // Do not update `cur` when TLV is removed.
1052 continue;
1053 }
1054
1055 break;
1056 }
1057
1058 case NetworkDataTlv::kTypeService:
1059 {
1060 ServiceTlv *service = As<ServiceTlv>(cur);
1061 ServiceData serviceData;
1062 const ServiceTlv *excludeService;
1063
1064 service->GetServiceData(serviceData);
1065
1066 excludeService =
1067 aExcludeNetworkData.FindService(service->GetEnterpriseNumber(), serviceData, kServiceExactMatch);
1068
1069 RemoveRlocInService(*service, aRloc16, aMatchMode, excludeService, aChangedFlags);
1070
1071 if (UpdateService(*service) == kTlvRemoved)
1072 {
1073 // Do not update `cur` when TLV is removed.
1074 continue;
1075 }
1076
1077 break;
1078 }
1079
1080 default:
1081 break;
1082 }
1083
1084 cur = cur->GetNext();
1085 }
1086 }
1087
RemoveRlocInPrefix(PrefixTlv & aPrefix,uint16_t aRloc16,MatchMode aMatchMode,const PrefixTlv * aExcludePrefix,ChangedFlags & aChangedFlags)1088 void Leader::RemoveRlocInPrefix(PrefixTlv &aPrefix,
1089 uint16_t aRloc16,
1090 MatchMode aMatchMode,
1091 const PrefixTlv *aExcludePrefix,
1092 ChangedFlags &aChangedFlags)
1093 {
1094 // Remove entries in `aPrefix` TLV matching the given `aRloc16`
1095 // excluding any entries that are present in `aExcludePrefix`.
1096
1097 NetworkDataTlv *cur = aPrefix.GetSubTlvs();
1098 ContextTlv *context;
1099
1100 while (cur < aPrefix.GetNext())
1101 {
1102 switch (cur->GetType())
1103 {
1104 case NetworkDataTlv::kTypeHasRoute:
1105 RemoveRlocInHasRoute(aPrefix, *As<HasRouteTlv>(cur), aRloc16, aMatchMode, aExcludePrefix, aChangedFlags);
1106
1107 if (cur->GetLength() == 0)
1108 {
1109 aPrefix.DecreaseLength(sizeof(HasRouteTlv));
1110 RemoveTlv(cur);
1111 continue;
1112 }
1113
1114 break;
1115
1116 case NetworkDataTlv::kTypeBorderRouter:
1117 RemoveRlocInBorderRouter(aPrefix, *As<BorderRouterTlv>(cur), aRloc16, aMatchMode, aExcludePrefix,
1118 aChangedFlags);
1119
1120 if (cur->GetLength() == 0)
1121 {
1122 aPrefix.DecreaseLength(sizeof(BorderRouterTlv));
1123 RemoveTlv(cur);
1124 continue;
1125 }
1126
1127 break;
1128
1129 default:
1130 break;
1131 }
1132
1133 cur = cur->GetNext();
1134 }
1135
1136 if ((context = aPrefix.FindSubTlv<ContextTlv>()) != nullptr)
1137 {
1138 if (aPrefix.FindSubTlv<BorderRouterTlv>() == nullptr)
1139 {
1140 context->ClearCompress();
1141 mContextIds.ScheduleToRemove(context->GetContextId());
1142 }
1143 else
1144 {
1145 context->SetCompress();
1146 mContextIds.MarkAsInUse(context->GetContextId());
1147 }
1148 }
1149 }
1150
RemoveRlocInService(ServiceTlv & aService,uint16_t aRloc16,MatchMode aMatchMode,const ServiceTlv * aExcludeService,ChangedFlags & aChangedFlags)1151 void Leader::RemoveRlocInService(ServiceTlv &aService,
1152 uint16_t aRloc16,
1153 MatchMode aMatchMode,
1154 const ServiceTlv *aExcludeService,
1155 ChangedFlags &aChangedFlags)
1156 {
1157 // Remove entries in `aService` TLV matching the given `aRloc16`
1158 // excluding any entries that are present in `aExcludeService`.
1159
1160 NetworkDataTlv *start = aService.GetSubTlvs();
1161 ServerTlv *server;
1162
1163 while ((server = NetworkDataTlv::Find<ServerTlv>(start, aService.GetNext())) != nullptr)
1164 {
1165 if (RlocMatch(server->GetServer16(), aRloc16, aMatchMode) && !ContainsMatchingServer(aExcludeService, *server))
1166 {
1167 uint8_t subTlvSize = server->GetSize();
1168
1169 aChangedFlags.Update(*server);
1170 RemoveTlv(server);
1171 aService.DecreaseLength(subTlvSize);
1172 continue;
1173 }
1174
1175 start = server->GetNext();
1176 }
1177 }
1178
RemoveRlocInHasRoute(PrefixTlv & aPrefix,HasRouteTlv & aHasRoute,uint16_t aRloc16,MatchMode aMatchMode,const PrefixTlv * aExcludePrefix,ChangedFlags & aChangedFlags)1179 void Leader::RemoveRlocInHasRoute(PrefixTlv &aPrefix,
1180 HasRouteTlv &aHasRoute,
1181 uint16_t aRloc16,
1182 MatchMode aMatchMode,
1183 const PrefixTlv *aExcludePrefix,
1184 ChangedFlags &aChangedFlags)
1185 {
1186 // Remove entries in `aHasRoute` (a sub-TLV of `aPrefix` TLV)
1187 // matching the given `aRloc16` excluding entries that are present
1188 // in `aExcludePrefix`.
1189
1190 HasRouteEntry *entry = aHasRoute.GetFirstEntry();
1191
1192 while (entry <= aHasRoute.GetLastEntry())
1193 {
1194 if (RlocMatch(entry->GetRloc(), aRloc16, aMatchMode) &&
1195 !ContainsMatchingEntry(aExcludePrefix, aHasRoute.IsStable(), *entry))
1196 {
1197 aChangedFlags.Update(aHasRoute);
1198 aHasRoute.DecreaseLength(sizeof(HasRouteEntry));
1199 aPrefix.DecreaseLength(sizeof(HasRouteEntry));
1200 Remove(entry, sizeof(HasRouteEntry));
1201 continue;
1202 }
1203
1204 entry = entry->GetNext();
1205 }
1206 }
1207
RemoveRlocInBorderRouter(PrefixTlv & aPrefix,BorderRouterTlv & aBorderRouter,uint16_t aRloc16,MatchMode aMatchMode,const PrefixTlv * aExcludePrefix,ChangedFlags & aChangedFlags)1208 void Leader::RemoveRlocInBorderRouter(PrefixTlv &aPrefix,
1209 BorderRouterTlv &aBorderRouter,
1210 uint16_t aRloc16,
1211 MatchMode aMatchMode,
1212 const PrefixTlv *aExcludePrefix,
1213 ChangedFlags &aChangedFlags)
1214 {
1215 // Remove entries in `aBorderRouter` (a sub-TLV of `aPrefix` TLV)
1216 // matching the given `aRloc16` excluding entries that are present
1217 // in `aExcludePrefix`.
1218
1219 BorderRouterEntry *entry = aBorderRouter.GetFirstEntry();
1220
1221 while (entry <= aBorderRouter.GetLastEntry())
1222 {
1223 if (RlocMatch(entry->GetRloc(), aRloc16, aMatchMode) &&
1224 !ContainsMatchingEntry(aExcludePrefix, aBorderRouter.IsStable(), *entry))
1225 {
1226 aChangedFlags.Update(aBorderRouter);
1227 aBorderRouter.DecreaseLength(sizeof(BorderRouterEntry));
1228 aPrefix.DecreaseLength(sizeof(BorderRouterEntry));
1229 Remove(entry, sizeof(*entry));
1230 continue;
1231 }
1232
1233 entry = entry->GetNext();
1234 }
1235 }
1236
RemoveContext(uint8_t aContextId)1237 void Leader::RemoveContext(uint8_t aContextId)
1238 {
1239 NetworkDataTlv *start = GetTlvsStart();
1240 PrefixTlv *prefix;
1241
1242 while ((prefix = NetworkDataTlv::Find<PrefixTlv>(start, GetTlvsEnd())) != nullptr)
1243 {
1244 RemoveContext(*prefix, aContextId);
1245
1246 if (UpdatePrefix(*prefix) == kTlvRemoved)
1247 {
1248 // Do not update `start` when TLV is removed.
1249 continue;
1250 }
1251
1252 start = prefix->GetNext();
1253 }
1254
1255 IncrementVersions(/* aIncludeStable */ true);
1256 }
1257
RemoveContext(PrefixTlv & aPrefix,uint8_t aContextId)1258 void Leader::RemoveContext(PrefixTlv &aPrefix, uint8_t aContextId)
1259 {
1260 NetworkDataTlv *start = aPrefix.GetSubTlvs();
1261 ContextTlv *context;
1262
1263 while ((context = NetworkDataTlv::Find<ContextTlv>(start, aPrefix.GetNext())) != nullptr)
1264 {
1265 if (context->GetContextId() == aContextId)
1266 {
1267 uint8_t subTlvSize = context->GetSize();
1268 RemoveTlv(context);
1269 aPrefix.DecreaseLength(subTlvSize);
1270 continue;
1271 }
1272
1273 start = context->GetNext();
1274 }
1275 }
1276
HandleNetworkDataRestoredAfterReset(void)1277 void Leader::HandleNetworkDataRestoredAfterReset(void)
1278 {
1279 const PrefixTlv *prefix;
1280 TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd());
1281 ChangedFlags flags;
1282 uint16_t rloc16;
1283 uint16_t sessionId;
1284 Rlocs rlocs;
1285
1286 mWaitingForNetDataSync = false;
1287
1288 // Remove entries in Network Data from any un-allocated Router ID.
1289 // This acts as a safeguard against an edge case where the leader
1290 // is reset at an inopportune time, such as right after it removed
1291 // an allocated router ID and sent MLE advertisement but before it
1292 // got the chance to send the updated Network Data to other
1293 // routers.
1294
1295 FindRlocs(kAnyBrOrServer, kAnyRole, rlocs);
1296
1297 for (uint16_t rloc : rlocs)
1298 {
1299 if (!Get<RouterTable>().IsAllocated(Mle::RouterIdFromRloc16(rloc)))
1300 {
1301 RemoveRloc(rloc, kMatchModeRouterId, flags);
1302 }
1303 }
1304
1305 IncrementVersions(flags);
1306
1307 // Synchronize internal 6LoWPAN Context ID Set with the
1308 // recently obtained Network Data.
1309
1310 while ((prefix = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
1311 {
1312 const ContextTlv *context = prefix->FindSubTlv<ContextTlv>();
1313
1314 if (context == nullptr)
1315 {
1316 continue;
1317 }
1318
1319 mContextIds.MarkAsInUse(context->GetContextId());
1320
1321 if (!context->IsCompress())
1322 {
1323 mContextIds.ScheduleToRemove(context->GetContextId());
1324 }
1325 }
1326
1327 // Update Commissioning Data. We adopt the same session ID
1328 // (if any) and resign active commissioner (if any) by
1329 // clearing the Commissioning Data.
1330
1331 if (FindCommissioningSessionId(sessionId) == kErrorNone)
1332 {
1333 Get<MeshCoP::Leader>().SetSessionId(sessionId);
1334 }
1335
1336 if (FindBorderAgentRloc(rloc16) == kErrorNone)
1337 {
1338 Get<MeshCoP::Leader>().SetEmptyCommissionerData();
1339 }
1340 }
1341
UpdateCommissioningData(uint16_t aDataLength,CommissioningDataTlv * & aDataTlv)1342 Error Leader::UpdateCommissioningData(uint16_t aDataLength, CommissioningDataTlv *&aDataTlv)
1343 {
1344 // First determine whether or not we can add Commissioning Data
1345 // TLV with the given `aDataLength`, taking into account that we
1346 // would remove the current Commissioning Data TLV. Then remove
1347 // the current TLV and append a new TLV with proper size which is
1348 // returned in `aDataTlv`.
1349
1350 Error error = kErrorNone;
1351 CommissioningDataTlv *dataTlv = FindCommissioningData();
1352 uint16_t insertLength;
1353
1354 if (dataTlv != nullptr)
1355 {
1356 insertLength = (aDataLength <= dataTlv->GetLength()) ? 0 : aDataLength - dataTlv->GetLength();
1357 }
1358 else
1359 {
1360 insertLength = sizeof(CommissioningDataTlv) + aDataLength;
1361 }
1362
1363 VerifyOrExit(CanInsert(insertLength), error = kErrorNoBufs);
1364
1365 if (dataTlv != nullptr)
1366 {
1367 RemoveTlv(dataTlv);
1368 }
1369
1370 aDataTlv = As<CommissioningDataTlv>(AppendTlv(sizeof(CommissioningDataTlv) + aDataLength));
1371
1372 OT_ASSERT(aDataTlv != nullptr);
1373
1374 aDataTlv->Init();
1375 aDataTlv->SetLength(static_cast<uint8_t>(aDataLength));
1376
1377 // The caller would fill the `aDataTlv` value.
1378
1379 mVersion++;
1380 SignalNetDataChanged();
1381
1382 exit:
1383 return error;
1384 }
1385
SetCommissioningData(const void * aData,uint8_t aDataLength)1386 Error Leader::SetCommissioningData(const void *aData, uint8_t aDataLength)
1387 {
1388 Error error = kErrorNone;
1389 CommissioningDataTlv *dataTlv;
1390
1391 SuccessOrExit(error = UpdateCommissioningData(aDataLength, dataTlv));
1392 memcpy(dataTlv->GetValue(), aData, aDataLength);
1393
1394 exit:
1395 return error;
1396 }
1397
SetCommissioningData(const Message & aMessage)1398 Error Leader::SetCommissioningData(const Message &aMessage)
1399 {
1400 Error error = kErrorNone;
1401 OffsetRange offsetRange;
1402 CommissioningDataTlv *dataTlv;
1403
1404 offsetRange.InitFromMessageOffsetToEnd(aMessage);
1405
1406 SuccessOrExit(error = UpdateCommissioningData(offsetRange.GetLength(), dataTlv));
1407 aMessage.ReadBytes(offsetRange, dataTlv->GetValue());
1408
1409 exit:
1410 return error;
1411 }
1412
HandleTimer(void)1413 void Leader::HandleTimer(void)
1414 {
1415 if (mWaitingForNetDataSync)
1416 {
1417 LogInfo("Timed out waiting for netdata on restoring leader role after reset");
1418 IgnoreError(Get<Mle::MleRouter>().BecomeDetached());
1419 }
1420 else
1421 {
1422 mContextIds.HandleTimer();
1423 }
1424 }
1425
1426 //---------------------------------------------------------------------------------------------------------------------
1427 // Leader::ContextIds
1428
ContextIds(Instance & aInstance)1429 Leader::ContextIds::ContextIds(Instance &aInstance)
1430 : InstanceLocator(aInstance)
1431 , mReuseDelay(kReuseDelay)
1432 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
1433 , mIsClone(false)
1434 #endif
1435 {
1436 }
1437
Clear(void)1438 void Leader::ContextIds::Clear(void)
1439 {
1440 for (uint8_t id = kMinId; id <= kMaxId; id++)
1441 {
1442 MarkAsUnallocated(id);
1443 }
1444 }
1445
GetUnallocatedId(uint8_t & aId)1446 Error Leader::ContextIds::GetUnallocatedId(uint8_t &aId)
1447 {
1448 Error error = kErrorNotFound;
1449
1450 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
1451 if (mIsClone)
1452 {
1453 aId = kMinId;
1454 error = kErrorNone;
1455 ExitNow();
1456 }
1457 #endif
1458
1459 for (uint8_t id = kMinId; id <= kMaxId; id++)
1460 {
1461 if (IsUnallocated(id))
1462 {
1463 aId = id;
1464 error = kErrorNone;
1465 ExitNow();
1466 }
1467 }
1468
1469 exit:
1470 return error;
1471 }
1472
ScheduleToRemove(uint8_t aId)1473 void Leader::ContextIds::ScheduleToRemove(uint8_t aId)
1474 {
1475 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
1476 VerifyOrExit(!mIsClone);
1477 #endif
1478
1479 VerifyOrExit(IsInUse(aId));
1480
1481 SetRemoveTime(aId, TimerMilli::GetNow() + Time::SecToMsec(mReuseDelay));
1482 Get<Leader>().mTimer.FireAtIfEarlier(GetRemoveTime(aId));
1483
1484 exit:
1485 return;
1486 }
1487
SetRemoveTime(uint8_t aId,TimeMilli aTime)1488 void Leader::ContextIds::SetRemoveTime(uint8_t aId, TimeMilli aTime)
1489 {
1490 uint32_t time = aTime.GetValue();
1491
1492 while ((time == kUnallocated) || (time == kInUse))
1493 {
1494 time++;
1495 }
1496
1497 mRemoveTimes[aId - kMinId].SetValue(time);
1498 }
1499
HandleTimer(void)1500 void Leader::ContextIds::HandleTimer(void)
1501 {
1502 NextFireTime nextTime;
1503
1504 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
1505 OT_ASSERT(!mIsClone);
1506 #endif
1507
1508 for (uint8_t id = kMinId; id <= kMaxId; id++)
1509 {
1510 if (IsUnallocated(id) || IsInUse(id))
1511 {
1512 continue;
1513 }
1514
1515 if (nextTime.GetNow() >= GetRemoveTime(id))
1516 {
1517 MarkAsUnallocated(id);
1518 Get<Leader>().RemoveContext(id);
1519 }
1520 else
1521 {
1522 nextTime.UpdateIfEarlier(GetRemoveTime(id));
1523 }
1524 }
1525
1526 Get<Leader>().mTimer.FireAt(nextTime);
1527 }
1528
1529 } // namespace NetworkData
1530 } // namespace ot
1531
1532 #endif // OPENTHREAD_FTD
1533