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