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 bool shouldIterateOverPrefixTlvs;
154
155 shouldIterateOverPrefixTlvs = ((aConfig.mOnMeshPrefix != nullptr) || (aConfig.mExternalRoute != nullptr) ||
156 (aConfig.mLowpanContext != nullptr));
157
158 for (const NetworkDataTlv *cur;
159 cur = iterator.GetTlv(mTlvs), (cur + 1 <= GetTlvsEnd()) && (cur->GetNext() <= GetTlvsEnd());
160 iterator.AdvanceTlv(mTlvs))
161 {
162 const NetworkDataTlv *subTlvs = nullptr;
163
164 switch (cur->GetType())
165 {
166 case NetworkDataTlv::kTypePrefix:
167 if (shouldIterateOverPrefixTlvs && As<PrefixTlv>(cur)->IsValid())
168 {
169 subTlvs = As<PrefixTlv>(cur)->GetSubTlvs();
170 }
171 break;
172 case NetworkDataTlv::kTypeService:
173 if ((aConfig.mService != nullptr) && As<ServiceTlv>(cur)->IsValid())
174 {
175 subTlvs = As<ServiceTlv>(cur)->GetSubTlvs();
176 }
177 break;
178 default:
179 break;
180 }
181
182 if (subTlvs == nullptr)
183 {
184 continue;
185 }
186
187 for (const NetworkDataTlv *subCur; subCur = iterator.GetSubTlv(subTlvs),
188 (subCur + 1 <= cur->GetNext()) && (subCur->GetNext() <= cur->GetNext());
189 iterator.AdvanceSubTlv(subTlvs))
190 {
191 if (cur->GetType() == NetworkDataTlv::kTypePrefix)
192 {
193 const PrefixTlv *prefixTlv = As<PrefixTlv>(cur);
194
195 switch (subCur->GetType())
196 {
197 case NetworkDataTlv::kTypeBorderRouter:
198 {
199 const BorderRouterTlv *borderRouter = As<BorderRouterTlv>(subCur);
200
201 if (aConfig.mOnMeshPrefix == nullptr)
202 {
203 continue;
204 }
205
206 for (uint8_t index; (index = iterator.GetAndAdvanceIndex()) < borderRouter->GetNumEntries();)
207 {
208 if (aRloc16 == Mac::kShortAddrBroadcast || borderRouter->GetEntry(index)->GetRloc() == aRloc16)
209 {
210 const BorderRouterEntry *borderRouterEntry = borderRouter->GetEntry(index);
211
212 aConfig.mExternalRoute = nullptr;
213 aConfig.mService = nullptr;
214 aConfig.mLowpanContext = nullptr;
215 aConfig.mOnMeshPrefix->SetFrom(*prefixTlv, *borderRouter, *borderRouterEntry);
216
217 ExitNow(error = kErrorNone);
218 }
219 }
220
221 break;
222 }
223
224 case NetworkDataTlv::kTypeHasRoute:
225 {
226 const HasRouteTlv *hasRoute = As<HasRouteTlv>(subCur);
227
228 if (aConfig.mExternalRoute == nullptr)
229 {
230 continue;
231 }
232
233 for (uint8_t index; (index = iterator.GetAndAdvanceIndex()) < hasRoute->GetNumEntries();)
234 {
235 if (aRloc16 == Mac::kShortAddrBroadcast || hasRoute->GetEntry(index)->GetRloc() == aRloc16)
236 {
237 const HasRouteEntry *hasRouteEntry = hasRoute->GetEntry(index);
238
239 aConfig.mOnMeshPrefix = nullptr;
240 aConfig.mService = nullptr;
241 aConfig.mLowpanContext = nullptr;
242 aConfig.mExternalRoute->SetFrom(GetInstance(), *prefixTlv, *hasRoute, *hasRouteEntry);
243
244 ExitNow(error = kErrorNone);
245 }
246 }
247
248 break;
249 }
250
251 case NetworkDataTlv::kTypeContext:
252 {
253 const ContextTlv *contextTlv = As<ContextTlv>(subCur);
254
255 if ((aConfig.mLowpanContext == nullptr) || !contextTlv->IsValid())
256 {
257 continue;
258 }
259
260 if (iterator.IsNewEntry())
261 {
262 aConfig.mOnMeshPrefix = nullptr;
263 aConfig.mExternalRoute = nullptr;
264 aConfig.mService = nullptr;
265 aConfig.mLowpanContext->SetFrom(*prefixTlv, *contextTlv);
266
267 iterator.MarkEntryAsNotNew();
268 ExitNow(error = kErrorNone);
269 }
270
271 break;
272 }
273
274 default:
275 break;
276 }
277 }
278 else // cur is `ServiceTLv`
279 {
280 const ServiceTlv *service = As<ServiceTlv>(cur);
281
282 if (aConfig.mService == nullptr)
283 {
284 continue;
285 }
286
287 if (subCur->GetType() == NetworkDataTlv::kTypeServer)
288 {
289 const ServerTlv *server = As<ServerTlv>(subCur);
290
291 if (!iterator.IsNewEntry() || !server->IsValid())
292 {
293 continue;
294 }
295
296 if ((aRloc16 == Mac::kShortAddrBroadcast) || (server->GetServer16() == aRloc16))
297 {
298 aConfig.mOnMeshPrefix = nullptr;
299 aConfig.mExternalRoute = nullptr;
300 aConfig.mLowpanContext = nullptr;
301 aConfig.mService->SetFrom(*service, *server);
302
303 iterator.MarkEntryAsNotNew();
304
305 ExitNow(error = kErrorNone);
306 }
307 }
308 }
309 }
310 }
311
312 exit:
313 return error;
314 }
315
ContainsOnMeshPrefix(const OnMeshPrefixConfig & aPrefix) const316 bool NetworkData::ContainsOnMeshPrefix(const OnMeshPrefixConfig &aPrefix) const
317 {
318 bool contains = false;
319 Iterator iterator = kIteratorInit;
320 OnMeshPrefixConfig prefix;
321
322 while (GetNextOnMeshPrefix(iterator, aPrefix.mRloc16, prefix) == kErrorNone)
323 {
324 if (prefix == aPrefix)
325 {
326 contains = true;
327 break;
328 }
329 }
330
331 return contains;
332 }
333
ContainsExternalRoute(const ExternalRouteConfig & aRoute) const334 bool NetworkData::ContainsExternalRoute(const ExternalRouteConfig &aRoute) const
335 {
336 bool contains = false;
337 Iterator iterator = kIteratorInit;
338 ExternalRouteConfig route;
339
340 while (GetNextExternalRoute(iterator, aRoute.mRloc16, route) == kErrorNone)
341 {
342 if (route == aRoute)
343 {
344 contains = true;
345 break;
346 }
347 }
348
349 return contains;
350 }
351
ContainsService(const ServiceConfig & aService) const352 bool NetworkData::ContainsService(const ServiceConfig &aService) const
353 {
354 bool contains = false;
355 Iterator iterator = kIteratorInit;
356 ServiceConfig service;
357
358 while (GetNextService(iterator, aService.GetServerConfig().mRloc16, service) == kErrorNone)
359 {
360 if (service == aService)
361 {
362 contains = true;
363 break;
364 }
365 }
366
367 return contains;
368 }
369
ContainsEntriesFrom(const NetworkData & aCompare,uint16_t aRloc16) const370 bool NetworkData::ContainsEntriesFrom(const NetworkData &aCompare, uint16_t aRloc16) const
371 {
372 bool contains = true;
373 Iterator iterator = kIteratorInit;
374
375 while (true)
376 {
377 Config config;
378 OnMeshPrefixConfig prefix;
379 ExternalRouteConfig route;
380 ServiceConfig service;
381
382 config.mOnMeshPrefix = &prefix;
383 config.mExternalRoute = &route;
384 config.mService = &service;
385 config.mLowpanContext = nullptr;
386
387 SuccessOrExit(aCompare.Iterate(iterator, aRloc16, config));
388
389 if (((config.mOnMeshPrefix != nullptr) && !ContainsOnMeshPrefix(*config.mOnMeshPrefix)) ||
390 ((config.mExternalRoute != nullptr) && !ContainsExternalRoute(*config.mExternalRoute)) ||
391 ((config.mService != nullptr) && !ContainsService(*config.mService)))
392 {
393 ExitNow(contains = false);
394 }
395 }
396
397 exit:
398 return contains;
399 }
400
FindPrefix(const uint8_t * aPrefix,uint8_t aPrefixLength) const401 const PrefixTlv *NetworkData::FindPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const
402 {
403 TlvIterator tlvIterator(mTlvs, mLength);
404 const PrefixTlv *prefixTlv;
405
406 while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
407 {
408 if (prefixTlv->IsEqual(aPrefix, aPrefixLength))
409 {
410 break;
411 }
412 }
413
414 return prefixTlv;
415 }
416
FindService(uint32_t aEnterpriseNumber,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode) const417 const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber,
418 const ServiceData &aServiceData,
419 ServiceMatchMode aServiceMatchMode) const
420 {
421 TlvIterator tlvIterator(mTlvs, mLength);
422 const ServiceTlv *serviceTlv;
423
424 while ((serviceTlv = tlvIterator.Iterate<ServiceTlv>()) != nullptr)
425 {
426 if (MatchService(*serviceTlv, aEnterpriseNumber, aServiceData, aServiceMatchMode))
427 {
428 break;
429 }
430 }
431
432 return serviceTlv;
433 }
434
FindNextService(const ServiceTlv * aPrevServiceTlv,uint32_t aEnterpriseNumber,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode) const435 const ServiceTlv *NetworkData::FindNextService(const ServiceTlv *aPrevServiceTlv,
436 uint32_t aEnterpriseNumber,
437 const ServiceData &aServiceData,
438 ServiceMatchMode aServiceMatchMode) const
439 {
440 const uint8_t *tlvs;
441 uint8_t length;
442
443 if (aPrevServiceTlv == nullptr)
444 {
445 tlvs = mTlvs;
446 length = mLength;
447 }
448 else
449 {
450 tlvs = reinterpret_cast<const uint8_t *>(aPrevServiceTlv->GetNext());
451 length = static_cast<uint8_t>((mTlvs + mLength) - tlvs);
452 }
453
454 return NetworkData(GetInstance(), tlvs, length).FindService(aEnterpriseNumber, aServiceData, aServiceMatchMode);
455 }
456
FindNextThreadService(const ServiceTlv * aPrevServiceTlv,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode) const457 const ServiceTlv *NetworkData::FindNextThreadService(const ServiceTlv *aPrevServiceTlv,
458 const ServiceData &aServiceData,
459 ServiceMatchMode aServiceMatchMode) const
460 {
461 return FindNextService(aPrevServiceTlv, ServiceTlv::kThreadEnterpriseNumber, aServiceData, aServiceMatchMode);
462 }
463
MatchService(const ServiceTlv & aServiceTlv,uint32_t aEnterpriseNumber,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode)464 bool NetworkData::MatchService(const ServiceTlv &aServiceTlv,
465 uint32_t aEnterpriseNumber,
466 const ServiceData &aServiceData,
467 ServiceMatchMode aServiceMatchMode)
468 {
469 bool match = false;
470 ServiceData serviceData;
471
472 VerifyOrExit(aServiceTlv.GetEnterpriseNumber() == aEnterpriseNumber);
473
474 aServiceTlv.GetServiceData(serviceData);
475
476 switch (aServiceMatchMode)
477 {
478 case kServiceExactMatch:
479 match = (serviceData == aServiceData);
480 break;
481
482 case kServicePrefixMatch:
483 match = serviceData.StartsWith(aServiceData);
484 break;
485 }
486
487 exit:
488 return match;
489 }
490
FindRlocs(BorderRouterFilter aBrFilter,RoleFilter aRoleFilter,Rlocs & aRlocs) const491 void NetworkData::FindRlocs(BorderRouterFilter aBrFilter, RoleFilter aRoleFilter, Rlocs &aRlocs) const
492 {
493 Iterator iterator = kIteratorInit;
494 OnMeshPrefixConfig prefix;
495 ExternalRouteConfig route;
496 ServiceConfig service;
497 Config config;
498
499 aRlocs.Clear();
500
501 while (true)
502 {
503 config.mOnMeshPrefix = &prefix;
504 config.mExternalRoute = &route;
505 config.mService = &service;
506 config.mLowpanContext = nullptr;
507
508 SuccessOrExit(Iterate(iterator, Mac::kShortAddrBroadcast, config));
509
510 if (config.mOnMeshPrefix != nullptr)
511 {
512 bool matches = true;
513
514 switch (aBrFilter)
515 {
516 case kAnyBrOrServer:
517 break;
518 case kBrProvidingExternalIpConn:
519 matches = prefix.mOnMesh && (prefix.mDefaultRoute || prefix.mDp);
520 break;
521 }
522
523 if (matches)
524 {
525 AddRloc16ToRlocs(prefix.mRloc16, aRlocs, aRoleFilter);
526 }
527 }
528 else if (config.mExternalRoute != nullptr)
529 {
530 AddRloc16ToRlocs(route.mRloc16, aRlocs, aRoleFilter);
531 }
532 else if (config.mService != nullptr)
533 {
534 switch (aBrFilter)
535 {
536 case kAnyBrOrServer:
537 AddRloc16ToRlocs(service.mServerConfig.mRloc16, aRlocs, aRoleFilter);
538 break;
539 case kBrProvidingExternalIpConn:
540 break;
541 }
542 }
543 }
544
545 exit:
546 return;
547 }
548
CountBorderRouters(RoleFilter aRoleFilter) const549 uint8_t NetworkData::CountBorderRouters(RoleFilter aRoleFilter) const
550 {
551 Rlocs rlocs;
552
553 FindRlocs(kBrProvidingExternalIpConn, aRoleFilter, rlocs);
554
555 return rlocs.GetLength();
556 }
557
ContainsBorderRouterWithRloc(uint16_t aRloc16) const558 bool NetworkData::ContainsBorderRouterWithRloc(uint16_t aRloc16) const
559 {
560 Rlocs rlocs;
561
562 FindRlocs(kBrProvidingExternalIpConn, kAnyRole, rlocs);
563
564 return rlocs.Contains(aRloc16);
565 }
566
AddRloc16ToRlocs(uint16_t aRloc16,Rlocs & aRlocs,RoleFilter aRoleFilter)567 void NetworkData::AddRloc16ToRlocs(uint16_t aRloc16, Rlocs &aRlocs, RoleFilter aRoleFilter)
568 {
569 switch (aRoleFilter)
570 {
571 case kAnyRole:
572 break;
573
574 case kRouterRoleOnly:
575 VerifyOrExit(Mle::IsRouterRloc16(aRloc16));
576 break;
577
578 case kChildRoleOnly:
579 VerifyOrExit(Mle::IsChildRloc16(aRloc16));
580 break;
581 }
582
583 VerifyOrExit(!aRlocs.Contains(aRloc16));
584 IgnoreError(aRlocs.PushBack(aRloc16));
585
586 exit:
587 return;
588 }
589
FindDomainIdFor(const Ip6::Prefix & aPrefix,uint8_t & aDomainId) const590 Error NetworkData::FindDomainIdFor(const Ip6::Prefix &aPrefix, uint8_t &aDomainId) const
591 {
592 Error error = kErrorNone;
593 const PrefixTlv *prefixTlv = FindPrefix(aPrefix);
594
595 VerifyOrExit(prefixTlv != nullptr, error = kErrorNotFound);
596 aDomainId = prefixTlv->GetDomainId();
597
598 exit:
599 return error;
600 }
601
602 //---------------------------------------------------------------------------------------------------------------------
603 // MutableNetworkData
604
RemoveTemporaryData(void)605 void MutableNetworkData::RemoveTemporaryData(void)
606 {
607 NetworkDataTlv *cur = GetTlvsStart();
608
609 while (cur < GetTlvsEnd())
610 {
611 bool shouldRemove = false;
612
613 switch (cur->GetType())
614 {
615 case NetworkDataTlv::kTypePrefix:
616 shouldRemove = RemoveTemporaryDataIn(*As<PrefixTlv>(cur));
617 break;
618
619 case NetworkDataTlv::kTypeService:
620 shouldRemove = RemoveTemporaryDataIn(*As<ServiceTlv>(cur));
621 break;
622
623 default:
624 shouldRemove = !cur->IsStable();
625 break;
626 }
627
628 if (shouldRemove)
629 {
630 RemoveTlv(cur);
631 continue;
632 }
633
634 cur = cur->GetNext();
635 }
636 }
637
RemoveTemporaryDataIn(PrefixTlv & aPrefix)638 bool MutableNetworkData::RemoveTemporaryDataIn(PrefixTlv &aPrefix)
639 {
640 NetworkDataTlv *cur = aPrefix.GetSubTlvs();
641
642 while (cur < aPrefix.GetNext())
643 {
644 if (cur->IsStable())
645 {
646 switch (cur->GetType())
647 {
648 case NetworkDataTlv::kTypeBorderRouter:
649 {
650 BorderRouterTlv *borderRouter = As<BorderRouterTlv>(cur);
651 ContextTlv *context = aPrefix.FindSubTlv<ContextTlv>();
652
653 // Replace p_border_router_16
654 for (BorderRouterEntry *entry = borderRouter->GetFirstEntry(); entry <= borderRouter->GetLastEntry();
655 entry = entry->GetNext())
656 {
657 if ((entry->IsDhcp() || entry->IsConfigure()) && (context != nullptr))
658 {
659 entry->SetRloc(0xfc00 | context->GetContextId());
660 }
661 else
662 {
663 entry->SetRloc(0xfffe);
664 }
665 }
666
667 break;
668 }
669
670 case NetworkDataTlv::kTypeHasRoute:
671 {
672 HasRouteTlv *hasRoute = As<HasRouteTlv>(cur);
673
674 // Replace r_border_router_16
675 for (HasRouteEntry *entry = hasRoute->GetFirstEntry(); entry <= hasRoute->GetLastEntry();
676 entry = entry->GetNext())
677 {
678 entry->SetRloc(0xfffe);
679 }
680
681 break;
682 }
683
684 default:
685 break;
686 }
687
688 // keep stable tlv
689 cur = cur->GetNext();
690 }
691 else
692 {
693 // remove temporary tlv
694 uint8_t subTlvSize = cur->GetSize();
695 RemoveTlv(cur);
696 aPrefix.SetSubTlvsLength(aPrefix.GetSubTlvsLength() - subTlvSize);
697 }
698 }
699
700 return (aPrefix.GetSubTlvsLength() == 0);
701 }
702
RemoveTemporaryDataIn(ServiceTlv & aService)703 bool MutableNetworkData::RemoveTemporaryDataIn(ServiceTlv &aService)
704 {
705 NetworkDataTlv *cur = aService.GetSubTlvs();
706
707 while (cur < aService.GetNext())
708 {
709 if (cur->IsStable())
710 {
711 switch (cur->GetType())
712 {
713 case NetworkDataTlv::kTypeServer:
714 As<ServerTlv>(cur)->SetServer16(Mle::ServiceAlocFromId(aService.GetServiceId()));
715 break;
716
717 default:
718 break;
719 }
720
721 // keep stable tlv
722 cur = cur->GetNext();
723 }
724 else
725 {
726 // remove temporary tlv
727 uint8_t subTlvSize = cur->GetSize();
728 RemoveTlv(cur);
729 aService.SetSubTlvsLength(aService.GetSubTlvsLength() - subTlvSize);
730 }
731 }
732
733 return (aService.GetSubTlvsLength() == 0);
734 }
735
AppendTlv(uint16_t aTlvSize)736 NetworkDataTlv *MutableNetworkData::AppendTlv(uint16_t aTlvSize)
737 {
738 NetworkDataTlv *tlv;
739
740 VerifyOrExit(CanInsert(aTlvSize), tlv = nullptr);
741
742 tlv = GetTlvsEnd();
743 mLength += static_cast<uint8_t>(aTlvSize);
744
745 exit:
746 return tlv;
747 }
748
Insert(void * aStart,uint8_t aLength)749 void MutableNetworkData::Insert(void *aStart, uint8_t aLength)
750 {
751 uint8_t *start = reinterpret_cast<uint8_t *>(aStart);
752
753 OT_ASSERT(CanInsert(aLength) && mTlvs <= start && start <= mTlvs + mLength);
754 memmove(start + aLength, start, mLength - static_cast<size_t>(start - mTlvs));
755 mLength += aLength;
756 }
757
Remove(void * aRemoveStart,uint8_t aRemoveLength)758 void MutableNetworkData::Remove(void *aRemoveStart, uint8_t aRemoveLength)
759 {
760 uint8_t *end = GetBytes() + mLength;
761 uint8_t *removeStart = reinterpret_cast<uint8_t *>(aRemoveStart);
762 uint8_t *removeEnd = removeStart + aRemoveLength;
763
764 OT_ASSERT((aRemoveLength <= mLength) && (GetBytes() <= removeStart) && (removeEnd <= end));
765
766 memmove(removeStart, removeEnd, static_cast<uint8_t>(end - removeEnd));
767 mLength -= aRemoveLength;
768 }
769
RemoveTlv(NetworkDataTlv * aTlv)770 void MutableNetworkData::RemoveTlv(NetworkDataTlv *aTlv) { Remove(aTlv, aTlv->GetSize()); }
771
772 } // namespace NetworkData
773 } // namespace ot
774