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