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/linked_list.hpp" 41 #include "common/locator.hpp" 42 #include "common/non_copyable.hpp" 43 #include "common/time_ticker.hpp" 44 #include "common/timer.hpp" 45 #include "mac/mac.hpp" 46 #include "net/icmp6.hpp" 47 #include "net/udp6.hpp" 48 #include "thread/thread_tlvs.hpp" 49 50 namespace ot { 51 52 /** 53 * @addtogroup core-arp 54 * 55 * @brief 56 * This module includes definitions for Thread EID-to-RLOC mapping and caching. 57 * 58 * @{ 59 */ 60 61 /** 62 * This class implements the EID-to-RLOC mapping and caching. 63 * 64 */ 65 class AddressResolver : public InstanceLocator, private NonCopyable 66 { 67 friend class TimeTicker; 68 69 public: 70 /** 71 * This type represents an iterator used for iterating through the EID cache table entries. 72 * 73 */ 74 typedef otCacheEntryIterator Iterator; 75 76 /** 77 * This type represents an EID cache entry. 78 * 79 */ 80 typedef otCacheEntryInfo EntryInfo; 81 82 /** 83 * This constructor initializes the object. 84 * 85 */ 86 explicit AddressResolver(Instance &aInstance); 87 88 #if OPENTHREAD_FTD 89 /** 90 * This method clears the EID-to-RLOC cache. 91 * 92 */ 93 void Clear(void); 94 95 /** 96 * This method gets the information about the next EID cache entry (using an iterator). 97 * 98 * @param[out] aInfo An `EntryInfo` where the EID cache entry information is placed. 99 * @param[in,out] aIterator An iterator. It will be updated to point to the next entry on success. 100 * To get the first entry, initialize the iterator by setting all its fields to zero. 101 * e.g., `memset` the the iterator structure to zero. 102 * 103 * @retval kErrorNone Successfully populated @p aInfo with the info for the next EID cache entry. 104 * @retval kErrorNotFound No more entries in the address cache table. 105 * 106 */ 107 Error GetNextCacheEntry(EntryInfo &aInfo, Iterator &aIterator) const; 108 109 /** 110 * This method removes the EID-to-RLOC cache entries corresponding to an RLOC16. 111 * 112 * @param[in] aRloc16 The RLOC16 address. 113 * 114 */ 115 void Remove(Mac::ShortAddress aRloc16); 116 117 /** 118 * This method removes all EID-to-RLOC cache entries associated with a Router ID. 119 * 120 * @param[in] aRouterId The Router ID. 121 * 122 */ 123 void Remove(uint8_t aRouterId); 124 125 /** 126 * This method removes the cache entry for the EID. 127 * 128 * @param[in] aEid A reference to the EID. 129 * 130 */ 131 void Remove(const Ip6::Address &aEid); 132 133 /** 134 * This method updates an existing entry or adds a snooped cache entry for a given EID. 135 * 136 * The method is intended to add an entry for snoop optimization (inspection of a received message to create a 137 * cache entry mapping an EID to a RLOC). 138 * 139 * @param[in] aEid A reference to the EID. 140 * @param[in] aRloc16 The RLOC16 corresponding to @p aEid. 141 * @param[in] aDest The short MAC address destination of the received snooped message. 142 * 143 */ 144 void UpdateSnoopedCacheEntry(const Ip6::Address &aEid, Mac::ShortAddress aRloc16, Mac::ShortAddress aDest); 145 146 /** 147 * This method returns the RLOC16 for a given EID, initiates an Address Query if the mapping is not known. 148 * 149 * @param[in] aEid A reference to the EID. 150 * @param[out] aRloc16 The RLOC16 corresponding to @p aEid. 151 * 152 * @retval kErrorNone Successfully provided the RLOC16. 153 * @retval kErrorAddressQuery Initiated an Address Query if allowed. 154 * @retval kErrorDrop Earlier Address Query for the EID timed out. In retry timeout interval. 155 * @retval kErrorNoBufs Insufficient buffer space available to send Address Query. 156 * 157 */ Resolve(const Ip6::Address & aEid,Mac::ShortAddress & aRloc16)158 Error Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16) 159 { 160 return Resolve(aEid, aRloc16, /* aAllowAddressQuery */ true); 161 } 162 163 /** 164 * This method looks up the RLOC16 for a given EID in the address cache. 165 * 166 * @param[in] aEid A reference to the EID. 167 * 168 * @returns The RLOC16 mapping to @p aEid or `Mac::kShortAddrInvalid` if it is not found in the address cache. 169 * 170 */ 171 Mac::ShortAddress LookUp(const Ip6::Address &aEid); 172 173 /** 174 * This method restarts any ongoing address queries. 175 * 176 * Any existing address queries will be restarted as if they are being sent for the first time. 177 * 178 */ 179 void RestartAddressQueries(void); 180 181 /** 182 * This method sends an Address Notification (ADDR_NTF.ans) message. 183 * 184 * @param[in] aTarget The target address of the ADDR_NTF.ans message. 185 * @param[in] aMeshLocalIid The ML-IID of the ADDR_NTF.ans message. 186 * @param[in] aLastTransactionTimeTlv A pointer to the Last Transaction Time if the ADDR_NTF.ans message contains 187 * a Last Transaction Time TLV. 188 * @param[in] aDestination The destination to send the ADDR_NTF.ans message. 189 * 190 */ 191 void SendAddressQueryResponse(const Ip6::Address & aTarget, 192 const Ip6::InterfaceIdentifier &aMeshLocalIid, 193 const uint32_t * aLastTransactionTimeTlv, 194 const Ip6::Address & aDestination); 195 196 /** 197 * This method sends an Address Error Notification (ADDR_ERR.ntf) message. 198 * 199 * @param aTarget The target address of the ADDR_ERR.ntf message. 200 * @param aMeshLocalIid The ML-IID of the ADDR_ERR.ntf message. 201 * @param aDestination The destination to send the ADDR_ERR.ntf message. 202 * 203 */ 204 void SendAddressError(const Ip6::Address & aTarget, 205 const Ip6::InterfaceIdentifier &aMeshLocalIid, 206 const Ip6::Address * aDestination); 207 208 private: 209 static constexpr uint16_t kCacheEntries = OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_ENTRIES; 210 static constexpr uint16_t kMaxNonEvictableSnoopedEntries = OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES; 211 212 // All time/delay values are in seconds 213 static constexpr uint16_t kAddressQueryTimeout = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT; 214 static constexpr uint16_t kAddressQueryInitialRetryDelay = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY; 215 static constexpr uint16_t kAddressQueryMaxRetryDelay = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY; 216 static constexpr uint16_t kSnoopBlockEvictionTimeout = OPENTHREAD_CONFIG_TMF_SNOOP_CACHE_ENTRY_TIMEOUT; 217 218 static constexpr uint8_t kIteratorListIndex = 0; 219 static constexpr uint8_t kIteratorEntryIndex = 1; 220 221 class CacheEntry : public InstanceLocatorInit 222 { 223 public: 224 void Init(Instance &aInstance); 225 226 CacheEntry * GetNext(void); 227 const CacheEntry *GetNext(void) const; 228 void SetNext(CacheEntry *aEntry); 229 GetTarget(void) const230 const Ip6::Address &GetTarget(void) const { return mTarget; } SetTarget(const Ip6::Address & aTarget)231 void SetTarget(const Ip6::Address &aTarget) { mTarget = aTarget; } 232 GetRloc16(void) const233 Mac::ShortAddress GetRloc16(void) const { return mRloc16; } SetRloc16(Mac::ShortAddress aRloc16)234 void SetRloc16(Mac::ShortAddress aRloc16) { mRloc16 = aRloc16; } 235 GetMeshLocalIid(void) const236 const Ip6::InterfaceIdentifier &GetMeshLocalIid(void) const { return mInfo.mCached.mMeshLocalIid; } SetMeshLocalIid(const Ip6::InterfaceIdentifier & aIid)237 void SetMeshLocalIid(const Ip6::InterfaceIdentifier &aIid) { mInfo.mCached.mMeshLocalIid = aIid; } 238 GetLastTransactionTime(void) const239 uint32_t GetLastTransactionTime(void) const { return mInfo.mCached.mLastTransactionTime; } SetLastTransactionTime(uint32_t aTime)240 void SetLastTransactionTime(uint32_t aTime) { mInfo.mCached.mLastTransactionTime = aTime; } IsLastTransactionTimeValid(void) const241 bool IsLastTransactionTimeValid(void) const { return GetLastTransactionTime() != kInvalidLastTransTime; } MarkLastTransactionTimeAsInvalid(void)242 void MarkLastTransactionTimeAsInvalid(void) { SetLastTransactionTime(kInvalidLastTransTime); } 243 DecrementTimeout(void)244 void DecrementTimeout(void) { mInfo.mOther.mTimeout--; } IsTimeoutZero(void) const245 bool IsTimeoutZero(void) const { return mInfo.mOther.mTimeout == 0; } GetTimeout(void) const246 uint16_t GetTimeout(void) const { return mInfo.mOther.mTimeout; } SetTimeout(uint16_t aTimeout)247 void SetTimeout(uint16_t aTimeout) { mInfo.mOther.mTimeout = aTimeout; } 248 GetRetryDelay(void) const249 uint16_t GetRetryDelay(void) const { return mInfo.mOther.mRetryDelay; } SetRetryDelay(uint16_t aDelay)250 void SetRetryDelay(uint16_t aDelay) { mInfo.mOther.mRetryDelay = aDelay; } 251 CanEvict(void) const252 bool CanEvict(void) const { return mInfo.mOther.mCanEvict; } SetCanEvict(bool aCanEvict)253 void SetCanEvict(bool aCanEvict) { mInfo.mOther.mCanEvict = aCanEvict; } 254 Matches(const Ip6::Address & aEid) const255 bool Matches(const Ip6::Address &aEid) const { return GetTarget() == aEid; } 256 257 private: 258 static constexpr uint16_t kNoNextIndex = 0xffff; // `mNextIndex` value when at end of list. 259 static constexpr uint32_t kInvalidLastTransTime = 0xffffffff; // Value when `mLastTransactionTime` is invalid. 260 261 Ip6::Address mTarget; 262 Mac::ShortAddress mRloc16; 263 uint16_t mNextIndex; 264 265 union 266 { 267 struct 268 { 269 uint32_t mLastTransactionTime; 270 Ip6::InterfaceIdentifier mMeshLocalIid; 271 } mCached; 272 273 struct 274 { 275 uint16_t mTimeout; 276 uint16_t mRetryDelay; 277 bool mCanEvict; 278 } mOther; 279 280 } mInfo; 281 }; 282 283 typedef Pool<CacheEntry, kCacheEntries> CacheEntryPool; 284 typedef LinkedList<CacheEntry> CacheEntryList; 285 286 enum EntryChange : uint8_t 287 { 288 kEntryAdded, 289 kEntryUpdated, 290 kEntryRemoved, 291 }; 292 293 enum Reason : uint8_t 294 { 295 kReasonQueryRequest, 296 kReasonSnoop, 297 kReasonReceivedNotification, 298 kReasonRemovingRouterId, 299 kReasonRemovingRloc16, 300 kReasonReceivedIcmpDstUnreachNoRoute, 301 kReasonEvictingForNewEntry, 302 kReasonRemovingEid, 303 }; 304 GetCacheEntryPool(void)305 CacheEntryPool &GetCacheEntryPool(void) { return mCacheEntryPool; } 306 307 Error Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16, bool aAllowAddressQuery); 308 void Remove(Mac::ShortAddress aRloc16, bool aMatchRouterId); 309 void Remove(const Ip6::Address &aEid, Reason aReason); 310 CacheEntry *FindCacheEntry(const Ip6::Address &aEid, CacheEntryList *&aList, CacheEntry *&aPrevEntry); 311 CacheEntry *NewCacheEntry(bool aSnoopedEntry); 312 void RemoveCacheEntry(CacheEntry &aEntry, CacheEntryList &aList, CacheEntry *aPrevEntry, Reason aReason); 313 Error UpdateCacheEntry(const Ip6::Address &aEid, Mac::ShortAddress aRloc16); 314 315 Error SendAddressQuery(const Ip6::Address &aEid); 316 317 static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); 318 319 #endif // OPENTHREAD_FTD 320 321 static void HandleAddressError(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); 322 void HandleAddressError(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 323 324 #if OPENTHREAD_FTD 325 static void HandleAddressQuery(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); 326 void HandleAddressQuery(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 327 328 static void HandleAddressNotification(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); 329 void HandleAddressNotification(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 330 331 static void HandleIcmpReceive(void * aContext, 332 otMessage * aMessage, 333 const otMessageInfo *aMessageInfo, 334 const otIcmp6Header *aIcmpHeader); 335 void HandleIcmpReceive(Message & aMessage, 336 const Ip6::MessageInfo & aMessageInfo, 337 const Ip6::Icmp::Header &aIcmpHeader); 338 339 void HandleTimeTick(void); 340 341 void LogCacheEntryChange(EntryChange aChange, 342 Reason aReason, 343 const CacheEntry &aEntry, 344 CacheEntryList * aList = nullptr); 345 346 const char *ListToString(const CacheEntryList *aList) const; 347 348 static AddressResolver::CacheEntry *GetEntryAfter(CacheEntry *aPrev, CacheEntryList &aList); 349 350 #endif // OPENTHREAD_FTD 351 Coap::Resource mAddressError; 352 #if OPENTHREAD_FTD 353 Coap::Resource mAddressQuery; 354 Coap::Resource mAddressNotification; 355 356 CacheEntryPool mCacheEntryPool; 357 CacheEntryList mCachedList; 358 CacheEntryList mSnoopedList; 359 CacheEntryList mQueryList; 360 CacheEntryList mQueryRetryList; 361 362 Ip6::Icmp::Handler mIcmpHandler; 363 #endif // OPENTHREAD_FTD 364 }; 365 366 /** 367 * @} 368 */ 369 370 } // namespace ot 371 372 #endif // ADDRESS_RESOLVER_HPP_ 373