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 2b9633e652f616de7121c303bfba4b3913b4660e
Author: Zhe Weng <[email protected]>
AuthorDate: Fri Aug 25 17:37:11 2023 +0800

    net: Support multiple IPv6 address per netdev
    
    Note that user-space related code, like procfs and lifreq related ioctl 
commands, are not touched in this commit.
    
    Signed-off-by: Zhe Weng <[email protected]>
---
 include/nuttx/net/netdev.h           |  7 ++++
 net/devif/devif_loopback.c           |  2 +-
 net/devif/ipv6_input.c               |  4 +-
 net/icmpv6/icmpv6.h                  |  1 +
 net/icmpv6/icmpv6_advertise.c        |  5 ++-
 net/icmpv6/icmpv6_autoconfig.c       | 23 +++++++----
 net/icmpv6/icmpv6_input.c            |  9 ++--
 net/icmpv6/icmpv6_neighbor.c         |  3 +-
 net/icmpv6/icmpv6_radvertise.c       | 35 ++++++++++++----
 net/icmpv6/icmpv6_reply.c            |  3 +-
 net/icmpv6/icmpv6_rnotify.c          | 35 ++++++++++------
 net/icmpv6/icmpv6_rsolicit.c         |  3 +-
 net/icmpv6/icmpv6_sendmsg.c          |  6 +--
 net/icmpv6/icmpv6_solicit.c          |  2 +-
 net/inet/ipv6_getsockname.c          |  3 +-
 net/mld/mld_query.c                  | 14 ++++++-
 net/mld/mld_send.c                   | 13 +++++-
 net/neighbor/neighbor_ethernet_out.c |  3 +-
 net/neighbor/neighbor_lookup.c       |  2 +-
 net/netdev/netdev_findbyaddr.c       |  6 +--
 net/netdev/netdev_ifconf.c           |  3 +-
 net/netlink/netlink_route.c          | 80 ++++++++++++++++++++++--------------
 net/route/netdev_router.c            |  3 +-
 net/sixlowpan/sixlowpan_tcpsend.c    |  3 +-
 net/sixlowpan/sixlowpan_udpsend.c    |  3 +-
 net/sixlowpan/sixlowpan_utils.c      |  3 +-
 net/tcp/tcp_conn.c                   |  3 +-
 net/tcp/tcp_connect.c                |  3 +-
 net/tcp/tcp_send.c                   |  8 +++-
 net/udp/udp_conn.c                   |  4 +-
 net/udp/udp_send.c                   |  3 +-
 31 files changed, 195 insertions(+), 100 deletions(-)

diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h
index cbfa19fb44..df9ecefc22 100644
--- a/include/nuttx/net/netdev.h
+++ b/include/nuttx/net/netdev.h
@@ -172,6 +172,13 @@
 #  ifndef CONFIG_NETDEV_MAX_IPv6_ADDR
 #    define CONFIG_NETDEV_MAX_IPv6_ADDR 1
 #  endif
+#  define NETDEV_HAS_V6ADDR(dev) \
+     (!net_ipv6addr_cmp(netdev_ipv6_srcaddr(dev, g_ipv6_unspecaddr), \
+                        g_ipv6_unspecaddr))
+#  define NETDEV_IS_MY_V6ADDR(dev,addr) \
+     (netdev_ipv6_lookup(dev, addr, false) != NULL)
+#  define NETDEV_V6ADDR_ONLINK(dev,addr) \
+     (netdev_ipv6_lookup(dev, addr, true) != NULL)
 #endif
 
 /****************************************************************************
diff --git a/net/devif/devif_loopback.c b/net/devif/devif_loopback.c
index a7379aa4e5..6fa8e89adc 100644
--- a/net/devif/devif_loopback.c
+++ b/net/devif/devif_loopback.c
@@ -62,7 +62,7 @@ bool devif_is_loopback(FAR struct net_driver_s *dev)
 
 #ifdef CONFIG_NET_IPv6
       if ((IPv6BUF->vtc & IP_VERSION_MASK) == IPv6_VERSION &&
-          net_ipv6addr_hdrcmp(IPv6BUF->destipaddr, dev->d_ipv6addr))
+          NETDEV_IS_MY_V6ADDR(dev, IPv6BUF->destipaddr))
         {
           return true;
         }
diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c
index 4565261c5d..b29daea10d 100644
--- a/net/devif/ipv6_input.c
+++ b/net/devif/ipv6_input.c
@@ -78,7 +78,7 @@ static int check_dev_destipaddr(FAR struct net_driver_s *dev, 
FAR void *arg)
    * to this device.
    */
 
-  if (net_ipv6addr_cmp(ipv6->destipaddr, dev->d_ipv6addr))
+  if (NETDEV_IS_MY_V6ADDR(dev, ipv6->destipaddr))
     {
       return 1;
     }
@@ -389,7 +389,7 @@ static int ipv6_in(FAR struct net_driver_s *dev)
    * (the all zero address is the "unspecified" address.
    */
 
-  if (net_ipv6addr_cmp(dev->d_ipv6addr, g_ipv6_unspecaddr))
+  if (!NETDEV_HAS_V6ADDR(dev))
     {
       nwarn("WARNING: No IP address assigned\n");
       goto drop;
diff --git a/net/icmpv6/icmpv6.h b/net/icmpv6/icmpv6.h
index c90c3722b1..ec11dbb0bb 100644
--- a/net/icmpv6/icmpv6.h
+++ b/net/icmpv6/icmpv6.h
@@ -313,6 +313,7 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev);
  ****************************************************************************/
 
 void icmpv6_advertise(FAR struct net_driver_s *dev,
+                      const net_ipv6addr_t tgtaddr,
                       const net_ipv6addr_t destipaddr);
 
 /****************************************************************************
diff --git a/net/icmpv6/icmpv6_advertise.c b/net/icmpv6/icmpv6_advertise.c
index 583522ac1b..8b27a8f012 100644
--- a/net/icmpv6/icmpv6_advertise.c
+++ b/net/icmpv6/icmpv6_advertise.c
@@ -65,6 +65,7 @@
  ****************************************************************************/
 
 void icmpv6_advertise(FAR struct net_driver_s *dev,
+                      const net_ipv6addr_t tgtaddr,
                       const net_ipv6addr_t destipaddr)
 {
   FAR struct icmpv6_neighbor_advertise_s *adv;
@@ -77,7 +78,7 @@ void icmpv6_advertise(FAR struct net_driver_s *dev,
   l3size       = SIZEOF_ICMPV6_NEIGHBOR_ADVERTISE_S(lladdrsize);
 
   ipv6_build_header(IPv6BUF, l3size, IP_PROTO_ICMP6,
-                    dev->d_ipv6addr, destipaddr, 255, 0);
+                    tgtaddr, destipaddr, 255, 0);
 
   /* Set up the ICMPv6 Neighbor Advertise response */
 
@@ -92,7 +93,7 @@ void icmpv6_advertise(FAR struct net_driver_s *dev,
 
   /* Copy the target address into the Neighbor Advertisement message */
 
-  net_ipv6addr_copy(adv->tgtaddr, dev->d_ipv6addr);
+  net_ipv6addr_copy(adv->tgtaddr, tgtaddr);
 
   /* Set up the options */
 
diff --git a/net/icmpv6/icmpv6_autoconfig.c b/net/icmpv6/icmpv6_autoconfig.c
index dfc87e6777..ec8adecaad 100644
--- a/net/icmpv6/icmpv6_autoconfig.c
+++ b/net/icmpv6/icmpv6_autoconfig.c
@@ -40,6 +40,7 @@
 #include "netdev/netdev.h"
 #include "inet/inet.h"
 #include "icmpv6/icmpv6.h"
+#include "utils/utils.h"
 
 #ifdef CONFIG_NET_ICMPv6_AUTOCONF
 
@@ -139,9 +140,11 @@ static uint16_t icmpv6_router_eventhandler(FAR struct 
net_driver_s *dev,
 
       if (state->snd_advertise)
         {
-          /* Send the ICMPv6 Neighbor Advertisement message */
+          /* Send the ICMPv6 Neighbor Advertisement message, we should
+           * already have link-local address by previous logic.
+           */
 
-          icmpv6_advertise(dev, g_ipv6_allnodes);
+          icmpv6_advertise(dev, netdev_ipv6_lladdr(dev), g_ipv6_allnodes);
         }
       else
         {
@@ -311,6 +314,11 @@ int icmpv6_autoconfig(FAR struct net_driver_s *dev)
    *    will be derived from the link layer (MAC) address.
    */
 
+  if (netdev_ipv6_lladdr(dev) != NULL)
+    {
+      goto got_lladdr;
+    }
+
   icmpv6_linkipaddr(dev, lladdr);
 
   ninfo("lladdr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
@@ -352,8 +360,13 @@ int icmpv6_autoconfig(FAR struct net_driver_s *dev)
    *    on the wider Internet (since link-local addresses are not routed).
    */
 
-  net_ipv6addr_copy(dev->d_ipv6addr, lladdr);
+  ret = netdev_ipv6_add(dev, lladdr, net_ipv6_mask2pref(g_ipv6_llnetmask));
+  if (ret < 0)
+    {
+      return ret;
+    }
 
+got_lladdr:
   /* 4. Router Contact: The node next attempts to contact a local router for
    *    more information on continuing the configuration. This is done either
    *    by listening for Router Advertisement messages sent periodically by
@@ -416,10 +429,6 @@ int icmpv6_autoconfig(FAR struct net_driver_s *dev)
       /* No off-link communications; No router address. */
 
       net_ipv6addr_copy(dev->d_ipv6draddr, g_ipv6_unspecaddr);
-
-      /* Set a netmask for the local link address */
-
-      net_ipv6addr_copy(dev->d_ipv6netmask, g_ipv6_llnetmask);
     }
 
   /* 5. Router Direction: The router provides direction to the node on how
diff --git a/net/icmpv6/icmpv6_input.c b/net/icmpv6/icmpv6_input.c
index f072e70d3d..79339b3e3a 100644
--- a/net/icmpv6/icmpv6_input.c
+++ b/net/icmpv6/icmpv6_input.c
@@ -299,7 +299,7 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned 
int iplen)
         /* Check if we are the target of the solicitation */
 
         sol = ICMPv6SOLICIT;
-        if (net_ipv6addr_cmp(sol->tgtaddr, dev->d_ipv6addr))
+        if (NETDEV_IS_MY_V6ADDR(dev, sol->tgtaddr))
           {
             if (sol->opttype == ICMPv6_OPT_SRCLLADDR)
               {
@@ -312,7 +312,7 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned 
int iplen)
              * solicitation came from.
              */
 
-            icmpv6_advertise(dev, ipv6->srcipaddr);
+            icmpv6_advertise(dev, sol->tgtaddr, ipv6->srcipaddr);
 
             /* All statistics have been updated.  Nothing to do but exit. */
 
@@ -341,7 +341,7 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned 
int iplen)
          */
 
         adv = ICMPv6ADVERTISE;
-        if (net_ipv6addr_cmp(ipv6->destipaddr, dev->d_ipv6addr))
+        if (NETDEV_IS_MY_V6ADDR(dev, ipv6->destipaddr))
           {
             /* This message is required to support the Target link-layer
              * address option.
@@ -544,7 +544,8 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned 
int iplen)
         icmpv6->type = ICMPv6_ECHO_REPLY;
 
         net_ipv6addr_copy(ipv6->destipaddr, ipv6->srcipaddr);
-        net_ipv6addr_copy(ipv6->srcipaddr, dev->d_ipv6addr);
+        net_ipv6addr_copy(ipv6->srcipaddr,
+                          netdev_ipv6_srcaddr(dev, ipv6->srcipaddr));
 
         icmpv6->chksum = 0;
         icmpv6->chksum = ~icmpv6_chksum(dev, iplen);
diff --git a/net/icmpv6/icmpv6_neighbor.c b/net/icmpv6/icmpv6_neighbor.c
index c7274d4fa8..ac2c7b4a94 100644
--- a/net/icmpv6/icmpv6_neighbor.c
+++ b/net/icmpv6/icmpv6_neighbor.c
@@ -218,8 +218,7 @@ int icmpv6_neighbor(FAR struct net_driver_s *dev,
 
   /* Check if the destination address is on the local network. */
 
-  if (net_ipv6addr_maskcmp(ipaddr, dev->d_ipv6addr, dev->d_ipv6netmask) ||
-      net_is_addr_linklocal(ipaddr))
+  if (NETDEV_V6ADDR_ONLINK(dev, ipaddr) || net_is_addr_linklocal(ipaddr))
     {
       /* Yes.. use the input address for the lookup */
 
diff --git a/net/icmpv6/icmpv6_radvertise.c b/net/icmpv6/icmpv6_radvertise.c
index f8926403f2..52cb4864ed 100644
--- a/net/icmpv6/icmpv6_radvertise.c
+++ b/net/icmpv6/icmpv6_radvertise.c
@@ -170,6 +170,9 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
   FAR struct icmpv6_srclladdr_s *srcaddr;
   FAR struct icmpv6_mtu_s *mtu;
   FAR struct icmpv6_prefixinfo_s *prefix;
+#ifndef CONFIG_NET_ICMPv6_ROUTER_MANUAL
+  FAR const struct netdev_ifaddr6_s *ifaddr;
+#endif
 #ifdef CONFIG_NET_ICMPv6_ROUTER_RDNSS
   FAR struct icmpv6_rdnss_s *rdnss;
   struct rdnss_add_dns_nameserver_s rndss_context;
@@ -183,12 +186,18 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
   lladdrsize   = netdev_lladdrsize(dev);
   l3size       = sizeof(struct icmpv6_router_advertise_s) +
                  SIZEOF_ICMPV6_SRCLLADDR_S(lladdrsize) +
-                 sizeof(struct icmpv6_mtu_s) +
-                 sizeof(struct icmpv6_prefixinfo_s);
+                 sizeof(struct icmpv6_mtu_s);
 
   /* Source IP address must be set to link-local IP */
 
-  icmpv6_linkipaddr(dev, srcv6addr);
+  if (netdev_ipv6_lladdr(dev) == NULL)
+    {
+      icmpv6_linkipaddr(dev, srcv6addr);
+    }
+  else
+    {
+      net_ipv6addr_copy(srcv6addr, netdev_ipv6_lladdr(dev));
+    }
 
   /* Set up the ICMPv6 Router Advertise response */
 
@@ -224,6 +233,16 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
   mtu->mtu[0]       = 0;
   mtu->mtu[1]       = HTONS(dev->d_pktsize - dev->d_llhdrlen);
 
+#ifndef CONFIG_NET_ICMPv6_ROUTER_MANUAL
+  /* We only anounce a prefix when we have one. */
+
+  ifaddr = netdev_ipv6_srcifaddr(dev, g_ipv6_unspecaddr);
+  if (net_ipv6addr_cmp(ifaddr->addr, g_ipv6_unspecaddr))
+    {
+      goto skip_prefix;
+    }
+#endif
+
   /* Set up the prefix option */
 
   prefix               = (FAR struct icmpv6_prefixinfo_s *)
@@ -238,6 +257,8 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
   prefix->reserved[0]  = 0;
   prefix->reserved[1]  = 0;
 
+  l3size              += sizeof(struct icmpv6_prefixinfo_s);
+
 #ifdef CONFIG_NET_ICMPv6_ROUTER_MANUAL
   /* Copy the configured prefex */
 
@@ -246,14 +267,14 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
 #else
   /* Set the prefix and prefix length based on net driver IP and netmask */
 
-  prefix->preflen     = net_ipv6_mask2pref(dev->d_ipv6netmask);
-  ipv6addr_mask(prefix->prefix, dev->d_ipv6addr, dev->d_ipv6netmask);
+  prefix->preflen     = net_ipv6_mask2pref(ifaddr->mask);
+  ipv6addr_mask(prefix->prefix, ifaddr->addr, ifaddr->mask);
+skip_prefix:
 #endif /* CONFIG_NET_ICMPv6_ROUTER_MANUAL */
 
 #ifdef CONFIG_NET_ICMPv6_ROUTER_RDNSS
   rdnss                  = (FAR struct icmpv6_rdnss_s *)
-                           ((FAR uint8_t *)prefix +
-                           sizeof(struct icmpv6_prefixinfo_s));
+                           ((FAR uint8_t *)adv + l3size);
   rndss_context.rdnss    = rdnss;
   rndss_context.nservers = 0;
 
diff --git a/net/icmpv6/icmpv6_reply.c b/net/icmpv6/icmpv6_reply.c
index 9aa0745983..726b499ca4 100644
--- a/net/icmpv6/icmpv6_reply.c
+++ b/net/icmpv6/icmpv6_reply.c
@@ -172,7 +172,8 @@ void icmpv6_reply(FAR struct net_driver_s *dev, int type, 
int code, int data)
   dev->d_len = ipicmplen + datalen;
 
   ipv6_build_header(IPv6BUF, dev->d_len - IPv6_HDRLEN, IP_PROTO_ICMP6,
-                    dev->d_ipv6addr, ipv6->srcipaddr, 255, 0);
+                    netdev_ipv6_srcaddr(dev, ipv6->srcipaddr),
+                    ipv6->srcipaddr, 255, 0);
 
   /* Initialize the ICMPv6 header */
 
diff --git a/net/icmpv6/icmpv6_rnotify.c b/net/icmpv6/icmpv6_rnotify.c
index fca0317750..9ea4a1683f 100644
--- a/net/icmpv6/icmpv6_rnotify.c
+++ b/net/icmpv6/icmpv6_rnotify.c
@@ -75,6 +75,9 @@ void icmpv6_setaddresses(FAR struct net_driver_s *dev,
                          const net_ipv6addr_t prefix,
                          unsigned int preflen)
 {
+  FAR const uint16_t *curaddr;
+  net_ipv6addr_t addr;
+  net_ipv6addr_t mask;
   unsigned int i;
 
   /* Lock the network.
@@ -100,20 +103,28 @@ void icmpv6_setaddresses(FAR struct net_driver_s *dev,
       preflen = 128;
     }
 
-  net_ipv6_pref2mask(preflen, dev->d_ipv6netmask);
+  net_ipv6_pref2mask(preflen, mask);
 
   ninfo("preflen=%d netmask=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-        preflen, NTOHS(dev->d_ipv6netmask[0]), NTOHS(dev->d_ipv6netmask[1]),
-        NTOHS(dev->d_ipv6netmask[2]), NTOHS(dev->d_ipv6netmask[3]),
-        NTOHS(dev->d_ipv6netmask[4]), NTOHS(dev->d_ipv6netmask[5]),
-        NTOHS(dev->d_ipv6netmask[6]), NTOHS(dev->d_ipv6netmask[7]));
+        preflen,
+        NTOHS(mask[0]), NTOHS(mask[1]), NTOHS(mask[2]), NTOHS(mask[3]),
+        NTOHS(mask[4]), NTOHS(mask[5]), NTOHS(mask[6]), NTOHS(mask[7]));
 
-  /* Copy prefix to the current IPv6 address, applying the mask */
+  /* Copy prefix to the current link local address, applying the mask.
+   * According to RFC4862, Section 5.5.3, Page 18, global address is formed
+   * by prefix + IID, and the IID is normally the link-local suffix.
+   */
+
+  curaddr = netdev_ipv6_lladdr(dev);
+  if (curaddr == NULL)
+    {
+      icmpv6_linkipaddr(dev, addr);
+      curaddr = addr;
+    }
 
   for (i = 0; i < 8; i++)
     {
-      dev->d_ipv6addr[i] = (dev->d_ipv6addr[i] & ~dev->d_ipv6netmask[i]) |
-                           (prefix[i] & dev->d_ipv6netmask[i]);
+      addr[i] = (curaddr[i] & ~mask[i]) | (prefix[i] & mask[i]);
     }
 
   ninfo("prefix=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
@@ -121,10 +132,10 @@ void icmpv6_setaddresses(FAR struct net_driver_s *dev,
         NTOHS(prefix[3]), NTOHS(prefix[4]), NTOHS(prefix[5]),
         NTOHS(prefix[6]), NTOHS(prefix[7]));
   ninfo("IP address=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-        NTOHS(dev->d_ipv6addr[0]), NTOHS(dev->d_ipv6addr[1]),
-        NTOHS(dev->d_ipv6addr[2]), NTOHS(dev->d_ipv6addr[3]),
-        NTOHS(dev->d_ipv6addr[4]), NTOHS(dev->d_ipv6addr[5]),
-        NTOHS(dev->d_ipv6addr[6]), NTOHS(dev->d_ipv6addr[7]));
+        NTOHS(addr[0]), NTOHS(addr[1]), NTOHS(addr[2]), NTOHS(addr[3]),
+        NTOHS(addr[4]), NTOHS(addr[5]), NTOHS(addr[6]), NTOHS(addr[7]));
+
+  netdev_ipv6_add(dev, addr, preflen);
 
   /* Finally, copy the router address */
 
diff --git a/net/icmpv6/icmpv6_rsolicit.c b/net/icmpv6/icmpv6_rsolicit.c
index 40f7f024b5..ea26f4ccc0 100644
--- a/net/icmpv6/icmpv6_rsolicit.c
+++ b/net/icmpv6/icmpv6_rsolicit.c
@@ -76,7 +76,8 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev)
   l3size        = SIZEOF_ICMPV6_ROUTER_SOLICIT_S(lladdrsize);
 
   ipv6_build_header(IPv6BUF, l3size, IP_PROTO_ICMP6,
-                    dev->d_ipv6addr, g_ipv6_allrouters, 255, 0);
+                    netdev_ipv6_srcaddr(dev, g_ipv6_allrouters),
+                    g_ipv6_allrouters, 255, 0);
 
   /* Set up the ICMPv6 Router Solicitation message */
 
diff --git a/net/icmpv6/icmpv6_sendmsg.c b/net/icmpv6/icmpv6_sendmsg.c
index e238e82fcb..7a73cab173 100644
--- a/net/icmpv6/icmpv6_sendmsg.c
+++ b/net/icmpv6/icmpv6_sendmsg.c
@@ -115,7 +115,8 @@ static void sendto_request(FAR struct net_driver_s *dev,
   dev->d_len = IPv6_HDRLEN + pstate->snd_buflen;
 
   ipv6_build_header(IPv6BUF, pstate->snd_buflen, IP_PROTO_ICMP6,
-                    dev->d_ipv6addr, pstate->snd_toaddr.s6_addr16, 255, 0);
+                    netdev_ipv6_srcaddr(dev, pstate->snd_toaddr.s6_addr16),
+                    pstate->snd_toaddr.s6_addr16, 255, 0);
 
   /* Copy the ICMPv6 request and payload into place after the IPv6 header */
 
@@ -405,8 +406,7 @@ ssize_t icmpv6_sendmsg(FAR struct socket *psock, FAR struct 
msghdr *msg,
                * destination device.
                */
 
-              if (!net_ipv6addr_maskcmp(state.snd_toaddr.s6_addr16,
-                                        dev->d_ipv6addr, dev->d_ipv6netmask))
+              if (!NETDEV_V6ADDR_ONLINK(dev, state.snd_toaddr.s6_addr16))
                 {
                   /* Destination address was not on the local network served
                    * by this device.  If a timeout occurs, then the most
diff --git a/net/icmpv6/icmpv6_solicit.c b/net/icmpv6/icmpv6_solicit.c
index 8519abd933..3c85d443d8 100644
--- a/net/icmpv6/icmpv6_solicit.c
+++ b/net/icmpv6/icmpv6_solicit.c
@@ -95,7 +95,7 @@ void icmpv6_solicit(FAR struct net_driver_s *dev,
   dstaddr[7] = ipaddr[7];
 
   ipv6_build_header(IPv6BUF, l3size, IP_PROTO_ICMP6,
-                    dev->d_ipv6addr, dstaddr, 255, 0);
+                    netdev_ipv6_srcaddr(dev, ipaddr), dstaddr, 255, 0);
 
   /* Set up the ICMPv6 Neighbor Solicitation message */
 
diff --git a/net/inet/ipv6_getsockname.c b/net/inet/ipv6_getsockname.c
index 771b0046e1..7ea4667e91 100644
--- a/net/inet/ipv6_getsockname.c
+++ b/net/inet/ipv6_getsockname.c
@@ -150,7 +150,8 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct 
sockaddr *addr,
   /* Set the address family and the IP address */
 
   outaddr->sin6_family = AF_INET6;
-  memcpy(outaddr->sin6_addr.in6_u.u6_addr8, dev->d_ipv6addr, 16);
+  net_ipv6addr_copy(outaddr->sin6_addr.in6_u.u6_addr8,
+                    netdev_ipv6_srcaddr(dev, *ripaddr));
   *addrlen = sizeof(struct sockaddr_in6);
 
   net_unlock();
diff --git a/net/mld/mld_query.c b/net/mld/mld_query.c
index fd144a4032..4014ab875a 100644
--- a/net/mld/mld_query.c
+++ b/net/mld/mld_query.c
@@ -139,11 +139,21 @@ static clock_t mld_mrc2mrd(uint16_t mrc)
 static bool mld_cmpaddr(FAR struct net_driver_s *dev,
                         const net_ipv6addr_t srcaddr)
 {
+  FAR const uint16_t *lladdr = netdev_ipv6_lladdr(dev);
   int i;
 
+  if (lladdr == NULL)
+    {
+      /* If no link-local address presents, regard address as ::, then nobody
+       * can be less than it.
+       */
+
+      return false;
+    }
+
   for (i = 0; i < 8; i++)
     {
-      if (srcaddr[i] < dev->d_ipv6addr[i])
+      if (srcaddr[i] < lladdr[i])
         {
           return true;
         }
@@ -439,7 +449,7 @@ int mld_query(FAR struct net_driver_s *dev,
 
   /* Not sent to all systems.  Check for Unicast General Query */
 
-  else if (net_ipv6addr_cmp(ipv6->destipaddr, dev->d_ipv6addr))
+  else if (NETDEV_IS_MY_V6ADDR(dev, ipv6->destipaddr))
     {
       mldinfo("Unicast query\n");
       MLD_STATINCR(g_netstats.mld.ucast_query_received);
diff --git a/net/mld/mld_send.c b/net/mld/mld_send.c
index 541156de60..a291b85d1d 100644
--- a/net/mld/mld_send.c
+++ b/net/mld/mld_send.c
@@ -89,6 +89,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct 
mld_group_s *group,
 {
   FAR struct ipv6_router_alert_s *ra;
   FAR const uint16_t *destipaddr;
+  FAR const uint16_t *srcipaddr;
   unsigned int mldsize;
 
   /* Only a general query message can have a NULL group */
@@ -210,8 +211,18 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct 
mld_group_s *group,
           NTOHS(destipaddr[3]), NTOHS(destipaddr[4]), NTOHS(destipaddr[5]),
           NTOHS(destipaddr[6]), NTOHS(destipaddr[7]));
 
+  srcipaddr = netdev_ipv6_lladdr(dev);
+  if (srcipaddr == NULL)
+    {
+      /* Unspecified address is used when link-local address is not
+       * available, as described in RFC 3590, Section 4, Page 2.
+       */
+
+      srcipaddr = g_ipv6_unspecaddr;
+    }
+
   ipv6_build_header(IPv6BUF, dev->d_sndlen, NEXT_HOPBYBOT_EH,
-                    dev->d_ipv6addr, destipaddr, MLD_TTL, 0);
+                    srcipaddr, destipaddr, MLD_TTL, 0);
 
   /* Add the router alert IP header option.
    *
diff --git a/net/neighbor/neighbor_ethernet_out.c 
b/net/neighbor/neighbor_ethernet_out.c
index ba6e462cb9..00b641e63a 100644
--- a/net/neighbor/neighbor_ethernet_out.c
+++ b/net/neighbor/neighbor_ethernet_out.c
@@ -126,8 +126,7 @@ void neighbor_ethernet_out(FAR struct net_driver_s *dev)
 
       /* Check if the destination address is on the local network. */
 
-      if (!net_ipv6addr_maskcmp(ip->destipaddr, dev->d_ipv6addr,
-                                dev->d_ipv6netmask))
+      if (!NETDEV_V6ADDR_ONLINK(dev, ip->destipaddr))
         {
           /* Destination address is not on the local network */
 
diff --git a/net/neighbor/neighbor_lookup.c b/net/neighbor/neighbor_lookup.c
index f6f3ce9fc0..e1e194f546 100644
--- a/net/neighbor/neighbor_lookup.c
+++ b/net/neighbor/neighbor_lookup.c
@@ -66,7 +66,7 @@ static int neighbor_match(FAR struct net_driver_s *dev, FAR 
void *arg)
    * lookup.
    */
 
-  if (!net_ipv6addr_cmp(dev->d_ipv6addr, info->ni_ipaddr))
+  if (!NETDEV_IS_MY_V6ADDR(dev, info->ni_ipaddr))
     {
       return 0;
     }
diff --git a/net/netdev/netdev_findbyaddr.c b/net/netdev/netdev_findbyaddr.c
index c89488bf09..35cb6c7054 100644
--- a/net/netdev/netdev_findbyaddr.c
+++ b/net/netdev/netdev_findbyaddr.c
@@ -126,13 +126,11 @@ FAR struct net_driver_s *netdev_findby_lipv6addr(
     {
       /* Is the interface in the "up" state? */
 
-      if ((dev->d_flags & IFF_UP) != 0 &&
-          !net_ipv6addr_cmp(dev->d_ipv6addr, g_ipv6_unspecaddr))
+      if ((dev->d_flags & IFF_UP) != 0 && NETDEV_HAS_V6ADDR(dev))
         {
           /* Yes.. check for an address match (under the netmask) */
 
-          if (net_ipv6addr_maskcmp(dev->d_ipv6addr, lipaddr,
-                                   dev->d_ipv6netmask))
+          if (NETDEV_V6ADDR_ONLINK(dev, lipaddr))
             {
               /* Its a match */
 
diff --git a/net/netdev/netdev_ifconf.c b/net/netdev/netdev_ifconf.c
index 323cc0811f..1e30f3c208 100644
--- a/net/netdev/netdev_ifconf.c
+++ b/net/netdev/netdev_ifconf.c
@@ -169,8 +169,7 @@ static int ifconf_ipv6_callback(FAR struct net_driver_s 
*dev, FAR void *arg)
    * state.
    */
 
-  if (!net_ipv6addr_cmp(dev->d_ipv6addr, g_ipv6_unspecaddr) &&
-      (dev->d_flags & IFF_UP) != 0)
+  if (NETDEV_HAS_V6ADDR(dev) && IFF_IS_UP(dev->d_flags))
     {
       /* Check if we would exceed the buffer space provided by the caller.
        * NOTE: A common usage model is:
diff --git a/net/netlink/netlink_route.c b/net/netlink/netlink_route.c
index 4409016da9..82192203ef 100644
--- a/net/netlink/netlink_route.c
+++ b/net/netlink/netlink_route.c
@@ -989,14 +989,16 @@ static int netlink_new_ipv6addr(NETLINK_HANDLE handle,
       return -ENODEV;
     }
 
-  memcpy(dev->d_ipv6addr, nla_data(tb[IFA_LOCAL]), 16);
-  net_ipv6_pref2mask(ifm->ifa_prefixlen, dev->d_ipv6netmask);
+  ret = netdev_ipv6_add(dev, nla_data(tb[IFA_LOCAL]), ifm->ifa_prefixlen);
+  if (ret == OK)
+    {
+      netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6,
+                                nla_data(tb[IFA_LOCAL]), ifm->ifa_prefixlen);
+    }
 
-  netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6, dev->d_ipv6addr,
-                               ifm->ifa_prefixlen);
   net_unlock();
 
-  return OK;
+  return ret;
 }
 #endif
 
@@ -1075,6 +1077,11 @@ static int netlink_del_ipv6addr(NETLINK_HANDLE handle,
       return ret;
     }
 
+  if (!tb[IFA_LOCAL] || ifm->ifa_prefixlen > 128)
+    {
+      return -EINVAL;
+    }
+
   net_lock();
   dev = netdev_findbyindex(ifm->ifa_index);
 
@@ -1084,20 +1091,22 @@ static int netlink_del_ipv6addr(NETLINK_HANDLE handle,
       return -ENODEV;
     }
 
-  if (tb[IFA_LOCAL] && !net_ipv6addr_cmp(dev->d_ipv6addr,
-                                         nla_data(tb[IFA_LOCAL])))
+  if (!NETDEV_IS_MY_V6ADDR(dev, 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));
+  ret = netdev_ipv6_del(dev, nla_data(tb[IFA_LOCAL]), ifm->ifa_prefixlen);
+  if (ret == OK)
+    {
+      netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6,
+                                nla_data(tb[IFA_LOCAL]), ifm->ifa_prefixlen);
+    }
 
   net_unlock();
 
-  return OK;
+  return ret;
 }
 #endif
 
@@ -1110,42 +1119,53 @@ static int netlink_del_ipv6addr(NETLINK_HANDLE handle,
  ****************************************************************************/
 
 #ifndef CONFIG_NETLINK_DISABLE_GETADDR
+#ifdef CONFIG_NET_IPv6
+static int netlink_ipv6_addr_callback(FAR struct net_driver_s *dev,
+                                      FAR struct netdev_ifaddr6_s *addr,
+                                      FAR void *arg)
+{
+  FAR struct nlroute_info_s *info = arg;
+  FAR struct netlink_response_s *resp;
+
+  resp = netlink_get_ifaddr(dev, AF_INET6, RTM_NEWADDR, addr->addr,
+                            net_ipv6_mask2pref(addr->mask), info->req);
+  if (resp == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  netlink_add_response(info->handle, resp);
+  return OK;
+}
+#endif
+
 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);
+      resp = netlink_get_ifaddr(dev, AF_INET, RTM_NEWADDR, &dev->d_ipaddr,
+                                net_ipv4_mask2pref(dev->d_netmask),
+                                info->req);
+      if (resp == NULL)
+        {
+          return -ENOMEM;
+        }
+
+      netlink_add_response(info->handle, resp);
     }
 #endif
 
 #ifdef CONFIG_NET_IPv6
   if (info->req->gen.rtgen_family == AF_INET6)
     {
-      addr = &dev->d_ipv6addr;
-      preflen = net_ipv6_mask2pref(dev->d_ipv6netmask);
+      return netdev_ipv6_foreach(dev, netlink_ipv6_addr_callback, arg);
     }
 #endif
 
-  if (addr == NULL)
-    {
-      return OK;
-    }
-
-  resp = netlink_get_ifaddr(dev, info->req->gen.rtgen_family, RTM_NEWADDR,
-                            addr, preflen, info->req);
-  if (resp == NULL)
-    {
-      return -ENOMEM;
-    }
-
-  netlink_add_response(info->handle, resp);
   return OK;
 }
 
diff --git a/net/route/netdev_router.c b/net/route/netdev_router.c
index cffd847a08..348e702281 100644
--- a/net/route/netdev_router.c
+++ b/net/route/netdev_router.c
@@ -167,8 +167,7 @@ static int net_ipv6_devmatch(FAR struct net_route_ipv6_s 
*route,
    */
 
   if (net_ipv6addr_maskcmp(route->target, match->target, route->netmask) &&
-      net_ipv6addr_maskcmp(route->router, dev->d_ipv6addr,
-                           dev->d_ipv6netmask))
+      NETDEV_V6ADDR_ONLINK(dev, route->router))
     {
 #ifdef CONFIG_ROUTE_IPv6_CACHEROUTE
       /* They match.. Copy the entire routing table entry */
diff --git a/net/sixlowpan/sixlowpan_tcpsend.c 
b/net/sixlowpan/sixlowpan_tcpsend.c
index 3fd90d4a5f..e8f534c700 100644
--- a/net/sixlowpan/sixlowpan_tcpsend.c
+++ b/net/sixlowpan/sixlowpan_tcpsend.c
@@ -213,7 +213,8 @@ static int sixlowpan_tcp_header(FAR struct tcp_conn_s *conn,
     }
   else
     {
-      net_ipv6addr_hdrcopy(ipv6tcp->ipv6.srcipaddr, dev->d_ipv6addr);
+      net_ipv6addr_hdrcopy(ipv6tcp->ipv6.srcipaddr,
+                           netdev_ipv6_srcaddr(dev, conn->u.ipv6.raddr));
     }
 
   ninfo("IPv6 length: %d\n",
diff --git a/net/sixlowpan/sixlowpan_udpsend.c 
b/net/sixlowpan/sixlowpan_udpsend.c
index 203e4561df..c28174c3ae 100644
--- a/net/sixlowpan/sixlowpan_udpsend.c
+++ b/net/sixlowpan/sixlowpan_udpsend.c
@@ -247,7 +247,8 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock,
     }
   else
     {
-      net_ipv6addr_hdrcopy(ipv6udp.ipv6.srcipaddr, dev->d_ipv6addr);
+      net_ipv6addr_hdrcopy(ipv6udp.ipv6.srcipaddr,
+                          netdev_ipv6_srcaddr(dev, ipv6udp.ipv6.destipaddr));
     }
 
   ninfo("IPv6 length: %d\n",
diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c
index 0b49c2682b..a31efb8aa5 100644
--- a/net/sixlowpan/sixlowpan_utils.c
+++ b/net/sixlowpan/sixlowpan_utils.c
@@ -319,8 +319,7 @@ int sixlowpan_destaddrfromip(FAR struct radio_driver_s 
*radio,
    */
 
   if (!sixlowpan_islinklocal(ipaddr) &&
-      !net_ipv6addr_maskcmp(radio->r_dev.d_ipv6addr, ipaddr,
-                            radio->r_dev.d_ipv6netmask))
+      !NETDEV_V6ADDR_ONLINK(&radio->r_dev, ipaddr))
     {
       return -EADDRNOTAVAIL;
     }
diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c
index 566a7b16da..8b721a2edf 100644
--- a/net/tcp/tcp_conn.c
+++ b/net/tcp/tcp_conn.c
@@ -440,8 +440,7 @@ static inline int tcp_ipv6_bind(FAR struct tcp_conn_s *conn,
 
       for (dev = g_netdevices; dev; dev = dev->flink)
         {
-          if (net_ipv6addr_cmp(addr->sin6_addr.in6_u.u6_addr16,
-                              dev->d_ipv6addr))
+          if (NETDEV_IS_MY_V6ADDR(dev, addr->sin6_addr.in6_u.u6_addr16))
             {
               ret = 0;
               break;
diff --git a/net/tcp/tcp_connect.c b/net/tcp/tcp_connect.c
index 1a78134c8c..1cbe5910f2 100644
--- a/net/tcp/tcp_connect.c
+++ b/net/tcp/tcp_connect.c
@@ -322,7 +322,8 @@ int psock_tcp_connect(FAR struct socket *psock,
 #endif
           if (net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr))
             {
-              net_ipv6addr_copy(conn->u.ipv6.laddr, conn->dev->d_ipv6addr);
+              net_ipv6addr_copy(conn->u.ipv6.laddr,
+                        netdev_ipv6_srcaddr(conn->dev, conn->u.ipv6.raddr));
             }
 #endif /* CONFIG_NET_IPv6 */
 
diff --git a/net/tcp/tcp_send.c b/net/tcp/tcp_send.c
index 7651839a46..025994e731 100644
--- a/net/tcp/tcp_send.c
+++ b/net/tcp/tcp_send.c
@@ -181,7 +181,9 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
     {
       ninfo("do IPv6 IP header build!\n");
       ipv6_build_header(IPv6BUF, dev->d_len - IPv6_HDRLEN,
-                        IP_PROTO_TCP, dev->d_ipv6addr, conn->u.ipv6.raddr,
+                        IP_PROTO_TCP,
+                        netdev_ipv6_srcaddr(dev, conn->u.ipv6.raddr),
+                        conn->u.ipv6.raddr,
                         conn->sconn.ttl, conn->sconn.s_tclass);
 
       /* Calculate TCP checksum. */
@@ -476,7 +478,9 @@ void tcp_reset(FAR struct net_driver_s *dev, FAR struct 
tcp_conn_s *conn)
       FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
 
       ipv6_build_header(ipv6, dev->d_len - IPv6_HDRLEN,
-                        IP_PROTO_TCP, dev->d_ipv6addr, ipv6->srcipaddr,
+                        IP_PROTO_TCP,
+                        netdev_ipv6_srcaddr(dev, ipv6->srcipaddr),
+                        ipv6->srcipaddr,
                         conn ? conn->sconn.ttl : IP_TTL_DEFAULT,
                         conn ? conn->sconn.s_tos : 0);
       tcp->tcpchksum = 0;
diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c
index 2bb4f64b22..49fa9c3f54 100644
--- a/net/udp/udp_conn.c
+++ b/net/udp/udp_conn.c
@@ -882,8 +882,8 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct 
sockaddr *addr)
 
           for (dev = g_netdevices; dev; dev = dev->flink)
             {
-              if (net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16,
-                                  dev->d_ipv6addr))
+              if (NETDEV_IS_MY_V6ADDR(dev,
+                                      inaddr->sin6_addr.in6_u.u6_addr16))
                 {
                   ret = 0;
                   break;
diff --git a/net/udp/udp_send.c b/net/udp/udp_send.c
index c3d5228f2e..b9c6d4d7e8 100644
--- a/net/udp/udp_send.c
+++ b/net/udp/udp_send.c
@@ -149,7 +149,8 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct 
udp_conn_s *conn)
           dev->d_len        = dev->d_sndlen + UDP_HDRLEN;
 
           ipv6_build_header(IPv6BUF, dev->d_len, IP_PROTO_UDP,
-                            dev->d_ipv6addr, conn->u.ipv6.raddr,
+                            netdev_ipv6_srcaddr(dev, conn->u.ipv6.raddr),
+                            conn->u.ipv6.raddr,
                             conn->sconn.ttl, conn->sconn.s_tclass);
 
           /* The total length to send is the size of the application data

Reply via email to