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 includes definitions for Thread EID-to-RLOC mapping and caching. 32 */ 33 34 #ifndef ADDRESS_RESOLVER_HPP_ 35 #define ADDRESS_RESOLVER_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include "coap/coap.hpp" 40 #include "common/as_core_type.hpp" 41 #include "common/linked_list.hpp" 42 #include "common/locator.hpp" 43 #include "common/non_copyable.hpp" 44 #include "common/time_ticker.hpp" 45 #include "common/timer.hpp" 46 #include "mac/mac.hpp" 47 #include "net/icmp6.hpp" 48 #include "net/udp6.hpp" 49 #include "thread/thread_tlvs.hpp" 50 #include "thread/tmf.hpp" 51 52 namespace ot { 53 54 /** 55 * @addtogroup core-arp 56 * 57 * @brief 58 * This module includes definitions for Thread EID-to-RLOC mapping and caching. 59 * 60 * @{ 61 */ 62 63 /** 64 * Implements the EID-to-RLOC mapping and caching. 65 */ 66 class AddressResolver : public InstanceLocator, private NonCopyable 67 { 68 friend class TimeTicker; 69 friend class Tmf::Agent; 70 71 class CacheEntry; 72 class CacheEntryList; 73 74 public: 75 /** 76 * Represents an iterator used for iterating through the EID cache table entries. 77 */ 78 class Iterator : public otCacheEntryIterator, public Clearable<Iterator> 79 { 80 friend class AddressResolver; 81 82 static constexpr uint8_t kListIndex = 0; 83 static constexpr uint8_t kEntryIndex = 1; 84 GetEntry(void) const85 const CacheEntry *GetEntry(void) const { return static_cast<const CacheEntry *>(mData[kEntryIndex]); } SetEntry(const CacheEntry * aEntry)86 void SetEntry(const CacheEntry *aEntry) { mData[kEntryIndex] = aEntry; } GetList(void) const87 const CacheEntryList *GetList(void) const { return static_cast<const CacheEntryList *>(mData[kListIndex]); } SetList(const CacheEntryList * aList)88 void SetList(const CacheEntryList *aList) { mData[kListIndex] = aList; } 89 }; 90 91 /** 92 * Represents an EID cache entry. 93 */ 94 class EntryInfo : public otCacheEntryInfo, public Clearable<EntryInfo> 95 { 96 public: 97 enum State : uint8_t ///< Entry state. 98 { 99 kStateCached = OT_CACHE_ENTRY_STATE_CACHED, ///< Cached and in-use. 100 kStateSnooped = OT_CACHE_ENTRY_STATE_SNOOPED, ///< Created by snoop optimization. 101 kStateQuery = OT_CACHE_ENTRY_STATE_QUERY, ///< Ongoing query for the EID. 102 kStateRetryQuery = OT_CACHE_ENTRY_STATE_RETRY_QUERY, ///< In retry wait mode. 103 }; 104 }; 105 106 /** 107 * Initializes the object. 108 */ 109 explicit AddressResolver(Instance &aInstance); 110 111 #if OPENTHREAD_FTD 112 /** 113 * Clears the EID-to-RLOC cache. 114 */ 115 void Clear(void); 116 117 /** 118 * Gets the information about the next EID cache entry (using an iterator). 119 * 120 * @param[out] aInfo An `EntryInfo` where the EID cache entry information is placed. 121 * @param[in,out] aIterator An iterator. It will be updated to point to the next entry on success. 122 * To get the first entry, initialize the iterator by setting all its fields to zero. 123 * e.g., `memset` the the iterator structure to zero. 124 * 125 * @retval kErrorNone Successfully populated @p aInfo with the info for the next EID cache entry. 126 * @retval kErrorNotFound No more entries in the address cache table. 127 */ 128 Error GetNextCacheEntry(EntryInfo &aInfo, Iterator &aIterator) const; 129 130 /** 131 * Removes the EID-to-RLOC cache entries corresponding to an RLOC16. 132 * 133 * @param[in] aRloc16 The RLOC16 address. 134 */ 135 void RemoveEntriesForRloc16(uint16_t aRloc16); 136 137 /** 138 * Removes all EID-to-RLOC cache entries associated with a Router ID. 139 * 140 * @param[in] aRouterId The Router ID. 141 */ 142 void RemoveEntriesForRouterId(uint8_t aRouterId); 143 144 /** 145 * Removes the cache entry for the EID. 146 * 147 * @param[in] aEid A reference to the EID. 148 */ 149 void RemoveEntryForAddress(const Ip6::Address &aEid); 150 151 /** 152 * Replaces all EID-to-RLOC cache entries corresponding to an old RLOC16 with a new RLOC16. 153 * 154 * @param[in] aOldRloc16 The old RLOC16. 155 * @param[in] aNewRloc16 The new RLOC16. 156 */ 157 void ReplaceEntriesForRloc16(uint16_t aOldRloc16, uint16_t aNewRloc16); 158 159 /** 160 * Updates an existing entry or adds a snooped cache entry for a given EID. 161 * 162 * The method is intended to add an entry for snoop optimization (inspection of a received message to create a 163 * cache entry mapping an EID to a RLOC). 164 * 165 * @param[in] aEid A reference to the EID. 166 * @param[in] aRloc16 The RLOC16 corresponding to @p aEid. 167 * @param[in] aDest The short MAC address destination of the received snooped message. 168 */ 169 void UpdateSnoopedCacheEntry(const Ip6::Address &aEid, uint16_t aRloc16, uint16_t aDest); 170 171 /** 172 * Returns the RLOC16 for a given EID, initiates an Address Query if the mapping is not known. 173 * 174 * @param[in] aEid A reference to the EID. 175 * @param[out] aRloc16 The RLOC16 corresponding to @p aEid. 176 * 177 * @retval kErrorNone Successfully provided the RLOC16. 178 * @retval kErrorAddressQuery Initiated an Address Query if allowed. 179 * @retval kErrorDrop Earlier Address Query for the EID timed out. In retry timeout interval. 180 * @retval kErrorNoBufs Insufficient buffer space available to send Address Query. 181 */ Resolve(const Ip6::Address & aEid,uint16_t & aRloc16)182 Error Resolve(const Ip6::Address &aEid, uint16_t &aRloc16) 183 { 184 return Resolve(aEid, aRloc16, /* aAllowAddressQuery */ true); 185 } 186 187 /** 188 * Looks up the RLOC16 for a given EID in the address cache. 189 * 190 * When a cache entry is successfully looked up using this method, it will be marked as "cached and in-use". 191 * Specifically, a snooped entry (`kStateSnooped`) will be marked as cached (`kStateCached`). 192 * 193 * @param[in] aEid A reference to the EID to lookup. 194 * 195 * @returns The RLOC16 mapping to @p aEid or `Mle::kInvalidRloc16` if it is not found in the address cache. 196 */ 197 uint16_t LookUp(const Ip6::Address &aEid); 198 199 /** 200 * Restarts any ongoing address queries. 201 * 202 * Any existing address queries will be restarted as if they are being sent for the first time. 203 */ 204 void RestartAddressQueries(void); 205 206 /** 207 * Sends an Address Notification (ADDR_NTF.ans) message. 208 * 209 * @param[in] aTarget The target address of the ADDR_NTF.ans message. 210 * @param[in] aMeshLocalIid The ML-IID of the ADDR_NTF.ans message. 211 * @param[in] aLastTransactionTimeTlv A pointer to the Last Transaction Time if the ADDR_NTF.ans message contains 212 * a Last Transaction Time TLV. 213 * @param[in] aDestination The destination to send the ADDR_NTF.ans message. 214 */ 215 void SendAddressQueryResponse(const Ip6::Address &aTarget, 216 const Ip6::InterfaceIdentifier &aMeshLocalIid, 217 const uint32_t *aLastTransactionTimeTlv, 218 const Ip6::Address &aDestination); 219 220 /** 221 * Sends an Address Error Notification (ADDR_ERR.ntf) message. 222 * 223 * @param aTarget The target address of the ADDR_ERR.ntf message. 224 * @param aMeshLocalIid The ML-IID of the ADDR_ERR.ntf message. 225 * @param aDestination The destination to send the ADDR_ERR.ntf message. 226 */ 227 void SendAddressError(const Ip6::Address &aTarget, 228 const Ip6::InterfaceIdentifier &aMeshLocalIid, 229 const Ip6::Address *aDestination); 230 231 private: 232 static constexpr uint16_t kCacheEntries = OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_ENTRIES; 233 static constexpr uint16_t kMaxNonEvictableSnoopedEntries = 234 OT_MAX(1, OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES); 235 236 // All time/delay values are in seconds 237 static constexpr uint16_t kAddressQueryTimeout = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT; 238 static constexpr uint16_t kAddressQueryInitialRetryDelay = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY; 239 static constexpr uint16_t kAddressQueryMaxRetryDelay = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY; 240 static constexpr uint16_t kSnoopBlockEvictionTimeout = OPENTHREAD_CONFIG_TMF_SNOOP_CACHE_ENTRY_TIMEOUT; 241 242 class CacheEntry : public InstanceLocatorInit 243 { 244 public: 245 void Init(Instance &aInstance); 246 247 CacheEntry *GetNext(void); 248 const CacheEntry *GetNext(void) const; 249 void SetNext(CacheEntry *aEntry); 250 GetTarget(void) const251 const Ip6::Address &GetTarget(void) const { return mTarget; } SetTarget(const Ip6::Address & aTarget)252 void SetTarget(const Ip6::Address &aTarget) { mTarget = aTarget; } 253 GetRloc16(void) const254 uint16_t GetRloc16(void) const { return mRloc16; } SetRloc16(uint16_t aRloc16)255 void SetRloc16(uint16_t aRloc16) { mRloc16 = aRloc16; } 256 GetMeshLocalIid(void) const257 const Ip6::InterfaceIdentifier &GetMeshLocalIid(void) const { return mInfo.mCached.mMeshLocalIid; } SetMeshLocalIid(const Ip6::InterfaceIdentifier & aIid)258 void SetMeshLocalIid(const Ip6::InterfaceIdentifier &aIid) { mInfo.mCached.mMeshLocalIid = aIid; } 259 GetLastTransactionTime(void) const260 uint32_t GetLastTransactionTime(void) const { return mInfo.mCached.mLastTransactionTime; } SetLastTransactionTime(uint32_t aTime)261 void SetLastTransactionTime(uint32_t aTime) { mInfo.mCached.mLastTransactionTime = aTime; } IsLastTransactionTimeValid(void) const262 bool IsLastTransactionTimeValid(void) const { return GetLastTransactionTime() != kInvalidLastTransTime; } MarkLastTransactionTimeAsInvalid(void)263 void MarkLastTransactionTimeAsInvalid(void) { SetLastTransactionTime(kInvalidLastTransTime); } 264 DecrementTimeout(void)265 void DecrementTimeout(void) { mInfo.mOther.mTimeout--; } IsTimeoutZero(void) const266 bool IsTimeoutZero(void) const { return mInfo.mOther.mTimeout == 0; } GetTimeout(void) const267 uint16_t GetTimeout(void) const { return mInfo.mOther.mTimeout; } SetTimeout(uint16_t aTimeout)268 void SetTimeout(uint16_t aTimeout) { mInfo.mOther.mTimeout = aTimeout; } 269 DecrementFreshnessTimeout(void)270 void DecrementFreshnessTimeout(void) { mFreshnessTimeout--; } IsFreshnessTimeoutZero(void) const271 bool IsFreshnessTimeoutZero(void) const { return mFreshnessTimeout == 0; } ResetFreshnessTimeout(void)272 void ResetFreshnessTimeout(void) { mFreshnessTimeout = kFreshnessTimeout; } 273 GetRetryDelay(void) const274 uint16_t GetRetryDelay(void) const { return mInfo.mOther.mRetryDelay; } SetRetryDelay(uint16_t aDelay)275 void SetRetryDelay(uint16_t aDelay) { mInfo.mOther.mRetryDelay = aDelay; } 276 CanEvict(void) const277 bool CanEvict(void) const { return mInfo.mOther.mCanEvict; } SetCanEvict(bool aCanEvict)278 void SetCanEvict(bool aCanEvict) { mInfo.mOther.mCanEvict = aCanEvict; } 279 IsInRampDown(void) const280 bool IsInRampDown(void) const { return mInfo.mOther.mRampDown; } SetRampDown(bool aRampDown)281 void SetRampDown(bool aRampDown) { mInfo.mOther.mRampDown = aRampDown; } 282 Matches(const Ip6::Address & aEid) const283 bool Matches(const Ip6::Address &aEid) const { return GetTarget() == aEid; } 284 285 private: 286 static constexpr uint16_t kNoNextIndex = 0x3fff; // `mNextIndex` value when at end of list. 287 static constexpr uint32_t kInvalidLastTransTime = 0xffffffff; // Value when `mLastTransactionTime` is invalid. 288 static constexpr uint8_t kFreshnessTimeout = 3; 289 290 static_assert(kCacheEntries < kNoNextIndex, "kCacheEntries is too large and does not fit in 14 bit index"); 291 292 Ip6::Address mTarget; 293 uint16_t mRloc16; 294 uint16_t mNextIndex : 14; 295 uint8_t mFreshnessTimeout : 2; 296 297 union 298 { 299 struct 300 { 301 uint32_t mLastTransactionTime; 302 Ip6::InterfaceIdentifier mMeshLocalIid; 303 } mCached; 304 305 struct 306 { 307 uint16_t mTimeout; 308 uint16_t mRetryDelay; 309 bool mCanEvict; 310 bool mRampDown; 311 } mOther; 312 313 } mInfo; 314 }; 315 316 typedef Pool<CacheEntry, kCacheEntries> CacheEntryPool; 317 318 class CacheEntryList : public LinkedList<CacheEntry> 319 { 320 }; 321 322 enum EntryChange : uint8_t 323 { 324 kEntryAdded, 325 kEntryUpdated, 326 kEntryRemoved, 327 }; 328 329 enum Reason : uint8_t 330 { 331 kReasonQueryRequest, 332 kReasonSnoop, 333 kReasonReceivedNotification, 334 kReasonRemovingRouterId, 335 kReasonRemovingRloc16, 336 kReasonReceivedIcmpDstUnreachNoRoute, 337 kReasonEvictingForNewEntry, 338 kReasonRemovingEid, 339 }; 340 GetCacheEntryPool(void)341 CacheEntryPool &GetCacheEntryPool(void) { return mCacheEntryPool; } 342 343 Error Resolve(const Ip6::Address &aEid, uint16_t &aRloc16, bool aAllowAddressQuery); 344 void Remove(uint16_t aRloc16, bool aMatchRouterId); 345 void Remove(const Ip6::Address &aEid, Reason aReason); 346 CacheEntry *FindCacheEntry(const Ip6::Address &aEid, CacheEntryList *&aList, CacheEntry *&aPrevEntry); 347 CacheEntry *NewCacheEntry(bool aSnoopedEntry); 348 void RemoveCacheEntry(CacheEntry &aEntry, CacheEntryList &aList, CacheEntry *aPrevEntry, Reason aReason); 349 Error UpdateCacheEntry(const Ip6::Address &aEid, uint16_t aRloc16); 350 Error SendAddressQuery(const Ip6::Address &aEid); 351 #if OPENTHREAD_CONFIG_TMF_ALLOW_ADDRESS_RESOLUTION_USING_NET_DATA_SERVICES 352 Error ResolveUsingNetDataServices(const Ip6::Address &aEid, uint16_t &aRloc16); 353 #endif 354 355 static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); 356 357 #endif // OPENTHREAD_FTD 358 359 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 360 361 #if OPENTHREAD_FTD 362 363 static void HandleIcmpReceive(void *aContext, 364 otMessage *aMessage, 365 const otMessageInfo *aMessageInfo, 366 const otIcmp6Header *aIcmpHeader); 367 void HandleIcmpReceive(Message &aMessage, 368 const Ip6::MessageInfo &aMessageInfo, 369 const Ip6::Icmp::Header &aIcmpHeader); 370 371 void HandleTimeTick(void); 372 void LogCacheEntryChange(EntryChange aChange, 373 Reason aReason, 374 const CacheEntry &aEntry, 375 CacheEntryList *aList = nullptr); 376 const char *ListToString(const CacheEntryList *aList) const; 377 378 static AddressResolver::CacheEntry *GetEntryAfter(CacheEntry *aPrev, CacheEntryList &aList); 379 380 CacheEntryPool mCacheEntryPool; 381 CacheEntryList mCachedList; 382 CacheEntryList mSnoopedList; 383 CacheEntryList mQueryList; 384 CacheEntryList mQueryRetryList; 385 Ip6::Icmp::Handler mIcmpHandler; 386 387 #endif // OPENTHREAD_FTD 388 }; 389 390 DeclareTmfHandler(AddressResolver, kUriAddressError); 391 #if OPENTHREAD_FTD 392 DeclareTmfHandler(AddressResolver, kUriAddressQuery); 393 DeclareTmfHandler(AddressResolver, kUriAddressNotify); 394 #endif 395 396 /** 397 * @} 398 */ 399 400 DefineCoreType(otCacheEntryIterator, AddressResolver::Iterator); 401 DefineCoreType(otCacheEntryInfo, AddressResolver::EntryInfo); 402 DefineMapEnum(otCacheEntryState, AddressResolver::EntryInfo::State); 403 404 } // namespace ot 405 406 #endif // ADDRESS_RESOLVER_HPP_ 407