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