• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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