3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2019 Google LLC.
5 * Copyright (c) 2013-2017 Nest Labs, Inc.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 * Implementation of network interface abstraction layer.
26 #ifndef __STDC_LIMIT_MACROS
27 #define __STDC_LIMIT_MACROS
30 #include "InetInterface.h"
32 #include "InetLayer.h"
33 #include "InetLayerEvents.h"
35 #include <support/CHIPMemString.h>
36 #include <support/CodeUtils.h>
37 #include <support/DLLUtil.h>
39 #if CHIP_SYSTEM_CONFIG_USE_LWIP
40 #include <lwip/netif.h>
42 #include <lwip/tcpip.h>
43 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
45 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
48 #include <sys/socket.h>
50 #ifdef HAVE_SYS_SOCKIO_H
51 #include <sys/sockio.h>
52 #endif /* HAVE_SYS_SOCKIO_H */
54 #include <sys/ioctl.h>
56 #include "ifaddrs-android.h"
57 #else // !defined(__ANDROID__)
59 #endif // !defined(__ANDROID__)
60 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
62 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
63 #include <net/net_if.h>
64 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
73 * @brief Get the name of a network interface
75 * @param[in] intfId a network interface
76 * @param[in] nameBuf region of memory to write the interface name
77 * @param[in] nameBufSize size of the region denoted by \c nameBuf
79 * @retval INET_NO_ERROR successful result, interface name written
80 * @retval INET_ERROR_NO_MEMORY name is too large to be written in buffer
81 * @retval other another system or platform error
84 * Writes the name of the network interface as \c NUL terminated text string
85 * at \c nameBuf. The name of the unspecified network interface is the empty
88 DLL_EXPORT INET_ERROR GetInterfaceName(InterfaceId intfId, char * nameBuf, size_t nameBufSize)
90 if (intfId != INET_NULL_INTERFACEID)
92 #if CHIP_SYSTEM_CONFIG_USE_LWIP
93 int status = snprintf(nameBuf, nameBufSize, "%c%c%d", intfId->name[0], intfId->name[1], intfId->num);
94 if (status >= static_cast<int>(nameBufSize))
95 return INET_ERROR_NO_MEMORY;
97 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
99 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
100 char intfName[IF_NAMESIZE];
101 if (if_indextoname(intfId, intfName) == nullptr)
102 return chip::System::MapErrorPOSIX(errno);
103 if (strlen(intfName) >= nameBufSize)
104 return INET_ERROR_NO_MEMORY;
105 strcpy(nameBuf, intfName);
106 return INET_NO_ERROR;
107 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
109 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
110 net_if * currentInterface = net_if_get_by_index(intfId);
111 if (!currentInterface)
112 return INET_ERROR_INCORRECT_STATE;
113 const char * name = net_if_get_device(currentInterface)->name;
114 if (strlen(name) >= nameBufSize)
115 return INET_ERROR_NO_MEMORY;
116 strcpy(nameBuf, name);
117 return INET_NO_ERROR;
119 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
123 return INET_ERROR_NO_MEMORY;
126 return INET_NO_ERROR;
130 * @brief Search the list of network interfaces for the indicated name.
132 * @param[in] intfName name of the network interface to find
133 * @param[out] intfId indicator of the network interface to assign
135 * @retval INET_NO_ERROR success, network interface indicated
136 * @retval INET_ERROR_UNKNOWN_INTERFACE no network interface found
137 * @retval other another system or platform error
140 * On LwIP, this function must be called with the LwIP stack lock acquired.
142 * The \c intfId parameter is not updated unless the value returned is
143 * \c INET_NO_ERROR. It should be initialized with \c INET_NULL_INTERFACEID
144 * before calling this function.
146 DLL_EXPORT INET_ERROR InterfaceNameToId(const char * intfName, InterfaceId & intfId)
148 #if CHIP_SYSTEM_CONFIG_USE_LWIP
149 if (strlen(intfName) < 3)
150 return INET_ERROR_UNKNOWN_INTERFACE;
152 unsigned long intfNum = strtoul(intfName + 2, &parseEnd, 10);
153 if (*parseEnd != 0 || intfNum > UINT8_MAX)
154 return INET_ERROR_UNKNOWN_INTERFACE;
156 #if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH)
159 for (intf = netif_list; intf != NULL; intf = intf->next)
162 if (intf->name[0] == intfName[0] && intf->name[1] == intfName[1] && intf->num == (uint8_t) intfNum)
165 return INET_NO_ERROR;
168 intfId = INET_NULL_INTERFACEID;
169 return INET_ERROR_UNKNOWN_INTERFACE;
170 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
172 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
173 intfId = if_nametoindex(intfName);
175 return (errno == ENXIO) ? INET_ERROR_UNKNOWN_INTERFACE : chip::System::MapErrorPOSIX(errno);
176 return INET_NO_ERROR;
177 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
179 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
181 net_if * currentInterface;
183 while ((currentInterface = net_if_get_by_index(++currentId)) != nullptr)
185 if (strcmp(net_if_get_device(currentInterface)->name, intfName) == 0)
188 return INET_NO_ERROR;
191 return INET_ERROR_UNKNOWN_INTERFACE;
192 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
195 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
197 static int sIOCTLSocket = -1;
200 * @brief Returns a global general purpose socket useful for invoking certain network IOCTLs.
202 * This function is thread-safe on all platforms.
206 if (sIOCTLSocket == -1)
210 s = socket(AF_INET, SOCK_STREAM, SOCK_CLOEXEC);
214 s = socket(AF_INET, SOCK_STREAM, 0);
218 if (!__sync_bool_compare_and_swap(&sIOCTLSocket, -1, s))
227 * @brief Close the global socket created by \c GetIOCTLSocket.
230 * This function is provided for cases were leaving the global IOCTL socket
231 * open would register as a leak.
233 * NB: This function is NOT thread-safe with respect to \c GetIOCTLSocket.
235 void CloseIOCTLSocket()
237 if (sIOCTLSocket == -1)
244 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
247 * @fn InterfaceIterator::InterfaceIterator(void)
249 * @brief Constructs an InterfaceIterator object.
252 * Starts the iterator at the first network interface. On some platforms,
253 * this constructor may allocate resources recycled by the destructor.
256 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
258 #if __ANDROID__ && __ANDROID_API__ < 24
260 static struct if_nameindex * backport_if_nameindex(void);
261 static void backport_if_freenameindex(struct if_nameindex *);
263 static void backport_if_freenameindex(struct if_nameindex * inArray)
270 for (size_t i = 0; inArray[i].if_index != 0; i++)
272 if (inArray[i].if_name != NULL)
274 free(inArray[i].if_name);
281 static struct if_nameindex * backport_if_nameindex(void)
286 size_t maxIntfNum = 0;
289 struct if_nameindex * retval = NULL;
290 struct if_nameindex * tmpval = NULL;
291 struct ifaddrs * addrList = NULL;
292 struct ifaddrs * addrIter = NULL;
293 const char * lastIntfName = "";
295 err = getifaddrs(&addrList);
296 VerifyOrExit(err >= 0, );
298 // coalesce on consecutive interface names
299 for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next)
302 if (strcmp(addrIter->ifa_name, lastIntfName) == 0)
307 lastIntfName = addrIter->ifa_name;
310 tmpval = (struct if_nameindex *) malloc((numIntf + 1) * sizeof(struct if_nameindex));
311 VerifyOrExit(tmpval != NULL, );
312 memset(tmpval, 0, (numIntf + 1) * sizeof(struct if_nameindex));
315 for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next)
317 if (strcmp(addrIter->ifa_name, lastIntfName) == 0)
322 index = if_nametoindex(addrIter->ifa_name);
325 tmpval[intfIter].if_index = index;
326 tmpval[intfIter].if_name = strdup(addrIter->ifa_name);
329 lastIntfName = addrIter->ifa_name;
332 // coalesce on interface index
334 for (size_t i = 0; tmpval[i].if_index != 0; i++)
336 if (maxIntfNum < tmpval[i].if_index)
338 maxIntfNum = tmpval[i].if_index;
342 retval = (struct if_nameindex *) malloc((maxIntfNum + 1) * sizeof(struct if_nameindex));
343 VerifyOrExit(retval != NULL, );
344 memset(retval, 0, (maxIntfNum + 1) * sizeof(struct if_nameindex));
346 for (size_t i = 0; tmpval[i].if_index != 0; i++)
348 struct if_nameindex * intf = &tmpval[i];
349 if (retval[intf->if_index - 1].if_index == 0)
351 retval[intf->if_index - 1] = *intf;
363 // coalesce potential gaps between indeces
364 for (size_t i = 0; i < maxIntfNum; i++)
366 if (retval[i].if_index != 0)
368 retval[intfIter] = retval[i];
373 for (size_t i = intfIter; i < maxIntfNum; i++)
375 retval[i].if_index = 0;
376 retval[i].if_name = NULL;
385 if (addrList != NULL)
387 freeifaddrs(addrList);
393 #endif // __ANDROID__ && __ANDROID_API__ < 24
395 InterfaceIterator::InterfaceIterator()
397 mIntfArray = nullptr;
400 mIntfFlagsCached = false;
403 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
405 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
406 InterfaceIterator::InterfaceIterator() : mCurrentInterface(net_if_get_by_index(mCurrentId)) {}
407 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
410 * @fn InterfaceIterator::~InterfaceIterator(void)
412 * @brief Destroys an InterfaceIterator object.
415 * Recycles any resources allocated by the constructor.
418 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
420 InterfaceIterator::~InterfaceIterator()
422 if (mIntfArray != nullptr)
424 #if __ANDROID__ && __ANDROID_API__ < 24
425 backport_if_freenameindex(mIntfArray);
427 if_freenameindex(mIntfArray);
429 mIntfArray = nullptr;
433 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
436 * @fn bool InterfaceIterator::HasCurrent(void)
438 * @brief Test whether the iterator is positioned on an interface
440 * @return \c true if the iterator is positioned on an interface;
441 * \c false if positioned beyond the end of the interface list.
444 #if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
445 bool InterfaceIterator::HasCurrent()
447 return (mIntfArray != nullptr) ? mIntfArray[mCurIntf].if_index != 0 : Next();
449 #endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
451 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
452 bool InterfaceIterator::HasCurrent(void)
454 return mCurrentInterface != nullptr;
456 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
459 * @fn bool InterfaceIterator::Next(void)
461 * @brief Advance the iterator to the next network interface.
463 * @return \c false if advanced beyond the end, else \c true.
466 * Advances the internal iterator to the next network interface or to a position
467 * beyond the end of the interface list.
469 * On multi-threaded LwIP systems, this method is thread-safe relative to other
470 * threads accessing the global LwIP state provided that: 1) the other threads
471 * hold the LwIP core lock while mutating the list of netifs; and 2) netif objects
472 * themselves are never destroyed.
474 * Iteration is stable in the face of changes to the underlying system's
475 * interfaces, *except* in the case of LwIP systems when the currently selected
476 * interface is removed from the list, which causes iteration to end immediately.
478 bool InterfaceIterator::Next()
480 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
482 if (mIntfArray == nullptr)
484 #if __ANDROID__ && __ANDROID_API__ < 24
485 mIntfArray = backport_if_nameindex();
487 mIntfArray = if_nameindex();
490 else if (mIntfArray[mCurIntf].if_index != 0)
494 mIntfFlagsCached = false;
496 return (mIntfArray != nullptr && mIntfArray[mCurIntf].if_index != 0);
498 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
500 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
501 mCurrentInterface = net_if_get_by_index(++mCurrentId);
503 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
505 #if CHIP_SYSTEM_CONFIG_USE_LWIP
510 // Verify the previous netif is still on the list if netifs. If so,
511 // advance to the next nextif.
512 struct netif * prevNetif = mCurNetif;
513 #if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH)
514 NETIF_FOREACH(mCurNetif)
516 for (mCurNetif = netif_list; mCurNetif != NULL; mCurNetif = mCurNetif->next)
519 if (mCurNetif == prevNetif)
521 mCurNetif = mCurNetif->next;
529 return mCurNetif != NULL;
531 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
535 * @fn InterfaceId InterfaceIterator::GetInterfaceId(void)
537 * @brief Returns the network interface id at the current iterator position.
539 * @retval INET_NULL_INTERFACEID if advanced beyond the end of the list.
540 * @retval id the current network interface id.
543 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
544 InterfaceId InterfaceIterator::GetInterfaceId()
546 return (HasCurrent()) ? mIntfArray[mCurIntf].if_index : INET_NULL_INTERFACEID;
548 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
550 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
551 InterfaceId InterfaceIterator::GetInterfaceId(void)
553 return HasCurrent() ? mCurrentId : INET_NULL_INTERFACEID;
555 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
558 * @brief Get the name of the current network interface
560 * @param[in] nameBuf region of memory to write the interface name
561 * @param[in] nameBufSize size of the region denoted by \c nameBuf
563 * @retval INET_NO_ERROR successful result, interface name written
564 * @retval INET_ERROR_INCORRECT_STATE
565 * iterator is positioned beyond the end of
567 * @retval INET_ERROR_NO_MEMORY name is too large to be written in buffer
568 * @retval other another system or platform error
571 * Writes the name of the network interface as \c NUL terminated text string
574 INET_ERROR InterfaceIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
576 INET_ERROR err = INET_ERROR_NOT_IMPLEMENTED;
578 VerifyOrExit(HasCurrent(), err = INET_ERROR_INCORRECT_STATE);
580 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
581 VerifyOrExit(strlen(mIntfArray[mCurIntf].if_name) < nameBufSize, err = INET_ERROR_NO_MEMORY);
582 strncpy(nameBuf, mIntfArray[mCurIntf].if_name, nameBufSize);
584 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
586 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
587 err = ::chip::Inet::GetInterfaceName(mCurrentId, nameBuf, nameBufSize);
588 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
590 #if CHIP_SYSTEM_CONFIG_USE_LWIP
591 err = ::chip::Inet::GetInterfaceName(mCurNetif, nameBuf, nameBufSize);
592 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
599 * @brief Returns whether the current network interface is up.
601 * @return \c true if current network interface is up, \c false if not
602 * or if the iterator is positioned beyond the end of the list.
604 bool InterfaceIterator::IsUp()
606 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
607 return (GetFlags() & IFF_UP) != 0;
608 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
610 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
611 return HasCurrent() && net_if_is_up(mCurrentInterface);
612 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
614 #if CHIP_SYSTEM_CONFIG_USE_LWIP
615 return HasCurrent() && netif_is_up(mCurNetif);
616 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
620 * @brief Returns whether the current network interface supports multicast.
622 * @return \c true if current network interface supports multicast, \c false
623 * if not, or if the iterator is positioned beyond the end of the list.
625 bool InterfaceIterator::SupportsMulticast()
627 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
628 return (GetFlags() & IFF_MULTICAST) != 0;
629 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
631 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
632 return HasCurrent() && NET_IF_MAX_IPV6_MADDR > 0;
633 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
635 #if CHIP_SYSTEM_CONFIG_USE_LWIP
636 return HasCurrent() &&
637 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
638 (mCurNetif->flags & (NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_BROADCAST)) != 0;
640 (mCurNetif->flags & NETIF_FLAG_POINTTOPOINT) == 0;
641 #endif // LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
642 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
646 * @brief Returns whether the current network interface has a broadcast address.
648 * @return \c true if current network interface has a broadcast address, \c false
649 * if not, or if the iterator is positioned beyond the end of the list.
651 bool InterfaceIterator::HasBroadcastAddress()
653 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
654 return (GetFlags() & IFF_BROADCAST) != 0;
655 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
657 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
658 // Zephyr seems to handle broadcast address for IPv4 implicitly
659 return HasCurrent() && INET_CONFIG_ENABLE_IPV4;
660 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
662 #if CHIP_SYSTEM_CONFIG_USE_LWIP
663 return HasCurrent() && (mCurNetif->flags & NETIF_FLAG_BROADCAST) != 0;
664 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
667 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
670 * @fn short InterfaceIterator::GetFlags(void)
672 * @brief Returns the ifr_flags value for the current interface.
674 short InterfaceIterator::GetFlags()
676 struct ifreq intfData;
678 if (!mIntfFlagsCached && HasCurrent())
680 strncpy(intfData.ifr_name, mIntfArray[mCurIntf].if_name, IFNAMSIZ);
681 intfData.ifr_name[IFNAMSIZ - 1] = '\0';
683 int res = ioctl(GetIOCTLSocket(), SIOCGIFFLAGS, &intfData);
686 mIntfFlags = intfData.ifr_flags;
687 mIntfFlagsCached = true;
694 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
696 #if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
698 * @fn InterfaceAddressIterator::InterfaceAddressIterator(void)
700 * @brief Constructs an InterfaceAddressIterator object.
703 * Starts the iterator at the first network address. On some platforms,
704 * this constructor may allocate resources recycled by the destructor.
706 InterfaceAddressIterator::InterfaceAddressIterator()
708 mAddrsList = nullptr;
711 #endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
713 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
714 InterfaceAddressIterator::InterfaceAddressIterator() = default;
715 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
718 * @fn InterfaceAddressIterator::~InterfaceAddressIterator(void)
720 * @brief Destroys an InterfaceAddressIterator object.
723 * Recycles any resources allocated by the constructor.
726 #if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
727 InterfaceAddressIterator::~InterfaceAddressIterator()
729 if (mAddrsList != nullptr)
731 freeifaddrs(mAddrsList);
732 mAddrsList = mCurAddr = nullptr;
735 #endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
738 * @fn bool InterfaceIterator::HasCurrent(void)
740 * @brief Test whether the iterator is positioned on an interface address
742 * @return \c true if the iterator is positioned on an interface address;
743 * \c false if positioned beyond the end of the address list.
745 bool InterfaceAddressIterator::HasCurrent()
747 #if CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
748 return (mAddrsList != nullptr) ? (mCurAddr != nullptr) : Next();
749 #endif // CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
751 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
752 return mIntfIter.HasCurrent() && (mCurAddrIndex >= 0 || Next());
753 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
755 #if CHIP_SYSTEM_CONFIG_USE_LWIP
756 return mIntfIter.HasCurrent() && ((mCurAddrIndex != kBeforeStartIndex) || Next());
757 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
761 * @fn bool InterfaceAddressIterator::Next(void)
763 * @brief Advance the iterator to the next interface address.
765 * @return \c false if advanced beyond the end, else \c true.
768 * Advances the iterator to the next interface address or to a position
769 * beyond the end of the address list.
771 * On LwIP, this method is thread-safe provided that: 1) other threads hold
772 * the LwIP core lock while mutating the netif list; and 2) netif objects
773 * themselves are never destroyed. Additionally, iteration on LwIP systems
774 * will terminate early if the current interface is removed from the list.
776 bool InterfaceAddressIterator::Next()
778 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
781 if (mAddrsList == nullptr)
783 int res = getifaddrs(&mAddrsList);
788 mCurAddr = mAddrsList;
790 else if (mCurAddr != nullptr)
792 mCurAddr = mCurAddr->ifa_next;
795 if (mCurAddr == nullptr)
800 if (mCurAddr->ifa_addr != nullptr &&
801 (mCurAddr->ifa_addr->sa_family == AF_INET6
802 #if INET_CONFIG_ENABLE_IPV4
803 || mCurAddr->ifa_addr->sa_family == AF_INET
804 #endif // INET_CONFIG_ENABLE_IPV4
810 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
812 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
813 while (mIntfIter.HasCurrent())
815 if (mCurAddrIndex == -1) // first address for the current interface
817 const net_if_config * config = net_if_get_config(net_if_get_by_index(mIntfIter.GetInterfaceId()));
818 mIpv6 = config->ip.ipv6;
821 while (++mCurAddrIndex < NET_IF_MAX_IPV6_ADDR)
822 if (mIpv6->unicast[mCurAddrIndex].is_used)
830 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
832 #if CHIP_SYSTEM_CONFIG_USE_LWIP
835 while (mIntfIter.HasCurrent())
837 struct netif * curIntf = mIntfIter.GetInterfaceId();
839 while (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES)
841 if (ip6_addr_isvalid(netif_ip6_addr_state(curIntf, mCurAddrIndex)))
848 #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
849 if (mCurAddrIndex == LWIP_IPV6_NUM_ADDRESSES)
851 if (!ip4_addr_isany(netif_ip4_addr(curIntf)))
856 #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
863 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
867 * @fn IPAddress InterfaceAddressIterator::GetAddress(void)
869 * @brief Get the current interface address.
871 * @return the current interface address or \c IPAddress::Any if the iterator
872 * is positioned beyond the end of the address list.
874 IPAddress InterfaceAddressIterator::GetAddress()
878 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
879 return IPAddress::FromSockAddr(*mCurAddr->ifa_addr);
880 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
882 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
883 return IPAddress::FromIPv6(mIpv6->unicast[mCurAddrIndex].address.in6_addr);
884 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
886 #if CHIP_SYSTEM_CONFIG_USE_LWIP
887 struct netif * curIntf = mIntfIter.GetInterfaceId();
889 if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES)
891 return IPAddress::FromIPv6(*netif_ip6_addr(curIntf, mCurAddrIndex));
893 #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
896 return IPAddress::FromIPv4(*netif_ip4_addr(curIntf));
898 #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
899 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
902 return IPAddress::Any;
906 * @fn uint8_t InterfaceAddressIterator::GetPrefixLength(void)
908 * @brief Gets the network prefix associated with the current interface address.
910 * @return the network prefix (in bits) or 0 if the iterator is positioned beyond
911 * the end of the address list.
914 * On LwIP, this method simply returns the hard-coded constant 64.
916 * Note Well: the standard subnet prefix on all links other than PPP
917 * links is 64 bits. On PPP links and some non-broadcast multipoint access
918 * links, the convention is either 127 bits or 128 bits, but it might be
919 * something else. On most platforms, the system's interface address
920 * structure can represent arbitrary prefix lengths between 0 and 128.
922 uint8_t InterfaceAddressIterator::GetPrefixLength()
926 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
927 if (mCurAddr->ifa_addr->sa_family == AF_INET6)
929 struct sockaddr_in6 & netmask = *reinterpret_cast<struct sockaddr_in6 *>(mCurAddr->ifa_netmask);
930 return NetmaskToPrefixLength(netmask.sin6_addr.s6_addr, 16);
932 if (mCurAddr->ifa_addr->sa_family == AF_INET)
934 struct sockaddr_in & netmask = *reinterpret_cast<struct sockaddr_in *>(mCurAddr->ifa_netmask);
935 return NetmaskToPrefixLength(reinterpret_cast<const uint8_t *>(&netmask.sin_addr.s_addr), 4);
937 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
939 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
940 net_if * const iface = net_if_get_by_index(mIntfIter.GetInterfaceId());
941 net_if_ipv6_prefix * const prefix = net_if_ipv6_prefix_get(iface, &mIpv6->unicast[mCurAddrIndex].address.in6_addr);
942 return prefix ? prefix->len : 128;
943 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
945 #if CHIP_SYSTEM_CONFIG_USE_LWIP
946 if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES)
950 #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
953 struct netif * curIntf = mIntfIter.GetInterfaceId();
954 return NetmaskToPrefixLength((const uint8_t *) netif_ip4_netmask(curIntf), 4);
956 #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4
957 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
963 * @fn InterfaceId InterfaceAddressIterator::GetInterfaceId(void)
965 * @brief Returns the network interface id associated with the current
968 * @return the interface id or \c INET_NULL_INTERFACEID if the iterator
969 * is positioned beyond the end of the address list.
971 InterfaceId InterfaceAddressIterator::GetInterfaceId()
975 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
976 return if_nametoindex(mCurAddr->ifa_name);
977 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
979 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
980 return mIntfIter.GetInterfaceId();
981 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
983 return INET_NULL_INTERFACEID;
987 * @fn INET_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
989 * @brief Get the name of the network interface associated with the
990 * current interface address.
992 * @param[in] nameBuf region of memory to write the interface name
993 * @param[in] nameBufSize size of the region denoted by \c nameBuf
995 * @retval INET_NO_ERROR successful result, interface name written
996 * @retval INET_ERROR_NO_MEMORY name is too large to be written in buffer
997 * @retval INET_ERROR_INCORRECT_STATE
998 * the iterator is not currently positioned on an
1000 * @retval other another system or platform error
1003 * Writes the name of the network interface as \c NUL terminated text string
1006 INET_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize)
1008 INET_ERROR err = INET_ERROR_NOT_IMPLEMENTED;
1010 VerifyOrExit(HasCurrent(), err = INET_ERROR_INCORRECT_STATE);
1012 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1013 VerifyOrExit(strlen(mCurAddr->ifa_name) < nameBufSize, err = INET_ERROR_NO_MEMORY);
1014 strncpy(nameBuf, mCurAddr->ifa_name, nameBufSize);
1015 err = INET_NO_ERROR;
1016 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1018 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1019 err = mIntfIter.GetInterfaceName(nameBuf, nameBufSize);
1020 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1027 * @fn bool InterfaceAddressIterator::IsUp(void)
1029 * @brief Returns whether the network interface associated with the current
1030 * interface address is up.
1032 * @return \c true if current network interface is up, \c false if not, or
1033 * if the iterator is not positioned on an interface address.
1035 bool InterfaceAddressIterator::IsUp()
1039 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1040 return (mCurAddr->ifa_flags & IFF_UP) != 0;
1041 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1043 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1044 return mIntfIter.IsUp();
1045 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1051 * @fn bool InterfaceAddressIterator::SupportsMulticast(void)
1053 * @brief Returns whether the network interface associated with the current
1054 * interface address supports multicast.
1056 * @return \c true if multicast is supported, \c false if not, or
1057 * if the iterator is not positioned on an interface address.
1059 bool InterfaceAddressIterator::SupportsMulticast()
1063 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1064 return (mCurAddr->ifa_flags & IFF_MULTICAST) != 0;
1065 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1067 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1068 return mIntfIter.SupportsMulticast();
1069 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1075 * @fn bool InterfaceAddressIterator::HasBroadcastAddress(void)
1077 * @brief Returns whether the network interface associated with the current
1078 * interface address has an IPv4 broadcast address.
1080 * @return \c true if the interface has a broadcast address, \c false if not, or
1081 * if the iterator is not positioned on an interface address.
1083 bool InterfaceAddressIterator::HasBroadcastAddress()
1087 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1088 return (mCurAddr->ifa_flags & IFF_BROADCAST) != 0;
1089 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS
1091 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1092 return mIntfIter.HasBroadcastAddress();
1093 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_NET_IF
1099 * @fn void InterfaceAddressIterator::GetAddressWithPrefix(IPPrefix & addrWithPrefix)
1101 * @brief Returns an IPPrefix containing the address and prefix length
1102 * for the current address.
1104 void InterfaceAddressIterator::GetAddressWithPrefix(IPPrefix & addrWithPrefix)
1108 addrWithPrefix.IPAddr = GetAddress();
1109 addrWithPrefix.Length = GetPrefixLength();
1113 addrWithPrefix = IPPrefix::Zero;
1118 * @fn uint8_t NetmaskToPrefixLength(const uint8_t * netmask, uint16_t netmaskLen)
1120 * @brief Compute a prefix length from a variable-length netmask.
1122 uint8_t NetmaskToPrefixLength(const uint8_t * netmask, uint16_t netmaskLen)
1124 uint8_t prefixLen = 0;
1126 for (uint16_t i = 0; i < netmaskLen; i++, prefixLen = static_cast<uint8_t>(prefixLen + 8u))
1128 uint8_t b = netmask[i];
1131 if ((b & 0xF0) == 0xF0)
1132 prefixLen = static_cast<uint8_t>(prefixLen + 4u);
1134 b = static_cast<uint8_t>(b >> 4);
1136 if ((b & 0x0C) == 0x0C)
1137 prefixLen = static_cast<uint8_t>(prefixLen + 2u);
1139 b = static_cast<uint8_t>(b >> 2);
1141 if ((b & 0x02) == 0x02)