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