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