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