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