/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2019 Google LLC.
* Copyright (c) 2013-2017 Nest Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file defines the Inet::InterfaceId type alias and related
* classes for iterating on the list of system network interfaces and the list
* of system interface addresses.
*/
#pragma once
#include
#include
#include
#include
#if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
#include
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
struct if_nameindex;
struct ifaddrs;
#endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
#if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
#include
struct net_if;
struct net_if_ipv4;
struct net_if_ipv6;
#endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
#if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
struct otIp6AddressInfo;
#endif
#include
#include
namespace chip {
namespace Inet {
class IPAddress;
class IPPrefix;
/**
* Data type describing interface type.
*/
enum class InterfaceType
{
Unknown = 0,
WiFi = 1,
Ethernet = 2,
Cellular = 3,
Thread = 4,
};
/**
* Indicator for system network interfaces.
*/
class InterfaceId
{
public:
#if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
using PlatformType = struct netif *;
static constexpr size_t kMaxIfNameLength = 13; // Names are formatted as %c%c%d
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
using PlatformType = unsigned int;
static constexpr size_t kMaxIfNameLength = IF_NAMESIZE;
#endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
#if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
using PlatformType = int;
static constexpr size_t kMaxIfNameLength = Z_DEVICE_MAX_NAME_LEN;
#endif
#if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
using PlatformType = unsigned int;
static constexpr size_t kMaxIfNameLength = 6;
#endif
~InterfaceId() = default;
constexpr InterfaceId() : mPlatformInterface(kPlatformNull) {}
explicit constexpr InterfaceId(PlatformType interface) : mPlatformInterface(interface) {}
constexpr InterfaceId(const InterfaceId & other) : mPlatformInterface(other.mPlatformInterface) {}
constexpr InterfaceId & operator=(const InterfaceId & other)
{
mPlatformInterface = other.mPlatformInterface;
return *this;
}
static constexpr InterfaceId Null() { return InterfaceId(); }
constexpr bool operator==(const InterfaceId & other) const { return mPlatformInterface == other.mPlatformInterface; }
constexpr bool operator!=(const InterfaceId & other) const { return mPlatformInterface != other.mPlatformInterface; }
/**
* Test for inequivalence with the null interface.
*/
bool IsPresent() const { return mPlatformInterface != kPlatformNull; }
/**
* Get the underlying platform representation of the interface.
*/
PlatformType GetPlatformInterface() const { return mPlatformInterface; }
/**
* Get the name of the network interface
*
* @param[in] nameBuf Region of memory to write the interface name.
* @param[in] nameBufSize Size of the region denoted by \c nameBuf.
*
* @retval CHIP_NO_ERROR Successful result, interface name written.
* @retval CHIP_ERROR_BUFFER_TOO_SMALL Buffer is too small for the interface name.
* @retval other Another system or platform error.
*
* Writes the name of the network interface as a \c NUL terminated text string at \c nameBuf.
* The name of the unspecified network interface is the empty string.
*/
CHIP_ERROR GetInterfaceName(char * nameBuf, size_t nameBufSize) const;
/**
* Search the list of network interfaces for the indicated name.
*
* @param[in] intfName Name of the network interface to find.
* @param[out] intfId Indicator of the network interface to assign.
*
* @retval CHIP_NO_ERROR Success, network interface indicated.
* @retval INET_ERROR_UNKNOWN_INTERFACE No network interface found.
* @retval other Another system or platform error.
*
* @note
* On LwIP, this function must be called with the LwIP stack lock acquired.
*/
static CHIP_ERROR InterfaceNameToId(const char * intfName, InterfaceId & intfId);
/**
* Get the interface identifier for the specified IP address. If the
* interface identifier cannot be derived it is set to the default InterfaceId.
*
* @note
* This function fetches the first interface (from the configured list
* of interfaces) that matches the specified IP address.
*/
static InterfaceId FromIPAddress(const IPAddress & addr);
/**
* Check if there is a prefix match between the specified IPv6 address and any of
* the locally configured IPv6 addresses.
*
* @param[in] addr The IPv6 address to check for the prefix-match.
* @return true if a successful match is found, otherwise false.
*/
static bool MatchLocalIPv6Subnet(const IPAddress & addr);
/**
* Get the link local IPv6 address.
*
* @param[out] llAddr The link local IPv6 address for the link.
*
* @retval #CHIP_ERROR_NOT_IMPLEMENTED If IPv6 is not supported.
* @retval #CHIP_ERROR_INVALID_ARGUMENT If the link local address
* is nullptr.
* @retval #INET_ERROR_ADDRESS_NOT_FOUND If the link does not have
* any address configured
* or if no link local (fe80::)
* address is present.
* @retval #CHIP_NO_ERROR On success.
*/
CHIP_ERROR GetLinkLocalAddr(IPAddress * llAddr) const;
private:
#if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
static constexpr PlatformType kPlatformNull = nullptr;
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
static constexpr PlatformType kPlatformNull = 0;
#endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
#if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
static constexpr PlatformType kPlatformNull = 0;
#endif
#if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
static constexpr PlatformType kPlatformNull = 0;
#endif
PlatformType mPlatformInterface;
};
/**
* Compute a prefix length from a variable-length netmask.
*/
extern uint8_t NetmaskToPrefixLength(const uint8_t * netmask, uint16_t netmaskLen);
/**
* @brief Iterator for the list of system network interfaces.
*
* @details
* Use objects of this class to iterate the list of system network interfaces.
*
* Methods on an individual instance of this class are *not* thread-safe;
* however separate instances may be used simultaneously by multiple threads.
*
* On multi-threaded LwIP systems, instances are thread-safe relative to other
* threads accessing the global LwIP state provided that the other threads hold
* the LwIP core lock while mutating the list of netifs, and that netif object
* themselves are never destroyed.
*
* On sockets-based systems, iteration is always stable in the face of changes
* to the underlying system's interfaces.
*
* On LwIP systems, iteration is stable except in the case where the currently
* selected interface is removed from the list, in which case iteration ends
* immediately.
*/
class InterfaceIterator
{
public:
/**
* Constructs an InterfaceIterator object.
*
* Starts the iterator at the first network interface. On some platforms,
* this constructor may allocate resources recycled by the destructor.
*/
InterfaceIterator();
~InterfaceIterator();
/**
* Test whether the iterator is positioned on an interface
*
* @return \c true if the iterator is positioned on an interface;
* \c false if positioned beyond the end of the interface list.
*/
bool HasCurrent();
/**
* Advance the iterator to the next network interface.
*
* @return \c false if advanced beyond the end, else \c true.
*
* Advances the internal iterator to the next network interface or to a position
* beyond the end of the interface list.
*
* On multi-threaded LwIP systems, this method is thread-safe relative to other
* threads accessing the global LwIP state provided that: 1) the other threads
* hold the LwIP core lock while mutating the list of netifs; and 2) netif objects
* themselves are never destroyed.
*
* Iteration is stable in the face of changes to the underlying system's
* interfaces, *except* in the case of LwIP systems when the currently selected
* interface is removed from the list, which causes iteration to end immediately.
*/
bool Next();
/**
* InterfaceId InterfaceIterator::GetInterfaceId(void)
*
* Returns the network interface id at the current iterator position.
*
* @retval id The current network interface id.
* @retval InterfaceId() If advanced beyond the end of the list.
*/
InterfaceId GetInterfaceId();
/**
* Get the name of the current network interface
*
* @param[in] nameBuf Region of memory to write the interface name.
* @param[in] nameBufSize Size of the region denoted by \c nameBuf.
*
* @retval CHIP_NO_ERROR Successful result, interface name written.
* @retval CHIP_ERROR_INCORRECT_STATE Iterator is positioned beyond the end of the list.
* @retval CHIP_ERROR_BUFFER_TOO_SMALL Name is too large to be written in buffer.
* @retval other Another system or platform error.
*
* Writes the name of the network interface as \c NUL terminated text string at \c nameBuf.
*/
CHIP_ERROR GetInterfaceName(char * nameBuf, size_t nameBufSize);
/**
* Returns whether the current network interface is up.
*
* @return \c true if current network interface is up, \c false if not
* or if the iterator is positioned beyond the end of the list.
*/
bool IsUp();
/**
* Returns whether the current network interface is a loopback interface
*
* @return \c true if current network interface is a loopback interface, \c false
* if not, or if the iterator is positioned beyond the end of the list.
*/
bool IsLoopback();
/**
* Returns whether the current network interface supports multicast.
*
* @return \c true if current network interface supports multicast, \c false
* if not, or if the iterator is positioned beyond the end of the list.
*/
bool SupportsMulticast();
/**
* Returns whether the current network interface has a broadcast address.
*
* @return \c true if current network interface has a broadcast address, \c false
* if not, or if the iterator is positioned beyond the end of the list.
*/
bool HasBroadcastAddress();
/**
* Get the interface type of the current network interface.
*
* @param[out] type Object to save the interface type.
*/
CHIP_ERROR GetInterfaceType(InterfaceType & type);
/**
* Get the hardware address of the current network interface
*
* @param[out] addressBuffer Region of memory to write the hardware address.
* @param[out] addressSize Size of the address saved to a buffer.
* @param[in] addressBufferSize Maximum size of a buffer to save data.
*/
CHIP_ERROR GetHardwareAddress(uint8_t * addressBuffer, uint8_t & addressSize, uint8_t addressBufferSize);
protected:
#if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
struct netif * mCurNetif;
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
struct if_nameindex * mIntfArray;
size_t mCurIntf;
short mIntfFlags;
bool mIntfFlagsCached;
short GetFlags();
#endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
#if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
InterfaceId::PlatformType mCurrentId = 1;
net_if * mCurrentInterface = nullptr;
#endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
#if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
struct otIp6AddressInfo * mCurNetif;
#endif
};
/**
* @brief Iterator for the list of system network interface IP addresses.
*
* @details
* Use objects of this class to iterate the list of system network interface
* interface IP addresses.
*
* Methods on an individual instance of this class are *not* thread-safe;
* however separate instances may be used simultaneously by multiple threads.
*
* On multi-threaded LwIP systems, instances are thread-safe relative to other
* threads accessing the global LwIP state provided that: 1) other threads hold
* the LwIP core lock while mutating the list of netifs; and 2) netif object
* themselves are never destroyed.
*
* On sockets-based systems, iteration is always stable in the face of changes
* to the underlying system's interfaces and/or addresses.
*
* On LwIP systems, iteration is stable except in the case where the interface
* associated with the current address is removed, in which case iteration may
* end prematurely.
*/
class DLL_EXPORT InterfaceAddressIterator
{
public:
/**
* Constructs an InterfaceAddressIterator object.
*
* Starts the iterator at the first network address. On some platforms,
* this constructor may allocate resources recycled by the destructor.
*/
InterfaceAddressIterator();
/**
* Destroys an InterfaceAddressIterator object.
*
* Recycles any resources allocated by the constructor.
*/
~InterfaceAddressIterator();
/**
* Test whether the iterator is positioned on an interface address
*
* @return \c true if the iterator is positioned on an interface address;
* \c false if positioned beyond the end of the address list.
*/
bool HasCurrent();
/**
* @fn bool InterfaceAddressIterator::Next(void)
*
* @brief Advance the iterator to the next interface address.
*
* @return \c false if advanced beyond the end, else \c true.
*
* @details
* Advances the iterator to the next interface address or to a position
* beyond the end of the address list.
*
* On LwIP, this method is thread-safe provided that: 1) other threads hold
* the LwIP core lock while mutating the netif list; and 2) netif objects
* themselves are never destroyed. Additionally, iteration on LwIP systems
* will terminate early if the current interface is removed from the list.
*/
bool Next();
/**
* @fn IPAddress InterfaceAddressIterator::GetAddress(void)
*
* @brief Get the current interface address.
*
* @param[out] outIPAddress The current interface address
*
* @return CHIP_NO_ERROR if the result IPAddress is valid.
* @return CHIP_ERROR_SENTINEL if the iterator is positioned beyond the end of the address list.
* @return other error from lower-level code
*/
CHIP_ERROR GetAddress(IPAddress & outIPAddress);
/**
* @fn uint8_t InterfaceAddressIterator::GetPrefixLength(void)
*
* @brief Gets the network prefix associated with the current interface address.
*
* @return the network prefix (in bits) or 0 if the iterator is positioned beyond
* the end of the address list.
*
* @details
* On LwIP, this method simply returns the hard-coded constant 64.
*
* Note Well: the standard subnet prefix on all links other than PPP
* links is 64 bits. On PPP links and some non-broadcast multipoint access
* links, the convention is either 127 bits or 128 bits, but it might be
* something else. On most platforms, the system's interface address
* structure can represent arbitrary prefix lengths between 0 and 128.
*/
uint8_t GetPrefixLength();
/**
* @fn InterfaceId InterfaceAddressIterator::GetInterfaceId(void)
*
* @brief Returns the network interface id associated with the current
* interface address.
*
* @return the interface id or \c InterfaceId() if the iterator
* is positioned beyond the end of the address list.
*/
InterfaceId GetInterfaceId();
/**
* @fn CHIP_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
*
* @brief Get the name of the network interface associated with the
* current interface address.
*
* @param[in] nameBuf region of memory to write the interface name
* @param[in] nameBufSize size of the region denoted by \c nameBuf
*
* @retval CHIP_NO_ERROR successful result, interface name written
* @retval CHIP_ERROR_BUFFER_TOO_SMALL name is too large to be written in buffer
* @retval CHIP_ERROR_INCORRECT_STATE
* the iterator is not currently positioned on an
* interface address
* @retval other another system or platform error
*
* @details
* Writes the name of the network interface as \c NUL terminated text string
* at \c nameBuf.
*/
CHIP_ERROR GetInterfaceName(char * nameBuf, size_t nameBufSize);
/**
* Returns whether the network interface associated with the current interface address is up.
*
* @return \c true if current network interface is up, \c false if not, or
* if the iterator is not positioned on an interface address.
*/
bool IsUp();
/**
* Returns whether the current network interface is a loopback interface
*
* @return \c true if current network interface is a loopback interface, \c false
* if not, or if the iterator is positioned beyond the end of the list.
*/
bool IsLoopback();
/**
* Returns whether the network interface associated with the current interface address supports multicast.
*
* @return \c true if multicast is supported, \c false if not, or
* if the iterator is not positioned on an interface address.
*/
bool SupportsMulticast();
/**
* Returns whether the network interface associated with the current interface address has an IPv4 broadcast address.
*
* @return \c true if the interface has a broadcast address, \c false if not, or
* if the iterator is not positioned on an interface address.
*/
bool HasBroadcastAddress();
private:
#if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
enum
{
kBeforeStartIndex = -1
};
InterfaceIterator mIntfIter;
int mCurAddrIndex;
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
struct ifaddrs * mAddrsList;
struct ifaddrs * mCurAddr;
#endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
#if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
InterfaceIterator mIntfIter;
net_if_ipv6 * mIpv6 = nullptr;
int mCurAddrIndex = -1;
#endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
#if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
const otNetifAddress * mNetifAddrList;
const otNetifAddress * mCurAddr;
#endif // #if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
};
#if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
inline InterfaceIterator::InterfaceIterator(void) {}
inline InterfaceIterator::~InterfaceIterator() = default;
inline InterfaceAddressIterator::~InterfaceAddressIterator() = default;
inline bool InterfaceIterator::HasCurrent(void)
{
return mCurNetif != NULL;
}
#endif
#if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
inline InterfaceIterator::InterfaceIterator(void)
{
mCurNetif = netif_list;
}
inline InterfaceIterator::~InterfaceIterator(void) {}
inline bool InterfaceIterator::HasCurrent(void)
{
return mCurNetif != NULL;
}
inline InterfaceId InterfaceIterator::GetInterfaceId(void)
{
return InterfaceId(mCurNetif);
}
inline InterfaceAddressIterator::InterfaceAddressIterator(void)
{
mCurAddrIndex = kBeforeStartIndex;
}
inline InterfaceAddressIterator::~InterfaceAddressIterator(void) {}
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
inline InterfaceIterator::~InterfaceIterator() = default;
inline InterfaceAddressIterator::~InterfaceAddressIterator() = default;
#endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
} // namespace Inet
} // namespace chip