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