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 * This class 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 * This type 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 * This type 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 * This constructor initializes the object. 111 * 112 */ 113 explicit AddressResolver(Instance &aInstance); 114 115 #if OPENTHREAD_FTD 116 /** 117 * This method clears the EID-to-RLOC cache. 118 * 119 */ 120 void Clear(void); 121 122 /** 123 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 Matches(const Ip6::Address & aEid) const288 bool Matches(const Ip6::Address &aEid) const { return GetTarget() == aEid; } 289 290 private: 291 static constexpr uint16_t kNoNextIndex = 0xffff; // `mNextIndex` value when at end of list. 292 static constexpr uint32_t kInvalidLastTransTime = 0xffffffff; // Value when `mLastTransactionTime` is invalid. 293 294 Ip6::Address mTarget; 295 Mac::ShortAddress mRloc16; 296 uint16_t mNextIndex; 297 298 union 299 { 300 struct 301 { 302 uint32_t mLastTransactionTime; 303 Ip6::InterfaceIdentifier mMeshLocalIid; 304 } mCached; 305 306 struct 307 { 308 uint16_t mTimeout; 309 uint16_t mRetryDelay; 310 bool mCanEvict; 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, Mac::ShortAddress &aRloc16, bool aAllowAddressQuery); 344 void Remove(Mac::ShortAddress 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, Mac::ShortAddress 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, Mac::ShortAddress &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