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