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