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/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.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