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 common methods for manipulating Thread Network Data.
32 */
33
34 #include "network_data.hpp"
35
36 #include "instance/instance.hpp"
37
38 namespace ot {
39 namespace NetworkData {
40
41 RegisterLogModule("NetworkData");
42
43 //---------------------------------------------------------------------------------------------------------------------
44 // NetworkData
45
CopyNetworkData(Type aType,uint8_t * aData,uint8_t & aDataLength) const46 Error NetworkData::CopyNetworkData(Type aType, uint8_t *aData, uint8_t &aDataLength) const
47 {
48 Error error;
49 MutableNetworkData netDataCopy(GetInstance(), aData, 0, aDataLength);
50
51 SuccessOrExit(error = CopyNetworkData(aType, netDataCopy));
52 aDataLength = netDataCopy.GetLength();
53
54 exit:
55 return error;
56 }
57
CopyNetworkData(Type aType,MutableNetworkData & aNetworkData) const58 Error NetworkData::CopyNetworkData(Type aType, MutableNetworkData &aNetworkData) const
59 {
60 Error error = kErrorNone;
61
62 VerifyOrExit(aNetworkData.GetSize() >= mLength, error = kErrorNoBufs);
63
64 memcpy(aNetworkData.GetBytes(), mTlvs, mLength);
65 aNetworkData.SetLength(mLength);
66
67 if (aType == kStableSubset)
68 {
69 aNetworkData.RemoveTemporaryData();
70 }
71
72 exit:
73 return error;
74 }
75
GetNextOnMeshPrefix(Iterator & aIterator,OnMeshPrefixConfig & aConfig) const76 Error NetworkData::GetNextOnMeshPrefix(Iterator &aIterator, OnMeshPrefixConfig &aConfig) const
77 {
78 return GetNextOnMeshPrefix(aIterator, Mac::kShortAddrBroadcast, aConfig);
79 }
80
GetNextOnMeshPrefix(Iterator & aIterator,uint16_t aRloc16,OnMeshPrefixConfig & aConfig) const81 Error NetworkData::GetNextOnMeshPrefix(Iterator &aIterator, uint16_t aRloc16, OnMeshPrefixConfig &aConfig) const
82 {
83 Config config;
84
85 config.mOnMeshPrefix = &aConfig;
86 config.mExternalRoute = nullptr;
87 config.mService = nullptr;
88 config.mLowpanContext = nullptr;
89
90 return Iterate(aIterator, aRloc16, config);
91 }
92
GetNextExternalRoute(Iterator & aIterator,ExternalRouteConfig & aConfig) const93 Error NetworkData::GetNextExternalRoute(Iterator &aIterator, ExternalRouteConfig &aConfig) const
94 {
95 return GetNextExternalRoute(aIterator, Mac::kShortAddrBroadcast, aConfig);
96 }
97
GetNextExternalRoute(Iterator & aIterator,uint16_t aRloc16,ExternalRouteConfig & aConfig) const98 Error NetworkData::GetNextExternalRoute(Iterator &aIterator, uint16_t aRloc16, ExternalRouteConfig &aConfig) const
99 {
100 Config config;
101
102 config.mOnMeshPrefix = nullptr;
103 config.mExternalRoute = &aConfig;
104 config.mService = nullptr;
105 config.mLowpanContext = nullptr;
106
107 return Iterate(aIterator, aRloc16, config);
108 }
109
GetNextService(Iterator & aIterator,ServiceConfig & aConfig) const110 Error NetworkData::GetNextService(Iterator &aIterator, ServiceConfig &aConfig) const
111 {
112 return GetNextService(aIterator, Mac::kShortAddrBroadcast, aConfig);
113 }
114
GetNextService(Iterator & aIterator,uint16_t aRloc16,ServiceConfig & aConfig) const115 Error NetworkData::GetNextService(Iterator &aIterator, uint16_t aRloc16, ServiceConfig &aConfig) const
116 {
117 Config config;
118
119 config.mOnMeshPrefix = nullptr;
120 config.mExternalRoute = nullptr;
121 config.mService = &aConfig;
122 config.mLowpanContext = nullptr;
123
124 return Iterate(aIterator, aRloc16, config);
125 }
126
GetNextLowpanContextInfo(Iterator & aIterator,LowpanContextInfo & aContextInfo) const127 Error NetworkData::GetNextLowpanContextInfo(Iterator &aIterator, LowpanContextInfo &aContextInfo) const
128 {
129 Config config;
130
131 config.mOnMeshPrefix = nullptr;
132 config.mExternalRoute = nullptr;
133 config.mService = nullptr;
134 config.mLowpanContext = &aContextInfo;
135
136 return Iterate(aIterator, Mac::kShortAddrBroadcast, config);
137 }
138
Iterate(Iterator & aIterator,uint16_t aRloc16,Config & aConfig) const139 Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfig) const
140 {
141 // Iterate to the next entry in Network Data matching `aRloc16`
142 // (can be set to `Mac::kShortAddrBroadcast` to allow any RLOC).
143 // The `aIterator` is used to track and save the current position.
144 // On input, the non-`nullptr` pointer members in `aConfig` specify
145 // the Network Data entry types (`mOnMeshPrefix`, `mExternalRoute`,
146 // `mService`) to iterate over. On successful exit, the `aConfig`
147 // is updated such that only one member pointer is not `nullptr`
148 // indicating the type of entry and the non-`nullptr` config is
149 // updated with the entry info.
150
151 Error error = kErrorNotFound;
152 NetworkDataIterator iterator(aIterator);
153
154 for (const NetworkDataTlv *cur;
155 cur = iterator.GetTlv(mTlvs), (cur + 1 <= GetTlvsEnd()) && (cur->GetNext() <= GetTlvsEnd());
156 iterator.AdvanceTlv(mTlvs))
157 {
158 const NetworkDataTlv *subTlvs = nullptr;
159
160 switch (cur->GetType())
161 {
162 case NetworkDataTlv::kTypePrefix:
163 if ((aConfig.mOnMeshPrefix != nullptr) || (aConfig.mExternalRoute != nullptr) ||
164 (aConfig.mLowpanContext != nullptr))
165 {
166 subTlvs = As<PrefixTlv>(cur)->GetSubTlvs();
167 }
168 break;
169 case NetworkDataTlv::kTypeService:
170 if (aConfig.mService != nullptr)
171 {
172 subTlvs = As<ServiceTlv>(cur)->GetSubTlvs();
173 }
174 break;
175 default:
176 break;
177 }
178
179 if (subTlvs == nullptr)
180 {
181 continue;
182 }
183
184 for (const NetworkDataTlv *subCur; subCur = iterator.GetSubTlv(subTlvs),
185 (subCur + 1 <= cur->GetNext()) && (subCur->GetNext() <= cur->GetNext());
186 iterator.AdvanceSubTlv(subTlvs))
187 {
188 if (cur->GetType() == NetworkDataTlv::kTypePrefix)
189 {
190 const PrefixTlv *prefixTlv = As<PrefixTlv>(cur);
191
192 switch (subCur->GetType())
193 {
194 case NetworkDataTlv::kTypeBorderRouter:
195 {
196 const BorderRouterTlv *borderRouter = As<BorderRouterTlv>(subCur);
197
198 if (aConfig.mOnMeshPrefix == nullptr)
199 {
200 continue;
201 }
202
203 for (uint8_t index; (index = iterator.GetAndAdvanceIndex()) < borderRouter->GetNumEntries();)
204 {
205 if (aRloc16 == Mac::kShortAddrBroadcast || borderRouter->GetEntry(index)->GetRloc() == aRloc16)
206 {
207 const BorderRouterEntry *borderRouterEntry = borderRouter->GetEntry(index);
208
209 aConfig.mExternalRoute = nullptr;
210 aConfig.mService = nullptr;
211 aConfig.mLowpanContext = nullptr;
212 aConfig.mOnMeshPrefix->SetFrom(*prefixTlv, *borderRouter, *borderRouterEntry);
213
214 ExitNow(error = kErrorNone);
215 }
216 }
217
218 break;
219 }
220
221 case NetworkDataTlv::kTypeHasRoute:
222 {
223 const HasRouteTlv *hasRoute = As<HasRouteTlv>(subCur);
224
225 if (aConfig.mExternalRoute == nullptr)
226 {
227 continue;
228 }
229
230 for (uint8_t index; (index = iterator.GetAndAdvanceIndex()) < hasRoute->GetNumEntries();)
231 {
232 if (aRloc16 == Mac::kShortAddrBroadcast || hasRoute->GetEntry(index)->GetRloc() == aRloc16)
233 {
234 const HasRouteEntry *hasRouteEntry = hasRoute->GetEntry(index);
235
236 aConfig.mOnMeshPrefix = nullptr;
237 aConfig.mService = nullptr;
238 aConfig.mLowpanContext = nullptr;
239 aConfig.mExternalRoute->SetFrom(GetInstance(), *prefixTlv, *hasRoute, *hasRouteEntry);
240
241 ExitNow(error = kErrorNone);
242 }
243 }
244
245 break;
246 }
247
248 case NetworkDataTlv::kTypeContext:
249 {
250 const ContextTlv *contextTlv = As<ContextTlv>(subCur);
251
252 if (aConfig.mLowpanContext == nullptr)
253 {
254 continue;
255 }
256
257 if (iterator.IsNewEntry())
258 {
259 aConfig.mOnMeshPrefix = nullptr;
260 aConfig.mExternalRoute = nullptr;
261 aConfig.mService = nullptr;
262 aConfig.mLowpanContext->SetFrom(*prefixTlv, *contextTlv);
263
264 iterator.MarkEntryAsNotNew();
265 ExitNow(error = kErrorNone);
266 }
267
268 break;
269 }
270
271 default:
272 break;
273 }
274 }
275 else // cur is `ServiceTLv`
276 {
277 const ServiceTlv *service = As<ServiceTlv>(cur);
278
279 if (aConfig.mService == nullptr)
280 {
281 continue;
282 }
283
284 if (subCur->GetType() == NetworkDataTlv::kTypeServer)
285 {
286 const ServerTlv *server = As<ServerTlv>(subCur);
287
288 if (!iterator.IsNewEntry())
289 {
290 continue;
291 }
292
293 if ((aRloc16 == Mac::kShortAddrBroadcast) || (server->GetServer16() == aRloc16))
294 {
295 aConfig.mOnMeshPrefix = nullptr;
296 aConfig.mExternalRoute = nullptr;
297 aConfig.mLowpanContext = nullptr;
298 aConfig.mService->SetFrom(*service, *server);
299
300 iterator.MarkEntryAsNotNew();
301
302 ExitNow(error = kErrorNone);
303 }
304 }
305 }
306 }
307 }
308
309 exit:
310 return error;
311 }
312
ContainsOnMeshPrefix(const OnMeshPrefixConfig & aPrefix) const313 bool NetworkData::ContainsOnMeshPrefix(const OnMeshPrefixConfig &aPrefix) const
314 {
315 bool contains = false;
316 Iterator iterator = kIteratorInit;
317 OnMeshPrefixConfig prefix;
318
319 while (GetNextOnMeshPrefix(iterator, aPrefix.mRloc16, prefix) == kErrorNone)
320 {
321 if (prefix == aPrefix)
322 {
323 contains = true;
324 break;
325 }
326 }
327
328 return contains;
329 }
330
ContainsExternalRoute(const ExternalRouteConfig & aRoute) const331 bool NetworkData::ContainsExternalRoute(const ExternalRouteConfig &aRoute) const
332 {
333 bool contains = false;
334 Iterator iterator = kIteratorInit;
335 ExternalRouteConfig route;
336
337 while (GetNextExternalRoute(iterator, aRoute.mRloc16, route) == kErrorNone)
338 {
339 if (route == aRoute)
340 {
341 contains = true;
342 break;
343 }
344 }
345
346 return contains;
347 }
348
ContainsService(const ServiceConfig & aService) const349 bool NetworkData::ContainsService(const ServiceConfig &aService) const
350 {
351 bool contains = false;
352 Iterator iterator = kIteratorInit;
353 ServiceConfig service;
354
355 while (GetNextService(iterator, aService.GetServerConfig().mRloc16, service) == kErrorNone)
356 {
357 if (service == aService)
358 {
359 contains = true;
360 break;
361 }
362 }
363
364 return contains;
365 }
366
ContainsEntriesFrom(const NetworkData & aCompare,uint16_t aRloc16) const367 bool NetworkData::ContainsEntriesFrom(const NetworkData &aCompare, uint16_t aRloc16) const
368 {
369 bool contains = true;
370 Iterator iterator = kIteratorInit;
371
372 while (true)
373 {
374 Config config;
375 OnMeshPrefixConfig prefix;
376 ExternalRouteConfig route;
377 ServiceConfig service;
378
379 config.mOnMeshPrefix = &prefix;
380 config.mExternalRoute = &route;
381 config.mService = &service;
382 config.mLowpanContext = nullptr;
383
384 SuccessOrExit(aCompare.Iterate(iterator, aRloc16, config));
385
386 if (((config.mOnMeshPrefix != nullptr) && !ContainsOnMeshPrefix(*config.mOnMeshPrefix)) ||
387 ((config.mExternalRoute != nullptr) && !ContainsExternalRoute(*config.mExternalRoute)) ||
388 ((config.mService != nullptr) && !ContainsService(*config.mService)))
389 {
390 ExitNow(contains = false);
391 }
392 }
393
394 exit:
395 return contains;
396 }
397
FindPrefix(const uint8_t * aPrefix,uint8_t aPrefixLength) const398 const PrefixTlv *NetworkData::FindPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const
399 {
400 TlvIterator tlvIterator(mTlvs, mLength);
401 const PrefixTlv *prefixTlv;
402
403 while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
404 {
405 if (prefixTlv->IsEqual(aPrefix, aPrefixLength))
406 {
407 break;
408 }
409 }
410
411 return prefixTlv;
412 }
413
FindService(uint32_t aEnterpriseNumber,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode) const414 const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
415 const ServiceData &aServiceData,
416 ServiceMatchMode aServiceMatchMode) const
417 {
418 TlvIterator tlvIterator(mTlvs, mLength);
419 const ServiceTlv *serviceTlv;
420
421 while ((serviceTlv = tlvIterator.Iterate<ServiceTlv>()) != nullptr)
422 {
423 if (MatchService(*serviceTlv, aEnterpriseNumber, aServiceData, aServiceMatchMode))
424 {
425 break;
426 }
427 }
428
429 return serviceTlv;
430 }
431
FindNextService(const ServiceTlv * aPrevServiceTlv,uint32_t aEnterpriseNumber,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode) const432 const ServiceTlv *NetworkData::FindNextService(const ServiceTlv *aPrevServiceTlv,
433 uint32_t aEnterpriseNumber,
434 const ServiceData &aServiceData,
435 ServiceMatchMode aServiceMatchMode) const
436 {
437 const uint8_t *tlvs;
438 uint8_t length;
439
440 if (aPrevServiceTlv == nullptr)
441 {
442 tlvs = mTlvs;
443 length = mLength;
444 }
445 else
446 {
447 tlvs = reinterpret_cast<const uint8_t *>(aPrevServiceTlv->GetNext());
448 length = static_cast<uint8_t>((mTlvs + mLength) - tlvs);
449 }
450
451 return NetworkData(GetInstance(), tlvs, length).FindService(aEnterpriseNumber, aServiceData, aServiceMatchMode);
452 }
453
FindNextThreadService(const ServiceTlv * aPrevServiceTlv,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode) const454 const ServiceTlv *NetworkData::FindNextThreadService(const ServiceTlv *aPrevServiceTlv,
455 const ServiceData &aServiceData,
456 ServiceMatchMode aServiceMatchMode) const
457 {
458 return FindNextService(aPrevServiceTlv, ServiceTlv::kThreadEnterpriseNumber, aServiceData, aServiceMatchMode);
459 }
460
MatchService(const ServiceTlv & aServiceTlv,uint32_t aEnterpriseNumber,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode)461 bool NetworkData::MatchService(const ServiceTlv &aServiceTlv,
462 uint32_t aEnterpriseNumber,
463 const ServiceData &aServiceData,
464 ServiceMatchMode aServiceMatchMode)
465 {
466 bool match = false;
467 ServiceData serviceData;
468
469 VerifyOrExit(aServiceTlv.GetEnterpriseNumber() == aEnterpriseNumber);
470
471 aServiceTlv.GetServiceData(serviceData);
472
473 switch (aServiceMatchMode)
474 {
475 case kServiceExactMatch:
476 match = (serviceData == aServiceData);
477 break;
478
479 case kServicePrefixMatch:
480 match = serviceData.StartsWith(aServiceData);
481 break;
482 }
483
484 exit:
485 return match;
486 }
487
FindRlocs(BorderRouterFilter aBrFilter,RoleFilter aRoleFilter,Rlocs & aRlocs) const488 void NetworkData::FindRlocs(BorderRouterFilter aBrFilter, RoleFilter aRoleFilter, Rlocs &aRlocs) const
489 {
490 Iterator iterator = kIteratorInit;
491 OnMeshPrefixConfig prefix;
492 ExternalRouteConfig route;
493 ServiceConfig service;
494 Config config;
495
496 aRlocs.Clear();
497
498 while (true)
499 {
500 config.mOnMeshPrefix = &prefix;
501 config.mExternalRoute = &route;
502 config.mService = &service;
503 config.mLowpanContext = nullptr;
504
505 SuccessOrExit(Iterate(iterator, Mac::kShortAddrBroadcast, config));
506
507 if (config.mOnMeshPrefix != nullptr)
508 {
509 bool matches = true;
510
511 switch (aBrFilter)
512 {
513 case kAnyBrOrServer:
514 break;
515 case kBrProvidingExternalIpConn:
516 matches = prefix.mOnMesh && (prefix.mDefaultRoute || prefix.mDp);
517 break;
518 }
519
520 if (matches)
521 {
522 AddRloc16ToRlocs(prefix.mRloc16, aRlocs, aRoleFilter);
523 }
524 }
525 else if (config.mExternalRoute != nullptr)
526 {
527 AddRloc16ToRlocs(route.mRloc16, aRlocs, aRoleFilter);
528 }
529 else if (config.mService != nullptr)
530 {
531 switch (aBrFilter)
532 {
533 case kAnyBrOrServer:
534 AddRloc16ToRlocs(service.mServerConfig.mRloc16, aRlocs, aRoleFilter);
535 break;
536 case kBrProvidingExternalIpConn:
537 break;
538 }
539 }
540 }
541
542 exit:
543 return;
544 }
545
CountBorderRouters(RoleFilter aRoleFilter) const546 uint8_t NetworkData::CountBorderRouters(RoleFilter aRoleFilter) const
547 {
548 Rlocs rlocs;
549
550 FindRlocs(kBrProvidingExternalIpConn, aRoleFilter, rlocs);
551
552 return rlocs.GetLength();
553 }
554
ContainsBorderRouterWithRloc(uint16_t aRloc16) const555 bool NetworkData::ContainsBorderRouterWithRloc(uint16_t aRloc16) const
556 {
557 Rlocs rlocs;
558
559 FindRlocs(kBrProvidingExternalIpConn, kAnyRole, rlocs);
560
561 return rlocs.Contains(aRloc16);
562 }
563
AddRloc16ToRlocs(uint16_t aRloc16,Rlocs & aRlocs,RoleFilter aRoleFilter)564 void NetworkData::AddRloc16ToRlocs(uint16_t aRloc16, Rlocs &aRlocs, RoleFilter aRoleFilter)
565 {
566 switch (aRoleFilter)
567 {
568 case kAnyRole:
569 break;
570
571 case kRouterRoleOnly:
572 VerifyOrExit(Mle::IsRouterRloc16(aRloc16));
573 break;
574
575 case kChildRoleOnly:
576 VerifyOrExit(Mle::IsChildRloc16(aRloc16));
577 break;
578 }
579
580 VerifyOrExit(!aRlocs.Contains(aRloc16));
581 IgnoreError(aRlocs.PushBack(aRloc16));
582
583 exit:
584 return;
585 }
586
FindDomainIdFor(const Ip6::Prefix & aPrefix,uint8_t & aDomainId) const587 Error NetworkData::FindDomainIdFor(const Ip6::Prefix &aPrefix, uint8_t &aDomainId) const
588 {
589 Error error = kErrorNone;
590 const PrefixTlv *prefixTlv = FindPrefix(aPrefix);
591
592 VerifyOrExit(prefixTlv != nullptr, error = kErrorNotFound);
593 aDomainId = prefixTlv->GetDomainId();
594
595 exit:
596 return error;
597 }
598
599 //---------------------------------------------------------------------------------------------------------------------
600 // MutableNetworkData
601
RemoveTemporaryData(void)602 void MutableNetworkData::RemoveTemporaryData(void)
603 {
604 NetworkDataTlv *cur = GetTlvsStart();
605
606 while (cur < GetTlvsEnd())
607 {
608 bool shouldRemove = false;
609
610 switch (cur->GetType())
611 {
612 case NetworkDataTlv::kTypePrefix:
613 shouldRemove = RemoveTemporaryDataIn(*As<PrefixTlv>(cur));
614 break;
615
616 case NetworkDataTlv::kTypeService:
617 shouldRemove = RemoveTemporaryDataIn(*As<ServiceTlv>(cur));
618 break;
619
620 default:
621 shouldRemove = !cur->IsStable();
622 break;
623 }
624
625 if (shouldRemove)
626 {
627 RemoveTlv(cur);
628 continue;
629 }
630
631 cur = cur->GetNext();
632 }
633 }
634
RemoveTemporaryDataIn(PrefixTlv & aPrefix)635 bool MutableNetworkData::RemoveTemporaryDataIn(PrefixTlv &aPrefix)
636 {
637 NetworkDataTlv *cur = aPrefix.GetSubTlvs();
638
639 while (cur < aPrefix.GetNext())
640 {
641 if (cur->IsStable())
642 {
643 switch (cur->GetType())
644 {
645 case NetworkDataTlv::kTypeBorderRouter:
646 {
647 BorderRouterTlv *borderRouter = As<BorderRouterTlv>(cur);
648 ContextTlv *context = aPrefix.FindSubTlv<ContextTlv>();
649
650 // Replace p_border_router_16
651 for (BorderRouterEntry *entry = borderRouter->GetFirstEntry(); entry <= borderRouter->GetLastEntry();
652 entry = entry->GetNext())
653 {
654 if ((entry->IsDhcp() || entry->IsConfigure()) && (context != nullptr))
655 {
656 entry->SetRloc(0xfc00 | context->GetContextId());
657 }
658 else
659 {
660 entry->SetRloc(0xfffe);
661 }
662 }
663
664 break;
665 }
666
667 case NetworkDataTlv::kTypeHasRoute:
668 {
669 HasRouteTlv *hasRoute = As<HasRouteTlv>(cur);
670
671 // Replace r_border_router_16
672 for (HasRouteEntry *entry = hasRoute->GetFirstEntry(); entry <= hasRoute->GetLastEntry();
673 entry = entry->GetNext())
674 {
675 entry->SetRloc(0xfffe);
676 }
677
678 break;
679 }
680
681 default:
682 break;
683 }
684
685 // keep stable tlv
686 cur = cur->GetNext();
687 }
688 else
689 {
690 // remove temporary tlv
691 uint8_t subTlvSize = cur->GetSize();
692 RemoveTlv(cur);
693 aPrefix.SetSubTlvsLength(aPrefix.GetSubTlvsLength() - subTlvSize);
694 }
695 }
696
697 return (aPrefix.GetSubTlvsLength() == 0);
698 }
699
RemoveTemporaryDataIn(ServiceTlv & aService)700 bool MutableNetworkData::RemoveTemporaryDataIn(ServiceTlv &aService)
701 {
702 NetworkDataTlv *cur = aService.GetSubTlvs();
703
704 while (cur < aService.GetNext())
705 {
706 if (cur->IsStable())
707 {
708 switch (cur->GetType())
709 {
710 case NetworkDataTlv::kTypeServer:
711 As<ServerTlv>(cur)->SetServer16(Mle::ServiceAlocFromId(aService.GetServiceId()));
712 break;
713
714 default:
715 break;
716 }
717
718 // keep stable tlv
719 cur = cur->GetNext();
720 }
721 else
722 {
723 // remove temporary tlv
724 uint8_t subTlvSize = cur->GetSize();
725 RemoveTlv(cur);
726 aService.SetSubTlvsLength(aService.GetSubTlvsLength() - subTlvSize);
727 }
728 }
729
730 return (aService.GetSubTlvsLength() == 0);
731 }
732
AppendTlv(uint16_t aTlvSize)733 NetworkDataTlv *MutableNetworkData::AppendTlv(uint16_t aTlvSize)
734 {
735 NetworkDataTlv *tlv;
736
737 VerifyOrExit(CanInsert(aTlvSize), tlv = nullptr);
738
739 tlv = GetTlvsEnd();
740 mLength += static_cast<uint8_t>(aTlvSize);
741
742 exit:
743 return tlv;
744 }
745
Insert(void * aStart,uint8_t aLength)746 void MutableNetworkData::Insert(void *aStart, uint8_t aLength)
747 {
748 uint8_t *start = reinterpret_cast<uint8_t *>(aStart);
749
750 OT_ASSERT(CanInsert(aLength) && mTlvs <= start && start <= mTlvs + mLength);
751 memmove(start + aLength, start, mLength - static_cast<size_t>(start - mTlvs));
752 mLength += aLength;
753 }
754
Remove(void * aRemoveStart,uint8_t aRemoveLength)755 void MutableNetworkData::Remove(void *aRemoveStart, uint8_t aRemoveLength)
756 {
757 uint8_t *end = GetBytes() + mLength;
758 uint8_t *removeStart = reinterpret_cast<uint8_t *>(aRemoveStart);
759 uint8_t *removeEnd = removeStart + aRemoveLength;
760
761 OT_ASSERT((aRemoveLength <= mLength) && (GetBytes() <= removeStart) && (removeEnd <= end));
762
763 memmove(removeStart, removeEnd, static_cast<uint8_t>(end - removeEnd));
764 mLength -= aRemoveLength;
765 }
766
RemoveTlv(NetworkDataTlv * aTlv)767 void MutableNetworkData::RemoveTlv(NetworkDataTlv *aTlv) { Remove(aTlv, aTlv->GetSize()); }
768
769 } // namespace NetworkData
770 } // namespace ot
771