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