/* * * Copyright (c) 2020-2022 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. * */ #include #include #include #include #include #include #include #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT #include #include #include #endif // CHIP_SYSTEM_CONFIG_USE_LWIP #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS #include #include #include #include #ifdef HAVE_SYS_SOCKIO_H #include #endif /* HAVE_SYS_SOCKIO_H */ #include "InetInterfaceImpl.h" #include #include #include #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF #include #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF #if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT #include #endif #include #include namespace chip { namespace Inet { #if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT CHIP_ERROR InterfaceId::GetInterfaceName(char * nameBuf, size_t nameBufSize) const { if (mPlatformInterface && nameBufSize >= kMaxIfNameLength) { nameBuf[0] = 'o'; nameBuf[1] = 't'; nameBuf[2] = 0; } else { 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 = nullptr; unsigned long intfNum = strtoul(intfName + 2, &parseEnd, 10); if (*parseEnd != 0 || intfNum > UINT8_MAX) { return INET_ERROR_UNKNOWN_INTERFACE; } interface = InterfaceId(intfNum); if (intfNum == 0) { return INET_ERROR_UNKNOWN_INTERFACE; } return CHIP_NO_ERROR; } bool InterfaceIterator::Next() { // TODO : Cleanup #17346 return false; } CHIP_ERROR InterfaceIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize) { VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE); return InterfaceId(1).GetInterfaceName(nameBuf, nameBufSize); } InterfaceId InterfaceIterator::GetInterfaceId() { // only 1 interface is supported return HasCurrent() ? InterfaceId(1) : InterfaceId::Null(); } bool InterfaceIterator::IsUp() { return HasCurrent() && (otThreadGetDeviceRole(Inet::globalOtInstance) != OT_DEVICE_ROLE_DISABLED); } InterfaceAddressIterator::InterfaceAddressIterator() { mNetifAddrList = nullptr; mCurAddr = nullptr; } bool InterfaceAddressIterator::HasCurrent() { return (mNetifAddrList != nullptr) ? (mCurAddr != nullptr) : Next(); } bool InterfaceAddressIterator::Next() { if (mNetifAddrList == nullptr) { if (Inet::globalOtInstance == nullptr) return false; mNetifAddrList = otIp6GetUnicastAddresses(Inet::globalOtInstance); mCurAddr = mNetifAddrList; } else if (mCurAddr != nullptr) { mCurAddr = mCurAddr->mNext; } return (mCurAddr != nullptr); } CHIP_ERROR InterfaceAddressIterator::GetAddress(IPAddress & outIPAddress) { if (!HasCurrent()) { return CHIP_ERROR_SENTINEL; } outIPAddress = IPAddress(mCurAddr->mAddress); return CHIP_NO_ERROR; } uint8_t InterfaceAddressIterator::GetPrefixLength() { // Only 64 bits prefix are supported return 64; } bool InterfaceAddressIterator::IsUp() { return HasCurrent() && (otThreadGetDeviceRole(Inet::globalOtInstance) != OT_DEVICE_ROLE_DISABLED); } InterfaceId InterfaceAddressIterator::GetInterfaceId() { // only 1 interface is supported return HasCurrent() ? InterfaceId(1) : InterfaceId::Null(); } bool InterfaceAddressIterator::HasBroadcastAddress() { return HasCurrent() && (otIp6GetMulticastAddresses(Inet::globalOtInstance) != nullptr); } #endif #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT 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(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 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 defined(NETIF_FOREACH) NETIF_FOREACH(mCurNetif) #else for (mCurNetif = netif_list; mCurNetif != nullptr; mCurNetif = mCurNetif->next) #endif { if (mCurNetif == prevNetif) { mCurNetif = mCurNetif->next; break; } } // Unlock LwIP stack UNLOCK_TCPIP_CORE(); return mCurNetif != nullptr; } 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() && (mCurNetif->flags & (NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_BROADCAST)) != 0; } bool InterfaceIterator::HasBroadcastAddress() { return HasCurrent() && (mCurNetif->flags & NETIF_FLAG_BROADCAST) != 0; } CHIP_ERROR InterfaceIterator::GetInterfaceType(InterfaceType & type) { return CHIP_ERROR_NOT_IMPLEMENTED; } CHIP_ERROR InterfaceIterator::GetHardwareAddress(uint8_t * addressBuffer, uint8_t & addressSize, uint8_t addressBufferSize) { VerifyOrReturnError(addressBuffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(addressBufferSize >= mCurNetif->hwaddr_len, CHIP_ERROR_BUFFER_TOO_SMALL); addressSize = mCurNetif->hwaddr_len; memcpy(addressBuffer, mCurNetif->hwaddr, addressSize); return CHIP_NO_ERROR; } 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; } CHIP_ERROR InterfaceAddressIterator::GetAddress(IPAddress & outIPAddress) { if (!HasCurrent()) { return CHIP_ERROR_SENTINEL; } struct netif * curIntf = mIntfIter.GetInterfaceId().GetPlatformInterface(); if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES) { outIPAddress = IPAddress(*netif_ip6_addr(curIntf, mCurAddrIndex)); return CHIP_NO_ERROR; } #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4 outIPAddress = IPAddress(*netif_ip4_addr(curIntf)); return CHIP_NO_ERROR; #else return CHIP_ERROR_INTERNAL; #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4 } uint8_t InterfaceAddressIterator::GetPrefixLength() { if (HasCurrent()) { if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES) { return 64; } #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4 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(); } CHIP_ERROR InterfaceId::GetLinkLocalAddr(IPAddress * llAddr) const { VerifyOrReturnError(llAddr != nullptr, CHIP_ERROR_INVALID_ARGUMENT); #if !LWIP_IPV6 return CHIP_ERROR_NOT_IMPLEMENTED; #endif //! LWIP_IPV6 for (struct netif * intf = netif_list; intf != nullptr; intf = intf->next) { if ((mPlatformInterface != nullptr) && (mPlatformInterface != intf)) continue; for (int j = 0; j < LWIP_IPV6_NUM_ADDRESSES; ++j) { if (ip6_addr_isvalid(netif_ip6_addr_state(intf, j)) && ip6_addr_islinklocal(netif_ip6_addr(intf, j))) { (*llAddr) = IPAddress(*netif_ip6_addr(intf, j)); return CHIP_NO_ERROR; } } if (mPlatformInterface != nullptr) { return INET_ERROR_ADDRESS_NOT_FOUND; } } return CHIP_NO_ERROR; } #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; } Platform::CopyString(nameBuf, nameBufSize, intfName); 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) { // First attempt to parse as a numeric ID: char * parseEnd; unsigned long intfNum = strtoul(intfName, &parseEnd, 10); if (*parseEnd == 0) { if (intfNum > 0 && intfNum < UINT8_MAX && CanCastTo(intfNum)) { interface = InterfaceId(static_cast(intfNum)); return CHIP_NO_ERROR; } return INET_ERROR_UNKNOWN_INTERFACE; } // Falling back to name -> ID lookup otherwise (e.g. wlan0) 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, 0); if (s < 0) #endif { s = socket(AF_INET, SOCK_STREAM, 0); fcntl(s, F_SETFD, 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; } } InterfaceIterator::InterfaceIterator() { mIntfArray = nullptr; mCurIntf = 0; mIntfFlags = 0; mIntfFlagsCached = false; } InterfaceIterator::~InterfaceIterator() { if (mIntfArray != nullptr) { if_freenameindexImpl(mIntfArray); mIntfArray = nullptr; } } bool InterfaceIterator::HasCurrent() { return (mIntfArray != nullptr) ? mIntfArray[mCurIntf].if_index != 0 : Next(); } bool InterfaceIterator::Next() { if (mIntfArray == nullptr) { mIntfArray = if_nameindexImpl(); } 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); Platform::CopyString(nameBuf, nameBufSize, mIntfArray[mCurIntf].if_name); return CHIP_NO_ERROR; } bool InterfaceIterator::IsUp() { return (GetFlags() & IFF_UP) != 0; } bool InterfaceIterator::IsLoopback() { return (GetFlags() & IFF_LOOPBACK) != 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()) { Platform::CopyString(intfData.ifr_name, mIntfArray[mCurIntf].if_name); int res = ioctl(GetIOCTLSocket(), SIOCGIFFLAGS, &intfData); if (res == 0) { mIntfFlags = intfData.ifr_flags; mIntfFlagsCached = true; } #ifdef __MBED__ CloseIOCTLSocket(); #endif } return mIntfFlags; } CHIP_ERROR InterfaceIterator::GetInterfaceType(InterfaceType & type) { return CHIP_ERROR_NOT_IMPLEMENTED; } CHIP_ERROR InterfaceIterator::GetHardwareAddress(uint8_t * addressBuffer, uint8_t & addressSize, uint8_t addressBufferSize) { return CHIP_ERROR_NOT_IMPLEMENTED; } 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; } } } CHIP_ERROR InterfaceAddressIterator::GetAddress(IPAddress & outIPAddress) { return HasCurrent() ? IPAddress::GetIPAddressFromSockAddr(*mCurAddr->ifa_addr, outIPAddress) : CHIP_ERROR_SENTINEL; } uint8_t InterfaceAddressIterator::GetPrefixLength() { if (HasCurrent()) { if (mCurAddr->ifa_addr->sa_family == AF_INET6) { #ifndef __MBED__ struct sockaddr_in6 & netmask = *reinterpret_cast(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(mCurAddr->ifa_netmask); return NetmaskToPrefixLength(reinterpret_cast(&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); Platform::CopyString(nameBuf, nameBufSize, mCurAddr->ifa_name); return CHIP_NO_ERROR; } bool InterfaceAddressIterator::IsUp() { return HasCurrent() && (mCurAddr->ifa_flags & IFF_UP) != 0; } bool InterfaceAddressIterator::IsLoopback() { return HasCurrent() && (mCurAddr->ifa_flags & IFF_LOOPBACK) != 0; } bool InterfaceAddressIterator::SupportsMulticast() { return HasCurrent() && (mCurAddr->ifa_flags & IFF_MULTICAST) != 0; } bool InterfaceAddressIterator::HasBroadcastAddress() { return HasCurrent() && (mCurAddr->ifa_flags & IFF_BROADCAST) != 0; } CHIP_ERROR InterfaceId::GetLinkLocalAddr(IPAddress * llAddr) const { VerifyOrReturnError(llAddr != nullptr, CHIP_ERROR_INVALID_ARGUMENT); struct ifaddrs * ifaddr; const int rv = getifaddrs(&ifaddr); bool found = false; if (rv == -1) { return INET_ERROR_ADDRESS_NOT_FOUND; } for (struct ifaddrs * ifaddr_iter = ifaddr; ifaddr_iter != nullptr; ifaddr_iter = ifaddr_iter->ifa_next) { if (ifaddr_iter->ifa_addr != nullptr) { if ((ifaddr_iter->ifa_addr->sa_family == AF_INET6) && ((mPlatformInterface == 0) || (mPlatformInterface == if_nametoindex(ifaddr_iter->ifa_name)))) { struct in6_addr * sin6_addr = &(reinterpret_cast(ifaddr_iter->ifa_addr))->sin6_addr; if ((sin6_addr->s6_addr[0] == 0xfe) && ((sin6_addr->s6_addr[1] & 0xc0) == 0x80)) // Link Local Address { (*llAddr) = IPAddress((reinterpret_cast(ifaddr_iter->ifa_addr))->sin6_addr); found = true; break; } } } } freeifaddrs(ifaddr); return (found) ? CHIP_NO_ERROR : INET_ERROR_ADDRESS_NOT_FOUND; } #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; } Platform::CopyString(nameBuf, nameBufSize, name); 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; } CHIP_ERROR InterfaceIterator::GetInterfaceType(InterfaceType & type) { VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE); const net_linkaddr * linkAddr = net_if_get_link_addr(mCurrentInterface); if (!linkAddr) return CHIP_ERROR_INCORRECT_STATE; // Do not consider other than WiFi and Thread for now. if (linkAddr->type == NET_LINK_IEEE802154) { type = InterfaceType::Thread; } // Zephyr doesn't define WiFi address type, so it shares the same type as Ethernet. else if (linkAddr->type == NET_LINK_ETHERNET) { type = InterfaceType::WiFi; } else { type = InterfaceType::Unknown; } return CHIP_NO_ERROR; } CHIP_ERROR InterfaceIterator::GetHardwareAddress(uint8_t * addressBuffer, uint8_t & addressSize, uint8_t addressBufferSize) { VerifyOrReturnError(HasCurrent(), CHIP_ERROR_INCORRECT_STATE); if (!addressBuffer) return CHIP_ERROR_INVALID_ARGUMENT; const net_linkaddr * linkAddr = net_if_get_link_addr(mCurrentInterface); if (!linkAddr) return CHIP_ERROR_INCORRECT_STATE; if (linkAddr->len > addressBufferSize) return CHIP_ERROR_BUFFER_TOO_SMALL; addressSize = linkAddr->len; memcpy(addressBuffer, linkAddr->addr, linkAddr->len); return CHIP_NO_ERROR; } 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; } CHIP_ERROR InterfaceAddressIterator::GetAddress(IPAddress & outIPAddress) { if (HasCurrent()) { outIPAddress = IPAddress(mIpv6->unicast[mCurAddrIndex].address.in6_addr); return CHIP_NO_ERROR; } return CHIP_ERROR_SENTINEL; } 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(); } CHIP_ERROR InterfaceId::GetLinkLocalAddr(IPAddress * llAddr) const { VerifyOrReturnError(llAddr != nullptr, CHIP_ERROR_INVALID_ARGUMENT); net_if * const iface = mPlatformInterface ? net_if_get_by_index(mPlatformInterface) : net_if_get_default(); VerifyOrReturnError(iface != nullptr, INET_ERROR_ADDRESS_NOT_FOUND); in6_addr * const ip6_addr = net_if_ipv6_get_ll(iface, NET_ADDR_PREFERRED); VerifyOrReturnError(ip6_addr != nullptr, INET_ERROR_ADDRESS_NOT_FOUND); *llAddr = IPAddress(*ip6_addr); return CHIP_NO_ERROR; } #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF // static InterfaceId InterfaceId::FromIPAddress(const IPAddress & addr) { InterfaceAddressIterator addrIter; for (; addrIter.HasCurrent(); addrIter.Next()) { IPAddress curAddr; if ((addrIter.GetAddress(curAddr) == CHIP_NO_ERROR) && (addr == curAddr)) { return addrIter.GetInterfaceId(); } } return InterfaceId::Null(); } // static bool InterfaceId::MatchLocalIPv6Subnet(const IPAddress & addr) { if (addr.IsIPv6LinkLocal()) return true; InterfaceAddressIterator ifAddrIter; for (; ifAddrIter.HasCurrent(); ifAddrIter.Next()) { IPPrefix addrPrefix; if (ifAddrIter.GetAddress(addrPrefix.IPAddr) != CHIP_NO_ERROR) continue; #if INET_CONFIG_ENABLE_IPV4 if (addrPrefix.IPAddr.IsIPv4()) continue; #endif // INET_CONFIG_ENABLE_IPV4 if (addrPrefix.IPAddr.IsIPv6LinkLocal()) continue; addrPrefix.Length = ifAddrIter.GetPrefixLength(); if (addrPrefix.MatchAddress(addr)) return true; } return false; } 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(prefixLen + 8u)) { uint8_t b = netmask[i]; if (b != 0xFF) { if ((b & 0xF0) == 0xF0) prefixLen = static_cast(prefixLen + 4u); else b = static_cast(b >> 4); if ((b & 0x0C) == 0x0C) prefixLen = static_cast(prefixLen + 2u); else b = static_cast(b >> 2); if ((b & 0x02) == 0x02) prefixLen++; break; } } return prefixLen; } } // namespace Inet } // namespace chip