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/code_utils.hpp"
40 #include "common/debug.hpp"
41 #include "common/encoding.hpp"
42 #include "common/instance.hpp"
43 #include "common/locator_getters.hpp"
44 #include "common/logging.hpp"
45 #include "common/message.hpp"
46 #include "common/timer.hpp"
47 #include "mac/mac_types.hpp"
48 #include "meshcop/meshcop.hpp"
49 #include "thread/lowpan.hpp"
50 #include "thread/mle_router.hpp"
51 #include "thread/thread_netif.hpp"
52 #include "thread/thread_tlvs.hpp"
53 #include "thread/uri_paths.hpp"
54 
55 namespace ot {
56 namespace NetworkData {
57 
Leader(Instance & aInstance)58 Leader::Leader(Instance &aInstance)
59     : LeaderBase(aInstance)
60     , mTimer(aInstance, Leader::HandleTimer)
61     , mServerData(UriPath::kServerData, &Leader::HandleServerData, this)
62     , mCommissioningDataGet(UriPath::kCommissionerGet, &Leader::HandleCommissioningGet, this)
63     , mCommissioningDataSet(UriPath::kCommissionerSet, &Leader::HandleCommissioningSet, this)
64 {
65     Reset();
66 }
67 
Reset(void)68 void Leader::Reset(void)
69 {
70     LeaderBase::Reset();
71 
72     memset(reinterpret_cast<void *>(mContextLastUsed), 0, sizeof(mContextLastUsed));
73     mContextUsed         = 0;
74     mContextIdReuseDelay = kContextIdReuseDelay;
75 }
76 
Start(void)77 void Leader::Start(void)
78 {
79     Get<Tmf::Agent>().AddResource(mServerData);
80     Get<Tmf::Agent>().AddResource(mCommissioningDataGet);
81     Get<Tmf::Agent>().AddResource(mCommissioningDataSet);
82 }
83 
Stop(void)84 void Leader::Stop(void)
85 {
86     Get<Tmf::Agent>().RemoveResource(mServerData);
87     Get<Tmf::Agent>().RemoveResource(mCommissioningDataGet);
88     Get<Tmf::Agent>().RemoveResource(mCommissioningDataSet);
89 }
90 
IncrementVersion(void)91 void Leader::IncrementVersion(void)
92 {
93     if (Get<Mle::MleRouter>().IsLeader())
94     {
95         IncrementVersions(/* aIncludeStable */ false);
96     }
97 }
98 
IncrementVersionAndStableVersion(void)99 void Leader::IncrementVersionAndStableVersion(void)
100 {
101     if (Get<Mle::MleRouter>().IsLeader())
102     {
103         IncrementVersions(/* aIncludeStable */ true);
104     }
105 }
106 
IncrementVersions(const ChangedFlags & aFlags)107 void Leader::IncrementVersions(const ChangedFlags &aFlags)
108 {
109     if (aFlags.DidChange())
110     {
111         IncrementVersions(aFlags.DidStableChange());
112     }
113 }
114 
IncrementVersions(bool aIncludeStable)115 void Leader::IncrementVersions(bool aIncludeStable)
116 {
117     if (aIncludeStable)
118     {
119         mStableVersion++;
120     }
121 
122     mVersion++;
123     Get<ot::Notifier>().Signal(kEventThreadNetdataChanged);
124 }
125 
RemoveBorderRouter(uint16_t aRloc16,MatchMode aMatchMode)126 void Leader::RemoveBorderRouter(uint16_t aRloc16, MatchMode aMatchMode)
127 {
128     ChangedFlags flags;
129 
130     RemoveRloc(aRloc16, aMatchMode, flags);
131     IncrementVersions(flags);
132 }
133 
HandleServerData(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)134 void Leader::HandleServerData(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
135 {
136     static_cast<Leader *>(aContext)->HandleServerData(*static_cast<Coap::Message *>(aMessage),
137                                                       *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
138 }
139 
HandleServerData(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)140 void Leader::HandleServerData(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
141 {
142     ThreadNetworkDataTlv networkData;
143     uint16_t             rloc16;
144 
145     otLogInfoNetData("Received network data registration");
146 
147     VerifyOrExit(aMessageInfo.GetPeerAddr().GetIid().IsRoutingLocator());
148 
149     switch (Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16))
150     {
151     case kErrorNone:
152         RemoveBorderRouter(rloc16, kMatchModeRloc16);
153         break;
154     case kErrorNotFound:
155         break;
156     default:
157         ExitNow();
158     }
159 
160     if (Tlv::FindTlv(aMessage, networkData) == kErrorNone)
161     {
162         VerifyOrExit(networkData.IsValid());
163         RegisterNetworkData(aMessageInfo.GetPeerAddr().GetIid().GetLocator(), networkData.GetTlvs(),
164                             networkData.GetLength());
165     }
166 
167     SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo));
168 
169     otLogInfoNetData("Sent network data registration acknowledgment");
170 
171 exit:
172     return;
173 }
174 
HandleCommissioningSet(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)175 void Leader::HandleCommissioningSet(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
176 {
177     static_cast<Leader *>(aContext)->HandleCommissioningSet(*static_cast<Coap::Message *>(aMessage),
178                                                             *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
179 }
180 
HandleCommissioningSet(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)181 void Leader::HandleCommissioningSet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
182 {
183     uint16_t                 offset = aMessage.GetOffset();
184     uint16_t                 length = aMessage.GetLength() - aMessage.GetOffset();
185     uint8_t                  tlvs[NetworkData::kMaxSize];
186     MeshCoP::StateTlv::State state        = MeshCoP::StateTlv::kReject;
187     bool                     hasSessionId = false;
188     bool                     hasValidTlv  = false;
189     uint16_t                 sessionId    = 0;
190     CommissioningDataTlv *   commDataTlv;
191 
192     MeshCoP::Tlv *cur;
193     MeshCoP::Tlv *end;
194 
195     VerifyOrExit(length <= sizeof(tlvs));
196     VerifyOrExit(Get<Mle::MleRouter>().IsLeader());
197 
198     aMessage.ReadBytes(offset, tlvs, length);
199 
200     // Session Id and Border Router Locator MUST NOT be set, but accept including unexpected or
201     // unknown TLV as long as there is at least one valid TLV.
202     cur = reinterpret_cast<MeshCoP::Tlv *>(tlvs);
203     end = reinterpret_cast<MeshCoP::Tlv *>(tlvs + length);
204 
205     while (cur < end)
206     {
207         MeshCoP::Tlv::Type type;
208 
209         VerifyOrExit(((cur + 1) <= end) && !cur->IsExtended() && (cur->GetNext() <= end));
210 
211         type = cur->GetType();
212 
213         if (type == MeshCoP::Tlv::kJoinerUdpPort || type == MeshCoP::Tlv::kSteeringData)
214         {
215             hasValidTlv = true;
216         }
217         else if (type == MeshCoP::Tlv::kBorderAgentLocator)
218         {
219             ExitNow();
220         }
221         else if (type == MeshCoP::Tlv::kCommissionerSessionId)
222         {
223             MeshCoP::CommissionerSessionIdTlv *tlv = static_cast<MeshCoP::CommissionerSessionIdTlv *>(cur);
224 
225             VerifyOrExit(tlv->IsValid());
226             sessionId    = tlv->GetCommissionerSessionId();
227             hasSessionId = true;
228         }
229         else
230         {
231             // do nothing for unexpected or unknown TLV
232         }
233 
234         cur = cur->GetNext();
235     }
236 
237     // verify whether or not commissioner session id TLV is included
238     VerifyOrExit(hasSessionId);
239 
240     // verify whether or not MGMT_COMM_SET.req includes at least one valid TLV
241     VerifyOrExit(hasValidTlv);
242 
243     // Find Commissioning Data TLV
244     commDataTlv = GetCommissioningData();
245 
246     if (commDataTlv != nullptr)
247     {
248         // Iterate over MeshCoP TLVs and extract desired data
249         for (cur = reinterpret_cast<MeshCoP::Tlv *>(commDataTlv->GetValue());
250              cur < reinterpret_cast<MeshCoP::Tlv *>(commDataTlv->GetValue() + commDataTlv->GetLength());
251              cur = cur->GetNext())
252         {
253             if (cur->GetType() == MeshCoP::Tlv::kCommissionerSessionId)
254             {
255                 VerifyOrExit(sessionId ==
256                              static_cast<MeshCoP::CommissionerSessionIdTlv *>(cur)->GetCommissionerSessionId());
257             }
258             else if (cur->GetType() == MeshCoP::Tlv::kBorderAgentLocator)
259             {
260                 VerifyOrExit(length + cur->GetSize() <= sizeof(tlvs));
261                 memcpy(tlvs + length, reinterpret_cast<uint8_t *>(cur), cur->GetSize());
262                 length += cur->GetSize();
263             }
264         }
265     }
266 
267     IgnoreError(SetCommissioningData(tlvs, static_cast<uint8_t>(length)));
268 
269     state = MeshCoP::StateTlv::kAccept;
270 
271 exit:
272 
273     if (Get<Mle::MleRouter>().IsLeader())
274     {
275         SendCommissioningSetResponse(aMessage, aMessageInfo, state);
276     }
277 }
278 
HandleCommissioningGet(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)279 void Leader::HandleCommissioningGet(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
280 {
281     static_cast<Leader *>(aContext)->HandleCommissioningGet(*static_cast<Coap::Message *>(aMessage),
282                                                             *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
283 }
284 
HandleCommissioningGet(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)285 void Leader::HandleCommissioningGet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
286 {
287     uint16_t length = 0;
288     uint16_t offset;
289 
290     SuccessOrExit(Tlv::FindTlvValueOffset(aMessage, MeshCoP::Tlv::kGet, offset, length));
291     aMessage.SetOffset(offset);
292 
293 exit:
294     SendCommissioningGetResponse(aMessage, length, aMessageInfo);
295 }
296 
SendCommissioningGetResponse(const Coap::Message & aRequest,uint16_t aLength,const Ip6::MessageInfo & aMessageInfo)297 void Leader::SendCommissioningGetResponse(const Coap::Message &   aRequest,
298                                           uint16_t                aLength,
299                                           const Ip6::MessageInfo &aMessageInfo)
300 {
301     Error                 error = kErrorNone;
302     Coap::Message *       message;
303     CommissioningDataTlv *commDataTlv;
304     uint8_t *             data   = nullptr;
305     uint8_t               length = 0;
306 
307     VerifyOrExit((message = MeshCoP::NewMeshCoPMessage(Get<Tmf::Agent>())) != nullptr, error = kErrorNoBufs);
308 
309     SuccessOrExit(error = message->SetDefaultResponseHeader(aRequest));
310     SuccessOrExit(error = message->SetPayloadMarker());
311 
312     commDataTlv = GetCommissioningData();
313 
314     if (commDataTlv != nullptr)
315     {
316         data   = commDataTlv->GetValue();
317         length = commDataTlv->GetLength();
318     }
319 
320     VerifyOrExit(data && length, error = kErrorDrop);
321 
322     if (aLength == 0)
323     {
324         SuccessOrExit(error = message->AppendBytes(data, length));
325     }
326     else
327     {
328         for (uint16_t index = 0; index < aLength; index++)
329         {
330             uint8_t type;
331 
332             IgnoreError(aRequest.Read(aRequest.GetOffset() + index, type));
333 
334             for (MeshCoP::Tlv *cur                                          = reinterpret_cast<MeshCoP::Tlv *>(data);
335                  cur < reinterpret_cast<MeshCoP::Tlv *>(data + length); cur = cur->GetNext())
336             {
337                 if (cur->GetType() == type)
338                 {
339                     SuccessOrExit(error = cur->AppendTo(*message));
340                     break;
341                 }
342             }
343         }
344     }
345 
346     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
347 
348     otLogInfoMeshCoP("sent commissioning dataset get response");
349 
350 exit:
351     FreeMessageOnError(message, error);
352 }
353 
SendCommissioningSetResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,MeshCoP::StateTlv::State aState)354 void Leader::SendCommissioningSetResponse(const Coap::Message &    aRequest,
355                                           const Ip6::MessageInfo & aMessageInfo,
356                                           MeshCoP::StateTlv::State aState)
357 {
358     Error          error = kErrorNone;
359     Coap::Message *message;
360 
361     VerifyOrExit((message = MeshCoP::NewMeshCoPMessage(Get<Tmf::Agent>())) != nullptr, error = kErrorNoBufs);
362 
363     SuccessOrExit(error = message->SetDefaultResponseHeader(aRequest));
364     SuccessOrExit(error = message->SetPayloadMarker());
365 
366     SuccessOrExit(error = Tlv::Append<MeshCoP::StateTlv>(*message, aState));
367 
368     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
369 
370     otLogInfoMeshCoP("sent commissioning dataset set response");
371 
372 exit:
373     FreeMessageOnError(message, error);
374 }
375 
RlocMatch(uint16_t aFirstRloc16,uint16_t aSecondRloc16,MatchMode aMatchMode)376 bool Leader::RlocMatch(uint16_t aFirstRloc16, uint16_t aSecondRloc16, MatchMode aMatchMode)
377 {
378     bool matched = false;
379 
380     switch (aMatchMode)
381     {
382     case kMatchModeRloc16:
383         matched = (aFirstRloc16 == aSecondRloc16);
384         break;
385 
386     case kMatchModeRouterId:
387         matched = Mle::Mle::RouterIdMatch(aFirstRloc16, aSecondRloc16);
388         break;
389     }
390 
391     return matched;
392 }
393 
Validate(const uint8_t * aTlvs,uint8_t aTlvsLength,uint16_t aRloc16)394 Error Leader::Validate(const uint8_t *aTlvs, uint8_t aTlvsLength, uint16_t aRloc16)
395 {
396     // Validate that the `aTlvs` contains well-formed TLVs, sub-TLVs,
397     // and entries all matching `aRloc16` (no other entry for other
398     // RLOCs and no duplicates TLVs).
399 
400     Error                 error = kErrorNone;
401     const NetworkDataTlv *end   = reinterpret_cast<const NetworkDataTlv *>(aTlvs + aTlvsLength);
402 
403     for (const NetworkDataTlv *cur = reinterpret_cast<const NetworkDataTlv *>(aTlvs); cur < end; cur = cur->GetNext())
404     {
405         uint8_t offset;
406 
407         VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end, error = kErrorParse);
408 
409         offset = static_cast<uint8_t>(reinterpret_cast<const uint8_t *>(cur) - aTlvs);
410 
411         switch (cur->GetType())
412         {
413         case NetworkDataTlv::kTypePrefix:
414         {
415             const PrefixTlv *prefix = static_cast<const PrefixTlv *>(cur);
416 
417             VerifyOrExit(prefix->IsValid(), error = kErrorParse);
418 
419             // Ensure there is no duplicate Prefix TLVs with same prefix.
420             VerifyOrExit(FindPrefix(prefix->GetPrefix(), prefix->GetPrefixLength(), aTlvs, offset) == nullptr,
421                          error = kErrorParse);
422 
423             SuccessOrExit(error = ValidatePrefix(*prefix, aRloc16));
424             break;
425         }
426 
427         case NetworkDataTlv::kTypeService:
428         {
429             const ServiceTlv *service = static_cast<const ServiceTlv *>(cur);
430 
431             VerifyOrExit(service->IsValid(), error = kErrorParse);
432 
433             // Ensure there is no duplicate Service TLV with same
434             // Enterprise Number and Service Data.
435             VerifyOrExit(FindService(service->GetEnterpriseNumber(), service->GetServiceData(),
436                                      service->GetServiceDataLength(), kServiceExactMatch, aTlvs, offset) == nullptr,
437                          error = kErrorParse);
438 
439             SuccessOrExit(error = ValidateService(*service, aRloc16));
440             break;
441         }
442 
443         default:
444             break;
445         }
446     }
447 
448 exit:
449     return error;
450 }
451 
ValidatePrefix(const PrefixTlv & aPrefix,uint16_t aRloc16)452 Error Leader::ValidatePrefix(const PrefixTlv &aPrefix, uint16_t aRloc16)
453 {
454     // Validate that `aPrefix` TLV contains well-formed sub-TLVs and
455     // and entries all matching `aRloc16` (no other entry for other
456     // RLOCs).
457 
458     Error                 error                   = kErrorParse;
459     const NetworkDataTlv *subEnd                  = aPrefix.GetNext();
460     bool                  foundTempHasRoute       = false;
461     bool                  foundStableHasRoute     = false;
462     bool                  foundTempBorderRouter   = false;
463     bool                  foundStableBorderRouter = false;
464 
465     for (const NetworkDataTlv *subCur = aPrefix.GetSubTlvs(); subCur < subEnd; subCur = subCur->GetNext())
466     {
467         VerifyOrExit((subCur + 1) <= subEnd && subCur->GetNext() <= subEnd);
468 
469         switch (subCur->GetType())
470         {
471         case NetworkDataTlv::kTypeBorderRouter:
472         {
473             const BorderRouterTlv *borderRouter = static_cast<const BorderRouterTlv *>(subCur);
474 
475             // Ensure Prefix TLV contains at most one stable and one
476             // temporary Border Router sub-TLV and the sub-TLVs have
477             // a single entry.
478 
479             if (borderRouter->IsStable())
480             {
481                 VerifyOrExit(!foundStableBorderRouter);
482                 foundStableBorderRouter = true;
483             }
484             else
485             {
486                 VerifyOrExit(!foundTempBorderRouter);
487                 foundTempBorderRouter = true;
488             }
489 
490             VerifyOrExit(borderRouter->GetFirstEntry() == borderRouter->GetLastEntry());
491             VerifyOrExit(borderRouter->GetFirstEntry()->GetRloc() == aRloc16);
492             break;
493         }
494 
495         case NetworkDataTlv::kTypeHasRoute:
496         {
497             const HasRouteTlv *hasRoute = static_cast<const HasRouteTlv *>(subCur);
498 
499             // Ensure Prefix TLV contains at most one stable and one
500             // temporary Has Route sub-TLV and the sub-TLVs have a
501             // single entry.
502 
503             if (hasRoute->IsStable())
504             {
505                 VerifyOrExit(!foundStableHasRoute);
506                 foundStableHasRoute = true;
507             }
508             else
509             {
510                 VerifyOrExit(!foundTempHasRoute);
511                 foundTempHasRoute = true;
512             }
513 
514             VerifyOrExit(hasRoute->GetFirstEntry() == hasRoute->GetLastEntry());
515             VerifyOrExit(hasRoute->GetFirstEntry()->GetRloc() == aRloc16);
516             break;
517         }
518 
519         default:
520             break;
521         }
522     }
523 
524     if (foundStableBorderRouter || foundTempBorderRouter || foundStableHasRoute || foundTempHasRoute)
525     {
526         error = kErrorNone;
527     }
528 
529 exit:
530     return error;
531 }
532 
ValidateService(const ServiceTlv & aService,uint16_t aRloc16)533 Error Leader::ValidateService(const ServiceTlv &aService, uint16_t aRloc16)
534 {
535     // Validate that `aService` TLV contains a single well-formed
536     // Server sub-TLV associated with `aRloc16`.
537 
538     Error                 error       = kErrorParse;
539     const NetworkDataTlv *subEnd      = aService.GetNext();
540     bool                  foundServer = false;
541 
542     for (const NetworkDataTlv *subCur = aService.GetSubTlvs(); subCur < subEnd; subCur = subCur->GetNext())
543     {
544         VerifyOrExit((subCur + 1) <= subEnd && subCur->GetNext() <= subEnd);
545 
546         switch (subCur->GetType())
547         {
548         case NetworkDataTlv::kTypeServer:
549         {
550             const ServerTlv *server = static_cast<const ServerTlv *>(subCur);
551 
552             VerifyOrExit(!foundServer);
553             foundServer = true;
554 
555             VerifyOrExit(server->IsValid() && server->GetServer16() == aRloc16);
556             break;
557         }
558 
559         default:
560             break;
561         }
562     }
563 
564     if (foundServer)
565     {
566         error = kErrorNone;
567     }
568 
569 exit:
570     return error;
571 }
572 
ContainsMatchingEntry(const PrefixTlv * aPrefix,bool aStable,const HasRouteEntry & aEntry)573 bool Leader::ContainsMatchingEntry(const PrefixTlv *aPrefix, bool aStable, const HasRouteEntry &aEntry)
574 {
575     // Check whether `aPrefix` has a Has Route sub-TLV with stable
576     // flag `aStable` containing a matching entry to `aEntry`.
577 
578     return (aPrefix == nullptr) ? false : ContainsMatchingEntry(aPrefix->FindSubTlv<HasRouteTlv>(aStable), aEntry);
579 }
580 
ContainsMatchingEntry(const HasRouteTlv * aHasRoute,const HasRouteEntry & aEntry)581 bool Leader::ContainsMatchingEntry(const HasRouteTlv *aHasRoute, const HasRouteEntry &aEntry)
582 {
583     // Check whether `aHasRoute` has a matching entry to `aEntry`.
584 
585     bool contains = false;
586 
587     VerifyOrExit(aHasRoute != nullptr);
588 
589     for (const HasRouteEntry *entry = aHasRoute->GetFirstEntry(); entry <= aHasRoute->GetLastEntry(); entry++)
590     {
591         if (*entry == aEntry)
592         {
593             contains = true;
594             break;
595         }
596     }
597 
598 exit:
599     return contains;
600 }
601 
ContainsMatchingEntry(const PrefixTlv * aPrefix,bool aStable,const BorderRouterEntry & aEntry)602 bool Leader::ContainsMatchingEntry(const PrefixTlv *aPrefix, bool aStable, const BorderRouterEntry &aEntry)
603 {
604     // Check whether `aPrefix` has a Border Router sub-TLV with stable
605     // flag `aStable` containing a matching entry to `aEntry`.
606 
607     return (aPrefix == nullptr) ? false : ContainsMatchingEntry(aPrefix->FindSubTlv<BorderRouterTlv>(aStable), aEntry);
608 }
609 
ContainsMatchingEntry(const BorderRouterTlv * aBorderRouter,const BorderRouterEntry & aEntry)610 bool Leader::ContainsMatchingEntry(const BorderRouterTlv *aBorderRouter, const BorderRouterEntry &aEntry)
611 {
612     // Check whether `aBorderRouter` has a matching entry to `aEntry`.
613 
614     bool contains = false;
615 
616     VerifyOrExit(aBorderRouter != nullptr);
617 
618     for (const BorderRouterEntry *entry = aBorderRouter->GetFirstEntry(); entry <= aBorderRouter->GetLastEntry();
619          entry++)
620     {
621         if (*entry == aEntry)
622         {
623             contains = true;
624             break;
625         }
626     }
627 
628 exit:
629     return contains;
630 }
631 
ContainsMatchingServer(const ServiceTlv * aService,const ServerTlv & aServer)632 bool Leader::ContainsMatchingServer(const ServiceTlv *aService, const ServerTlv &aServer)
633 {
634     // Check whether the `aService` has a matching Server sub-TLV
635     // same as `aServer`.
636 
637     bool contains = false;
638 
639     if (aService != nullptr)
640     {
641         const ServerTlv *server;
642         TlvIterator      subTlvIterator(*aService);
643 
644         while ((server = subTlvIterator.Iterate<ServerTlv>(aServer.IsStable())) != nullptr)
645         {
646             if (*server == aServer)
647             {
648                 contains = true;
649                 break;
650             }
651         }
652     }
653 
654     return contains;
655 }
656 
UpdatePrefix(PrefixTlv & aPrefix)657 Leader::UpdateStatus Leader::UpdatePrefix(PrefixTlv &aPrefix)
658 {
659     return UpdateTlv(aPrefix, aPrefix.GetSubTlvs());
660 }
661 
UpdateService(ServiceTlv & aService)662 Leader::UpdateStatus Leader::UpdateService(ServiceTlv &aService)
663 {
664     return UpdateTlv(aService, aService.GetSubTlvs());
665 }
666 
UpdateTlv(NetworkDataTlv & aTlv,const NetworkDataTlv * aSubTlvs)667 Leader::UpdateStatus Leader::UpdateTlv(NetworkDataTlv &aTlv, const NetworkDataTlv *aSubTlvs)
668 {
669     // If `aTlv` contains no sub-TLVs, remove it from Network Data,
670     // otherwise update its stable flag based on its sub-TLVs.
671 
672     UpdateStatus status = kTlvUpdated;
673 
674     if (aSubTlvs == aTlv.GetNext())
675     {
676         RemoveTlv(&aTlv);
677         ExitNow(status = kTlvRemoved);
678     }
679 
680     for (const NetworkDataTlv *subCur = aSubTlvs; subCur < aTlv.GetNext(); subCur = subCur->GetNext())
681     {
682         if (subCur->IsStable())
683         {
684             aTlv.SetStable();
685             ExitNow();
686         }
687     }
688 
689     aTlv.ClearStable();
690 
691 exit:
692     return status;
693 }
694 
RegisterNetworkData(uint16_t aRloc16,const uint8_t * aTlvs,uint8_t aTlvsLength)695 void Leader::RegisterNetworkData(uint16_t aRloc16, const uint8_t *aTlvs, uint8_t aTlvsLength)
696 {
697     Error                 error = kErrorNone;
698     const NetworkDataTlv *end   = reinterpret_cast<const NetworkDataTlv *>(aTlvs + aTlvsLength);
699     ChangedFlags          flags;
700 
701     VerifyOrExit(Get<RouterTable>().IsAllocated(Mle::Mle::RouterIdFromRloc16(aRloc16)), error = kErrorNoRoute);
702 
703     // Validate that the `aTlvs` contains well-formed TLVs, sub-TLVs,
704     // and entries all matching `aRloc16` (no other RLOCs).
705     SuccessOrExit(error = Validate(aTlvs, aTlvsLength, aRloc16));
706 
707     // Remove all entries matching `aRloc16` excluding entries that are
708     // present in `aTlvs`
709     RemoveRloc(aRloc16, kMatchModeRloc16, aTlvs, aTlvsLength, flags);
710 
711     // Now add all new entries in `aTlvs` to Network Data.
712     for (const NetworkDataTlv *cur = reinterpret_cast<const NetworkDataTlv *>(aTlvs); cur < end; cur = cur->GetNext())
713     {
714         switch (cur->GetType())
715         {
716         case NetworkDataTlv::kTypePrefix:
717             SuccessOrExit(error = AddPrefix(*static_cast<const PrefixTlv *>(cur), flags));
718             break;
719 
720         case NetworkDataTlv::kTypeService:
721             SuccessOrExit(error = AddService(*static_cast<const ServiceTlv *>(cur), flags));
722             break;
723 
724         default:
725             break;
726         }
727     }
728 
729     IncrementVersions(flags);
730 
731     otDumpDebgNetData("add done", mTlvs, mLength);
732 
733 exit:
734 
735     if (error != kErrorNone)
736     {
737         otLogNoteNetData("Failed to register network data: %s", ErrorToString(error));
738     }
739 }
740 
AddPrefix(const PrefixTlv & aPrefix,ChangedFlags & aChangedFlags)741 Error Leader::AddPrefix(const PrefixTlv &aPrefix, ChangedFlags &aChangedFlags)
742 {
743     Error      error     = kErrorNone;
744     PrefixTlv *dstPrefix = FindPrefix(aPrefix.GetPrefix(), aPrefix.GetPrefixLength());
745 
746     if (dstPrefix == nullptr)
747     {
748         dstPrefix = static_cast<PrefixTlv *>(AppendTlv(PrefixTlv::CalculateSize(aPrefix.GetPrefixLength())));
749         VerifyOrExit(dstPrefix != nullptr, error = kErrorNoBufs);
750 
751         dstPrefix->Init(aPrefix.GetDomainId(), aPrefix.GetPrefixLength(), aPrefix.GetPrefix());
752     }
753 
754     for (const NetworkDataTlv *subCur = aPrefix.GetSubTlvs(); subCur < aPrefix.GetNext(); subCur = subCur->GetNext())
755     {
756         switch (subCur->GetType())
757         {
758         case NetworkDataTlv::kTypeHasRoute:
759             SuccessOrExit(error = AddHasRoute(*static_cast<const HasRouteTlv *>(subCur), *dstPrefix, aChangedFlags));
760             break;
761 
762         case NetworkDataTlv::kTypeBorderRouter:
763             SuccessOrExit(
764                 error = AddBorderRouter(*static_cast<const BorderRouterTlv *>(subCur), *dstPrefix, aChangedFlags));
765             break;
766 
767         default:
768             break;
769         }
770     }
771 
772 exit:
773     if (dstPrefix != nullptr)
774     {
775         // `UpdatePrefix()` updates the TLV's stable flag based on
776         // its sub-TLVs, or removes the TLV if it contains no sub-TLV.
777         // This is called at `exit` to ensure that if appending
778         // sub-TLVs fail (e.g., out of space in network data), we
779         // remove an empty Prefix TLV.
780 
781         IgnoreReturnValue(UpdatePrefix(*dstPrefix));
782     }
783 
784     return error;
785 }
786 
AddService(const ServiceTlv & aService,ChangedFlags & aChangedFlags)787 Error Leader::AddService(const ServiceTlv &aService, ChangedFlags &aChangedFlags)
788 {
789     Error            error      = kErrorNone;
790     ServiceTlv *     dstService = FindService(aService.GetEnterpriseNumber(), aService.GetServiceData(),
791                                          aService.GetServiceDataLength(), kServiceExactMatch);
792     const ServerTlv *server;
793 
794     if (dstService == nullptr)
795     {
796         uint8_t serviceId;
797 
798         SuccessOrExit(error = AllocateServiceId(serviceId));
799 
800         dstService = static_cast<ServiceTlv *>(
801             AppendTlv(ServiceTlv::CalculateSize(aService.GetEnterpriseNumber(), aService.GetServiceDataLength())));
802         VerifyOrExit(dstService != nullptr, error = kErrorNoBufs);
803 
804         dstService->Init(serviceId, aService.GetEnterpriseNumber(), aService.GetServiceData(),
805                          aService.GetServiceDataLength());
806     }
807 
808     server = NetworkDataTlv::Find<ServerTlv>(aService.GetSubTlvs(), aService.GetNext());
809     OT_ASSERT(server != nullptr);
810 
811     SuccessOrExit(error = AddServer(*server, *dstService, aChangedFlags));
812 
813 exit:
814     if (dstService != nullptr)
815     {
816         // `UpdateService()` updates the TLV's stable flag based on
817         // its sub-TLVs, or removes the TLV if it contains no sub-TLV.
818         // This is called at `exit` to ensure that if appending
819         // sub-TLVs fail (e.g., out of space in network data), we
820         // remove an empty Service TLV.
821 
822         IgnoreReturnValue(UpdateService(*dstService));
823     }
824 
825     return error;
826 }
827 
AddHasRoute(const HasRouteTlv & aHasRoute,PrefixTlv & aDstPrefix,ChangedFlags & aChangedFlags)828 Error Leader::AddHasRoute(const HasRouteTlv &aHasRoute, PrefixTlv &aDstPrefix, ChangedFlags &aChangedFlags)
829 {
830     Error                error       = kErrorNone;
831     HasRouteTlv *        dstHasRoute = aDstPrefix.FindSubTlv<HasRouteTlv>(aHasRoute.IsStable());
832     const HasRouteEntry *entry       = aHasRoute.GetFirstEntry();
833 
834     if (dstHasRoute == nullptr)
835     {
836         // Ensure there is space for `HasRouteTlv` and a single entry.
837         VerifyOrExit(CanInsert(sizeof(HasRouteTlv) + sizeof(HasRouteEntry)), error = kErrorNoBufs);
838 
839         dstHasRoute = static_cast<HasRouteTlv *>(aDstPrefix.GetNext());
840         Insert(dstHasRoute, sizeof(HasRouteTlv));
841         aDstPrefix.IncreaseLength(sizeof(HasRouteTlv));
842         dstHasRoute->Init();
843 
844         if (aHasRoute.IsStable())
845         {
846             dstHasRoute->SetStable();
847         }
848     }
849 
850     VerifyOrExit(!ContainsMatchingEntry(dstHasRoute, *entry));
851 
852     VerifyOrExit(CanInsert(sizeof(HasRouteEntry)), error = kErrorNoBufs);
853 
854     Insert(dstHasRoute->GetNext(), sizeof(HasRouteEntry));
855     dstHasRoute->IncreaseLength(sizeof(HasRouteEntry));
856     aDstPrefix.IncreaseLength(sizeof(HasRouteEntry));
857 
858     *dstHasRoute->GetLastEntry() = *entry;
859     aChangedFlags.Update(*dstHasRoute);
860 
861 exit:
862     return error;
863 }
864 
AddBorderRouter(const BorderRouterTlv & aBorderRouter,PrefixTlv & aDstPrefix,ChangedFlags & aChangedFlags)865 Error Leader::AddBorderRouter(const BorderRouterTlv &aBorderRouter, PrefixTlv &aDstPrefix, ChangedFlags &aChangedFlags)
866 {
867     Error                    error           = kErrorNone;
868     BorderRouterTlv *        dstBorderRouter = aDstPrefix.FindSubTlv<BorderRouterTlv>(aBorderRouter.IsStable());
869     ContextTlv *             dstContext      = aDstPrefix.FindSubTlv<ContextTlv>();
870     uint8_t                  contextId       = 0;
871     const BorderRouterEntry *entry           = aBorderRouter.GetFirstEntry();
872 
873     if (dstContext == nullptr)
874     {
875         // Allocate a Context ID first. This ensure that if we cannot
876         // allocate, we fail and exit before potentially inserting a
877         // Border Router sub-TLV.
878         SuccessOrExit(error = AllocateContextId(contextId));
879     }
880 
881     if (dstBorderRouter == nullptr)
882     {
883         // Ensure there is space for `BorderRouterTlv` with a single entry
884         // and a `ContextTlv` (if not already present).
885         VerifyOrExit(CanInsert(sizeof(BorderRouterTlv) + sizeof(BorderRouterEntry) +
886                                ((dstContext == nullptr) ? sizeof(ContextTlv) : 0)),
887                      error = kErrorNoBufs);
888 
889         dstBorderRouter = static_cast<BorderRouterTlv *>(aDstPrefix.GetNext());
890         Insert(dstBorderRouter, sizeof(BorderRouterTlv));
891         aDstPrefix.IncreaseLength(sizeof(BorderRouterTlv));
892         dstBorderRouter->Init();
893 
894         if (aBorderRouter.IsStable())
895         {
896             dstBorderRouter->SetStable();
897         }
898     }
899 
900     if (dstContext == nullptr)
901     {
902         // Ensure there is space for a `ContextTlv` and a single entry.
903         VerifyOrExit(CanInsert(sizeof(BorderRouterEntry) + sizeof(ContextTlv)), error = kErrorNoBufs);
904 
905         dstContext = static_cast<ContextTlv *>(aDstPrefix.GetNext());
906         Insert(dstContext, sizeof(ContextTlv));
907         aDstPrefix.IncreaseLength(sizeof(ContextTlv));
908         dstContext->Init(static_cast<uint8_t>(contextId), aDstPrefix.GetPrefixLength());
909     }
910 
911     if (aBorderRouter.IsStable())
912     {
913         dstContext->SetStable();
914     }
915 
916     dstContext->SetCompress();
917     StopContextReuseTimer(dstContext->GetContextId());
918 
919     VerifyOrExit(!ContainsMatchingEntry(dstBorderRouter, *entry));
920 
921     VerifyOrExit(CanInsert(sizeof(BorderRouterEntry)), error = kErrorNoBufs);
922 
923     Insert(dstBorderRouter->GetNext(), sizeof(BorderRouterEntry));
924     dstBorderRouter->IncreaseLength(sizeof(BorderRouterEntry));
925     aDstPrefix.IncreaseLength(sizeof(BorderRouterEntry));
926     *dstBorderRouter->GetLastEntry() = *entry;
927     aChangedFlags.Update(*dstBorderRouter);
928 
929 exit:
930     return error;
931 }
932 
AddServer(const ServerTlv & aServer,ServiceTlv & aDstService,ChangedFlags & aChangedFlags)933 Error Leader::AddServer(const ServerTlv &aServer, ServiceTlv &aDstService, ChangedFlags &aChangedFlags)
934 {
935     Error      error = kErrorNone;
936     ServerTlv *dstServer;
937     uint8_t    tlvSize = aServer.GetSize();
938 
939     VerifyOrExit(!ContainsMatchingServer(&aDstService, aServer));
940 
941     VerifyOrExit(CanInsert(tlvSize), error = kErrorNoBufs);
942 
943     dstServer = static_cast<ServerTlv *>(aDstService.GetNext());
944     Insert(dstServer, tlvSize);
945     dstServer->Init(aServer.GetServer16(), aServer.GetServerData(), aServer.GetServerDataLength());
946 
947     if (aServer.IsStable())
948     {
949         dstServer->SetStable();
950     }
951 
952     aDstService.IncreaseLength(tlvSize);
953     aChangedFlags.Update(*dstServer);
954 
955 exit:
956     return error;
957 }
958 
AllocateServiceId(uint8_t & aServiceId) const959 Error Leader::AllocateServiceId(uint8_t &aServiceId) const
960 {
961     Error   error = kErrorNotFound;
962     uint8_t serviceId;
963 
964     for (serviceId = Mle::kServiceMinId; serviceId <= Mle::kServiceMaxId; serviceId++)
965     {
966         if (FindServiceById(serviceId) == nullptr)
967         {
968             aServiceId = serviceId;
969             error      = kErrorNone;
970             otLogInfoNetData("Allocated Service ID = %d", serviceId);
971             break;
972         }
973     }
974 
975     return error;
976 }
977 
FindServiceById(uint8_t aServiceId) const978 const ServiceTlv *Leader::FindServiceById(uint8_t aServiceId) const
979 {
980     const ServiceTlv *service;
981     TlvIterator       tlvIterator(GetTlvsStart(), GetTlvsEnd());
982 
983     while ((service = tlvIterator.Iterate<ServiceTlv>()) != nullptr)
984     {
985         if (service->GetServiceId() == aServiceId)
986         {
987             break;
988         }
989     }
990 
991     return service;
992 }
993 
AllocateContextId(uint8_t & aContextId)994 Error Leader::AllocateContextId(uint8_t &aContextId)
995 {
996     Error error = kErrorNotFound;
997 
998     for (uint8_t contextId = kMinContextId; contextId < kMinContextId + kNumContextIds; contextId++)
999     {
1000         if ((mContextUsed & (1 << contextId)) == 0)
1001         {
1002             mContextUsed |= (1 << contextId);
1003             aContextId = contextId;
1004             error      = kErrorNone;
1005             otLogInfoNetData("Allocated Context ID = %d", contextId);
1006             break;
1007         }
1008     }
1009 
1010     return error;
1011 }
1012 
FreeContextId(uint8_t aContextId)1013 void Leader::FreeContextId(uint8_t aContextId)
1014 {
1015     otLogInfoNetData("Free Context Id = %d", aContextId);
1016     RemoveContext(aContextId);
1017     mContextUsed &= ~(1 << aContextId);
1018     IncrementVersions(/* aIncludeStable */ true);
1019 }
1020 
StartContextReuseTimer(uint8_t aContextId)1021 void Leader::StartContextReuseTimer(uint8_t aContextId)
1022 {
1023     mContextLastUsed[aContextId - kMinContextId] = TimerMilli::GetNow();
1024 
1025     if (mContextLastUsed[aContextId - kMinContextId].GetValue() == 0)
1026     {
1027         mContextLastUsed[aContextId - kMinContextId].SetValue(1);
1028     }
1029 
1030     mTimer.Start(kStateUpdatePeriod);
1031 }
1032 
StopContextReuseTimer(uint8_t aContextId)1033 void Leader::StopContextReuseTimer(uint8_t aContextId)
1034 {
1035     mContextLastUsed[aContextId - kMinContextId].SetValue(0);
1036 }
1037 
RemoveRloc(uint16_t aRloc16,MatchMode aMatchMode,ChangedFlags & aChangedFlags)1038 void Leader::RemoveRloc(uint16_t aRloc16, MatchMode aMatchMode, ChangedFlags &aChangedFlags)
1039 {
1040     RemoveRloc(aRloc16, aMatchMode, nullptr, 0, aChangedFlags);
1041 }
1042 
RemoveRloc(uint16_t aRloc16,MatchMode aMatchMode,const uint8_t * aExcludeTlvs,uint8_t aExcludeTlvsLength,ChangedFlags & aChangedFlags)1043 void Leader::RemoveRloc(uint16_t       aRloc16,
1044                         MatchMode      aMatchMode,
1045                         const uint8_t *aExcludeTlvs,
1046                         uint8_t        aExcludeTlvsLength,
1047                         ChangedFlags & aChangedFlags)
1048 {
1049     // Remove entries from Network Data matching `aRloc16` (using
1050     // `aMatchMode` to determine the match) but exclude any entries
1051     // that are present in `aExcludeTlvs`. As entries are removed
1052     // update `aChangedFlags` to indicate if Network Data (stable or
1053     // not) got changed.
1054 
1055     NetworkDataTlv *cur = GetTlvsStart();
1056 
1057     while (cur < GetTlvsEnd())
1058     {
1059         switch (cur->GetType())
1060         {
1061         case NetworkDataTlv::kTypePrefix:
1062         {
1063             PrefixTlv *      prefix = static_cast<PrefixTlv *>(cur);
1064             const PrefixTlv *excludePrefix =
1065                 FindPrefix(prefix->GetPrefix(), prefix->GetPrefixLength(), aExcludeTlvs, aExcludeTlvsLength);
1066 
1067             RemoveRlocInPrefix(*prefix, aRloc16, aMatchMode, excludePrefix, aChangedFlags);
1068 
1069             if (UpdatePrefix(*prefix) == kTlvRemoved)
1070             {
1071                 // Do not update `cur` when TLV is removed.
1072                 continue;
1073             }
1074 
1075             break;
1076         }
1077 
1078         case NetworkDataTlv::kTypeService:
1079         {
1080             ServiceTlv *      service = static_cast<ServiceTlv *>(cur);
1081             const ServiceTlv *excludeService =
1082                 FindService(service->GetEnterpriseNumber(), service->GetServiceData(), service->GetServiceDataLength(),
1083                             kServiceExactMatch, aExcludeTlvs, aExcludeTlvsLength);
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     otDumpDebgNetData("remove done", mTlvs, mLength);
1104 }
1105 
RemoveRlocInPrefix(PrefixTlv & aPrefix,uint16_t aRloc16,MatchMode aMatchMode,const PrefixTlv * aExcludePrefix,ChangedFlags & aChangedFlags)1106 void Leader::RemoveRlocInPrefix(PrefixTlv &      aPrefix,
1107                                 uint16_t         aRloc16,
1108                                 MatchMode        aMatchMode,
1109                                 const PrefixTlv *aExcludePrefix,
1110                                 ChangedFlags &   aChangedFlags)
1111 {
1112     // Remove entries in `aPrefix` TLV matching the given `aRloc16`
1113     // excluding any entries that are present in `aExcludePrefix`.
1114 
1115     NetworkDataTlv *cur = aPrefix.GetSubTlvs();
1116     ContextTlv *    context;
1117 
1118     while (cur < aPrefix.GetNext())
1119     {
1120         switch (cur->GetType())
1121         {
1122         case NetworkDataTlv::kTypeHasRoute:
1123             RemoveRlocInHasRoute(aPrefix, *static_cast<HasRouteTlv *>(cur), aRloc16, aMatchMode, aExcludePrefix,
1124                                  aChangedFlags);
1125 
1126             if (cur->GetLength() == 0)
1127             {
1128                 aPrefix.DecreaseLength(sizeof(HasRouteTlv));
1129                 RemoveTlv(cur);
1130                 continue;
1131             }
1132 
1133             break;
1134 
1135         case NetworkDataTlv::kTypeBorderRouter:
1136             RemoveRlocInBorderRouter(aPrefix, *static_cast<BorderRouterTlv *>(cur), aRloc16, aMatchMode, aExcludePrefix,
1137                                      aChangedFlags);
1138 
1139             if (cur->GetLength() == 0)
1140             {
1141                 aPrefix.DecreaseLength(sizeof(BorderRouterTlv));
1142                 RemoveTlv(cur);
1143                 continue;
1144             }
1145 
1146             break;
1147 
1148         default:
1149             break;
1150         }
1151 
1152         cur = cur->GetNext();
1153     }
1154 
1155     if ((context = aPrefix.FindSubTlv<ContextTlv>()) != nullptr)
1156     {
1157         if (aPrefix.GetSubTlvsLength() == sizeof(ContextTlv))
1158         {
1159             context->ClearCompress();
1160             StartContextReuseTimer(context->GetContextId());
1161         }
1162         else
1163         {
1164             context->SetCompress();
1165             StopContextReuseTimer(context->GetContextId());
1166         }
1167     }
1168 }
1169 
RemoveRlocInService(ServiceTlv & aService,uint16_t aRloc16,MatchMode aMatchMode,const ServiceTlv * aExcludeService,ChangedFlags & aChangedFlags)1170 void Leader::RemoveRlocInService(ServiceTlv &      aService,
1171                                  uint16_t          aRloc16,
1172                                  MatchMode         aMatchMode,
1173                                  const ServiceTlv *aExcludeService,
1174                                  ChangedFlags &    aChangedFlags)
1175 {
1176     // Remove entries in `aService` TLV matching the given `aRloc16`
1177     // excluding any entries that are present in `aExcludeService`.
1178 
1179     NetworkDataTlv *start = aService.GetSubTlvs();
1180     ServerTlv *     server;
1181 
1182     while ((server = NetworkDataTlv::Find<ServerTlv>(start, aService.GetNext())) != nullptr)
1183     {
1184         if (RlocMatch(server->GetServer16(), aRloc16, aMatchMode) && !ContainsMatchingServer(aExcludeService, *server))
1185         {
1186             uint8_t subTlvSize = server->GetSize();
1187 
1188             aChangedFlags.Update(*server);
1189             RemoveTlv(server);
1190             aService.DecreaseLength(subTlvSize);
1191             continue;
1192         }
1193 
1194         start = server->GetNext();
1195     }
1196 }
1197 
RemoveRlocInHasRoute(PrefixTlv & aPrefix,HasRouteTlv & aHasRoute,uint16_t aRloc16,MatchMode aMatchMode,const PrefixTlv * aExcludePrefix,ChangedFlags & aChangedFlags)1198 void Leader::RemoveRlocInHasRoute(PrefixTlv &      aPrefix,
1199                                   HasRouteTlv &    aHasRoute,
1200                                   uint16_t         aRloc16,
1201                                   MatchMode        aMatchMode,
1202                                   const PrefixTlv *aExcludePrefix,
1203                                   ChangedFlags &   aChangedFlags)
1204 {
1205     // Remove entries in `aHasRoute` (a sub-TLV of `aPrefix` TLV)
1206     // matching the given `aRloc16` excluding entries that are present
1207     // in `aExcludePrefix`.
1208 
1209     HasRouteEntry *entry = aHasRoute.GetFirstEntry();
1210 
1211     while (entry <= aHasRoute.GetLastEntry())
1212     {
1213         if (RlocMatch(entry->GetRloc(), aRloc16, aMatchMode) &&
1214             !ContainsMatchingEntry(aExcludePrefix, aHasRoute.IsStable(), *entry))
1215         {
1216             aChangedFlags.Update(aHasRoute);
1217             aHasRoute.DecreaseLength(sizeof(HasRouteEntry));
1218             aPrefix.DecreaseLength(sizeof(HasRouteEntry));
1219             Remove(entry, sizeof(HasRouteEntry));
1220             continue;
1221         }
1222 
1223         entry = entry->GetNext();
1224     }
1225 }
1226 
RemoveRlocInBorderRouter(PrefixTlv & aPrefix,BorderRouterTlv & aBorderRouter,uint16_t aRloc16,MatchMode aMatchMode,const PrefixTlv * aExcludePrefix,ChangedFlags & aChangedFlags)1227 void Leader::RemoveRlocInBorderRouter(PrefixTlv &      aPrefix,
1228                                       BorderRouterTlv &aBorderRouter,
1229                                       uint16_t         aRloc16,
1230                                       MatchMode        aMatchMode,
1231                                       const PrefixTlv *aExcludePrefix,
1232                                       ChangedFlags &   aChangedFlags)
1233 {
1234     // Remove entries in `aBorderRouter` (a sub-TLV of `aPrefix` TLV)
1235     // matching the given `aRloc16` excluding entries that are present
1236     // in `aExcludePrefix`.
1237 
1238     BorderRouterEntry *entry = aBorderRouter.GetFirstEntry();
1239 
1240     while (entry <= aBorderRouter.GetLastEntry())
1241     {
1242         if (RlocMatch(entry->GetRloc(), aRloc16, aMatchMode) &&
1243             !ContainsMatchingEntry(aExcludePrefix, aBorderRouter.IsStable(), *entry))
1244         {
1245             aChangedFlags.Update(aBorderRouter);
1246             aBorderRouter.DecreaseLength(sizeof(BorderRouterEntry));
1247             aPrefix.DecreaseLength(sizeof(BorderRouterEntry));
1248             Remove(entry, sizeof(*entry));
1249             continue;
1250         }
1251 
1252         entry = entry->GetNext();
1253     }
1254 }
1255 
RemoveContext(uint8_t aContextId)1256 void Leader::RemoveContext(uint8_t aContextId)
1257 {
1258     NetworkDataTlv *start = GetTlvsStart();
1259     PrefixTlv *     prefix;
1260 
1261     while ((prefix = NetworkDataTlv::Find<PrefixTlv>(start, GetTlvsEnd())) != nullptr)
1262     {
1263         RemoveContext(*prefix, aContextId);
1264 
1265         if (UpdatePrefix(*prefix) == kTlvRemoved)
1266         {
1267             // Do not update `start` when TLV is removed.
1268             continue;
1269         }
1270 
1271         start = prefix->GetNext();
1272     }
1273 }
1274 
RemoveContext(PrefixTlv & aPrefix,uint8_t aContextId)1275 void Leader::RemoveContext(PrefixTlv &aPrefix, uint8_t aContextId)
1276 {
1277     NetworkDataTlv *start = aPrefix.GetSubTlvs();
1278     ContextTlv *    context;
1279 
1280     while ((context = NetworkDataTlv::Find<ContextTlv>(start, aPrefix.GetNext())) != nullptr)
1281     {
1282         if (context->GetContextId() == aContextId)
1283         {
1284             uint8_t subTlvSize = context->GetSize();
1285             RemoveTlv(context);
1286             aPrefix.DecreaseLength(subTlvSize);
1287             continue;
1288         }
1289 
1290         start = context->GetNext();
1291     }
1292 }
1293 
UpdateContextsAfterReset(void)1294 void Leader::UpdateContextsAfterReset(void)
1295 {
1296     const PrefixTlv *prefix;
1297     TlvIterator      tlvIterator(GetTlvsStart(), GetTlvsEnd());
1298 
1299     while ((prefix = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
1300     {
1301         const ContextTlv *context = prefix->FindSubTlv<ContextTlv>();
1302 
1303         if (context == nullptr)
1304         {
1305             continue;
1306         }
1307 
1308         mContextUsed |= 1 << context->GetContextId();
1309 
1310         if (context->IsCompress())
1311         {
1312             StopContextReuseTimer(context->GetContextId());
1313         }
1314         else
1315         {
1316             StartContextReuseTimer(context->GetContextId());
1317         }
1318     }
1319 }
1320 
HandleTimer(Timer & aTimer)1321 void Leader::HandleTimer(Timer &aTimer)
1322 {
1323     aTimer.Get<Leader>().HandleTimer();
1324 }
1325 
HandleTimer(void)1326 void Leader::HandleTimer(void)
1327 {
1328     bool contextsWaiting = false;
1329 
1330     for (uint8_t i = 0; i < kNumContextIds; i++)
1331     {
1332         if (mContextLastUsed[i].GetValue() == 0)
1333         {
1334             continue;
1335         }
1336 
1337         if (TimerMilli::GetNow() - mContextLastUsed[i] >= Time::SecToMsec(mContextIdReuseDelay))
1338         {
1339             FreeContextId(kMinContextId + i);
1340         }
1341         else
1342         {
1343             contextsWaiting = true;
1344         }
1345     }
1346 
1347     if (contextsWaiting)
1348     {
1349         mTimer.Start(kStateUpdatePeriod);
1350     }
1351 }
1352 
RemoveStaleChildEntries(Coap::ResponseHandler aHandler,void * aContext)1353 Error Leader::RemoveStaleChildEntries(Coap::ResponseHandler aHandler, void *aContext)
1354 {
1355     Error    error    = kErrorNotFound;
1356     Iterator iterator = kIteratorInit;
1357     uint16_t rloc16;
1358 
1359     VerifyOrExit(Get<Mle::MleRouter>().IsRouterOrLeader());
1360 
1361     while (GetNextServer(iterator, rloc16) == kErrorNone)
1362     {
1363         if (!Mle::Mle::IsActiveRouter(rloc16) && Mle::Mle::RouterIdMatch(Get<Mle::MleRouter>().GetRloc16(), rloc16) &&
1364             Get<ChildTable>().FindChild(rloc16, Child::kInStateValid) == nullptr)
1365         {
1366             // In Thread 1.1 Specification 5.15.6.1, only one RLOC16 TLV entry may appear in SRV_DATA.ntf.
1367             error = SendServerDataNotification(rloc16, aHandler, aContext);
1368             ExitNow();
1369         }
1370     }
1371 
1372 exit:
1373     return error;
1374 }
1375 
1376 } // namespace NetworkData
1377 } // namespace ot
1378 
1379 #endif // OPENTHREAD_FTD
1380