This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 96233e0c4262ae4a46c6a79c3a050301e2ddb59c Author: Zhe Weng <[email protected]> AuthorDate: Fri Aug 25 15:55:53 2023 +0800 net/netdev: Support multiple IPv6 addresses per device Compatible with previous usage, because may network drivers are using old member name to print logs, and there's no significant need to change them now. Signed-off-by: Zhe Weng <[email protected]> --- include/nuttx/net/netdev.h | 164 +++++++++++++++- net/netdev/CMakeLists.txt | 4 + net/netdev/Kconfig | 18 ++ net/netdev/Make.defs | 4 + net/netdev/netdev_ipv6.c | 466 +++++++++++++++++++++++++++++++++++++++++++++ net/utils/net_mask2pref.c | 38 ++++ net/utils/utils.h | 19 ++ 7 files changed, 710 insertions(+), 3 deletions(-) diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index 9e279a0fe0..cbfa19fb44 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -168,6 +168,12 @@ #define IPv4BUF ((FAR struct ipv4_hdr_s *)IPBUF(0)) #define IPv6BUF ((FAR struct ipv6_hdr_s *)IPBUF(0)) +#ifdef CONFIG_NET_IPv6 +# ifndef CONFIG_NETDEV_MAX_IPv6_ADDR +# define CONFIG_NETDEV_MAX_IPv6_ADDR 1 +# endif +#endif + /**************************************************************************** * Public Types ****************************************************************************/ @@ -230,6 +236,14 @@ struct netdev_varaddr_s }; #endif +#ifdef CONFIG_NET_IPv6 +struct netdev_ifaddr6_s +{ + net_ipv6addr_t addr; /* Host IPv6 address */ + net_ipv6addr_t mask; /* Network IPv6 subnet mask */ +}; +#endif + /* This structure collects information that is specific to a specific network * interface driver. If the hardware platform supports only a single * instance of this structure. @@ -302,10 +316,30 @@ struct net_driver_s #endif #ifdef CONFIG_NET_IPv6 - net_ipv6addr_t d_ipv6addr; /* Host IPv6 address assigned to the network interface */ + /* Host IPv6 addresses assigned to the network interface. + * For historical reason, we keep the old name d_ipv6addr and d_ipv6netmask + * for backward compatibility. Please use d_ipv6 for new drivers. + */ + +# if defined(CONFIG_HAVE_ANONYMOUS_STRUCT) && \ + defined(CONFIG_HAVE_ANONYMOUS_UNION) + union /* Try to limit the scope of backward compatibility alias. */ + { + struct netdev_ifaddr6_s d_ipv6[CONFIG_NETDEV_MAX_IPv6_ADDR]; + struct + { + net_ipv6addr_t d_ipv6addr; /* Compatible with previous usage */ + net_ipv6addr_t d_ipv6netmask; /* Compatible with previous usage */ + }; + }; +# else /* Without anonymous union/struct support, we can only use macros. */ + struct netdev_ifaddr6_s d_ipv6[CONFIG_NETDEV_MAX_IPv6_ADDR]; +# define d_ipv6addr d_ipv6[0].addr /* Compatible with previous usage */ +# define d_ipv6netmask d_ipv6[0].mask /* Compatible with previous usage */ +# endif /* CONFIG_HAVE_ANONYMOUS_STRUCT && CONFIG_HAVE_ANONYMOUS_UNION */ + net_ipv6addr_t d_ipv6draddr; /* Default router IPv6 address */ - net_ipv6addr_t d_ipv6netmask; /* Network IPv6 subnet mask */ -#endif +#endif /* CONFIG_NET_IPv6 */ /* This is a new design that uses d_iob as packets input and output * buffer which used by some NICs such as celluler net driver. Case for * data input, note that d_iob maybe a linked chain only when using @@ -445,6 +479,9 @@ struct net_driver_s }; typedef CODE int (*devif_poll_callback_t)(FAR struct net_driver_s *dev); +typedef CODE int (*devif_ipv6_callback_t)(FAR struct net_driver_s *dev, + FAR struct netdev_ifaddr6_s *addr, + FAR void *arg); /**************************************************************************** * Public Function Prototypes @@ -979,4 +1016,125 @@ void netdev_iob_clear(FAR struct net_driver_s *dev); void netdev_iob_release(FAR struct net_driver_s *dev); +/**************************************************************************** + * Name: netdev_ipv6_add/del + * + * Description: + * Add or delete an IPv6 address on the network device + * + * Returned Value: + * OK - Success + * -EINVAL - Invalid prefix length + * -EADDRNOTAVAIL - Delete on non-existent address + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +int netdev_ipv6_add(FAR struct net_driver_s *dev, const net_ipv6addr_t addr, + unsigned int preflen); +int netdev_ipv6_del(FAR struct net_driver_s *dev, const net_ipv6addr_t addr, + unsigned int preflen); +#endif + +/**************************************************************************** + * Name: netdev_ipv6_srcaddr/srcifaddr + * + * Description: + * Get the source IPv6 address (RFC6724). + * + * Returned Value: + * A pointer to the IPv6 address is returned on success. It will never be + * NULL, but can be an address containing g_ipv6_unspecaddr. + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +FAR const uint16_t *netdev_ipv6_srcaddr(FAR struct net_driver_s *dev, + const net_ipv6addr_t dst); +FAR const struct netdev_ifaddr6_s * +netdev_ipv6_srcifaddr(FAR struct net_driver_s *dev, + const net_ipv6addr_t dst); +#endif + +/**************************************************************************** + * Name: netdev_ipv6_lladdr + * + * Description: + * Get the link-local address of the network device. + * + * Returned Value: + * A pointer to the link-local address is returned on success. + * NULL is returned if the address is not found on the device. + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +FAR const uint16_t *netdev_ipv6_lladdr(FAR struct net_driver_s *dev); +#endif + +/**************************************************************************** + * Name: netdev_ipv6_lookup + * + * Description: + * Look up an IPv6 address in the network device's IPv6 addresses + * + * Input Parameters: + * dev - The network device to use in the lookup + * addr - The IPv6 address to be looked up + * maskcmp - If true, then the IPv6 address is compared to the network + * device's IPv6 addresses with mask compare. + * If false, then the IPv6 address should be exactly the same as + * the network device's IPv6 address. + * + * Returned Value: + * A pointer to the matching IPv6 address entry is returned on success. + * NULL is returned if the IPv6 address is not found in the device. + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +FAR struct netdev_ifaddr6_s * +netdev_ipv6_lookup(FAR struct net_driver_s *dev, const net_ipv6addr_t addr, + bool maskcmp); +#endif + +/**************************************************************************** + * Name: netdev_ipv6_foreach + * + * Description: + * Enumerate each IPv6 address on a network device. This function will + * terminate when either (1) all addresses have been enumerated or (2) when + * a callback returns any non-zero value. + * + * Input Parameters: + * dev - The network device + * callback - Will be called for each IPv6 address + * arg - Opaque user argument passed to callback() + * + * Returned Value: + * Zero: Enumeration completed + * Non-zero: Enumeration terminated early by callback + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +int netdev_ipv6_foreach(FAR struct net_driver_s *dev, + devif_ipv6_callback_t callback, FAR void *arg); +#endif + #endif /* __INCLUDE_NUTTX_NET_NETDEV_H */ diff --git a/net/netdev/CMakeLists.txt b/net/netdev/CMakeLists.txt index a20df4d684..53c9254bac 100644 --- a/net/netdev/CMakeLists.txt +++ b/net/netdev/CMakeLists.txt @@ -42,4 +42,8 @@ if(CONFIG_NETDOWN_NOTIFIER) list(APPEND SRCS netdown_notifier.c) endif() +if(CONFIG_NET_IPv6) + list(APPEND SRCS netdev_ipv6.c) +endif() + target_sources(net PRIVATE ${SRCS}) diff --git a/net/netdev/Kconfig b/net/netdev/Kconfig index 6aa4699b51..27ba60c5e8 100644 --- a/net/netdev/Kconfig +++ b/net/netdev/Kconfig @@ -61,6 +61,24 @@ config NETDEV_IFINDEX When enabled, these option also enables the user interfaces: if_nametoindex() and if_indextoname(). +config NETDEV_MULTIPLE_IPv6 + bool "Enable multiple IPv6 addresses support" + default n + select NETDEV_IFINDEX + depends on NET_IPv6 + ---help--- + Enable support for multiple IPv6 addresses per network device. + +config NETDEV_MAX_IPv6_ADDR + int "Maximum number of IPv6 addresses per network device" + range 2 255 + default 2 + depends on NETDEV_MULTIPLE_IPv6 + ---help--- + Maximum number of IPv6 addresses that can be assigned to a single + network device. Normally a link-local address and a global address + are needed. + config NETDOWN_NOTIFIER bool "Support network down notifications" default n diff --git a/net/netdev/Make.defs b/net/netdev/Make.defs index ace44637da..a273c5d6a9 100644 --- a/net/netdev/Make.defs +++ b/net/netdev/Make.defs @@ -34,6 +34,10 @@ ifeq ($(CONFIG_NETDOWN_NOTIFIER),y) SOCK_CSRCS += netdown_notifier.c endif +ifeq ($(CONFIG_NET_IPv6),y) +NETDEV_CSRCS += netdev_ipv6.c +endif + # Include netdev build support DEPPATH += --dep-path netdev diff --git a/net/netdev/netdev_ipv6.c b/net/netdev/netdev_ipv6.c new file mode 100644 index 0000000000..0692d32305 --- /dev/null +++ b/net/netdev/netdev_ipv6.c @@ -0,0 +1,466 @@ +/**************************************************************************** + * net/netdev/netdev_ipv6.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <debug.h> +#include <errno.h> +#include <stdint.h> + +#include <nuttx/net/netdev.h> + +#include "inet/inet.h" +#include "utils/utils.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Defined in Section 2.7 of RFC4291 */ + +#define IPv6_SCOPE_INTERFACE_LOCAL 0x1 +#define IPv6_SCOPE_LINK_LOCAL 0x2 +#define IPv6_SCOPE_ADMIN_LOCAL 0x4 +#define IPv6_SCOPE_SITE_LOCAL 0x5 +#define IPv6_SCOPE_ORGANIZATION_LOCAL 0x8 +#define IPv6_SCOPE_GLOBAL 0xe + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netdev_ipv6_get_scope + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_MULTIPLE_IPv6 +static uint8_t netdev_ipv6_get_scope(const net_ipv6addr_t addr) +{ + if (net_is_addr_mcast(addr)) + { + /* As defined in Section 2.7 of RFC4291: + * | 8 | 4 | 4 | 112 bits | + * +------ -+----+----+---------------------------------------------+ + * |11111111|flgs|scop| group ID | + * +--------+----+----+---------------------------------------------+ + */ + + return NTOHS(addr[0]) & 0x000f; + } + + if (net_is_addr_linklocal(addr)) + { + return IPv6_SCOPE_LINK_LOCAL; + } + + if (net_is_addr_sitelocal(addr)) + { + return IPv6_SCOPE_SITE_LOCAL; + } + + return IPv6_SCOPE_GLOBAL; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netdev_ipv6_add/del + * + * Description: + * Add or delete an IPv6 address on the network device + * + * Returned Value: + * OK - Success + * -EINVAL - Invalid prefix length + * -EADDRNOTAVAIL - Delete on non-existent address + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +int netdev_ipv6_add(FAR struct net_driver_s *dev, const net_ipv6addr_t addr, + unsigned int preflen) +{ + FAR struct netdev_ifaddr6_s *ifaddr = &dev->d_ipv6[0]; +#ifdef CONFIG_NETDEV_MULTIPLE_IPv6 + uint8_t scope; + int i; +#endif + + /* Verify the prefix length */ + + if (preflen > 128) + { + return -EINVAL; + } + +#ifdef CONFIG_NETDEV_MULTIPLE_IPv6 + /* Avoid duplicate address. */ + + ifaddr = netdev_ipv6_lookup(dev, addr, false); + if (ifaddr != NULL) + { + /* Check if net mask is the same. */ + + if (net_ipv6_mask2pref(ifaddr->mask) == preflen) + { + nwarn("WARNING: Trying to add same IPv6 address on net device! " + "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%d\n", + NTOHS(addr[0]), NTOHS(addr[1]), NTOHS(addr[2]), + NTOHS(addr[3]), NTOHS(addr[4]), NTOHS(addr[5]), + NTOHS(addr[6]), NTOHS(addr[7]), preflen); + return -EEXIST; + } + + /* Not exactly the same, update the net mask. + * REVISIT: Currently try to keep logic same as previous, which always + * allows to override the address. But not sure if it's good. + */ + + net_ipv6_pref2mask(preflen, ifaddr->mask); + return OK; + } + + /* Now we start to find a proper slot to put this address. */ + + ifaddr = &dev->d_ipv6[0]; /* Set default to a valid address. */ + scope = netdev_ipv6_get_scope(addr); + + for (i = 0; i < CONFIG_NETDEV_MAX_IPv6_ADDR; i++) + { + FAR struct netdev_ifaddr6_s *current = &dev->d_ipv6[i]; + + /* Select empty address. */ + + if (net_ipv6addr_cmp(current->addr, g_ipv6_unspecaddr)) + { + ifaddr = current; + break; + } + + /* Select address with same scope. */ + + if (netdev_ipv6_get_scope(current->addr) == scope) + { + ifaddr = current; + continue; /* Good slot, but maybe we have empty slot later. */ + } + } +#endif /* CONFIG_NETDEV_MULTIPLE_IPv6 */ + + net_ipv6addr_copy(ifaddr->addr, addr); + net_ipv6_pref2mask(preflen, ifaddr->mask); + + return OK; +} + +int netdev_ipv6_del(FAR struct net_driver_s *dev, const net_ipv6addr_t addr, + unsigned int preflen) +{ + FAR struct netdev_ifaddr6_s *ifaddr; + + /* Verify the prefix length */ + + if (preflen > 128) + { + return -EINVAL; + } + + /* Find the matching address entry */ + + ifaddr = netdev_ipv6_lookup(dev, addr, false); + if (ifaddr == NULL) + { + /* The address does not exist on the device */ + + return -EADDRNOTAVAIL; + } + + if (net_ipv6_mask2pref(ifaddr->mask) != preflen) + { + /* Prefix length does not match, regard as not found (same as Linux) */ + + return -EADDRNOTAVAIL; + } + + /* Delete the address */ + + net_ipv6addr_copy(ifaddr->addr, g_ipv6_unspecaddr); + net_ipv6addr_copy(ifaddr->mask, g_ipv6_unspecaddr); + + return OK; +} + +/**************************************************************************** + * Name: netdev_ipv6_srcaddr/srcifaddr + * + * Description: + * Get the source IPv6 address (RFC6724). + * + * Returned Value: + * A pointer to the IPv6 address is returned on success. It will never be + * NULL, but can be an address containing g_ipv6_unspecaddr. + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +FAR const uint16_t *netdev_ipv6_srcaddr(FAR struct net_driver_s *dev, + const net_ipv6addr_t dst) +{ + return netdev_ipv6_srcifaddr(dev, dst)->addr; +} + +FAR const struct netdev_ifaddr6_s * +netdev_ipv6_srcifaddr(FAR struct net_driver_s *dev, const net_ipv6addr_t dst) +{ + FAR struct netdev_ifaddr6_s *best = &dev->d_ipv6[0]; /* Don't be NULL */ +#ifdef CONFIG_NETDEV_MULTIPLE_IPv6 + uint8_t scope_dst = netdev_ipv6_get_scope(dst); + uint8_t scope_best = 0; /* All scope is larget than 0 */ + uint8_t pref_best = 0; + int i; + + for (i = 0; i < CONFIG_NETDEV_MAX_IPv6_ADDR; i++) + { + FAR struct netdev_ifaddr6_s *current = &dev->d_ipv6[i]; + uint8_t scope_cur; + uint8_t pref_cur; + + /* Skip empty address */ + + if (net_ipv6addr_cmp(current->addr, g_ipv6_unspecaddr)) + { + continue; + } + + /* Rule 1: Prefer same address */ + + if (net_ipv6addr_cmp(dst, current->addr)) + { + best = current; + break; + } + + scope_cur = netdev_ipv6_get_scope(current->addr); + pref_cur = net_ipv6_common_pref(current->addr, dst); + + /* Rule 2: Prefer appropriate scope */ + + if (scope_cur != scope_best) + { + /* According to RFC6724: + * If Scope(SA) < Scope(SB): + * If Scope(SA) < Scope(D), then prefer SB and otherwise prefer SA + * If Scope(SB) < Scope(SA): + * If Scope(SB) < Scope(D), then prefer SA and otherwise prefer SB + * Let Scope(SA)->Scope(cur), Scope(SB)->Scope(best) in our case. + */ + + if ((scope_cur < scope_best && scope_cur >= scope_dst) || + (scope_best < scope_cur && scope_best < scope_dst)) + { + best = current; + scope_best = scope_cur; + pref_best = pref_cur; + } + + continue; + } + + /* Rule 3: Avoid deprecated and optimistic addresses + * [Not implemented: Need DAD & address type support] + * Rule 4: Prefer home address + * [Not implemented: Need MIP6] + * Rule 5: Prefer outgoing interface + * [Already satisfied: We already have the device] + * Rule 6: Prefer matching label + * [Not implemented: Need policy table support] + * [Note: Neither lwIP nor Zephyr supports policy table yet] + * Rule 7: Prefer temporary addresses + * [Not implemented: Need DAD & temporary addresses support] + */ + + /* Rule 8: Use longest matching prefix */ + + if (pref_cur > pref_best) + { + best = current; + scope_best = scope_cur; + pref_best = pref_cur; + } + } +#endif /* CONFIG_NETDEV_MULTIPLE_IPv6 */ + + return best; +} + +/**************************************************************************** + * Name: netdev_ipv6_lladdr + * + * Description: + * Get the link-local address of the network device. + * + * Returned Value: + * A pointer to the link-local address is returned on success. + * NULL is returned if the address is not found on the device. + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +FAR const uint16_t *netdev_ipv6_lladdr(FAR struct net_driver_s *dev) +{ + int i; + + for (i = 0; i < CONFIG_NETDEV_MAX_IPv6_ADDR; i++) + { + FAR struct netdev_ifaddr6_s *ifaddr = &dev->d_ipv6[i]; + + if (net_is_addr_linklocal(ifaddr->addr)) + { + return ifaddr->addr; + } + } + + return NULL; +} + +/**************************************************************************** + * Name: netdev_ipv6_lookup + * + * Description: + * Look up an IPv6 address in the network device's IPv6 addresses + * + * Input Parameters: + * dev - The network device to use in the lookup + * addr - The IPv6 address to be looked up + * maskcmp - If true, then the IPv6 address is compared to the network + * device's IPv6 addresses with mask compare. + * If false, then the IPv6 address should be exactly the same as + * the network device's IPv6 address. + * + * Returned Value: + * A pointer to the matching IPv6 address entry is returned on success. + * NULL is returned if the IPv6 address is not found in the device. + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +FAR struct netdev_ifaddr6_s * +netdev_ipv6_lookup(FAR struct net_driver_s *dev, const net_ipv6addr_t addr, + bool maskcmp) +{ + int i; + + for (i = 0; i < CONFIG_NETDEV_MAX_IPv6_ADDR; i++) + { + FAR struct netdev_ifaddr6_s *ifaddr = &dev->d_ipv6[i]; + + /* Skip empty address */ + + if (net_ipv6addr_cmp(ifaddr->addr, g_ipv6_unspecaddr)) + { + continue; + } + + /* Check if the address matches */ + + if (maskcmp) + { + if (net_ipv6addr_maskcmp(addr, ifaddr->addr, ifaddr->mask)) + { + return ifaddr; + } + } + else + { + if (net_ipv6addr_cmp(addr, ifaddr->addr)) + { + return ifaddr; + } + } + } + + /* No match found */ + + return NULL; +} + +/**************************************************************************** + * Name: netdev_ipv6_foreach + * + * Description: + * Enumerate each IPv6 address on a network device. This function will + * terminate when either (1) all addresses have been enumerated or (2) when + * a callback returns any non-zero value. + * + * Input Parameters: + * dev - The network device + * callback - Will be called for each IPv6 address + * arg - Opaque user argument passed to callback() + * + * Returned Value: + * Zero: Enumeration completed + * Non-zero: Enumeration terminated early by callback + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +int netdev_ipv6_foreach(FAR struct net_driver_s *dev, + devif_ipv6_callback_t callback, FAR void *arg) +{ + int i; + + if (callback == NULL) + { + return OK; + } + + for (i = 0; i < CONFIG_NETDEV_MAX_IPv6_ADDR; i++) + { + FAR struct netdev_ifaddr6_s *ifaddr = &dev->d_ipv6[i]; + + if (!net_ipv6addr_cmp(ifaddr->addr, g_ipv6_unspecaddr)) + { + int ret = callback(dev, ifaddr, arg); + if (ret != 0) /* Stop on any error and return it */ + { + return ret; + } + } + } + + return OK; +} diff --git a/net/utils/net_mask2pref.c b/net/utils/net_mask2pref.c index 2c06a6607e..252c1f6b72 100644 --- a/net/utils/net_mask2pref.c +++ b/net/utils/net_mask2pref.c @@ -207,4 +207,42 @@ uint8_t net_ipv6_mask2pref(FAR const uint16_t *mask) return preflen; } +/**************************************************************************** + * Name: net_ipv6_common_pref + * + * Description: + * Calculate the common prefix length of two IPv6 addresses. + * + * Input Parameters: + * a1,a2 Points to IPv6 addresses in the form of uint16_t[8] + * + * Returned Value: + * The common prefix length, range 0-128 on success; This function will + * not fail. + * + ****************************************************************************/ + +uint8_t net_ipv6_common_pref(FAR const uint16_t *a1, FAR const uint16_t *a2) +{ + uint8_t preflen; + int i; + + /* Count the leading same 16-bit groups */ + + for (i = 0, preflen = 0; i < 8 && a1[i] == a2[i]; i++, preflen += 16); + + /* Now i either, (1) indexes past the end of the mask, or (2) is the index + * to the first half-word that is not equal between the addresses. + */ + + if (i < 8) + { + preflen += net_msbits16(NTOHS(~(a1[i] ^ a2[i]))); + } + + /* Return the prefix length */ + + return preflen; +} + #endif /* CONFIG_NET_IPv6 */ diff --git a/net/utils/utils.h b/net/utils/utils.h index 9688cac7fd..757e0580b9 100644 --- a/net/utils/utils.h +++ b/net/utils/utils.h @@ -187,6 +187,25 @@ void net_getrandom(FAR void *bytes, size_t nbytes); uint8_t net_ipv4_mask2pref(in_addr_t mask); #endif +/**************************************************************************** + * Name: net_ipv6_common_pref + * + * Description: + * Calculate the common prefix length of two IPv6 addresses. + * + * Input Parameters: + * a1,a2 Points to IPv6 addresses in the form of uint16_t[8] + * + * Returned Value: + * The common prefix length, range 0-128 on success; This function will + * not fail. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +uint8_t net_ipv6_common_pref(FAR const uint16_t *a1, FAR const uint16_t *a2); +#endif + /**************************************************************************** * Name: net_ipv6_mask2pref *
