1 /*
2  *  Copyright (c) 2021, 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 includes definition of Network Data Publisher.
32  */
33 
34 #ifndef NETWORK_DATA_PUBLISHER_HPP_
35 #define NETWORK_DATA_PUBLISHER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
40 
41 #if !OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE && !OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
42 #error "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE requires either OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE"\
43             "or OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE"
44 #endif
45 
46 #include <openthread/netdata_publisher.h>
47 
48 #include "common/clearable.hpp"
49 #include "common/equatable.hpp"
50 #include "common/error.hpp"
51 #include "common/locator.hpp"
52 #include "common/non_copyable.hpp"
53 #include "common/notifier.hpp"
54 #include "common/string.hpp"
55 #include "common/timer.hpp"
56 #include "net/ip6_address.hpp"
57 #include "thread/network_data_types.hpp"
58 
59 namespace ot {
60 namespace NetworkData {
61 
62 /**
63  * This class implements the Network Data Publisher.
64  *
65  * It provides mechanisms to limit the number of similar Service and/or Prefix (on-mesh prefix or external route)
66  * entries in the Thread Network Data by monitoring the Network Data and managing if or when to add or remove entries.
67  *
68  */
69 class Publisher : public InstanceLocator, private NonCopyable
70 {
71     friend class ot::Notifier;
72 
73 public:
74     /**
75      * This enumeration represents the events reported from the Publisher callbacks.
76      *
77      */
78     enum Event : uint8_t
79     {
80         kEventEntryAdded   = OT_NETDATA_PUBLISHER_EVENT_ENTRY_ADDED,   ///< Entry is added to Network Data.
81         kEventEntryRemoved = OT_NETDATA_PUBLISHER_EVENT_ENTRY_REMOVED, ///< Entry is removed from Network Data.
82     };
83 
84     /**
85      * This constructor initializes `Publisher` object.
86      *
87      * @param[in]  aInstance     A reference to the OpenThread instance.
88      *
89      */
90     explicit Publisher(Instance &aInstance);
91 
92 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
93 
94     /**
95      * This type represents the callback function pointer used to notify when a "DNS/SRP Service" entry is added to or
96      * removed from the Thread Network Data.
97      *
98      * On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there
99      * are too many similar entries already present in the Network Data) or through an explicit call to unpublish the
100      * entry (i.e., a call to `UnpublishDnsSrpService()`).
101      *
102      */
103     typedef otNetDataDnsSrpServicePublisherCallback DnsSrpServiceCallback;
104 
105     /**
106      * This method sets a callback for notifying when a published "DNS/SRP Service" is actually added to or removed
107      * from the Thread Network Data.
108      *
109      * A subsequent call to this method replaces any previously set callback function.
110      *
111      * @param[in] aCallback        The callback function pointer (can be NULL if not needed).
112      * @param[in] aContext         A pointer to application-specific context (used when @p aCallback is invoked).
113      *
114      */
SetDnsSrpServiceCallback(DnsSrpServiceCallback aCallback,void * aContext)115     void SetDnsSrpServiceCallback(DnsSrpServiceCallback aCallback, void *aContext)
116     {
117         mDnsSrpServiceEntry.SetCallback(aCallback, aContext);
118     }
119 
120     /**
121      * This method requests "DNS/SRP Service Anycast Address" to be published in the Thread Network Data.
122      *
123      * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published
124      * (from earlier call to any of `PublishDnsSrpService{Type}()` methods).
125      *
126      * @param[in] aSequenceNumber  The sequence number of DNS/SRP Anycast Service.
127      *
128      */
PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber)129     void PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber) { mDnsSrpServiceEntry.PublishAnycast(aSequenceNumber); }
130 
131     /**
132      * This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data.
133      *
134      * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published
135      * (from earlier call to any of `PublishDnsSrpService{Type}()` methods).
136      *
137      * This method publishes the "DNS/SRP Service Unicast Address" by including the address and port info in the
138      * Service TLV data.
139      *
140      * @param[in] aAddress   The DNS/SRP server address to publish.
141      * @param[in] aPort      The SRP server port number to publish.
142      *
143      */
PublishDnsSrpServiceUnicast(const Ip6::Address & aAddress,uint16_t aPort)144     void PublishDnsSrpServiceUnicast(const Ip6::Address &aAddress, uint16_t aPort)
145     {
146         mDnsSrpServiceEntry.PublishUnicast(aAddress, aPort);
147     }
148 
149     /**
150      * This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data.
151      *
152      * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published
153      * (from earlier call to any of `PublishDnsSrpService{Type}()` methods).
154      *
155      * Unlike the `PublishDnsSrpServiceUnicast(aAddress, aPort)` which requires the published address to be given and
156      * includes the info in the Service TLV data, this method uses the device's mesh-local EID and includes the info
157      * in the Server TLV data.
158      *
159      * @param[in] aPort      The SRP server port number to publish.
160      *
161      */
PublishDnsSrpServiceUnicast(uint16_t aPort)162     void PublishDnsSrpServiceUnicast(uint16_t aPort) { mDnsSrpServiceEntry.PublishUnicast(aPort); }
163 
164     /**
165      * This method indicates whether or not currently the "DNS/SRP Service" entry is added to the Thread Network Data.
166      *
167      * @retval TRUE    The published DNS/SRP Service entry is added to the Thread Network Data.
168      * @retval FLASE   The entry is not added to Thread Network Data or there is no entry to publish.
169      *
170      */
IsDnsSrpServiceAdded(void) const171     bool IsDnsSrpServiceAdded(void) const { return mDnsSrpServiceEntry.IsAdded(); }
172 
173     /**
174      * This method unpublishes any previously added "DNS/SRP (Anycast or Unicast) Service" entry from the Thread
175      * Network Data.
176      *
177      */
UnpublishDnsSrpService(void)178     void UnpublishDnsSrpService(void) { mDnsSrpServiceEntry.Unpublish(); }
179 
180 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
181 
182 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
183     /**
184      * This type represents the callback function pointer used to notify when a prefix (on-mesh or external route)
185      * entry is added to or removed from the Thread Network Data.
186      *
187      * On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there
188      * are too many similar entries already present in the Network Data) or through an explicit call to unpublish the
189      * entry.
190      *
191      */
192     typedef otNetDataPrefixPublisherCallback PrefixCallback;
193 
194     /**
195      * This method sets a callback for notifying when a published prefix entry is actually added to or removed from
196      * the Thread Network Data.
197      *
198      * A subsequent call to this method replaces any previously set callback function.
199      *
200      * @param[in] aCallback        The callback function pointer (can be NULL if not needed).
201      * @param[in] aContext         A pointer to application-specific context (used when @p aCallback is invoked).
202      *
203      */
204     void SetPrefixCallback(PrefixCallback aCallback, void *aContext);
205 
206     /**
207      * This method requests an on-mesh prefix to be published in the Thread Network Data.
208      *
209      * Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`).
210      *
211      * @param[in] aConfig         The on-mesh prefix config to publish.
212      *
213      * @retval kErrorNone         The on-mesh prefix is published successfully.
214      * @retval kErrorInvalidArgs  The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
215      * @retval kErrorAlready      An entry with the same prefix is already in the published list.
216      * @retval kErrorNoBufs       Could not allocate an entry for the new request. Publisher supports a limited number
217      *                            of entries (shared between on-mesh prefix and external route) determined by config
218      *                            `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.
219      *
220      *
221      */
222     Error PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig);
223 
224     /**
225      * This method requests an external route prefix to be published in the Thread Network Data.
226      *
227      * Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`).
228      *
229      * @param[in] aConfig         The external route config to publish.
230      *
231      * @retval kErrorNone         The external route is published successfully.
232      * @retval kErrorInvalidArgs  The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
233      * @retval kErrorAlready      An entry with the same prefix is already in the published list.
234      * @retval kErrorNoBufs       Could not allocate an entry for the new request. Publisher supports a limited number
235      *                            of entries (shared between on-mesh prefix and external route) determined by config
236      *                            `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.
237      *
238      *
239      */
240     Error PublishExternalRoute(const ExternalRouteConfig &aConfig);
241 
242     /**
243      * This method indicates whether or not currently a published prefix entry (on-mesh or external route) is added to
244      * the Thread Network Data.
245      *
246      * @param[in] aPrefix   The prefix to check.
247      *
248      * @retval TRUE    The published prefix entry is added to the Thread Network Data.
249      * @retval FLASE   The entry is not added to Thread Network Data or there is no matching entry to publish.
250      *
251      */
252     bool IsPrefixAdded(const Ip6::Prefix &aPrefix) const;
253 
254     /**
255      * This method unpublishes a previously published prefix (on-mesh or external route).
256      *
257      * @param[in] aPrefix       The prefix to unpublish.
258      *
259      * @retval kErrorNone       The prefix was unpublished successfully.
260      * @retval kErrorNotFound   Could not find the prefix in the published list.
261      *
262      */
263     Error UnpublishPrefix(const Ip6::Prefix &aPrefix);
264 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
265 
266 private:
267     class Entry : public InstanceLocatorInit
268     {
269     protected:
270         enum State : uint8_t
271         {
272             kNoEntry,  // Entry is unused (there is no entry).
273             kToAdd,    // Entry is ready to be added, monitoring network data to decide if/when to add it.
274             kAdding,   // Entry is being added in network data (random wait interval before add).
275             kAdded,    // Entry is added in network data, monitoring to determine if/when to remove.
276             kRemoving, // Entry is being removed from network data (random wait interval before remove).
277         };
278 
279         // All intervals are in milliseconds.
280         static constexpr uint32_t kMaxDelayToAdd    = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_ADD;
281         static constexpr uint32_t kMaxDelayToRemove = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE;
282         static constexpr uint32_t kExtraDelayToRemovePeferred =
283             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_EXTRA_DELAY_TIME_TO_REMOVE_PREFERRED;
284 
285         static constexpr uint16_t kInfoStringSize = 50;
286 
287         typedef String<kInfoStringSize> InfoString;
288 
Entry(void)289         Entry(void)
290             : mState(kNoEntry)
291         {
292         }
293 
Init(Instance & aInstance)294         void             Init(Instance &aInstance) { InstanceLocatorInit::Init(aInstance); }
GetState(void) const295         State            GetState(void) const { return mState; }
296         void             SetState(State aState);
GetUpdateTime(void) const297         const TimeMilli &GetUpdateTime(void) const { return mUpdateTime; }
298         bool             IsPreferred(uint16_t aRloc16) const;
299         void             UpdateState(uint8_t aNumEntries, uint8_t aNumPreferredEntries, uint8_t aDesiredNumEntries);
300         bool             HandleTimer(void);
301         InfoString       ToString(bool aIncludeState = true) const;
302 
303     public:
IsAdded(void) const304         bool IsAdded(void) const { return (mState == kAdded); }
305 
306     private:
307         bool               Add(void);
308         bool               Remove(State aNextState);
309         void               LogUpdateTime(void) const;
310         static const char *StateToString(State aState);
311 
312         TimeMilli mUpdateTime;
313         State     mState;
314     };
315 
316 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
317     class DnsSrpServiceEntry : public Entry, private NonCopyable
318     {
319         friend class Entry;
320 
321     public:
322         explicit DnsSrpServiceEntry(Instance &aInstance);
323         void SetCallback(DnsSrpServiceCallback aCallback, void *aContext);
324         void PublishAnycast(uint8_t aSequenceNumber);
325         void PublishUnicast(const Ip6::Address &aAddress, uint16_t aPort);
326         void PublishUnicast(uint16_t aPort);
327         void Unpublish(void);
HandleTimer(void)328         bool HandleTimer(void) { return Entry::HandleTimer(); }
329         bool HandleNotifierEvents(Events aEvents);
330 
331     private:
332         static constexpr uint8_t kDesiredNumAnycast =
333             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ANYCAST_DNS_SRP_SERVICE_ENTRIES;
334 
335         static constexpr uint8_t kDesiredNumUnicast =
336             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_UNICAST_DNS_SRP_SERVICE_ENTRIES;
337 
338         enum Type : uint8_t
339         {
340             kTypeAnycast,
341             kTypeUnicast,
342             kTypeUnicastMeshLocalEid,
343         };
344 
345         class Info : public Clearable<Info>, public Equatable<Info>
346         {
347         public:
Info(void)348             Info(void) { Clear(); }
GetType(void) const349             Type                GetType(void) const { return mType; }
GetSequenceNumber(void) const350             uint8_t             GetSequenceNumber(void) const { return static_cast<uint8_t>(mPortOrSeqNumber); }
GetPort(void) const351             uint16_t            GetPort(void) const { return mPortOrSeqNumber; }
GetAddress(void) const352             const Ip6::Address &GetAddress(void) const { return mAddress; }
SetAddress(const Ip6::Address & aAddress)353             void                SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; }
354 
InfoAnycast(uint8_t aSequenceNumber)355             static Info InfoAnycast(uint8_t aSequenceNumber) { return Info(kTypeAnycast, aSequenceNumber); }
InfoUnicast(Type aType,const Ip6::Address & aAddress,uint16_t aPort)356             static Info InfoUnicast(Type aType, const Ip6::Address &aAddress, uint16_t aPort)
357             {
358                 return Info(aType, aPort, &aAddress);
359             }
360 
361         private:
362             Info(Type aType, uint16_t aPortOrSeqNumber, const Ip6::Address *aAddress = nullptr);
363 
364             Ip6::Address mAddress;
365             uint16_t     mPortOrSeqNumber;
366             Type         mType;
367         };
368 
GetType(void) const369         Type GetType(void) const { return mInfo.GetType(); }
370         void Publish(const Info &aInfo);
371         bool Add(void);
372         bool Remove(State aNextState);
373         void Notify(Event aEvent) const;
374         void Process(void);
375         void CountAnycastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
376         void CountUnicastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
377 
378         Info                  mInfo;
379         DnsSrpServiceCallback mCallback;
380         void *                mCallbackContext;
381     };
382 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
383 
384 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
385     // Max number of prefix (on-mesh or external route) entries.
386     static constexpr uint16_t kMaxPrefixEntries = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES;
387 
388     class PrefixEntry : public Entry, private NonCopyable
389     {
390         friend class Entry;
391 
392     public:
Init(Instance & aInstance)393         void Init(Instance &aInstance) { Entry::Init(aInstance); }
IsInUse(void) const394         bool IsInUse(void) const { return GetState() != kNoEntry; }
Matches(const Ip6::Prefix & aPrefix) const395         bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
396         void Publish(const OnMeshPrefixConfig &aConfig);
397         void Publish(const ExternalRouteConfig &aConfig);
398         void Unpublish(void);
HandleTimer(void)399         bool HandleTimer(void) { return Entry::HandleTimer(); }
400         void HandleNotifierEvents(Events aEvents);
401 
402     private:
403         static constexpr uint8_t kDesiredNumOnMeshPrefix =
404             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ON_MESH_PREFIX_ENTRIES;
405 
406         static constexpr uint8_t kDesiredNumExternalRoute =
407             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_EXTERNAL_ROUTE_ENTRIES;
408 
409         enum Type : uint8_t
410         {
411             kTypeOnMeshPrefix,
412             kTypeExternalRoute,
413         };
414 
415         bool  Add(void);
416         Error AddOnMeshPrefix(void);
417         Error AddExternalRoute(void);
418         bool  Remove(State aNextState);
419         void  Process(void);
420         void  CountOnMeshPrefixEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
421         void  CountExternalRouteEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
422 
423         Type        mType;
424         Ip6::Prefix mPrefix;
425         uint16_t    mFlags;
426     };
427 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
428 
429 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
IsADnsSrpServiceEntry(const Entry & aEntry) const430     bool IsADnsSrpServiceEntry(const Entry &aEntry) const { return (&aEntry == &mDnsSrpServiceEntry); }
431 #endif
432 
433 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
434     Error              AllocatePrefixEntry(const Ip6::Prefix &aPrefix, PrefixEntry *&aEntry);
435     PrefixEntry *      FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix);
436     const PrefixEntry *FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix) const;
437     bool               IsAPrefixEntry(const Entry &aEntry) const;
438     void               NotifyPrefixEntryChange(Event aEvent, const Ip6::Prefix &aPrefix) const;
439 #endif
440 
GetTimer(void)441     TimerMilli &GetTimer(void) { return mTimer; }
442     void        HandleNotifierEvents(Events aEvents);
443     static void HandleTimer(Timer &aTimer);
444     void        HandleTimer(void);
445 
446 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
447     DnsSrpServiceEntry mDnsSrpServiceEntry;
448 #endif
449 
450 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
451     PrefixEntry    mPrefixEntries[kMaxPrefixEntries];
452     PrefixCallback mPrefixCallback;
453     void *         mPrefixCallbackContext;
454 #endif
455 
456     TimerMilli mTimer;
457 };
458 
459 } // namespace NetworkData
460 } // namespace ot
461 
462 #endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
463 
464 #endif // NETWORK_DATA_PUBLISHER_HPP_
465