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