blob: 0cff70e50b425d9de66f6ad20ef2ac1ad84e2461 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 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
* Implementation of network interface abstraction layer.
*
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include "InetInterface.h"
#include "InetLayer.h"
#include "InetLayerEvents.h"
#include <lib/support/CHIPMemString.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/DLLUtil.h>
#if CHIP_SYSTEM_CONFIG_USE_LWIP
#include <lwip/netif.h>
#include <lwip/sys.h>
#include <lwip/tcpip.h>
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <unistd.h>
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif /* HAVE_SYS_SOCKIO_H */
#include <net/if.h>
#include <sys/ioctl.h>
#ifdef __ANDROID__
#include "ifaddrs-android.h"
#else // !defined(__ANDROID__)
#include <ifaddrs.h>
#endif // !defined(__ANDROID__)
#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
#if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
#include <net/net_if.h>
#endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
#include <stdio.h>
#include <string.h>
namespace chip {
namespace Inet {
#if CHIP_SYSTEM_CONFIG_USE_LWIP
CHIP_ERROR InterfaceId::GetInterfaceName(char * nameBuf, size_t nameBufSize) const
{
if (mPlatformInterface)
{
int status = snprintf(nameBuf, nameBufSize, "%c%c%d", mPlatformInterface->name[0], mPlatformInterface->name[1],
mPlatformInterface->num);
if (status >= static_cast<int>(nameBufSize))
return CHIP_ERROR_BUFFER_TOO_SMALL;
return CHIP_NO_ERROR;
}
if (nameBufSize < 1)
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
nameBuf[0] = 0;
return CHIP_NO_ERROR;
}
CHIP_ERROR InterfaceId::InterfaceNameToId(const char * intfName, InterfaceId & interface)
{
if (strlen(intfName) < 3)
{
return INET_ERROR_UNKNOWN_INTERFACE;
}
char * parseEnd;
unsigned long intfNum = strtoul(intfName + 2, &parseEnd, 10);
if (*parseEnd != 0 || intfNum > UINT8_MAX)
{
return INET_ERROR_UNKNOWN_INTERFACE;
}
struct netif * intf;
#if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH)
NETIF_FOREACH(intf)
#else
for (intf = netif_list; intf != NULL; intf = intf->next)
#endif
{
if (intf->name[0] == intfName[0] && intf->name[1] == intfName[1] && intf->num == (uint8_t) intfNum)
{
interface = InterfaceId(intf);
return CHIP_NO_ERROR;
}
}
interface = InterfaceId::Null();
return INET_ERROR_UNKNOWN_INTERFACE;
}
bool InterfaceIterator::Next()
{
// Lock LwIP stack
LOCK_TCPIP_CORE();
// Verify the previous netif is still on the list if netifs. If so,
// advance to the next nextif.
struct netif * prevNetif = mCurNetif;
#if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH)
NETIF_FOREACH(mCurNetif)
#else
for (mCurNetif = netif_list; mCurNetif != NULL; mCurNetif = mCurNetif->next)
#endif
{
if (mCurNetif == prevNetif)
{
mCurNetif = mCurNetif->next;
break;
}
}
// Unlock LwIP stack
UNLOCK_TCPIP_CORE();
return mCurNetif != NULL;
}
CHIP_ERROR InterfaceIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
{
VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE);
return InterfaceId(mCurNetif).GetInterfaceName(nameBuf, nameBufSize);
}
bool InterfaceIterator::IsUp()
{
return HasCurrent() && netif_is_up(mCurNetif);
}
bool InterfaceIterator::SupportsMulticast()
{
return HasCurrent() &&
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
(mCurNetif->flags & (NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_BROADCAST)) != 0;
#else
(mCurNetif->flags & NETIF_FLAG_POINTTOPOINT) == 0;
#endif // LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
}
bool InterfaceIterator::HasBroadcastAddress()
{
return HasCurrent() && (mCurNetif->flags & NETIF_FLAG_BROADCAST) != 0;
}
bool InterfaceAddressIterator::HasCurrent()
{
return mIntfIter.HasCurrent() && ((mCurAddrIndex != kBeforeStartIndex) || Next());
}
bool InterfaceAddressIterator::Next()
{
mCurAddrIndex++;
while (mIntfIter.HasCurrent())
{
struct netif * curIntf = mIntfIter.GetInterfaceId().GetPlatformInterface();
while (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES)
{
if (ip6_addr_isvalid(netif_ip6_addr_state(curIntf, mCurAddrIndex)))
{
return true;
}
mCurAddrIndex++;
}
#if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
if (mCurAddrIndex == LWIP_IPV6_NUM_ADDRESSES)
{
if (!ip4_addr_isany(netif_ip4_addr(curIntf)))
{
return true;
}
}
#endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
mIntfIter.Next();
mCurAddrIndex = 0;
}
return false;
}
IPAddress InterfaceAddressIterator::GetAddress()
{
if (HasCurrent())
{
struct netif * curIntf = mIntfIter.GetInterfaceId().GetPlatformInterface();
if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES)
{
return IPAddress(*netif_ip6_addr(curIntf, mCurAddrIndex));
}
#if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
else
{
return IPAddress(*netif_ip4_addr(curIntf));
}
#endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
}
return IPAddress::Any;
}
uint8_t InterfaceAddressIterator::GetPrefixLength()
{
if (HasCurrent())
{
if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES)
{
return 64;
}
#if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
else
{
struct netif * curIntf = mIntfIter.GetInterfaceId().GetPlatformInterface();
return NetmaskToPrefixLength((const uint8_t *) netif_ip4_netmask(curIntf), 4);
}
#endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
}
return 0;
}
InterfaceId InterfaceAddressIterator::GetInterfaceId()
{
return HasCurrent() ? mIntfIter.GetInterfaceId() : InterfaceId::Null();
}
CHIP_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
{
VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE);
return mIntfIter.GetInterfaceName(nameBuf, nameBufSize);
}
bool InterfaceAddressIterator::IsUp()
{
return HasCurrent() && mIntfIter.IsUp();
}
bool InterfaceAddressIterator::SupportsMulticast()
{
return HasCurrent() && mIntfIter.SupportsMulticast();
}
bool InterfaceAddressIterator::HasBroadcastAddress()
{
return HasCurrent() && mIntfIter.HasBroadcastAddress();
}
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
CHIP_ERROR InterfaceId::GetInterfaceName(char * nameBuf, size_t nameBufSize) const
{
if (mPlatformInterface)
{
char intfName[IF_NAMESIZE];
if (if_indextoname(mPlatformInterface, intfName) == nullptr)
{
return CHIP_ERROR_POSIX(errno);
}
size_t nameLength = strlen(intfName);
if (nameLength >= nameBufSize)
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
strncpy(nameBuf, intfName, nameLength + 1);
return CHIP_NO_ERROR;
}
if (nameBufSize < 1)
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
nameBuf[0] = 0;
return CHIP_NO_ERROR;
}
CHIP_ERROR InterfaceId::InterfaceNameToId(const char * intfName, InterfaceId & interface)
{
unsigned int intfId = if_nametoindex(intfName);
interface = InterfaceId(intfId);
if (intfId == 0)
{
return (errno == ENXIO) ? INET_ERROR_UNKNOWN_INTERFACE : CHIP_ERROR_POSIX(errno);
}
return CHIP_NO_ERROR;
}
static int sIOCTLSocket = -1;
/**
* @brief Returns a global general purpose socket useful for invoking certain network IOCTLs.
*
* This function is thread-safe on all platforms.
*/
int GetIOCTLSocket()
{
if (sIOCTLSocket == -1)
{
int s;
#ifdef SOCK_CLOEXEC
s = socket(AF_INET, SOCK_STREAM, SOCK_CLOEXEC);
if (s < 0)
#endif
{
s = socket(AF_INET, SOCK_STREAM, 0);
fcntl(s, O_CLOEXEC);
}
if (!__sync_bool_compare_and_swap(&sIOCTLSocket, -1, s))
{
close(s);
}
}
return sIOCTLSocket;
}
/**
* @brief Close the global socket created by \c GetIOCTLSocket.
*
* @details
* This function is provided for cases were leaving the global IOCTL socket
* open would register as a leak.
*
* NB: This function is NOT thread-safe with respect to \c GetIOCTLSocket.
*/
void CloseIOCTLSocket()
{
if (sIOCTLSocket != -1)
{
close(sIOCTLSocket);
sIOCTLSocket = -1;
}
}
#if __ANDROID__ && __ANDROID_API__ < 24
static struct if_nameindex * backport_if_nameindex(void);
static void backport_if_freenameindex(struct if_nameindex *);
static void backport_if_freenameindex(struct if_nameindex * inArray)
{
if (inArray == NULL)
{
return;
}
for (size_t i = 0; inArray[i].if_index != 0; i++)
{
if (inArray[i].if_name != NULL)
{
free(inArray[i].if_name);
}
}
free(inArray);
}
static struct if_nameindex * backport_if_nameindex(void)
{
int err;
unsigned index;
size_t intfIter = 0;
size_t maxIntfNum = 0;
size_t numIntf = 0;
size_t numAddrs = 0;
struct if_nameindex * retval = NULL;
struct if_nameindex * tmpval = NULL;
struct ifaddrs * addrList = NULL;
struct ifaddrs * addrIter = NULL;
const char * lastIntfName = "";
err = getifaddrs(&addrList);
VerifyOrExit(err >= 0, );
// coalesce on consecutive interface names
for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next)
{
numAddrs++;
if (strcmp(addrIter->ifa_name, lastIntfName) == 0)
{
continue;
}
numIntf++;
lastIntfName = addrIter->ifa_name;
}
tmpval = (struct if_nameindex *) malloc((numIntf + 1) * sizeof(struct if_nameindex));
VerifyOrExit(tmpval != NULL, );
memset(tmpval, 0, (numIntf + 1) * sizeof(struct if_nameindex));
lastIntfName = "";
for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next)
{
if (strcmp(addrIter->ifa_name, lastIntfName) == 0)
{
continue;
}
index = if_nametoindex(addrIter->ifa_name);
if (index != 0)
{
tmpval[intfIter].if_index = index;
tmpval[intfIter].if_name = strdup(addrIter->ifa_name);
intfIter++;
}
lastIntfName = addrIter->ifa_name;
}
// coalesce on interface index
maxIntfNum = 0;
for (size_t i = 0; tmpval[i].if_index != 0; i++)
{
if (maxIntfNum < tmpval[i].if_index)
{
maxIntfNum = tmpval[i].if_index;
}
}
retval = (struct if_nameindex *) malloc((maxIntfNum + 1) * sizeof(struct if_nameindex));
VerifyOrExit(retval != NULL, );
memset(retval, 0, (maxIntfNum + 1) * sizeof(struct if_nameindex));
for (size_t i = 0; tmpval[i].if_index != 0; i++)
{
struct if_nameindex * intf = &tmpval[i];
if (retval[intf->if_index - 1].if_index == 0)
{
retval[intf->if_index - 1] = *intf;
}
else
{
free(intf->if_name);
intf->if_index = 0;
intf->if_name = 0;
}
}
intfIter = 0;
// coalesce potential gaps between indeces
for (size_t i = 0; i < maxIntfNum; i++)
{
if (retval[i].if_index != 0)
{
retval[intfIter] = retval[i];
intfIter++;
}
}
for (size_t i = intfIter; i < maxIntfNum; i++)
{
retval[i].if_index = 0;
retval[i].if_name = NULL;
}
exit:
if (tmpval != NULL)
{
free(tmpval);
}
if (addrList != NULL)
{
freeifaddrs(addrList);
}
return retval;
}
#endif // __ANDROID__ && __ANDROID_API__ < 24
InterfaceIterator::InterfaceIterator()
{
mIntfArray = nullptr;
mCurIntf = 0;
mIntfFlags = 0;
mIntfFlagsCached = false;
}
InterfaceIterator::~InterfaceIterator()
{
if (mIntfArray != nullptr)
{
#if __ANDROID__ && __ANDROID_API__ < 24
backport_if_freenameindex(mIntfArray);
#else
if_freenameindex(mIntfArray);
#endif
mIntfArray = nullptr;
}
}
bool InterfaceIterator::HasCurrent()
{
return (mIntfArray != nullptr) ? mIntfArray[mCurIntf].if_index != 0 : Next();
}
bool InterfaceIterator::Next()
{
if (mIntfArray == nullptr)
{
#if __ANDROID__ && __ANDROID_API__ < 24
mIntfArray = backport_if_nameindex();
#else
mIntfArray = if_nameindex();
#endif
}
else if (mIntfArray[mCurIntf].if_index != 0)
{
mCurIntf++;
mIntfFlags = 0;
mIntfFlagsCached = false;
}
return (mIntfArray != nullptr && mIntfArray[mCurIntf].if_index != 0);
}
InterfaceId InterfaceIterator::GetInterfaceId()
{
return HasCurrent() ? InterfaceId(mIntfArray[mCurIntf].if_index) : InterfaceId::Null();
}
CHIP_ERROR InterfaceIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
{
VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(strlen(mIntfArray[mCurIntf].if_name) < nameBufSize, CHIP_ERROR_BUFFER_TOO_SMALL);
strncpy(nameBuf, mIntfArray[mCurIntf].if_name, nameBufSize);
return CHIP_NO_ERROR;
}
bool InterfaceIterator::IsUp()
{
return (GetFlags() & IFF_UP) != 0;
}
bool InterfaceIterator::SupportsMulticast()
{
return (GetFlags() & IFF_MULTICAST) != 0;
}
bool InterfaceIterator::HasBroadcastAddress()
{
return (GetFlags() & IFF_BROADCAST) != 0;
}
short InterfaceIterator::GetFlags()
{
struct ifreq intfData;
if (!mIntfFlagsCached && HasCurrent())
{
strncpy(intfData.ifr_name, mIntfArray[mCurIntf].if_name, IFNAMSIZ);
intfData.ifr_name[IFNAMSIZ - 1] = '\0';
int res = ioctl(GetIOCTLSocket(), SIOCGIFFLAGS, &intfData);
if (res == 0)
{
mIntfFlags = intfData.ifr_flags;
mIntfFlagsCached = true;
}
}
return mIntfFlags;
}
InterfaceAddressIterator::InterfaceAddressIterator()
{
mAddrsList = nullptr;
mCurAddr = nullptr;
}
InterfaceAddressIterator::~InterfaceAddressIterator()
{
if (mAddrsList != nullptr)
{
freeifaddrs(mAddrsList);
mAddrsList = mCurAddr = nullptr;
}
}
bool InterfaceAddressIterator::HasCurrent()
{
return (mAddrsList != nullptr) ? (mCurAddr != nullptr) : Next();
}
bool InterfaceAddressIterator::Next()
{
while (true)
{
if (mAddrsList == nullptr)
{
int res = getifaddrs(&mAddrsList);
if (res < 0)
{
return false;
}
mCurAddr = mAddrsList;
}
else if (mCurAddr != nullptr)
{
mCurAddr = mCurAddr->ifa_next;
}
if (mCurAddr == nullptr)
{
return false;
}
if (mCurAddr->ifa_addr != nullptr &&
(mCurAddr->ifa_addr->sa_family == AF_INET6
#if INET_CONFIG_ENABLE_IPV4
|| mCurAddr->ifa_addr->sa_family == AF_INET
#endif // INET_CONFIG_ENABLE_IPV4
))
{
return true;
}
}
}
IPAddress InterfaceAddressIterator::GetAddress()
{
return HasCurrent() ? IPAddress::FromSockAddr(*mCurAddr->ifa_addr) : IPAddress::Any;
}
uint8_t InterfaceAddressIterator::GetPrefixLength()
{
if (HasCurrent())
{
if (mCurAddr->ifa_addr->sa_family == AF_INET6)
{
#if !__MBED__
struct sockaddr_in6 & netmask = *reinterpret_cast<struct sockaddr_in6 *>(mCurAddr->ifa_netmask);
return NetmaskToPrefixLength(netmask.sin6_addr.s6_addr, 16);
#else // __MBED__
// netmask is not available through an API for IPv6 interface in Mbed.
// Default prefix length to 64.
return 64;
#endif // !__MBED__
}
if (mCurAddr->ifa_addr->sa_family == AF_INET)
{
struct sockaddr_in & netmask = *reinterpret_cast<struct sockaddr_in *>(mCurAddr->ifa_netmask);
return NetmaskToPrefixLength(reinterpret_cast<const uint8_t *>(&netmask.sin_addr.s_addr), 4);
}
}
return 0;
}
InterfaceId InterfaceAddressIterator::GetInterfaceId()
{
return HasCurrent() ? InterfaceId(if_nametoindex(mCurAddr->ifa_name)) : InterfaceId::Null();
}
CHIP_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
{
VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(strlen(mCurAddr->ifa_name) < nameBufSize, CHIP_ERROR_BUFFER_TOO_SMALL);
strncpy(nameBuf, mCurAddr->ifa_name, nameBufSize);
return CHIP_NO_ERROR;
}
bool InterfaceAddressIterator::IsUp()
{
return HasCurrent() && (mCurAddr->ifa_flags & IFF_UP) != 0;
}
bool InterfaceAddressIterator::SupportsMulticast()
{
return HasCurrent() && (mCurAddr->ifa_flags & IFF_MULTICAST) != 0;
}
bool InterfaceAddressIterator::HasBroadcastAddress()
{
return HasCurrent() && (mCurAddr->ifa_flags & IFF_BROADCAST) != 0;
}
#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
#if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
CHIP_ERROR InterfaceId::GetInterfaceName(char * nameBuf, size_t nameBufSize) const
{
if (mPlatformInterface)
{
net_if * currentInterface = net_if_get_by_index(mPlatformInterface);
if (!currentInterface)
{
return CHIP_ERROR_INCORRECT_STATE;
}
const char * name = net_if_get_device(currentInterface)->name;
size_t nameLength = strlen(name);
if (nameLength >= nameBufSize)
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
strncpy(nameBuf, name, nameLength + 1);
return CHIP_NO_ERROR;
}
if (nameBufSize < 1)
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
nameBuf[0] = 0;
return CHIP_NO_ERROR;
}
CHIP_ERROR InterfaceId::InterfaceNameToId(const char * intfName, InterfaceId & interface)
{
int currentId = 0;
net_if * currentInterface;
while ((currentInterface = net_if_get_by_index(++currentId)) != nullptr)
{
if (strcmp(net_if_get_device(currentInterface)->name, intfName) == 0)
{
interface = InterfaceId(currentId);
return CHIP_NO_ERROR;
}
}
interface = InterfaceId::Null();
return INET_ERROR_UNKNOWN_INTERFACE;
}
InterfaceIterator::InterfaceIterator() : mCurrentInterface(net_if_get_by_index(mCurrentId)) {}
bool InterfaceIterator::HasCurrent(void)
{
return mCurrentInterface != nullptr;
}
bool InterfaceIterator::Next()
{
mCurrentInterface = net_if_get_by_index(++mCurrentId);
return HasCurrent();
}
InterfaceId InterfaceIterator::GetInterfaceId(void)
{
return HasCurrent() ? InterfaceId(mCurrentId) : InterfaceId::Null();
}
CHIP_ERROR InterfaceIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
{
VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE);
return InterfaceId(mCurrentId).GetInterfaceName(nameBuf, nameBufSize);
}
bool InterfaceIterator::IsUp()
{
return HasCurrent() && net_if_is_up(mCurrentInterface);
}
bool InterfaceIterator::SupportsMulticast()
{
return HasCurrent() && NET_IF_MAX_IPV6_MADDR > 0;
}
bool InterfaceIterator::HasBroadcastAddress()
{
// Zephyr seems to handle broadcast address for IPv4 implicitly
return HasCurrent() && INET_CONFIG_ENABLE_IPV4;
}
InterfaceAddressIterator::InterfaceAddressIterator() = default;
bool InterfaceAddressIterator::HasCurrent()
{
return mIntfIter.HasCurrent() && (mCurAddrIndex >= 0 || Next());
}
bool InterfaceAddressIterator::Next()
{
while (mIntfIter.HasCurrent())
{
if (mCurAddrIndex == -1) // first address for the current interface
{
const net_if_config * config =
net_if_get_config(net_if_get_by_index(mIntfIter.GetInterfaceId().GetPlatformInterface()));
mIpv6 = config->ip.ipv6;
}
while (++mCurAddrIndex < NET_IF_MAX_IPV6_ADDR)
if (mIpv6->unicast[mCurAddrIndex].is_used)
return true;
mCurAddrIndex = -1;
mIntfIter.Next();
}
return false;
}
IPAddress InterfaceAddressIterator::GetAddress()
{
return HasCurrent() ? IPAddress(mIpv6->unicast[mCurAddrIndex].address.in6_addr) : IPAddress::Any;
}
uint8_t InterfaceAddressIterator::GetPrefixLength()
{
if (HasCurrent())
{
net_if * const iface = net_if_get_by_index(mIntfIter.GetInterfaceId().GetPlatformInterface());
net_if_ipv6_prefix * const prefix = net_if_ipv6_prefix_get(iface, &mIpv6->unicast[mCurAddrIndex].address.in6_addr);
return prefix ? prefix->len : 128;
}
return 0;
}
InterfaceId InterfaceAddressIterator::GetInterfaceId()
{
return HasCurrent() ? mIntfIter.GetInterfaceId() : InterfaceId::Null();
}
CHIP_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
{
VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE);
return mIntfIter.GetInterfaceName(nameBuf, nameBufSize);
}
bool InterfaceAddressIterator::IsUp()
{
return HasCurrent() && mIntfIter.IsUp();
}
bool InterfaceAddressIterator::SupportsMulticast()
{
return HasCurrent() && mIntfIter.SupportsMulticast();
}
bool InterfaceAddressIterator::HasBroadcastAddress()
{
return HasCurrent() && mIntfIter.HasBroadcastAddress();
}
#endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
void InterfaceAddressIterator::GetAddressWithPrefix(IPPrefix & addrWithPrefix)
{
if (HasCurrent())
{
addrWithPrefix.IPAddr = GetAddress();
addrWithPrefix.Length = GetPrefixLength();
}
else
{
addrWithPrefix = IPPrefix::Zero;
}
}
uint8_t NetmaskToPrefixLength(const uint8_t * netmask, uint16_t netmaskLen)
{
uint8_t prefixLen = 0;
for (uint16_t i = 0; i < netmaskLen; i++, prefixLen = static_cast<uint8_t>(prefixLen + 8u))
{
uint8_t b = netmask[i];
if (b != 0xFF)
{
if ((b & 0xF0) == 0xF0)
prefixLen = static_cast<uint8_t>(prefixLen + 4u);
else
b = static_cast<uint8_t>(b >> 4);
if ((b & 0x0C) == 0x0C)
prefixLen = static_cast<uint8_t>(prefixLen + 2u);
else
b = static_cast<uint8_t>(b >> 2);
if ((b & 0x02) == 0x02)
prefixLen++;
break;
}
}
return prefixLen;
}
} // namespace Inet
} // namespace chip