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 
CopyNetworkData(Type aType,uint8_t * aData,uint8_t & aDataLength) const53 Error NetworkData::CopyNetworkData(Type aType, uint8_t *aData, uint8_t &aDataLength) const
54 {
55     Error              error;
56     MutableNetworkData netDataCopy(GetInstance(), aData, 0, aDataLength);
57 
58     SuccessOrExit(error = CopyNetworkData(aType, netDataCopy));
59     aDataLength = netDataCopy.GetLength();
60 
61 exit:
62     return error;
63 }
64 
CopyNetworkData(Type aType,MutableNetworkData & aNetworkData) const65 Error NetworkData::CopyNetworkData(Type aType, MutableNetworkData &aNetworkData) const
66 {
67     Error error = kErrorNone;
68 
69     VerifyOrExit(aNetworkData.GetSize() >= mLength, error = kErrorNoBufs);
70 
71     memcpy(aNetworkData.GetBytes(), mTlvs, mLength);
72     aNetworkData.SetLength(mLength);
73 
74     if (aType == kStableSubset)
75     {
76         aNetworkData.RemoveTemporaryData();
77     }
78 
79 exit:
80     return error;
81 }
82 
GetNextOnMeshPrefix(Iterator & aIterator,OnMeshPrefixConfig & aConfig) const83 Error NetworkData::GetNextOnMeshPrefix(Iterator &aIterator, OnMeshPrefixConfig &aConfig) const
84 {
85     return GetNextOnMeshPrefix(aIterator, Mac::kShortAddrBroadcast, aConfig);
86 }
87 
GetNextOnMeshPrefix(Iterator & aIterator,uint16_t aRloc16,OnMeshPrefixConfig & aConfig) const88 Error NetworkData::GetNextOnMeshPrefix(Iterator &aIterator, uint16_t aRloc16, OnMeshPrefixConfig &aConfig) const
89 {
90     Config config;
91 
92     config.mOnMeshPrefix  = &aConfig;
93     config.mExternalRoute = nullptr;
94     config.mService       = nullptr;
95     config.mLowpanContext = nullptr;
96 
97     return Iterate(aIterator, aRloc16, config);
98 }
99 
GetNextExternalRoute(Iterator & aIterator,ExternalRouteConfig & aConfig) const100 Error NetworkData::GetNextExternalRoute(Iterator &aIterator, ExternalRouteConfig &aConfig) const
101 {
102     return GetNextExternalRoute(aIterator, Mac::kShortAddrBroadcast, aConfig);
103 }
104 
GetNextExternalRoute(Iterator & aIterator,uint16_t aRloc16,ExternalRouteConfig & aConfig) const105 Error NetworkData::GetNextExternalRoute(Iterator &aIterator, uint16_t aRloc16, ExternalRouteConfig &aConfig) const
106 {
107     Config config;
108 
109     config.mOnMeshPrefix  = nullptr;
110     config.mExternalRoute = &aConfig;
111     config.mService       = nullptr;
112     config.mLowpanContext = nullptr;
113 
114     return Iterate(aIterator, aRloc16, config);
115 }
116 
GetNextService(Iterator & aIterator,ServiceConfig & aConfig) const117 Error NetworkData::GetNextService(Iterator &aIterator, ServiceConfig &aConfig) const
118 {
119     return GetNextService(aIterator, Mac::kShortAddrBroadcast, aConfig);
120 }
121 
GetNextService(Iterator & aIterator,uint16_t aRloc16,ServiceConfig & aConfig) const122 Error NetworkData::GetNextService(Iterator &aIterator, uint16_t aRloc16, ServiceConfig &aConfig) const
123 {
124     Config config;
125 
126     config.mOnMeshPrefix  = nullptr;
127     config.mExternalRoute = nullptr;
128     config.mService       = &aConfig;
129     config.mLowpanContext = nullptr;
130 
131     return Iterate(aIterator, aRloc16, config);
132 }
133 
GetNextLowpanContextInfo(Iterator & aIterator,LowpanContextInfo & aContextInfo) const134 Error NetworkData::GetNextLowpanContextInfo(Iterator &aIterator, LowpanContextInfo &aContextInfo) const
135 {
136     Config config;
137 
138     config.mOnMeshPrefix  = nullptr;
139     config.mExternalRoute = nullptr;
140     config.mService       = nullptr;
141     config.mLowpanContext = &aContextInfo;
142 
143     return Iterate(aIterator, Mac::kShortAddrBroadcast, config);
144 }
145 
Iterate(Iterator & aIterator,uint16_t aRloc16,Config & aConfig) const146 Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfig) const
147 {
148     // Iterate to the next entry in Network Data matching `aRloc16`
149     // (can be set to `Mac::kShortAddrBroadcast` to allow any RLOC).
150     // The `aIterator` is used to track and save the current position.
151     // On input, the non-`nullptr` pointer members in `aConfig` specify
152     // the Network Data entry types (`mOnMeshPrefix`, `mExternalRoute`,
153     // `mService`) to iterate over. On successful exit, the `aConfig`
154     // is updated such that only one member pointer is not `nullptr`
155     // indicating the type of entry and the non-`nullptr` config is
156     // updated with the entry info.
157 
158     Error               error = kErrorNotFound;
159     NetworkDataIterator iterator(aIterator);
160 
161     for (const NetworkDataTlv *cur;
162          cur = iterator.GetTlv(mTlvs), (cur + 1 <= GetTlvsEnd()) && (cur->GetNext() <= GetTlvsEnd());
163          iterator.AdvanceTlv(mTlvs))
164     {
165         const NetworkDataTlv *subTlvs = nullptr;
166 
167         switch (cur->GetType())
168         {
169         case NetworkDataTlv::kTypePrefix:
170             if ((aConfig.mOnMeshPrefix != nullptr) || (aConfig.mExternalRoute != nullptr) ||
171                 (aConfig.mLowpanContext != nullptr))
172             {
173                 subTlvs = As<PrefixTlv>(cur)->GetSubTlvs();
174             }
175             break;
176         case NetworkDataTlv::kTypeService:
177             if (aConfig.mService != nullptr)
178             {
179                 subTlvs = As<ServiceTlv>(cur)->GetSubTlvs();
180             }
181             break;
182         default:
183             break;
184         }
185 
186         if (subTlvs == nullptr)
187         {
188             continue;
189         }
190 
191         for (const NetworkDataTlv *subCur; subCur = iterator.GetSubTlv(subTlvs),
192                                            (subCur + 1 <= cur->GetNext()) && (subCur->GetNext() <= cur->GetNext());
193              iterator.AdvanceSubTlv(subTlvs))
194         {
195             if (cur->GetType() == NetworkDataTlv::kTypePrefix)
196             {
197                 const PrefixTlv *prefixTlv = As<PrefixTlv>(cur);
198 
199                 switch (subCur->GetType())
200                 {
201                 case NetworkDataTlv::kTypeBorderRouter:
202                 {
203                     const BorderRouterTlv *borderRouter = As<BorderRouterTlv>(subCur);
204 
205                     if (aConfig.mOnMeshPrefix == nullptr)
206                     {
207                         continue;
208                     }
209 
210                     for (uint8_t index; (index = iterator.GetAndAdvanceIndex()) < borderRouter->GetNumEntries();)
211                     {
212                         if (aRloc16 == Mac::kShortAddrBroadcast || borderRouter->GetEntry(index)->GetRloc() == aRloc16)
213                         {
214                             const BorderRouterEntry *borderRouterEntry = borderRouter->GetEntry(index);
215 
216                             aConfig.mExternalRoute = nullptr;
217                             aConfig.mService       = nullptr;
218                             aConfig.mLowpanContext = nullptr;
219                             aConfig.mOnMeshPrefix->SetFrom(*prefixTlv, *borderRouter, *borderRouterEntry);
220 
221                             ExitNow(error = kErrorNone);
222                         }
223                     }
224 
225                     break;
226                 }
227 
228                 case NetworkDataTlv::kTypeHasRoute:
229                 {
230                     const HasRouteTlv *hasRoute = As<HasRouteTlv>(subCur);
231 
232                     if (aConfig.mExternalRoute == nullptr)
233                     {
234                         continue;
235                     }
236 
237                     for (uint8_t index; (index = iterator.GetAndAdvanceIndex()) < hasRoute->GetNumEntries();)
238                     {
239                         if (aRloc16 == Mac::kShortAddrBroadcast || hasRoute->GetEntry(index)->GetRloc() == aRloc16)
240                         {
241                             const HasRouteEntry *hasRouteEntry = hasRoute->GetEntry(index);
242 
243                             aConfig.mOnMeshPrefix  = nullptr;
244                             aConfig.mService       = nullptr;
245                             aConfig.mLowpanContext = nullptr;
246                             aConfig.mExternalRoute->SetFrom(GetInstance(), *prefixTlv, *hasRoute, *hasRouteEntry);
247 
248                             ExitNow(error = kErrorNone);
249                         }
250                     }
251 
252                     break;
253                 }
254 
255                 case NetworkDataTlv::kTypeContext:
256                 {
257                     const ContextTlv *contextTlv = As<ContextTlv>(subCur);
258 
259                     if (aConfig.mLowpanContext == nullptr)
260                     {
261                         continue;
262                     }
263 
264                     if (iterator.IsNewEntry())
265                     {
266                         aConfig.mOnMeshPrefix  = nullptr;
267                         aConfig.mExternalRoute = nullptr;
268                         aConfig.mService       = nullptr;
269                         aConfig.mLowpanContext->SetFrom(*prefixTlv, *contextTlv);
270 
271                         iterator.MarkEntryAsNotNew();
272                         ExitNow(error = kErrorNone);
273                     }
274 
275                     break;
276                 }
277 
278                 default:
279                     break;
280                 }
281             }
282             else // cur is `ServiceTLv`
283             {
284                 const ServiceTlv *service = As<ServiceTlv>(cur);
285 
286                 if (aConfig.mService == nullptr)
287                 {
288                     continue;
289                 }
290 
291                 if (subCur->GetType() == NetworkDataTlv::kTypeServer)
292                 {
293                     const ServerTlv *server = As<ServerTlv>(subCur);
294 
295                     if (!iterator.IsNewEntry())
296                     {
297                         continue;
298                     }
299 
300                     if ((aRloc16 == Mac::kShortAddrBroadcast) || (server->GetServer16() == aRloc16))
301                     {
302                         aConfig.mOnMeshPrefix  = nullptr;
303                         aConfig.mExternalRoute = nullptr;
304                         aConfig.mLowpanContext = nullptr;
305                         aConfig.mService->SetFrom(*service, *server);
306 
307                         iterator.MarkEntryAsNotNew();
308 
309                         ExitNow(error = kErrorNone);
310                     }
311                 }
312             }
313         }
314     }
315 
316 exit:
317     return error;
318 }
319 
ContainsOnMeshPrefix(const OnMeshPrefixConfig & aPrefix) const320 bool NetworkData::ContainsOnMeshPrefix(const OnMeshPrefixConfig &aPrefix) const
321 {
322     bool               contains = false;
323     Iterator           iterator = kIteratorInit;
324     OnMeshPrefixConfig prefix;
325 
326     while (GetNextOnMeshPrefix(iterator, aPrefix.mRloc16, prefix) == kErrorNone)
327     {
328         if (prefix == aPrefix)
329         {
330             contains = true;
331             break;
332         }
333     }
334 
335     return contains;
336 }
337 
ContainsExternalRoute(const ExternalRouteConfig & aRoute) const338 bool NetworkData::ContainsExternalRoute(const ExternalRouteConfig &aRoute) const
339 {
340     bool                contains = false;
341     Iterator            iterator = kIteratorInit;
342     ExternalRouteConfig route;
343 
344     while (GetNextExternalRoute(iterator, aRoute.mRloc16, route) == kErrorNone)
345     {
346         if (route == aRoute)
347         {
348             contains = true;
349             break;
350         }
351     }
352 
353     return contains;
354 }
355 
ContainsService(const ServiceConfig & aService) const356 bool NetworkData::ContainsService(const ServiceConfig &aService) const
357 {
358     bool          contains = false;
359     Iterator      iterator = kIteratorInit;
360     ServiceConfig service;
361 
362     while (GetNextService(iterator, aService.GetServerConfig().mRloc16, service) == kErrorNone)
363     {
364         if (service == aService)
365         {
366             contains = true;
367             break;
368         }
369     }
370 
371     return contains;
372 }
373 
ContainsEntriesFrom(const NetworkData & aCompare,uint16_t aRloc16) const374 bool NetworkData::ContainsEntriesFrom(const NetworkData &aCompare, uint16_t aRloc16) const
375 {
376     bool     contains = true;
377     Iterator iterator = kIteratorInit;
378 
379     while (true)
380     {
381         Config              config;
382         OnMeshPrefixConfig  prefix;
383         ExternalRouteConfig route;
384         ServiceConfig       service;
385 
386         config.mOnMeshPrefix  = &prefix;
387         config.mExternalRoute = &route;
388         config.mService       = &service;
389         config.mLowpanContext = nullptr;
390 
391         SuccessOrExit(aCompare.Iterate(iterator, aRloc16, config));
392 
393         if (((config.mOnMeshPrefix != nullptr) && !ContainsOnMeshPrefix(*config.mOnMeshPrefix)) ||
394             ((config.mExternalRoute != nullptr) && !ContainsExternalRoute(*config.mExternalRoute)) ||
395             ((config.mService != nullptr) && !ContainsService(*config.mService)))
396         {
397             ExitNow(contains = false);
398         }
399     }
400 
401 exit:
402     return contains;
403 }
404 
RemoveTemporaryData(void)405 void MutableNetworkData::RemoveTemporaryData(void)
406 {
407     NetworkDataTlv *cur = GetTlvsStart();
408 
409     while (cur < GetTlvsEnd())
410     {
411         switch (cur->GetType())
412         {
413         case NetworkDataTlv::kTypePrefix:
414         {
415             PrefixTlv *prefix = As<PrefixTlv>(cur);
416 
417             RemoveTemporaryDataIn(*prefix);
418 
419             if (prefix->GetSubTlvsLength() == 0)
420             {
421                 RemoveTlv(cur);
422                 continue;
423             }
424 
425             break;
426         }
427 
428         case NetworkDataTlv::kTypeService:
429         {
430             ServiceTlv *service = As<ServiceTlv>(cur);
431 
432             RemoveTemporaryDataIn(*service);
433 
434             if (service->GetSubTlvsLength() == 0)
435             {
436                 RemoveTlv(cur);
437                 continue;
438             }
439 
440             break;
441         }
442 
443         default:
444             // remove temporary tlv
445             if (!cur->IsStable())
446             {
447                 RemoveTlv(cur);
448                 continue;
449             }
450 
451             break;
452         }
453 
454         cur = cur->GetNext();
455     }
456 }
457 
RemoveTemporaryDataIn(PrefixTlv & aPrefix)458 void MutableNetworkData::RemoveTemporaryDataIn(PrefixTlv &aPrefix)
459 {
460     NetworkDataTlv *cur = aPrefix.GetSubTlvs();
461 
462     while (cur < aPrefix.GetNext())
463     {
464         if (cur->IsStable())
465         {
466             switch (cur->GetType())
467             {
468             case NetworkDataTlv::kTypeBorderRouter:
469             {
470                 BorderRouterTlv *borderRouter = As<BorderRouterTlv>(cur);
471                 ContextTlv      *context      = aPrefix.FindSubTlv<ContextTlv>();
472 
473                 // Replace p_border_router_16
474                 for (BorderRouterEntry *entry = borderRouter->GetFirstEntry(); entry <= borderRouter->GetLastEntry();
475                      entry                    = entry->GetNext())
476                 {
477                     if ((entry->IsDhcp() || entry->IsConfigure()) && (context != nullptr))
478                     {
479                         entry->SetRloc(0xfc00 | context->GetContextId());
480                     }
481                     else
482                     {
483                         entry->SetRloc(0xfffe);
484                     }
485                 }
486 
487                 break;
488             }
489 
490             case NetworkDataTlv::kTypeHasRoute:
491             {
492                 HasRouteTlv *hasRoute = As<HasRouteTlv>(cur);
493 
494                 // Replace r_border_router_16
495                 for (HasRouteEntry *entry = hasRoute->GetFirstEntry(); entry <= hasRoute->GetLastEntry();
496                      entry                = entry->GetNext())
497                 {
498                     entry->SetRloc(0xfffe);
499                 }
500 
501                 break;
502             }
503 
504             default:
505                 break;
506             }
507 
508             // keep stable tlv
509             cur = cur->GetNext();
510         }
511         else
512         {
513             // remove temporary tlv
514             uint8_t subTlvSize = cur->GetSize();
515             RemoveTlv(cur);
516             aPrefix.SetSubTlvsLength(aPrefix.GetSubTlvsLength() - subTlvSize);
517         }
518     }
519 }
520 
RemoveTemporaryDataIn(ServiceTlv & aService)521 void MutableNetworkData::RemoveTemporaryDataIn(ServiceTlv &aService)
522 {
523     NetworkDataTlv *cur = aService.GetSubTlvs();
524 
525     while (cur < aService.GetNext())
526     {
527         if (cur->IsStable())
528         {
529             switch (cur->GetType())
530             {
531             case NetworkDataTlv::kTypeServer:
532                 As<ServerTlv>(cur)->SetServer16(Mle::ServiceAlocFromId(aService.GetServiceId()));
533                 break;
534 
535             default:
536                 break;
537             }
538 
539             // keep stable tlv
540             cur = cur->GetNext();
541         }
542         else
543         {
544             // remove temporary tlv
545             uint8_t subTlvSize = cur->GetSize();
546             RemoveTlv(cur);
547             aService.SetSubTlvsLength(aService.GetSubTlvsLength() - subTlvSize);
548         }
549     }
550 }
551 
FindPrefix(const uint8_t * aPrefix,uint8_t aPrefixLength) const552 const PrefixTlv *NetworkData::FindPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const
553 {
554     TlvIterator      tlvIterator(mTlvs, mLength);
555     const PrefixTlv *prefixTlv;
556 
557     while ((prefixTlv = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
558     {
559         if (prefixTlv->IsEqual(aPrefix, aPrefixLength))
560         {
561             break;
562         }
563     }
564 
565     return prefixTlv;
566 }
567 
FindService(uint32_t aEnterpriseNumber,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode) const568 const ServiceTlv *NetworkData::FindService(uint32_t           aEnterpriseNumber,
569                                            const ServiceData &aServiceData,
570                                            ServiceMatchMode   aServiceMatchMode) const
571 {
572     TlvIterator       tlvIterator(mTlvs, mLength);
573     const ServiceTlv *serviceTlv;
574 
575     while ((serviceTlv = tlvIterator.Iterate<ServiceTlv>()) != nullptr)
576     {
577         if (MatchService(*serviceTlv, aEnterpriseNumber, aServiceData, aServiceMatchMode))
578         {
579             break;
580         }
581     }
582 
583     return serviceTlv;
584 }
585 
FindNextService(const ServiceTlv * aPrevServiceTlv,uint32_t aEnterpriseNumber,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode) const586 const ServiceTlv *NetworkData::FindNextService(const ServiceTlv  *aPrevServiceTlv,
587                                                uint32_t           aEnterpriseNumber,
588                                                const ServiceData &aServiceData,
589                                                ServiceMatchMode   aServiceMatchMode) const
590 {
591     const uint8_t *tlvs;
592     uint8_t        length;
593 
594     if (aPrevServiceTlv == nullptr)
595     {
596         tlvs   = mTlvs;
597         length = mLength;
598     }
599     else
600     {
601         tlvs   = reinterpret_cast<const uint8_t *>(aPrevServiceTlv->GetNext());
602         length = static_cast<uint8_t>((mTlvs + mLength) - tlvs);
603     }
604 
605     return NetworkData(GetInstance(), tlvs, length).FindService(aEnterpriseNumber, aServiceData, aServiceMatchMode);
606 }
607 
FindNextThreadService(const ServiceTlv * aPrevServiceTlv,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode) const608 const ServiceTlv *NetworkData::FindNextThreadService(const ServiceTlv  *aPrevServiceTlv,
609                                                      const ServiceData &aServiceData,
610                                                      ServiceMatchMode   aServiceMatchMode) const
611 {
612     return FindNextService(aPrevServiceTlv, ServiceTlv::kThreadEnterpriseNumber, aServiceData, aServiceMatchMode);
613 }
614 
MatchService(const ServiceTlv & aServiceTlv,uint32_t aEnterpriseNumber,const ServiceData & aServiceData,ServiceMatchMode aServiceMatchMode)615 bool NetworkData::MatchService(const ServiceTlv  &aServiceTlv,
616                                uint32_t           aEnterpriseNumber,
617                                const ServiceData &aServiceData,
618                                ServiceMatchMode   aServiceMatchMode)
619 {
620     bool        match = false;
621     ServiceData serviceData;
622 
623     VerifyOrExit(aServiceTlv.GetEnterpriseNumber() == aEnterpriseNumber);
624 
625     aServiceTlv.GetServiceData(serviceData);
626 
627     switch (aServiceMatchMode)
628     {
629     case kServiceExactMatch:
630         match = (serviceData == aServiceData);
631         break;
632 
633     case kServicePrefixMatch:
634         match = serviceData.StartsWith(aServiceData);
635         break;
636     }
637 
638 exit:
639     return match;
640 }
641 
AppendTlv(uint16_t aTlvSize)642 NetworkDataTlv *MutableNetworkData::AppendTlv(uint16_t aTlvSize)
643 {
644     NetworkDataTlv *tlv;
645 
646     VerifyOrExit(CanInsert(aTlvSize), tlv = nullptr);
647 
648     tlv = GetTlvsEnd();
649     mLength += static_cast<uint8_t>(aTlvSize);
650 
651 exit:
652     return tlv;
653 }
654 
Insert(void * aStart,uint8_t aLength)655 void MutableNetworkData::Insert(void *aStart, uint8_t aLength)
656 {
657     uint8_t *start = reinterpret_cast<uint8_t *>(aStart);
658 
659     OT_ASSERT(CanInsert(aLength) && mTlvs <= start && start <= mTlvs + mLength);
660     memmove(start + aLength, start, mLength - static_cast<size_t>(start - mTlvs));
661     mLength += aLength;
662 }
663 
Remove(void * aRemoveStart,uint8_t aRemoveLength)664 void MutableNetworkData::Remove(void *aRemoveStart, uint8_t aRemoveLength)
665 {
666     uint8_t *end         = GetBytes() + mLength;
667     uint8_t *removeStart = reinterpret_cast<uint8_t *>(aRemoveStart);
668     uint8_t *removeEnd   = removeStart + aRemoveLength;
669 
670     OT_ASSERT((aRemoveLength <= mLength) && (GetBytes() <= removeStart) && (removeEnd <= end));
671 
672     memmove(removeStart, removeEnd, static_cast<uint8_t>(end - removeEnd));
673     mLength -= aRemoveLength;
674 }
675 
RemoveTlv(NetworkDataTlv * aTlv)676 void MutableNetworkData::RemoveTlv(NetworkDataTlv *aTlv) { Remove(aTlv, aTlv->GetSize()); }
677 
GetNextServer(Iterator & aIterator,uint16_t & aRloc16) const678 Error NetworkData::GetNextServer(Iterator &aIterator, uint16_t &aRloc16) const
679 {
680     Error               error;
681     OnMeshPrefixConfig  prefixConfig;
682     ExternalRouteConfig routeConfig;
683     ServiceConfig       serviceConfig;
684     Config              config;
685 
686     config.mOnMeshPrefix  = &prefixConfig;
687     config.mExternalRoute = &routeConfig;
688     config.mService       = &serviceConfig;
689     config.mLowpanContext = nullptr;
690 
691     SuccessOrExit(error = Iterate(aIterator, Mac::kShortAddrBroadcast, config));
692 
693     if (config.mOnMeshPrefix != nullptr)
694     {
695         aRloc16 = config.mOnMeshPrefix->mRloc16;
696     }
697     else if (config.mExternalRoute != nullptr)
698     {
699         aRloc16 = config.mExternalRoute->mRloc16;
700     }
701     else if (config.mService != nullptr)
702     {
703         aRloc16 = config.mService->mServerConfig.mRloc16;
704     }
705     else
706     {
707         OT_ASSERT(false);
708     }
709 
710 exit:
711     return error;
712 }
713 
FindBorderRouters(RoleFilter aRoleFilter,uint16_t aRlocs[],uint8_t & aRlocsLength) const714 Error NetworkData::FindBorderRouters(RoleFilter aRoleFilter, uint16_t aRlocs[], uint8_t &aRlocsLength) const
715 {
716     class Rlocs // Wrapper over an array of RLOC16s.
717     {
718     public:
719         Rlocs(RoleFilter aRoleFilter, uint16_t *aRlocs, uint8_t aRlocsMaxLength)
720             : mRoleFilter(aRoleFilter)
721             , mRlocs(aRlocs)
722             , mLength(0)
723             , mMaxLength(aRlocsMaxLength)
724         {
725         }
726 
727         uint8_t GetLength(void) const { return mLength; }
728 
729         Error AddRloc16(uint16_t aRloc16)
730         {
731             // Add `aRloc16` into the array if it matches `RoleFilter` and
732             // it is not in the array already. If we need to add the `aRloc16`
733             // but there is no more room in the array, return `kErrorNoBufs`.
734 
735             Error   error = kErrorNone;
736             uint8_t index;
737 
738             switch (mRoleFilter)
739             {
740             case kAnyRole:
741                 break;
742 
743             case kRouterRoleOnly:
744                 VerifyOrExit(Mle::IsActiveRouter(aRloc16));
745                 break;
746 
747             case kChildRoleOnly:
748                 VerifyOrExit(!Mle::IsActiveRouter(aRloc16));
749                 break;
750             }
751 
752             for (index = 0; index < mLength; index++)
753             {
754                 if (mRlocs[index] == aRloc16)
755                 {
756                     break;
757                 }
758             }
759 
760             if (index == mLength)
761             {
762                 VerifyOrExit(mLength < mMaxLength, error = kErrorNoBufs);
763                 mRlocs[mLength++] = aRloc16;
764             }
765 
766         exit:
767             return error;
768         }
769 
770     private:
771         RoleFilter mRoleFilter;
772         uint16_t  *mRlocs;
773         uint8_t    mLength;
774         uint8_t    mMaxLength;
775     };
776 
777     Error               error = kErrorNone;
778     Rlocs               rlocs(aRoleFilter, aRlocs, aRlocsLength);
779     Iterator            iterator = kIteratorInit;
780     ExternalRouteConfig route;
781     OnMeshPrefixConfig  prefix;
782 
783     while (GetNextExternalRoute(iterator, route) == kErrorNone)
784     {
785         SuccessOrExit(error = rlocs.AddRloc16(route.mRloc16));
786     }
787 
788     iterator = kIteratorInit;
789 
790     while (GetNextOnMeshPrefix(iterator, prefix) == kErrorNone)
791     {
792         if (!prefix.mDefaultRoute || !prefix.mOnMesh)
793         {
794             continue;
795         }
796 
797         SuccessOrExit(error = rlocs.AddRloc16(prefix.mRloc16));
798     }
799 
800 exit:
801     aRlocsLength = rlocs.GetLength();
802     return error;
803 }
804 
CountBorderRouters(RoleFilter aRoleFilter) const805 uint8_t NetworkData::CountBorderRouters(RoleFilter aRoleFilter) const
806 {
807     // We use an over-estimate of max number of border routers in the
808     // Network Data using the facts that network data is limited to 254
809     // bytes and that an external route entry uses at minimum 3 bytes
810     // for RLOC16 and flag, so `ceil(254/3) = 85`.
811 
812     static constexpr uint16_t kMaxRlocs = 85;
813 
814     uint16_t rlocs[kMaxRlocs];
815     uint8_t  rlocsLength = kMaxRlocs;
816 
817     SuccessOrAssert(FindBorderRouters(aRoleFilter, rlocs, rlocsLength));
818 
819     return rlocsLength;
820 }
821 
ContainsBorderRouterWithRloc(uint16_t aRloc16) const822 bool NetworkData::ContainsBorderRouterWithRloc(uint16_t aRloc16) const
823 {
824     bool                contains = false;
825     Iterator            iterator = kIteratorInit;
826     ExternalRouteConfig route;
827     OnMeshPrefixConfig  prefix;
828 
829     while (GetNextExternalRoute(iterator, route) == kErrorNone)
830     {
831         if (route.mRloc16 == aRloc16)
832         {
833             ExitNow(contains = true);
834         }
835     }
836 
837     iterator = kIteratorInit;
838 
839     while (GetNextOnMeshPrefix(iterator, prefix) == kErrorNone)
840     {
841         if ((prefix.mRloc16 == aRloc16) && prefix.mOnMesh && (prefix.mDefaultRoute || prefix.mDp))
842         {
843             ExitNow(contains = true);
844         }
845     }
846 
847 exit:
848     return contains;
849 }
850 
851 } // namespace NetworkData
852 } // namespace ot
853