blob: c86b7cea5fdd643d171023c66443d796b7fb4392 [file] [log] [blame]
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for Thread EID-to-RLOC mapping and caching.
*/
#ifndef ADDRESS_RESOLVER_HPP_
#define ADDRESS_RESOLVER_HPP_
#include "openthread-core-config.h"
#include "coap/coap.hpp"
#include "common/linked_list.hpp"
#include "common/locator.hpp"
#include "common/timer.hpp"
#include "mac/mac.hpp"
#include "net/icmp6.hpp"
#include "net/udp6.hpp"
#include "thread/thread_tlvs.hpp"
namespace ot {
/**
* @addtogroup core-arp
*
* @brief
* This module includes definitions for Thread EID-to-RLOC mapping and caching.
*
* @{
*/
/**
* This class implements the EID-to-RLOC mapping and caching.
*
*/
class AddressResolver : public InstanceLocator
{
public:
/**
* This type represents an iterator used for iterating through the EID cache table entries.
*
*/
typedef otCacheEntryIterator Iterator;
/**
* This type represents an EID cache entry.
*
*/
typedef otCacheEntryInfo EntryInfo;
/**
* This constructor initializes the object.
*
*/
explicit AddressResolver(Instance &aInstance);
/**
* This method clears the EID-to-RLOC cache.
*
*/
void Clear(void);
/**
* This method gets the information about the next EID cache entry (using an iterator).
*
* @param[out] aInfo An `EntryInfo` where the EID cache entry information is placed.
* @param[inout] aIterator An iterator. It will be updated to point to the next entry on success.
* To get the first entry, initialize the iterator by setting all its fields to zero.
* e.g., `memset` the the iterator structure to zero.
*
* @retval OT_ERROR_NONE Successfully populated @p aInfo with the info for the next EID cache entry.
* @retval OT_ERROR_NOT_FOUND No more entries in the address cache table.
*
*/
otError GetNextCacheEntry(EntryInfo &aInfo, Iterator &aIterator) const;
/**
* This method removes the EID-to-RLOC cache entries corresponding to an RLOC16.
*
* @param[in] aRloc16 The RLOC16 address.
*
*/
void Remove(Mac::ShortAddress aRloc16);
/**
* This method removes all EID-to-RLOC cache entries associated with a Router ID.
*
* @param[in] aRouterId The Router ID.
*
*/
void Remove(uint8_t aRouterId);
/**
* This method removes the cache entry for the EID.
*
* @param[in] aEid A reference to the EID.
*
*/
void Remove(const Ip6::Address &aEid);
/**
* This method updates an existing cache entry for the EID.
*
* @param[in] aEid A reference to the EID.
* @param[in] aRloc16 The RLOC16 corresponding to @p aEid.
*
* @retval OT_ERROR_NONE Successfully updates an existing cache entry.
* @retval OT_ERROR_NOT_FOUND No cache entry with @p aEid.
*
*/
otError UpdateCacheEntry(const Ip6::Address &aEid, Mac::ShortAddress aRloc16);
/**
* This method adds a snooped cache entry for a given EID.
*
* The method is intended to add an entry for snoop optimization (inspection of a received message to create a
* cache entry mapping an EID to a RLOC).
*
* @param[in] aEid A reference to the EID.
* @param[in] aRloc16 The RLOC16 corresponding to @p aEid.
*
*/
void AddSnoopedCacheEntry(const Ip6::Address &aEid, Mac::ShortAddress aRloc16);
/**
* This method returns the RLOC16 for a given EID, or initiates an Address Query if the mapping is not known.
*
* @param[in] aEid A reference to the EID.
* @param[out] aRloc16 The RLOC16 corresponding to @p aEid.
*
* @retval OT_ERROR_NONE Successfully provided the RLOC16.
* @retval OT_ERROR_ADDRESS_QUERY Initiated an Address Query.
* @retval OT_ERROR_DROP Earlier Address Query for the EID timed out. In retry timeout interval.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to send Address Query.
*
*/
otError Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16);
/**
* This method restarts any ongoing address queries.
*
* Any existing address queries will be restarted as if they are being sent for the first time.
*
*/
void RestartAddressQueries(void);
private:
enum
{
kCacheEntries = OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_ENTRIES,
kMaxNonEvictableSnoopedEntries = OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES,
kAddressQueryTimeout = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_TIMEOUT, // in seconds
kAddressQueryInitialRetryDelay = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_INITIAL_RETRY_DELAY, // in seconds
kAddressQueryMaxRetryDelay = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY, // in seconds
kSnoopBlockEvictionTimeout = OPENTHREAD_CONFIG_TMF_SNOOP_CACHE_ENTRY_TIMEOUT, // in seconds
kStateUpdatePeriod = 1000u, // in milliseconds
kIteratorListIndex = 0,
kIteratorEntryIndex = 1,
};
class CacheEntry : public InstanceLocatorInit
{
public:
void Init(Instance &aInstance);
CacheEntry * GetNext(void);
const CacheEntry *GetNext(void) const;
void SetNext(CacheEntry *aEntry);
const Ip6::Address &GetTarget(void) const { return mTarget; }
void SetTarget(const Ip6::Address &aTarget) { mTarget = aTarget; }
Mac::ShortAddress GetRloc16(void) const { return mRloc16; }
void SetRloc16(Mac::ShortAddress aRloc16) { mRloc16 = aRloc16; }
const uint8_t *GetMeshLocalIid(void) const { return mInfo.mCached.mMeshLocalIid; }
bool HasMeshLocalIid(const uint8_t *aIid) const;
void SetMeshLocalIid(const uint8_t *aIid);
uint32_t GetLastTransactionTime(void) const { return mInfo.mCached.mLastTransactionTime; }
void SetLastTransactionTime(uint32_t aTime) { mInfo.mCached.mLastTransactionTime = aTime; }
bool IsLastTransactionTimeValid(void) const { return GetLastTransactionTime() != kInvalidLastTransTime; }
void MarkLastTransactionTimeAsInvalid(void) { SetLastTransactionTime(kInvalidLastTransTime); }
void DecrementTimeout(void) { mInfo.mOther.mTimeout--; }
bool IsTimeoutZero(void) const { return mInfo.mOther.mTimeout == 0; }
uint16_t GetTimeout(void) const { return mInfo.mOther.mTimeout; }
void SetTimeout(uint16_t aTimeout) { mInfo.mOther.mTimeout = aTimeout; }
uint16_t GetRetryDelay(void) const { return mInfo.mOther.mRetryDelay; }
void SetRetryDelay(uint16_t aDelay) { mInfo.mOther.mRetryDelay = aDelay; }
bool CanEvict(void) const { return mInfo.mOther.mCanEvict; }
void SetCanEvict(bool aCanEvict) { mInfo.mOther.mCanEvict = aCanEvict; }
bool Matches(const Ip6::Address &aEid) const { return GetTarget() == aEid; }
private:
enum
{
kNoNextIndex = 0xffff, // mNextIndex value when at end of list.
kInvalidLastTransTime = 0xffffffff, // Value indicating mLastTransactionTime is invalid.
};
Ip6::Address mTarget;
Mac::ShortAddress mRloc16;
uint16_t mNextIndex;
union
{
struct
{
uint32_t mLastTransactionTime;
uint8_t mMeshLocalIid[Ip6::Address::kInterfaceIdentifierSize];
} mCached;
struct
{
uint16_t mTimeout;
uint16_t mRetryDelay;
bool mCanEvict;
} mOther;
} mInfo;
};
typedef LinkedList<CacheEntry> CacheEntryList;
enum EntryChange
{
kEntryAdded,
kEntryUpdated,
kEntryRemoved,
};
enum Reason
{
kReasonQueryRequest,
kReasonSnoop,
kReasonReceivedNotification,
kReasonRemovingRouterId,
kReasonRemovingRloc16,
kReasonReceivedIcmpDstUnreachNoRoute,
kReasonEvictingForNewEntry,
kReasonRemovingEid,
};
void Remove(Mac::ShortAddress aRloc16, bool aMatchRouterId);
void Remove(const Ip6::Address &aEid, Reason aReason);
CacheEntry *FindCacheEntry(const Ip6::Address &aEid, CacheEntryList *&aList, CacheEntry *&aPrevEntry);
CacheEntry *NewCacheEntry(bool aSnoopedEntry);
void RemoveCacheEntry(CacheEntry &aEntry, CacheEntryList &aList, CacheEntry *aPrevEntry, Reason aReason);
otError SendAddressQuery(const Ip6::Address &aEid);
void SendAddressError(const Ip6::Address &aTarget, const uint8_t *aMeshLocalIid, const Ip6::Address *aDestination);
void SendAddressQueryResponse(const Ip6::Address &aTarget,
const uint8_t * aMeshLocalIid,
const uint32_t * aLastTransactionTimeTlv,
const Ip6::Address &aDestination);
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
static void HandleAddressError(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
void HandleAddressError(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleAddressQuery(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
void HandleAddressQuery(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleAddressNotification(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
void HandleAddressNotification(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleIcmpReceive(void * aContext,
otMessage * aMessage,
const otMessageInfo *aMessageInfo,
const otIcmp6Header *aIcmpHeader);
void HandleIcmpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Ip6::IcmpHeader &aIcmpHeader);
static void HandleTimer(Timer &aTimer);
void HandleTimer(void);
void LogCacheEntryChange(EntryChange aChange,
Reason aReason,
const CacheEntry &aEntry,
CacheEntryList * aList = nullptr);
const char *ListToString(const CacheEntryList *aList) const;
static AddressResolver::CacheEntry *GetEntryAfter(CacheEntry *aPrev, CacheEntryList &aList);
Coap::Resource mAddressError;
Coap::Resource mAddressQuery;
Coap::Resource mAddressNotification;
CacheEntry mCacheEntries[kCacheEntries];
CacheEntryList mCachedList;
CacheEntryList mSnoopedList;
CacheEntryList mQueryList;
CacheEntryList mQueryRetryList;
CacheEntryList mUnusedList;
Ip6::IcmpHandler mIcmpHandler;
TimerMilli mTimer;
};
/**
* @}
*/
} // namespace ot
#endif // ADDRESS_RESOLVER_HPP_