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 c7845f5b257a41c0b7cb2b8b1b5fae2f763c24bc
Author: Zhe Weng <[email protected]>
AuthorDate: Thu Oct 19 15:04:23 2023 +0800

    netlink: Explicitly set ip address for netlink notify
    
    Prepare for multiple IPv6 addresses per net device, then we can notify
    add/remove of a single address later.
    
    Signed-off-by: Zhe Weng <[email protected]>
---
 net/netdev/netdev_ioctl.c                          | 13 +++--
 net/netlink/netlink.h                              |  5 +-
 net/netlink/netlink_route.c                        | 67 ++++++++++++++--------
 net/utils/CMakeLists.txt                           |  5 +-
 net/utils/Make.defs                                |  4 +-
 .../{net_ipv6_mask2pref.c => net_mask2pref.c}      | 48 +++++++++++++++-
 net/utils/utils.h                                  | 28 +++++++++
 7 files changed, 134 insertions(+), 36 deletions(-)

diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c
index d1eea0c40e..9a89f96f8f 100644
--- a/net/netdev/netdev_ioctl.c
+++ b/net/netdev/netdev_ioctl.c
@@ -83,6 +83,7 @@
 #include "icmpv6/icmpv6.h"
 #include "route/route.h"
 #include "netlink/netlink.h"
+#include "utils/utils.h"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -858,7 +859,8 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int 
cmd,
 
       case SIOCSIFADDR:  /* Set IP address */
         ioctl_set_ipv4addr(&dev->d_ipaddr, &req->ifr_addr);
-        netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET);
+        netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET,
+                         &dev->d_ipaddr, net_ipv4_mask2pref(dev->d_netmask));
         break;
 
       case SIOCGIFDSTADDR:  /* Get P-to-P address */
@@ -899,7 +901,8 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int 
cmd,
         {
           FAR struct lifreq *lreq = (FAR struct lifreq *)req;
           ioctl_set_ipv6addr(dev->d_ipv6addr, &lreq->lifr_addr);
-          netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6);
+          netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6,
+                    dev->d_ipv6addr, net_ipv6_mask2pref(dev->d_ipv6netmask));
         }
         break;
 
@@ -1056,12 +1059,14 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, 
int cmd,
 
       case SIOCDIFADDR:  /* Delete IP address */
 #ifdef CONFIG_NET_IPv4
+        netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET,
+                         &dev->d_ipaddr, net_ipv4_mask2pref(dev->d_netmask));
         dev->d_ipaddr = 0;
-        netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET);
 #endif
 #ifdef CONFIG_NET_IPv6
+        netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6,
+                    dev->d_ipv6addr, net_ipv6_mask2pref(dev->d_ipv6netmask));
         memset(&dev->d_ipv6addr, 0, sizeof(net_ipv6addr_t));
-        netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6);
 #endif
         break;
 
diff --git a/net/netlink/netlink.h b/net/netlink/netlink.h
index c14514f0f2..c86882266f 100644
--- a/net/netlink/netlink.h
+++ b/net/netlink/netlink.h
@@ -45,7 +45,7 @@
 
 #ifndef CONFIG_NETLINK_ROUTE
 #  define netlink_device_notify(dev)
-#  define netlink_device_notify_ipaddr(dev, type, domain)
+#  define netlink_device_notify_ipaddr(dev, type, domain, addr, preflen)
 #endif
 
 #ifdef CONFIG_NET_NETLINK
@@ -502,7 +502,8 @@ void netlink_device_notify(FAR struct net_driver_s *dev);
  ****************************************************************************/
 
 void netlink_device_notify_ipaddr(FAR struct net_driver_s *dev,
-                                  int type, int domain);
+                                  int type, int domain,
+                                  FAR const void *addr, uint8_t preflen);
 
 /****************************************************************************
  * Name: nla_next
diff --git a/net/netlink/netlink_route.c b/net/netlink/netlink_route.c
index 8ed9caa4c4..4409016da9 100644
--- a/net/netlink/netlink_route.c
+++ b/net/netlink/netlink_route.c
@@ -369,16 +369,6 @@ static uint32_t make_mask(int prefixlen)
 
   return 0;
 }
-
-static uint8_t mask_len(uint32_t nmask)
-{
-  uint8_t prefixlen = 0;
-  uint32_t hmask = NTOHL(nmask);
-
-  for (; hmask; ++prefixlen, hmask <<= 1);
-
-  return prefixlen;
-}
 #endif
 
 /****************************************************************************
@@ -392,6 +382,7 @@ static uint8_t mask_len(uint32_t nmask)
 #ifndef CONFIG_NETLINK_DISABLE_GETLINK
 static FAR struct netlink_response_s *
 netlink_get_ifaddr(FAR struct net_driver_s *dev, int domain, int type,
+                   FAR const void *local_addr, uint8_t prefixlen,
                    FAR const struct nlroute_sendto_request_s *req)
 {
   FAR struct getaddr_recvfrom_rsplist_s *alloc;
@@ -429,8 +420,8 @@ netlink_get_ifaddr(FAR struct net_driver_s *dev, int 
domain, int type,
   if (domain == AF_INET)
     {
       resp->attr.rta_len = RTA_LENGTH(sizeof(struct in_addr));
-      memcpy(&resp->local_addr, &dev->d_ipaddr, sizeof(struct in_addr));
-      resp->ifaddr.ifa_prefixlen = mask_len(dev->d_netmask);
+      memcpy(&resp->local_addr, local_addr, sizeof(struct in_addr));
+      resp->ifaddr.ifa_prefixlen = prefixlen;
     }
 #endif
 
@@ -438,8 +429,8 @@ netlink_get_ifaddr(FAR struct net_driver_s *dev, int 
domain, int type,
   if (domain == AF_INET6)
     {
       resp->attr.rta_len = RTA_LENGTH(sizeof(struct in6_addr));
-      memcpy(&resp->local_addr, dev->d_ipv6addr, sizeof(struct in6_addr));
-      resp->ifaddr.ifa_prefixlen = net_ipv6_mask2pref(dev->d_ipv6netmask);
+      memcpy(&resp->local_addr, local_addr, sizeof(struct in6_addr));
+      resp->ifaddr.ifa_prefixlen = prefixlen;
     }
 #endif
 
@@ -951,7 +942,8 @@ static int netlink_new_ipv4addr(NETLINK_HANDLE handle,
   dev->d_ipaddr  = nla_get_in_addr(tb[IFA_LOCAL]);
   dev->d_netmask = make_mask(ifm->ifa_prefixlen);
 
-  netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET);
+  netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET, &dev->d_ipaddr,
+                               ifm->ifa_prefixlen);
   net_unlock();
 
   return OK;
@@ -1000,7 +992,8 @@ static int netlink_new_ipv6addr(NETLINK_HANDLE handle,
   memcpy(dev->d_ipv6addr, nla_data(tb[IFA_LOCAL]), 16);
   net_ipv6_pref2mask(ifm->ifa_prefixlen, dev->d_ipv6netmask);
 
-  netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6);
+  netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6, dev->d_ipv6addr,
+                               ifm->ifa_prefixlen);
   net_unlock();
 
   return OK;
@@ -1047,9 +1040,10 @@ static int netlink_del_ipv4addr(NETLINK_HANDLE handle,
       return -EADDRNOTAVAIL;
     }
 
+  netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET, &dev->d_ipaddr,
+                               net_ipv4_mask2pref(dev->d_netmask));
   dev->d_ipaddr  = 0;
 
-  netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET);
   net_unlock();
 
   return OK;
@@ -1090,15 +1084,17 @@ static int netlink_del_ipv6addr(NETLINK_HANDLE handle,
       return -ENODEV;
     }
 
-  if (tb[IFA_LOCAL] && dev->d_ipaddr != nla_get_in_addr(tb[IFA_LOCAL]))
+  if (tb[IFA_LOCAL] && !net_ipv6addr_cmp(dev->d_ipv6addr,
+                                         nla_data(tb[IFA_LOCAL])))
     {
       net_unlock();
       return -EADDRNOTAVAIL;
     }
 
+  netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6, dev->d_ipv6addr,
+                               net_ipv6_mask2pref(dev->d_ipv6netmask));
   memset(&dev->d_ipv6addr, 0, sizeof(net_ipv6addr_t));
 
-  netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6);
   net_unlock();
 
   return OK;
@@ -1114,14 +1110,36 @@ static int netlink_del_ipv6addr(NETLINK_HANDLE handle,
  ****************************************************************************/
 
 #ifndef CONFIG_NETLINK_DISABLE_GETADDR
-static int netlink_addr_callback(FAR struct net_driver_s *dev,
-                                   FAR void *arg)
+static int netlink_addr_callback(FAR struct net_driver_s *dev, FAR void *arg)
 {
   FAR struct nlroute_info_s *info = arg;
   FAR struct netlink_response_s *resp;
+  FAR void *addr = NULL;
+  uint8_t preflen;
+
+#ifdef CONFIG_NET_IPv4
+  if (info->req->gen.rtgen_family == AF_INET)
+    {
+      addr = &dev->d_ipaddr;
+      preflen = net_ipv4_mask2pref(dev->d_netmask);
+    }
+#endif
+
+#ifdef CONFIG_NET_IPv6
+  if (info->req->gen.rtgen_family == AF_INET6)
+    {
+      addr = &dev->d_ipv6addr;
+      preflen = net_ipv6_mask2pref(dev->d_ipv6netmask);
+    }
+#endif
+
+  if (addr == NULL)
+    {
+      return OK;
+    }
 
   resp = netlink_get_ifaddr(dev, info->req->gen.rtgen_family, RTM_NEWADDR,
-                            info->req);
+                            addr, preflen, info->req);
   if (resp == NULL)
     {
       return -ENOMEM;
@@ -1378,14 +1396,15 @@ void netlink_device_notify(FAR struct net_driver_s *dev)
     !defined(CONFIG_NETLINK_DISABLE_DELADDR) || \
     !defined(CONFIG_NETLINK_DISABLE_GETADDR)
 void netlink_device_notify_ipaddr(FAR struct net_driver_s *dev,
-                                  int type, int domain)
+                                  int type, int domain,
+                                  FAR const void *addr, uint8_t preflen)
 {
   FAR struct netlink_response_s *resp;
   int group;
 
   DEBUGASSERT(dev != NULL);
 
-  resp = netlink_get_ifaddr(dev, domain, type, NULL);
+  resp = netlink_get_ifaddr(dev, domain, type, addr, preflen, NULL);
   if (resp != NULL)
     {
 #ifdef CONFIG_NET_IPv4
diff --git a/net/utils/CMakeLists.txt b/net/utils/CMakeLists.txt
index 8c779bfe0b..27868b2fcd 100644
--- a/net/utils/CMakeLists.txt
+++ b/net/utils/CMakeLists.txt
@@ -31,12 +31,13 @@ set(SRCS
     net_snoop.c
     net_cmsg.c
     net_iob_concat.c
-    net_getrandom.c)
+    net_getrandom.c
+    net_mask2pref.c)
 
 # IPv6 utilities
 
 if(CONFIG_NET_IPv6)
-  list(APPEND SRCS net_ipv6_maskcmp.c net_ipv6_mask2pref.c 
net_ipv6_pref2mask.c)
+  list(APPEND SRCS net_ipv6_maskcmp.c net_ipv6_pref2mask.c)
 endif()
 
 # TCP utilities
diff --git a/net/utils/Make.defs b/net/utils/Make.defs
index 400d0367fb..764dee1481 100644
--- a/net/utils/Make.defs
+++ b/net/utils/Make.defs
@@ -22,12 +22,12 @@
 
 NET_CSRCS += net_dsec2tick.c net_dsec2timeval.c net_timeval2dsec.c
 NET_CSRCS += net_chksum.c net_ipchksum.c net_incr32.c net_lock.c net_snoop.c
-NET_CSRCS += net_cmsg.c net_iob_concat.c net_getrandom.c
+NET_CSRCS += net_cmsg.c net_iob_concat.c net_getrandom.c net_mask2pref.c
 
 # IPv6 utilities
 
 ifeq ($(CONFIG_NET_IPv6),y)
-NET_CSRCS += net_ipv6_maskcmp.c net_ipv6_mask2pref.c net_ipv6_pref2mask.c
+NET_CSRCS += net_ipv6_maskcmp.c net_ipv6_pref2mask.c
 endif
 
 # TCP utilities
diff --git a/net/utils/net_ipv6_mask2pref.c b/net/utils/net_mask2pref.c
similarity index 78%
rename from net/utils/net_ipv6_mask2pref.c
rename to net/utils/net_mask2pref.c
index 4c5de09173..2c06a6607e 100644
--- a/net/utils/net_ipv6_mask2pref.c
+++ b/net/utils/net_mask2pref.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * net/utils/net_ipv6_mask2pref.c
+ * net/utils/net_mask2pref.c
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -26,7 +26,7 @@
 
 #include "utils/utils.h"
 
-#ifdef CONFIG_NET_IPv6
+#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6)
 
 /****************************************************************************
  * Private Data
@@ -112,10 +112,52 @@ static inline uint8_t net_msbits16(uint16_t hword)
   return ones;
 }
 
+#endif /* CONFIG_NET_IPv4 || CONFIG_NET_IPv6 */
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: net_ipv4_mask2pref
+ *
+ * Description:
+ *   Convert a 32-bit netmask to a prefix length.  The NuttX IPv4
+ *   networking uses 32-bit network masks internally.  This function
+ *   converts the IPv4 netmask to a prefix length.
+ *
+ *   The prefix length is the number of MS '1' bits on in the netmask.
+ *   This, of course, assumes that all MS bits are '1' and all LS bits are
+ *   '0' with no intermixed 1's and 0's.  This function searches from the MS
+ *   bit until the first '0' is found (this does not necessary mean that
+ *   there might not be additional '1' bits following the firs '0', but that
+ *   will be a malformed netmask.
+ *
+ * Input Parameters:
+ *   mask   An IPv4 netmask in the form of in_addr_t
+ *
+ * Returned Value:
+ *   The prefix length, range 0-32 on success;  This function will not
+ *   fail.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+
+uint8_t net_ipv4_mask2pref(in_addr_t mask)
+{
+  uint32_t hmask = NTOHL(mask);
+  uint8_t ones = net_msbits16((uint16_t)(hmask >> 16));
+  if (ones == 16)
+    {
+      ones += net_msbits16((uint16_t)(hmask & 0xffff));
+    }
+
+  return ones;
+}
+
+#endif /* CONFIG_NET_IPv4 */
+
 /****************************************************************************
  * Name: net_ipv6_mask2pref
  *
@@ -140,6 +182,8 @@ static inline uint8_t net_msbits16(uint16_t hword)
  *
  ****************************************************************************/
 
+#ifdef CONFIG_NET_IPv6
+
 uint8_t net_ipv6_mask2pref(FAR const uint16_t *mask)
 {
   uint8_t preflen;
diff --git a/net/utils/utils.h b/net/utils/utils.h
index 401f2e1161..9688cac7fd 100644
--- a/net/utils/utils.h
+++ b/net/utils/utils.h
@@ -159,6 +159,34 @@ unsigned int net_timeval2dsec(FAR struct timeval *tv,
 
 void net_getrandom(FAR void *bytes, size_t nbytes);
 
+/****************************************************************************
+ * Name: net_ipv4_mask2pref
+ *
+ * Description:
+ *   Convert a 32-bit netmask to a prefix length.  The NuttX IPv4
+ *   networking uses 32-bit network masks internally.  This function
+ *   converts the IPv4 netmask to a prefix length.
+ *
+ *   The prefix length is the number of MS '1' bits on in the netmask.
+ *   This, of course, assumes that all MS bits are '1' and all LS bits are
+ *   '0' with no intermixed 1's and 0's.  This function searches from the MS
+ *   bit until the first '0' is found (this does not necessary mean that
+ *   there might not be additional '1' bits following the firs '0', but that
+ *   will be a malformed netmask.
+ *
+ * Input Parameters:
+ *   mask   An IPv4 netmask in the form of in_addr_t
+ *
+ * Returned Value:
+ *   The prefix length, range 0-32 on success;  This function will not
+ *   fail.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+uint8_t net_ipv4_mask2pref(in_addr_t mask);
+#endif
+
 /****************************************************************************
  * Name: net_ipv6_mask2pref
  *

Reply via email to