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 LogWarnOnError(error, "register network data");
684 }
685 }
686
AddPrefix(const PrefixTlv & aPrefix,ChangedFlags & aChangedFlags)687 Error Leader::AddPrefix(const PrefixTlv &aPrefix, ChangedFlags &aChangedFlags)
688 {
689 Error error = kErrorNone;
690 PrefixTlv *dstPrefix = FindPrefix(aPrefix.GetPrefix(), aPrefix.GetPrefixLength());
691
692 if (dstPrefix == nullptr)
693 {
694 dstPrefix = As<PrefixTlv>(AppendTlv(PrefixTlv::CalculateSize(aPrefix.GetPrefixLength())));
695 VerifyOrExit(dstPrefix != nullptr, error = kErrorNoBufs);
696
697 dstPrefix->Init(aPrefix.GetDomainId(), aPrefix.GetPrefixLength(), aPrefix.GetPrefix());
698 }
699
700 for (const NetworkDataTlv *subCur = aPrefix.GetSubTlvs(); subCur < aPrefix.GetNext(); subCur = subCur->GetNext())
701 {
702 switch (subCur->GetType())
703 {
704 case NetworkDataTlv::kTypeHasRoute:
705 SuccessOrExit(error = AddHasRoute(*As<HasRouteTlv>(subCur), *dstPrefix, aChangedFlags));
706 break;
707
708 case NetworkDataTlv::kTypeBorderRouter:
709 SuccessOrExit(error = AddBorderRouter(*As<BorderRouterTlv>(subCur), *dstPrefix, aChangedFlags));
710 break;
711
712 default:
713 break;
714 }
715 }
716
717 exit:
718 if (dstPrefix != nullptr)
719 {
720 // `UpdatePrefix()` updates the TLV's stable flag based on
721 // its sub-TLVs, or removes the TLV if it contains no sub-TLV.
722 // This is called at `exit` to ensure that if appending
723 // sub-TLVs fail (e.g., out of space in network data), we
724 // remove an empty Prefix TLV.
725
726 IgnoreReturnValue(UpdatePrefix(*dstPrefix));
727 }
728
729 return error;
730 }
731
AddService(const ServiceTlv & aService,ChangedFlags & aChangedFlags)732 Error Leader::AddService(const ServiceTlv &aService, ChangedFlags &aChangedFlags)
733 {
734 Error error = kErrorNone;
735 ServiceTlv *dstService;
736 ServiceData serviceData;
737 const ServerTlv *server;
738
739 aService.GetServiceData(serviceData);
740 dstService = FindService(aService.GetEnterpriseNumber(), serviceData, kServiceExactMatch);
741
742 if (dstService == nullptr)
743 {
744 uint8_t serviceId;
745
746 SuccessOrExit(error = AllocateServiceId(serviceId));
747
748 dstService = As<ServiceTlv>(
749 AppendTlv(ServiceTlv::CalculateSize(aService.GetEnterpriseNumber(), serviceData.GetLength())));
750 VerifyOrExit(dstService != nullptr, error = kErrorNoBufs);
751
752 dstService->Init(serviceId, aService.GetEnterpriseNumber(), serviceData);
753 }
754
755 server = NetworkDataTlv::Find<ServerTlv>(aService.GetSubTlvs(), aService.GetNext());
756 OT_ASSERT(server != nullptr);
757
758 SuccessOrExit(error = AddServer(*server, *dstService, aChangedFlags));
759
760 exit:
761 if (dstService != nullptr)
762 {
763 // `UpdateService()` updates the TLV's stable flag based on
764 // its sub-TLVs, or removes the TLV if it contains no sub-TLV.
765 // This is called at `exit` to ensure that if appending
766 // sub-TLVs fail (e.g., out of space in network data), we
767 // remove an empty Service TLV.
768
769 IgnoreReturnValue(UpdateService(*dstService));
770 }
771
772 return error;
773 }
774
AddHasRoute(const HasRouteTlv & aHasRoute,PrefixTlv & aDstPrefix,ChangedFlags & aChangedFlags)775 Error Leader::AddHasRoute(const HasRouteTlv &aHasRoute, PrefixTlv &aDstPrefix, ChangedFlags &aChangedFlags)
776 {
777 Error error = kErrorNone;
778 HasRouteTlv *dstHasRoute = aDstPrefix.FindSubTlv<HasRouteTlv>(aHasRoute.IsStable());
779 const HasRouteEntry *entry = aHasRoute.GetFirstEntry();
780
781 if (dstHasRoute == nullptr)
782 {
783 // Ensure there is space for `HasRouteTlv` and a single entry.
784 VerifyOrExit(CanInsert(sizeof(HasRouteTlv) + sizeof(HasRouteEntry)), error = kErrorNoBufs);
785
786 dstHasRoute = As<HasRouteTlv>(aDstPrefix.GetNext());
787 Insert(dstHasRoute, sizeof(HasRouteTlv));
788 aDstPrefix.IncreaseLength(sizeof(HasRouteTlv));
789 dstHasRoute->Init();
790
791 if (aHasRoute.IsStable())
792 {
793 dstHasRoute->SetStable();
794 }
795 }
796
797 VerifyOrExit(!ContainsMatchingEntry(dstHasRoute, *entry));
798
799 VerifyOrExit(CanInsert(sizeof(HasRouteEntry)), error = kErrorNoBufs);
800
801 Insert(dstHasRoute->GetNext(), sizeof(HasRouteEntry));
802 dstHasRoute->IncreaseLength(sizeof(HasRouteEntry));
803 aDstPrefix.IncreaseLength(sizeof(HasRouteEntry));
804
805 *dstHasRoute->GetLastEntry() = *entry;
806 aChangedFlags.Update(*dstHasRoute);
807
808 exit:
809 return error;
810 }
811
AddBorderRouter(const BorderRouterTlv & aBorderRouter,PrefixTlv & aDstPrefix,ChangedFlags & aChangedFlags)812 Error Leader::AddBorderRouter(const BorderRouterTlv &aBorderRouter, PrefixTlv &aDstPrefix, ChangedFlags &aChangedFlags)
813 {
814 Error error = kErrorNone;
815 BorderRouterTlv *dstBorderRouter = aDstPrefix.FindSubTlv<BorderRouterTlv>(aBorderRouter.IsStable());
816 ContextTlv *dstContext = aDstPrefix.FindSubTlv<ContextTlv>();
817 uint8_t contextId = 0;
818 const BorderRouterEntry *entry = aBorderRouter.GetFirstEntry();
819
820 if (dstContext == nullptr)
821 {
822 // Get a new Context ID first. This ensure that if we cannot
823 // get new Context ID, we fail and exit before potentially
824 // inserting a Border Router sub-TLV.
825 SuccessOrExit(error = mContextIds.GetUnallocatedId(contextId));
826 }
827
828 if (dstBorderRouter == nullptr)
829 {
830 // Ensure there is space for `BorderRouterTlv` with a single entry
831 // and a `ContextTlv` (if not already present).
832 VerifyOrExit(CanInsert(sizeof(BorderRouterTlv) + sizeof(BorderRouterEntry) +
833 ((dstContext == nullptr) ? sizeof(ContextTlv) : 0)),
834 error = kErrorNoBufs);
835
836 dstBorderRouter = As<BorderRouterTlv>(aDstPrefix.GetNext());
837 Insert(dstBorderRouter, sizeof(BorderRouterTlv));
838 aDstPrefix.IncreaseLength(sizeof(BorderRouterTlv));
839 dstBorderRouter->Init();
840
841 if (aBorderRouter.IsStable())
842 {
843 dstBorderRouter->SetStable();
844 }
845 }
846
847 if (dstContext == nullptr)
848 {
849 // Ensure there is space for a `ContextTlv` and a single entry.
850 VerifyOrExit(CanInsert(sizeof(BorderRouterEntry) + sizeof(ContextTlv)), error = kErrorNoBufs);
851
852 dstContext = As<ContextTlv>(aDstPrefix.GetNext());
853 Insert(dstContext, sizeof(ContextTlv));
854 aDstPrefix.IncreaseLength(sizeof(ContextTlv));
855 dstContext->Init(static_cast<uint8_t>(contextId), aDstPrefix.GetPrefixLength());
856 }
857
858 if (aBorderRouter.IsStable())
859 {
860 dstContext->SetStable();
861 }
862
863 dstContext->SetCompress();
864 mContextIds.MarkAsInUse(dstContext->GetContextId());
865
866 VerifyOrExit(!ContainsMatchingEntry(dstBorderRouter, *entry));
867
868 VerifyOrExit(CanInsert(sizeof(BorderRouterEntry)), error = kErrorNoBufs);
869
870 Insert(dstBorderRouter->GetNext(), sizeof(BorderRouterEntry));
871 dstBorderRouter->IncreaseLength(sizeof(BorderRouterEntry));
872 aDstPrefix.IncreaseLength(sizeof(BorderRouterEntry));
873 *dstBorderRouter->GetLastEntry() = *entry;
874 aChangedFlags.Update(*dstBorderRouter);
875
876 exit:
877 return error;
878 }
879
AddServer(const ServerTlv & aServer,ServiceTlv & aDstService,ChangedFlags & aChangedFlags)880 Error Leader::AddServer(const ServerTlv &aServer, ServiceTlv &aDstService, ChangedFlags &aChangedFlags)
881 {
882 Error error = kErrorNone;
883 ServerTlv *dstServer;
884 ServerData serverData;
885 uint8_t tlvSize = aServer.GetSize();
886
887 VerifyOrExit(!ContainsMatchingServer(&aDstService, aServer));
888
889 VerifyOrExit(CanInsert(tlvSize), error = kErrorNoBufs);
890
891 aServer.GetServerData(serverData);
892
893 dstServer = As<ServerTlv>(aDstService.GetNext());
894 Insert(dstServer, tlvSize);
895 dstServer->Init(aServer.GetServer16(), serverData);
896
897 if (aServer.IsStable())
898 {
899 dstServer->SetStable();
900 }
901
902 aDstService.IncreaseLength(tlvSize);
903 aChangedFlags.Update(*dstServer);
904
905 exit:
906 return error;
907 }
908
AllocateServiceId(uint8_t & aServiceId) const909 Error Leader::AllocateServiceId(uint8_t &aServiceId) const
910 {
911 Error error = kErrorNotFound;
912 uint8_t serviceId;
913
914 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
915 if (mIsClone)
916 {
917 aServiceId = kMinServiceId;
918 error = kErrorNone;
919 ExitNow();
920 }
921 #endif
922
923 for (serviceId = kMinServiceId; serviceId <= kMaxServiceId; serviceId++)
924 {
925 if (FindServiceById(serviceId) == nullptr)
926 {
927 aServiceId = serviceId;
928 error = kErrorNone;
929 LogInfo("Allocated Service ID = %d", serviceId);
930 ExitNow();
931 }
932 }
933
934 exit:
935 return error;
936 }
937
FindServiceById(uint8_t aServiceId) const938 const ServiceTlv *Leader::FindServiceById(uint8_t aServiceId) const
939 {
940 const ServiceTlv *service;
941 TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd());
942
943 while ((service = tlvIterator.Iterate<ServiceTlv>()) != nullptr)
944 {
945 if (service->GetServiceId() == aServiceId)
946 {
947 break;
948 }
949 }
950
951 return service;
952 }
953
RemoveRloc(uint16_t aRloc16,MatchMode aMatchMode,ChangedFlags & aChangedFlags)954 void Leader::RemoveRloc(uint16_t aRloc16, MatchMode aMatchMode, ChangedFlags &aChangedFlags)
955 {
956 NetworkData excludeNetworkData(GetInstance()); // Empty network data.
957
958 RemoveRloc(aRloc16, aMatchMode, excludeNetworkData, aChangedFlags);
959 }
960
RemoveRloc(uint16_t aRloc16,MatchMode aMatchMode,const NetworkData & aExcludeNetworkData,ChangedFlags & aChangedFlags)961 void Leader::RemoveRloc(uint16_t aRloc16,
962 MatchMode aMatchMode,
963 const NetworkData &aExcludeNetworkData,
964 ChangedFlags &aChangedFlags)
965 {
966 // Remove entries from Network Data matching `aRloc16` (using
967 // `aMatchMode` to determine the match) but exclude any entries
968 // that are present in `aExcludeNetworkData`. As entries are
969 // removed update `aChangedFlags` to indicate if Network Data
970 // (stable or not) got changed.
971
972 NetworkDataTlv *cur = GetTlvsStart();
973
974 while (cur < GetTlvsEnd())
975 {
976 switch (cur->GetType())
977 {
978 case NetworkDataTlv::kTypePrefix:
979 {
980 PrefixTlv *prefix = As<PrefixTlv>(cur);
981 const PrefixTlv *excludePrefix =
982 aExcludeNetworkData.FindPrefix(prefix->GetPrefix(), prefix->GetPrefixLength());
983
984 RemoveRlocInPrefix(*prefix, aRloc16, aMatchMode, excludePrefix, aChangedFlags);
985
986 if (UpdatePrefix(*prefix) == kTlvRemoved)
987 {
988 // Do not update `cur` when TLV is removed.
989 continue;
990 }
991
992 break;
993 }
994
995 case NetworkDataTlv::kTypeService:
996 {
997 ServiceTlv *service = As<ServiceTlv>(cur);
998 ServiceData serviceData;
999 const ServiceTlv *excludeService;
1000
1001 service->GetServiceData(serviceData);
1002
1003 excludeService =
1004 aExcludeNetworkData.FindService(service->GetEnterpriseNumber(), serviceData, kServiceExactMatch);
1005
1006 RemoveRlocInService(*service, aRloc16, aMatchMode, excludeService, aChangedFlags);
1007
1008 if (UpdateService(*service) == kTlvRemoved)
1009 {
1010 // Do not update `cur` when TLV is removed.
1011 continue;
1012 }
1013
1014 break;
1015 }
1016
1017 default:
1018 break;
1019 }
1020
1021 cur = cur->GetNext();
1022 }
1023 }
1024
RemoveRlocInPrefix(PrefixTlv & aPrefix,uint16_t aRloc16,MatchMode aMatchMode,const PrefixTlv * aExcludePrefix,ChangedFlags & aChangedFlags)1025 void Leader::RemoveRlocInPrefix(PrefixTlv &aPrefix,
1026 uint16_t aRloc16,
1027 MatchMode aMatchMode,
1028 const PrefixTlv *aExcludePrefix,
1029 ChangedFlags &aChangedFlags)
1030 {
1031 // Remove entries in `aPrefix` TLV matching the given `aRloc16`
1032 // excluding any entries that are present in `aExcludePrefix`.
1033
1034 NetworkDataTlv *cur = aPrefix.GetSubTlvs();
1035 ContextTlv *context;
1036
1037 while (cur < aPrefix.GetNext())
1038 {
1039 switch (cur->GetType())
1040 {
1041 case NetworkDataTlv::kTypeHasRoute:
1042 RemoveRlocInHasRoute(aPrefix, *As<HasRouteTlv>(cur), aRloc16, aMatchMode, aExcludePrefix, aChangedFlags);
1043
1044 if (cur->GetLength() == 0)
1045 {
1046 aPrefix.DecreaseLength(sizeof(HasRouteTlv));
1047 RemoveTlv(cur);
1048 continue;
1049 }
1050
1051 break;
1052
1053 case NetworkDataTlv::kTypeBorderRouter:
1054 RemoveRlocInBorderRouter(aPrefix, *As<BorderRouterTlv>(cur), aRloc16, aMatchMode, aExcludePrefix,
1055 aChangedFlags);
1056
1057 if (cur->GetLength() == 0)
1058 {
1059 aPrefix.DecreaseLength(sizeof(BorderRouterTlv));
1060 RemoveTlv(cur);
1061 continue;
1062 }
1063
1064 break;
1065
1066 default:
1067 break;
1068 }
1069
1070 cur = cur->GetNext();
1071 }
1072
1073 if ((context = aPrefix.FindSubTlv<ContextTlv>()) != nullptr)
1074 {
1075 if (aPrefix.FindSubTlv<BorderRouterTlv>() == nullptr)
1076 {
1077 context->ClearCompress();
1078 mContextIds.ScheduleToRemove(context->GetContextId());
1079 }
1080 else
1081 {
1082 context->SetCompress();
1083 mContextIds.MarkAsInUse(context->GetContextId());
1084 }
1085 }
1086 }
1087
RemoveRlocInService(ServiceTlv & aService,uint16_t aRloc16,MatchMode aMatchMode,const ServiceTlv * aExcludeService,ChangedFlags & aChangedFlags)1088 void Leader::RemoveRlocInService(ServiceTlv &aService,
1089 uint16_t aRloc16,
1090 MatchMode aMatchMode,
1091 const ServiceTlv *aExcludeService,
1092 ChangedFlags &aChangedFlags)
1093 {
1094 // Remove entries in `aService` TLV matching the given `aRloc16`
1095 // excluding any entries that are present in `aExcludeService`.
1096
1097 NetworkDataTlv *start = aService.GetSubTlvs();
1098 ServerTlv *server;
1099
1100 while ((server = NetworkDataTlv::Find<ServerTlv>(start, aService.GetNext())) != nullptr)
1101 {
1102 if (RlocMatch(server->GetServer16(), aRloc16, aMatchMode) && !ContainsMatchingServer(aExcludeService, *server))
1103 {
1104 uint8_t subTlvSize = server->GetSize();
1105
1106 aChangedFlags.Update(*server);
1107 RemoveTlv(server);
1108 aService.DecreaseLength(subTlvSize);
1109 continue;
1110 }
1111
1112 start = server->GetNext();
1113 }
1114 }
1115
RemoveRlocInHasRoute(PrefixTlv & aPrefix,HasRouteTlv & aHasRoute,uint16_t aRloc16,MatchMode aMatchMode,const PrefixTlv * aExcludePrefix,ChangedFlags & aChangedFlags)1116 void Leader::RemoveRlocInHasRoute(PrefixTlv &aPrefix,
1117 HasRouteTlv &aHasRoute,
1118 uint16_t aRloc16,
1119 MatchMode aMatchMode,
1120 const PrefixTlv *aExcludePrefix,
1121 ChangedFlags &aChangedFlags)
1122 {
1123 // Remove entries in `aHasRoute` (a sub-TLV of `aPrefix` TLV)
1124 // matching the given `aRloc16` excluding entries that are present
1125 // in `aExcludePrefix`.
1126
1127 HasRouteEntry *entry = aHasRoute.GetFirstEntry();
1128
1129 while (entry <= aHasRoute.GetLastEntry())
1130 {
1131 if (RlocMatch(entry->GetRloc(), aRloc16, aMatchMode) &&
1132 !ContainsMatchingEntry(aExcludePrefix, aHasRoute.IsStable(), *entry))
1133 {
1134 aChangedFlags.Update(aHasRoute);
1135 aHasRoute.DecreaseLength(sizeof(HasRouteEntry));
1136 aPrefix.DecreaseLength(sizeof(HasRouteEntry));
1137 Remove(entry, sizeof(HasRouteEntry));
1138 continue;
1139 }
1140
1141 entry = entry->GetNext();
1142 }
1143 }
1144
RemoveRlocInBorderRouter(PrefixTlv & aPrefix,BorderRouterTlv & aBorderRouter,uint16_t aRloc16,MatchMode aMatchMode,const PrefixTlv * aExcludePrefix,ChangedFlags & aChangedFlags)1145 void Leader::RemoveRlocInBorderRouter(PrefixTlv &aPrefix,
1146 BorderRouterTlv &aBorderRouter,
1147 uint16_t aRloc16,
1148 MatchMode aMatchMode,
1149 const PrefixTlv *aExcludePrefix,
1150 ChangedFlags &aChangedFlags)
1151 {
1152 // Remove entries in `aBorderRouter` (a sub-TLV of `aPrefix` TLV)
1153 // matching the given `aRloc16` excluding entries that are present
1154 // in `aExcludePrefix`.
1155
1156 BorderRouterEntry *entry = aBorderRouter.GetFirstEntry();
1157
1158 while (entry <= aBorderRouter.GetLastEntry())
1159 {
1160 if (RlocMatch(entry->GetRloc(), aRloc16, aMatchMode) &&
1161 !ContainsMatchingEntry(aExcludePrefix, aBorderRouter.IsStable(), *entry))
1162 {
1163 aChangedFlags.Update(aBorderRouter);
1164 aBorderRouter.DecreaseLength(sizeof(BorderRouterEntry));
1165 aPrefix.DecreaseLength(sizeof(BorderRouterEntry));
1166 Remove(entry, sizeof(*entry));
1167 continue;
1168 }
1169
1170 entry = entry->GetNext();
1171 }
1172 }
1173
RemoveContext(uint8_t aContextId)1174 void Leader::RemoveContext(uint8_t aContextId)
1175 {
1176 NetworkDataTlv *start = GetTlvsStart();
1177 PrefixTlv *prefix;
1178
1179 while ((prefix = NetworkDataTlv::Find<PrefixTlv>(start, GetTlvsEnd())) != nullptr)
1180 {
1181 RemoveContext(*prefix, aContextId);
1182
1183 if (UpdatePrefix(*prefix) == kTlvRemoved)
1184 {
1185 // Do not update `start` when TLV is removed.
1186 continue;
1187 }
1188
1189 start = prefix->GetNext();
1190 }
1191
1192 IncrementVersions(/* aIncludeStable */ true);
1193 }
1194
RemoveContext(PrefixTlv & aPrefix,uint8_t aContextId)1195 void Leader::RemoveContext(PrefixTlv &aPrefix, uint8_t aContextId)
1196 {
1197 NetworkDataTlv *start = aPrefix.GetSubTlvs();
1198 ContextTlv *context;
1199
1200 while ((context = NetworkDataTlv::Find<ContextTlv>(start, aPrefix.GetNext())) != nullptr)
1201 {
1202 if (context->GetContextId() == aContextId)
1203 {
1204 uint8_t subTlvSize = context->GetSize();
1205 RemoveTlv(context);
1206 aPrefix.DecreaseLength(subTlvSize);
1207 continue;
1208 }
1209
1210 start = context->GetNext();
1211 }
1212 }
1213
HandleNetworkDataRestoredAfterReset(void)1214 void Leader::HandleNetworkDataRestoredAfterReset(void)
1215 {
1216 const PrefixTlv *prefix;
1217 TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd());
1218 ChangedFlags flags;
1219 uint16_t rloc16;
1220 uint16_t sessionId;
1221 Rlocs rlocs;
1222
1223 mWaitingForNetDataSync = false;
1224
1225 // Remove entries in Network Data from any un-allocated Router ID.
1226 // This acts as a safeguard against an edge case where the leader
1227 // is reset at an inopportune time, such as right after it removed
1228 // an allocated router ID and sent MLE advertisement but before it
1229 // got the chance to send the updated Network Data to other
1230 // routers.
1231
1232 FindRlocs(kAnyBrOrServer, kAnyRole, rlocs);
1233
1234 for (uint16_t rloc : rlocs)
1235 {
1236 if (!Get<RouterTable>().IsAllocated(Mle::RouterIdFromRloc16(rloc)))
1237 {
1238 RemoveRloc(rloc, kMatchModeRouterId, flags);
1239 }
1240 }
1241
1242 IncrementVersions(flags);
1243
1244 // Synchronize internal 6LoWPAN Context ID Set with the
1245 // recently obtained Network Data.
1246
1247 while ((prefix = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
1248 {
1249 const ContextTlv *context = prefix->FindSubTlv<ContextTlv>();
1250
1251 if (context == nullptr)
1252 {
1253 continue;
1254 }
1255
1256 mContextIds.MarkAsInUse(context->GetContextId());
1257
1258 if (!context->IsCompress())
1259 {
1260 mContextIds.ScheduleToRemove(context->GetContextId());
1261 }
1262 }
1263
1264 // Update Commissioning Data. We adopt the same session ID
1265 // (if any) and resign active commissioner (if any) by
1266 // clearing the Commissioning Data.
1267
1268 if (FindCommissioningSessionId(sessionId) == kErrorNone)
1269 {
1270 Get<MeshCoP::Leader>().SetSessionId(sessionId);
1271 }
1272
1273 if (FindBorderAgentRloc(rloc16) == kErrorNone)
1274 {
1275 Get<MeshCoP::Leader>().SetEmptyCommissionerData();
1276 }
1277 }
1278
UpdateCommissioningData(uint16_t aDataLength,CommissioningDataTlv * & aDataTlv)1279 Error Leader::UpdateCommissioningData(uint16_t aDataLength, CommissioningDataTlv *&aDataTlv)
1280 {
1281 // First determine whether or not we can add Commissioning Data
1282 // TLV with the given `aDataLength`, taking into account that we
1283 // would remove the current Commissioning Data TLV. Then remove
1284 // the current TLV and append a new TLV with proper size which is
1285 // returned in `aDataTlv`.
1286
1287 Error error = kErrorNone;
1288 CommissioningDataTlv *dataTlv = FindCommissioningData();
1289 uint16_t insertLength;
1290
1291 if (dataTlv != nullptr)
1292 {
1293 insertLength = (aDataLength <= dataTlv->GetLength()) ? 0 : aDataLength - dataTlv->GetLength();
1294 }
1295 else
1296 {
1297 insertLength = sizeof(CommissioningDataTlv) + aDataLength;
1298 }
1299
1300 VerifyOrExit(CanInsert(insertLength), error = kErrorNoBufs);
1301
1302 if (dataTlv != nullptr)
1303 {
1304 RemoveTlv(dataTlv);
1305 }
1306
1307 aDataTlv = As<CommissioningDataTlv>(AppendTlv(sizeof(CommissioningDataTlv) + aDataLength));
1308
1309 OT_ASSERT(aDataTlv != nullptr);
1310
1311 aDataTlv->Init();
1312 aDataTlv->SetLength(static_cast<uint8_t>(aDataLength));
1313
1314 // The caller would fill the `aDataTlv` value.
1315
1316 mVersion++;
1317 SignalNetDataChanged();
1318
1319 exit:
1320 return error;
1321 }
1322
SetCommissioningData(const void * aData,uint8_t aDataLength)1323 Error Leader::SetCommissioningData(const void *aData, uint8_t aDataLength)
1324 {
1325 Error error = kErrorNone;
1326 CommissioningDataTlv *dataTlv;
1327
1328 SuccessOrExit(error = UpdateCommissioningData(aDataLength, dataTlv));
1329 memcpy(dataTlv->GetValue(), aData, aDataLength);
1330
1331 exit:
1332 return error;
1333 }
1334
SetCommissioningData(const Message & aMessage)1335 Error Leader::SetCommissioningData(const Message &aMessage)
1336 {
1337 Error error = kErrorNone;
1338 uint16_t dataLength = aMessage.GetLength() - aMessage.GetOffset();
1339 CommissioningDataTlv *dataTlv;
1340
1341 SuccessOrExit(error = UpdateCommissioningData(dataLength, dataTlv));
1342 aMessage.ReadBytes(aMessage.GetOffset(), dataTlv->GetValue(), dataLength);
1343
1344 exit:
1345 return error;
1346 }
1347
HandleTimer(void)1348 void Leader::HandleTimer(void)
1349 {
1350 if (mWaitingForNetDataSync)
1351 {
1352 LogInfo("Timed out waiting for netdata on restoring leader role after reset");
1353 IgnoreError(Get<Mle::MleRouter>().BecomeDetached());
1354 }
1355 else
1356 {
1357 mContextIds.HandleTimer();
1358 }
1359 }
1360
1361 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
ContainsOmrPrefix(const Ip6::Prefix & aPrefix)1362 bool Leader::ContainsOmrPrefix(const Ip6::Prefix &aPrefix)
1363 {
1364 PrefixTlv *prefixTlv;
1365 bool contains = false;
1366
1367 VerifyOrExit(BorderRouter::RoutingManager::IsValidOmrPrefix(aPrefix));
1368
1369 prefixTlv = FindPrefix(aPrefix);
1370 VerifyOrExit(prefixTlv != nullptr);
1371
1372 for (int i = 0; i < 2; i++)
1373 {
1374 const BorderRouterTlv *borderRouter = prefixTlv->FindSubTlv<BorderRouterTlv>(/* aStable */ (i == 0));
1375
1376 if (borderRouter == nullptr)
1377 {
1378 continue;
1379 }
1380
1381 for (const BorderRouterEntry *entry = borderRouter->GetFirstEntry(); entry <= borderRouter->GetLastEntry();
1382 entry = entry->GetNext())
1383 {
1384 OnMeshPrefixConfig config;
1385
1386 config.SetFrom(*prefixTlv, *borderRouter, *entry);
1387
1388 if (BorderRouter::RoutingManager::IsValidOmrPrefix(config))
1389 {
1390 ExitNow(contains = true);
1391 }
1392 }
1393 }
1394
1395 exit:
1396 return contains;
1397 }
1398 #endif
1399
1400 //---------------------------------------------------------------------------------------------------------------------
1401 // Leader::ContextIds
1402
ContextIds(Instance & aInstance)1403 Leader::ContextIds::ContextIds(Instance &aInstance)
1404 : InstanceLocator(aInstance)
1405 , mReuseDelay(kReuseDelay)
1406 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
1407 , mIsClone(false)
1408 #endif
1409 {
1410 }
1411
Clear(void)1412 void Leader::ContextIds::Clear(void)
1413 {
1414 for (uint8_t id = kMinId; id <= kMaxId; id++)
1415 {
1416 MarkAsUnallocated(id);
1417 }
1418 }
1419
GetUnallocatedId(uint8_t & aId)1420 Error Leader::ContextIds::GetUnallocatedId(uint8_t &aId)
1421 {
1422 Error error = kErrorNotFound;
1423
1424 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
1425 if (mIsClone)
1426 {
1427 aId = kMinId;
1428 error = kErrorNone;
1429 ExitNow();
1430 }
1431 #endif
1432
1433 for (uint8_t id = kMinId; id <= kMaxId; id++)
1434 {
1435 if (IsUnallocated(id))
1436 {
1437 aId = id;
1438 error = kErrorNone;
1439 ExitNow();
1440 }
1441 }
1442
1443 exit:
1444 return error;
1445 }
1446
ScheduleToRemove(uint8_t aId)1447 void Leader::ContextIds::ScheduleToRemove(uint8_t aId)
1448 {
1449 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
1450 VerifyOrExit(!mIsClone);
1451 #endif
1452
1453 VerifyOrExit(IsInUse(aId));
1454
1455 SetRemoveTime(aId, TimerMilli::GetNow() + Time::SecToMsec(mReuseDelay));
1456 Get<Leader>().mTimer.FireAtIfEarlier(GetRemoveTime(aId));
1457
1458 exit:
1459 return;
1460 }
1461
SetRemoveTime(uint8_t aId,TimeMilli aTime)1462 void Leader::ContextIds::SetRemoveTime(uint8_t aId, TimeMilli aTime)
1463 {
1464 uint32_t time = aTime.GetValue();
1465
1466 while ((time == kUnallocated) || (time == kInUse))
1467 {
1468 time++;
1469 }
1470
1471 mRemoveTimes[aId - kMinId].SetValue(time);
1472 }
1473
HandleTimer(void)1474 void Leader::ContextIds::HandleTimer(void)
1475 {
1476 TimeMilli now = TimerMilli::GetNow();
1477 TimeMilli nextTime = now.GetDistantFuture();
1478
1479 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
1480 OT_ASSERT(!mIsClone);
1481 #endif
1482
1483 for (uint8_t id = kMinId; id <= kMaxId; id++)
1484 {
1485 if (IsUnallocated(id) || IsInUse(id))
1486 {
1487 continue;
1488 }
1489
1490 if (now >= GetRemoveTime(id))
1491 {
1492 MarkAsUnallocated(id);
1493 Get<Leader>().RemoveContext(id);
1494 }
1495 else
1496 {
1497 nextTime = Min(nextTime, GetRemoveTime(id));
1498 }
1499 }
1500
1501 if (nextTime != now.GetDistantFuture())
1502 {
1503 Get<Leader>().mTimer.FireAt(nextTime);
1504 }
1505 }
1506
1507 } // namespace NetworkData
1508 } // namespace ot
1509
1510 #endif // OPENTHREAD_FTD
1511