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