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