/* * * 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