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(Mac::ShortAddress 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, Mac::ShortAddress aRloc16, Mac::ShortAddress 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,Mac::ShortAddress & aRloc16)194 Error Resolve(const Ip6::Address &aEid, Mac::ShortAddress &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 * @param[in] aEid A reference to the EID. 203 * 204 * @returns The RLOC16 mapping to @p aEid or `Mac::kShortAddrInvalid` if it is not found in the address cache. 205 * 206 */ 207 Mac::ShortAddress LookUp(const Ip6::Address &aEid); 208 209 /** 210 * Restarts any ongoing address queries. 211 * 212 * Any existing address queries will be restarted as if they are being sent for the first time. 213 * 214 */ 215 void RestartAddressQueries(void); 216 217 /** 218 * Sends an Address Notification (ADDR_NTF.ans) message. 219 * 220 * @param[in] aTarget The target address of the ADDR_NTF.ans message. 221 * @param[in] aMeshLocalIid The ML-IID of the ADDR_NTF.ans message. 222 * @param[in] aLastTransactionTimeTlv A pointer to the Last Transaction Time if the ADDR_NTF.ans message contains 223 * a Last Transaction Time TLV. 224 * @param[in] aDestination The destination to send the ADDR_NTF.ans message. 225 * 226 */ 227 void SendAddressQueryResponse(const Ip6::Address &aTarget, 228 const Ip6::InterfaceIdentifier &aMeshLocalIid, 229 const uint32_t *aLastTransactionTimeTlv, 230 const Ip6::Address &aDestination); 231 232 /** 233 * Sends an Address Error Notification (ADDR_ERR.ntf) message. 234 * 235 * @param aTarget The target address of the ADDR_ERR.ntf message. 236 * @param aMeshLocalIid The ML-IID of the ADDR_ERR.ntf message. 237 * @param aDestination The destination to send the ADDR_ERR.ntf message. 238 * 239 */ 240 void SendAddressError(const Ip6::Address &aTarget, 241 const Ip6::InterfaceIdentifier &aMeshLocalIid, 242 const Ip6::Address *aDestination); 243 244 private: 245 static constexpr uint16_t kCacheEntries = OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_ENTRIES; 246 static constexpr uint16_t kMaxNonEvictableSnoopedEntries = OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES; 247 248 // All time/delay values are in seconds 249 static constexpr uint16_t kAddressQueryTimeout = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT; 250 static constexpr uint16_t kAddressQueryInitialRetryDelay = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY; 251 static constexpr uint16_t kAddressQueryMaxRetryDelay = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY; 252 static constexpr uint16_t kSnoopBlockEvictionTimeout = OPENTHREAD_CONFIG_TMF_SNOOP_CACHE_ENTRY_TIMEOUT; 253 254 class CacheEntry : public InstanceLocatorInit 255 { 256 public: 257 void Init(Instance &aInstance); 258 259 CacheEntry *GetNext(void); 260 const CacheEntry *GetNext(void) const; 261 void SetNext(CacheEntry *aEntry); 262 GetTarget(void) const263 const Ip6::Address &GetTarget(void) const { return mTarget; } SetTarget(const Ip6::Address & aTarget)264 void SetTarget(const Ip6::Address &aTarget) { mTarget = aTarget; } 265 GetRloc16(void) const266 Mac::ShortAddress GetRloc16(void) const { return mRloc16; } SetRloc16(Mac::ShortAddress aRloc16)267 void SetRloc16(Mac::ShortAddress aRloc16) { mRloc16 = aRloc16; } 268 GetMeshLocalIid(void) const269 const Ip6::InterfaceIdentifier &GetMeshLocalIid(void) const { return mInfo.mCached.mMeshLocalIid; } SetMeshLocalIid(const Ip6::InterfaceIdentifier & aIid)270 void SetMeshLocalIid(const Ip6::InterfaceIdentifier &aIid) { mInfo.mCached.mMeshLocalIid = aIid; } 271 GetLastTransactionTime(void) const272 uint32_t GetLastTransactionTime(void) const { return mInfo.mCached.mLastTransactionTime; } SetLastTransactionTime(uint32_t aTime)273 void SetLastTransactionTime(uint32_t aTime) { mInfo.mCached.mLastTransactionTime = aTime; } IsLastTransactionTimeValid(void) const274 bool IsLastTransactionTimeValid(void) const { return GetLastTransactionTime() != kInvalidLastTransTime; } MarkLastTransactionTimeAsInvalid(void)275 void MarkLastTransactionTimeAsInvalid(void) { SetLastTransactionTime(kInvalidLastTransTime); } 276 DecrementTimeout(void)277 void DecrementTimeout(void) { mInfo.mOther.mTimeout--; } IsTimeoutZero(void) const278 bool IsTimeoutZero(void) const { return mInfo.mOther.mTimeout == 0; } GetTimeout(void) const279 uint16_t GetTimeout(void) const { return mInfo.mOther.mTimeout; } SetTimeout(uint16_t aTimeout)280 void SetTimeout(uint16_t aTimeout) { mInfo.mOther.mTimeout = aTimeout; } 281 GetRetryDelay(void) const282 uint16_t GetRetryDelay(void) const { return mInfo.mOther.mRetryDelay; } SetRetryDelay(uint16_t aDelay)283 void SetRetryDelay(uint16_t aDelay) { mInfo.mOther.mRetryDelay = aDelay; } 284 CanEvict(void) const285 bool CanEvict(void) const { return mInfo.mOther.mCanEvict; } SetCanEvict(bool aCanEvict)286 void SetCanEvict(bool aCanEvict) { mInfo.mOther.mCanEvict = aCanEvict; } 287 IsInRampDown(void) const288 bool IsInRampDown(void) const { return mInfo.mOther.mRampDown; } SetRampDown(bool aRampDown)289 void SetRampDown(bool aRampDown) { mInfo.mOther.mRampDown = aRampDown; } 290 Matches(const Ip6::Address & aEid) const291 bool Matches(const Ip6::Address &aEid) const { return GetTarget() == aEid; } 292 293 private: 294 static constexpr uint16_t kNoNextIndex = 0xffff; // `mNextIndex` value when at end of list. 295 static constexpr uint32_t kInvalidLastTransTime = 0xffffffff; // Value when `mLastTransactionTime` is invalid. 296 297 Ip6::Address mTarget; 298 Mac::ShortAddress mRloc16; 299 uint16_t mNextIndex; 300 301 union 302 { 303 struct 304 { 305 uint32_t mLastTransactionTime; 306 Ip6::InterfaceIdentifier mMeshLocalIid; 307 } mCached; 308 309 struct 310 { 311 uint16_t mTimeout; 312 uint16_t mRetryDelay; 313 bool mCanEvict; 314 bool mRampDown; 315 } mOther; 316 317 } mInfo; 318 }; 319 320 typedef Pool<CacheEntry, kCacheEntries> CacheEntryPool; 321 322 class CacheEntryList : public LinkedList<CacheEntry> 323 { 324 }; 325 326 enum EntryChange : uint8_t 327 { 328 kEntryAdded, 329 kEntryUpdated, 330 kEntryRemoved, 331 }; 332 333 enum Reason : uint8_t 334 { 335 kReasonQueryRequest, 336 kReasonSnoop, 337 kReasonReceivedNotification, 338 kReasonRemovingRouterId, 339 kReasonRemovingRloc16, 340 kReasonReceivedIcmpDstUnreachNoRoute, 341 kReasonEvictingForNewEntry, 342 kReasonRemovingEid, 343 }; 344 GetCacheEntryPool(void)345 CacheEntryPool &GetCacheEntryPool(void) { return mCacheEntryPool; } 346 347 Error Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16, bool aAllowAddressQuery); 348 void Remove(Mac::ShortAddress aRloc16, bool aMatchRouterId); 349 void Remove(const Ip6::Address &aEid, Reason aReason); 350 CacheEntry *FindCacheEntry(const Ip6::Address &aEid, CacheEntryList *&aList, CacheEntry *&aPrevEntry); 351 CacheEntry *NewCacheEntry(bool aSnoopedEntry); 352 void RemoveCacheEntry(CacheEntry &aEntry, CacheEntryList &aList, CacheEntry *aPrevEntry, Reason aReason); 353 Error UpdateCacheEntry(const Ip6::Address &aEid, Mac::ShortAddress aRloc16); 354 Error SendAddressQuery(const Ip6::Address &aEid); 355 #if OPENTHREAD_CONFIG_TMF_ALLOW_ADDRESS_RESOLUTION_USING_NET_DATA_SERVICES 356 Error ResolveUsingNetDataServices(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16); 357 #endif 358 359 static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); 360 361 #endif // OPENTHREAD_FTD 362 363 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 364 365 #if OPENTHREAD_FTD 366 367 static void HandleIcmpReceive(void *aContext, 368 otMessage *aMessage, 369 const otMessageInfo *aMessageInfo, 370 const otIcmp6Header *aIcmpHeader); 371 void HandleIcmpReceive(Message &aMessage, 372 const Ip6::MessageInfo &aMessageInfo, 373 const Ip6::Icmp::Header &aIcmpHeader); 374 375 void HandleTimeTick(void); 376 void LogCacheEntryChange(EntryChange aChange, 377 Reason aReason, 378 const CacheEntry &aEntry, 379 CacheEntryList *aList = nullptr); 380 const char *ListToString(const CacheEntryList *aList) const; 381 382 static AddressResolver::CacheEntry *GetEntryAfter(CacheEntry *aPrev, CacheEntryList &aList); 383 384 CacheEntryPool mCacheEntryPool; 385 CacheEntryList mCachedList; 386 CacheEntryList mSnoopedList; 387 CacheEntryList mQueryList; 388 CacheEntryList mQueryRetryList; 389 Ip6::Icmp::Handler mIcmpHandler; 390 391 #endif // OPENTHREAD_FTD 392 }; 393 394 DeclareTmfHandler(AddressResolver, kUriAddressError); 395 #if OPENTHREAD_FTD 396 DeclareTmfHandler(AddressResolver, kUriAddressQuery); 397 DeclareTmfHandler(AddressResolver, kUriAddressNotify); 398 #endif 399 400 /** 401 * @} 402 */ 403 404 DefineCoreType(otCacheEntryIterator, AddressResolver::Iterator); 405 DefineCoreType(otCacheEntryInfo, AddressResolver::EntryInfo); 406 DefineMapEnum(otCacheEntryState, AddressResolver::EntryInfo::State); 407 408 } // namespace ot 409 410 #endif // ADDRESS_RESOLVER_HPP_ 411