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