• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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