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