| /* |
| * Copyright (c) 2021, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** |
| * @file |
| * This file includes definition of Network Data Publisher. |
| */ |
| |
| #ifndef NETWORK_DATA_PUBLISHER_HPP_ |
| #define NETWORK_DATA_PUBLISHER_HPP_ |
| |
| #include "openthread-core-config.h" |
| |
| #if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE |
| |
| #if !OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE && !OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| #error "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE requires either OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE"\ |
| "or OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE" |
| #endif |
| |
| #include <openthread/netdata_publisher.h> |
| |
| #include "common/clearable.hpp" |
| #include "common/equatable.hpp" |
| #include "common/error.hpp" |
| #include "common/locator.hpp" |
| #include "common/non_copyable.hpp" |
| #include "common/notifier.hpp" |
| #include "common/string.hpp" |
| #include "common/timer.hpp" |
| #include "net/ip6_address.hpp" |
| #include "thread/network_data_types.hpp" |
| |
| namespace ot { |
| namespace NetworkData { |
| |
| /** |
| * This class implements the Network Data Publisher. |
| * |
| * It provides mechanisms to limit the number of similar Service and/or Prefix (on-mesh prefix or external route) |
| * entries in the Thread Network Data by monitoring the Network Data and managing if or when to add or remove entries. |
| * |
| */ |
| class Publisher : public InstanceLocator, private NonCopyable |
| { |
| friend class ot::Notifier; |
| |
| public: |
| /** |
| * This enumeration represents the events reported from the Publisher callbacks. |
| * |
| */ |
| enum Event : uint8_t |
| { |
| kEventEntryAdded = OT_NETDATA_PUBLISHER_EVENT_ENTRY_ADDED, ///< Entry is added to Network Data. |
| kEventEntryRemoved = OT_NETDATA_PUBLISHER_EVENT_ENTRY_REMOVED, ///< Entry is removed from Network Data. |
| }; |
| |
| /** |
| * This constructor initializes `Publisher` object. |
| * |
| * @param[in] aInstance A reference to the OpenThread instance. |
| * |
| */ |
| explicit Publisher(Instance &aInstance); |
| |
| #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
| |
| /** |
| * This type represents the callback function pointer used to notify when a "DNS/SRP Service" entry is added to or |
| * removed from the Thread Network Data. |
| * |
| * On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there |
| * are too many similar entries already present in the Network Data) or through an explicit call to unpublish the |
| * entry (i.e., a call to `UnpublishDnsSrpService()`). |
| * |
| */ |
| typedef otNetDataDnsSrpServicePublisherCallback DnsSrpServiceCallback; |
| |
| /** |
| * This method sets a callback for notifying when a published "DNS/SRP Service" is actually added to or removed |
| * from the Thread Network Data. |
| * |
| * A subsequent call to this method replaces any previously set callback function. |
| * |
| * @param[in] aCallback The callback function pointer (can be NULL if not needed). |
| * @param[in] aContext A pointer to application-specific context (used when @p aCallback is invoked). |
| * |
| */ |
| void SetDnsSrpServiceCallback(DnsSrpServiceCallback aCallback, void *aContext) |
| { |
| mDnsSrpServiceEntry.SetCallback(aCallback, aContext); |
| } |
| |
| /** |
| * This method requests "DNS/SRP Service Anycast Address" to be published in the Thread Network Data. |
| * |
| * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published |
| * (from earlier call to any of `PublishDnsSrpService{Type}()` methods). |
| * |
| * @param[in] aSequenceNumber The sequence number of DNS/SRP Anycast Service. |
| * |
| */ |
| void PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber) { mDnsSrpServiceEntry.PublishAnycast(aSequenceNumber); } |
| |
| /** |
| * This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data. |
| * |
| * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published |
| * (from earlier call to any of `PublishDnsSrpService{Type}()` methods). |
| * |
| * This method publishes the "DNS/SRP Service Unicast Address" by including the address and port info in the |
| * Service TLV data. |
| * |
| * @param[in] aAddress The DNS/SRP server address to publish. |
| * @param[in] aPort The SRP server port number to publish. |
| * |
| */ |
| void PublishDnsSrpServiceUnicast(const Ip6::Address &aAddress, uint16_t aPort) |
| { |
| mDnsSrpServiceEntry.PublishUnicast(aAddress, aPort); |
| } |
| |
| /** |
| * This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data. |
| * |
| * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published |
| * (from earlier call to any of `PublishDnsSrpService{Type}()` methods). |
| * |
| * Unlike the `PublishDnsSrpServiceUnicast(aAddress, aPort)` which requires the published address to be given and |
| * includes the info in the Service TLV data, this method uses the device's mesh-local EID and includes the info |
| * in the Server TLV data. |
| * |
| * @param[in] aPort The SRP server port number to publish. |
| * |
| */ |
| void PublishDnsSrpServiceUnicast(uint16_t aPort) { mDnsSrpServiceEntry.PublishUnicast(aPort); } |
| |
| /** |
| * This method indicates whether or not currently the "DNS/SRP Service" entry is added to the Thread Network Data. |
| * |
| * @retval TRUE The published DNS/SRP Service entry is added to the Thread Network Data. |
| * @retval FALSE The entry is not added to Thread Network Data or there is no entry to publish. |
| * |
| */ |
| bool IsDnsSrpServiceAdded(void) const { return mDnsSrpServiceEntry.IsAdded(); } |
| |
| /** |
| * This method unpublishes any previously added "DNS/SRP (Anycast or Unicast) Service" entry from the Thread |
| * Network Data. |
| * |
| */ |
| void UnpublishDnsSrpService(void) { mDnsSrpServiceEntry.Unpublish(); } |
| |
| #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| /** |
| * This type represents the callback function pointer used to notify when a prefix (on-mesh or external route) |
| * entry is added to or removed from the Thread Network Data. |
| * |
| * On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there |
| * are too many similar entries already present in the Network Data) or through an explicit call to unpublish the |
| * entry. |
| * |
| */ |
| typedef otNetDataPrefixPublisherCallback PrefixCallback; |
| |
| /** |
| * This method sets a callback for notifying when a published prefix entry is actually added to or removed from |
| * the Thread Network Data. |
| * |
| * A subsequent call to this method replaces any previously set callback function. |
| * |
| * @param[in] aCallback The callback function pointer (can be NULL if not needed). |
| * @param[in] aContext A pointer to application-specific context (used when @p aCallback is invoked). |
| * |
| */ |
| void SetPrefixCallback(PrefixCallback aCallback, void *aContext); |
| |
| /** |
| * This method requests an on-mesh prefix to be published in the Thread Network Data. |
| * |
| * Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`). |
| * |
| * @param[in] aConfig The on-mesh prefix config to publish. |
| * |
| * @retval kErrorNone The on-mesh prefix is published successfully. |
| * @retval kErrorInvalidArgs The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable). |
| * @retval kErrorAlready An entry with the same prefix is already in the published list. |
| * @retval kErrorNoBufs Could not allocate an entry for the new request. Publisher supports a limited number |
| * of entries (shared between on-mesh prefix and external route) determined by config |
| * `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`. |
| * |
| * |
| */ |
| Error PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig); |
| |
| /** |
| * This method requests an external route prefix to be published in the Thread Network Data. |
| * |
| * Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`). |
| * |
| * @param[in] aConfig The external route config to publish. |
| * |
| * @retval kErrorNone The external route is published successfully. |
| * @retval kErrorInvalidArgs The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable). |
| * @retval kErrorAlready An entry with the same prefix is already in the published list. |
| * @retval kErrorNoBufs Could not allocate an entry for the new request. Publisher supports a limited number |
| * of entries (shared between on-mesh prefix and external route) determined by config |
| * `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`. |
| * |
| * |
| */ |
| Error PublishExternalRoute(const ExternalRouteConfig &aConfig); |
| |
| /** |
| * This method indicates whether or not currently a published prefix entry (on-mesh or external route) is added to |
| * the Thread Network Data. |
| * |
| * @param[in] aPrefix The prefix to check. |
| * |
| * @retval TRUE The published prefix entry is added to the Thread Network Data. |
| * @retval FALSE The entry is not added to Thread Network Data or there is no matching entry to publish. |
| * |
| */ |
| bool IsPrefixAdded(const Ip6::Prefix &aPrefix) const; |
| |
| /** |
| * This method unpublishes a previously published prefix (on-mesh or external route). |
| * |
| * @param[in] aPrefix The prefix to unpublish. |
| * |
| * @retval kErrorNone The prefix was unpublished successfully. |
| * @retval kErrorNotFound Could not find the prefix in the published list. |
| * |
| */ |
| Error UnpublishPrefix(const Ip6::Prefix &aPrefix); |
| #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| private: |
| class Entry : public InstanceLocatorInit |
| { |
| protected: |
| enum State : uint8_t |
| { |
| kNoEntry, // Entry is unused (there is no entry). |
| kToAdd, // Entry is ready to be added, monitoring network data to decide if/when to add it. |
| kAdding, // Entry is being added in network data (random wait interval before add). |
| kAdded, // Entry is added in network data, monitoring to determine if/when to remove. |
| kRemoving, // Entry is being removed from network data (random wait interval before remove). |
| }; |
| |
| // All intervals are in milliseconds. |
| static constexpr uint32_t kMaxDelayToAdd = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_ADD; |
| static constexpr uint32_t kMaxDelayToRemove = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE; |
| static constexpr uint32_t kExtraDelayToRemovePeferred = |
| OPENTHREAD_CONFIG_NETDATA_PUBLISHER_EXTRA_DELAY_TIME_TO_REMOVE_PREFERRED; |
| |
| static constexpr uint16_t kInfoStringSize = 50; |
| |
| typedef String<kInfoStringSize> InfoString; |
| |
| Entry(void) |
| : mState(kNoEntry) |
| { |
| } |
| |
| void Init(Instance &aInstance) { InstanceLocatorInit::Init(aInstance); } |
| State GetState(void) const { return mState; } |
| void SetState(State aState); |
| const TimeMilli &GetUpdateTime(void) const { return mUpdateTime; } |
| bool IsPreferred(uint16_t aRloc16) const; |
| void UpdateState(uint8_t aNumEntries, uint8_t aNumPreferredEntries, uint8_t aDesiredNumEntries); |
| bool HandleTimer(void); |
| InfoString ToString(bool aIncludeState = true) const; |
| |
| public: |
| bool IsAdded(void) const { return (mState == kAdded); } |
| |
| private: |
| bool Add(void); |
| bool Remove(State aNextState); |
| void LogUpdateTime(void) const; |
| static const char *StateToString(State aState); |
| |
| TimeMilli mUpdateTime; |
| State mState; |
| }; |
| |
| #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
| class DnsSrpServiceEntry : public Entry, private NonCopyable |
| { |
| friend class Entry; |
| |
| public: |
| explicit DnsSrpServiceEntry(Instance &aInstance); |
| void SetCallback(DnsSrpServiceCallback aCallback, void *aContext); |
| void PublishAnycast(uint8_t aSequenceNumber); |
| void PublishUnicast(const Ip6::Address &aAddress, uint16_t aPort); |
| void PublishUnicast(uint16_t aPort); |
| void Unpublish(void); |
| bool HandleTimer(void) { return Entry::HandleTimer(); } |
| bool HandleNotifierEvents(Events aEvents); |
| |
| private: |
| static constexpr uint8_t kDesiredNumAnycast = |
| OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ANYCAST_DNS_SRP_SERVICE_ENTRIES; |
| |
| static constexpr uint8_t kDesiredNumUnicast = |
| OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_UNICAST_DNS_SRP_SERVICE_ENTRIES; |
| |
| enum Type : uint8_t |
| { |
| kTypeAnycast, |
| kTypeUnicast, |
| kTypeUnicastMeshLocalEid, |
| }; |
| |
| class Info : public Clearable<Info>, public Equatable<Info> |
| { |
| public: |
| Info(void) { Clear(); } |
| Type GetType(void) const { return mType; } |
| uint8_t GetSequenceNumber(void) const { return static_cast<uint8_t>(mPortOrSeqNumber); } |
| uint16_t GetPort(void) const { return mPortOrSeqNumber; } |
| const Ip6::Address &GetAddress(void) const { return mAddress; } |
| void SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; } |
| |
| static Info InfoAnycast(uint8_t aSequenceNumber) { return Info(kTypeAnycast, aSequenceNumber); } |
| static Info InfoUnicast(Type aType, const Ip6::Address &aAddress, uint16_t aPort) |
| { |
| return Info(aType, aPort, &aAddress); |
| } |
| |
| private: |
| Info(Type aType, uint16_t aPortOrSeqNumber, const Ip6::Address *aAddress = nullptr); |
| |
| Ip6::Address mAddress; |
| uint16_t mPortOrSeqNumber; |
| Type mType; |
| }; |
| |
| Type GetType(void) const { return mInfo.GetType(); } |
| void Publish(const Info &aInfo); |
| bool Add(void); |
| bool Remove(State aNextState); |
| void Notify(Event aEvent) const; |
| void Process(void); |
| void CountAnycastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const; |
| void CountUnicastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const; |
| |
| Info mInfo; |
| DnsSrpServiceCallback mCallback; |
| void * mCallbackContext; |
| }; |
| #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| // Max number of prefix (on-mesh or external route) entries. |
| static constexpr uint16_t kMaxPrefixEntries = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES; |
| |
| class PrefixEntry : public Entry, private NonCopyable |
| { |
| friend class Entry; |
| |
| public: |
| void Init(Instance &aInstance) { Entry::Init(aInstance); } |
| bool IsInUse(void) const { return GetState() != kNoEntry; } |
| bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; } |
| void Publish(const OnMeshPrefixConfig &aConfig); |
| void Publish(const ExternalRouteConfig &aConfig); |
| void Unpublish(void); |
| bool HandleTimer(void) { return Entry::HandleTimer(); } |
| void HandleNotifierEvents(Events aEvents); |
| |
| private: |
| static constexpr uint8_t kDesiredNumOnMeshPrefix = |
| OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ON_MESH_PREFIX_ENTRIES; |
| |
| static constexpr uint8_t kDesiredNumExternalRoute = |
| OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_EXTERNAL_ROUTE_ENTRIES; |
| |
| enum Type : uint8_t |
| { |
| kTypeOnMeshPrefix, |
| kTypeExternalRoute, |
| }; |
| |
| bool Add(void); |
| Error AddOnMeshPrefix(void); |
| Error AddExternalRoute(void); |
| bool Remove(State aNextState); |
| void Process(void); |
| void CountOnMeshPrefixEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const; |
| void CountExternalRouteEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const; |
| |
| Type mType; |
| Ip6::Prefix mPrefix; |
| uint16_t mFlags; |
| }; |
| #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
| bool IsADnsSrpServiceEntry(const Entry &aEntry) const { return (&aEntry == &mDnsSrpServiceEntry); } |
| #endif |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| Error AllocatePrefixEntry(const Ip6::Prefix &aPrefix, PrefixEntry *&aEntry); |
| PrefixEntry * FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix); |
| const PrefixEntry *FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix) const; |
| bool IsAPrefixEntry(const Entry &aEntry) const; |
| void NotifyPrefixEntryChange(Event aEvent, const Ip6::Prefix &aPrefix) const; |
| #endif |
| |
| TimerMilli &GetTimer(void) { return mTimer; } |
| void HandleNotifierEvents(Events aEvents); |
| static void HandleTimer(Timer &aTimer); |
| void HandleTimer(void); |
| |
| #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
| DnsSrpServiceEntry mDnsSrpServiceEntry; |
| #endif |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| PrefixEntry mPrefixEntries[kMaxPrefixEntries]; |
| PrefixCallback mPrefixCallback; |
| void * mPrefixCallbackContext; |
| #endif |
| |
| TimerMilli mTimer; |
| }; |
| |
| } // namespace NetworkData |
| } // namespace ot |
| |
| #endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE |
| |
| #endif // NETWORK_DATA_PUBLISHER_HPP_ |