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


The following commit(s) were added to refs/heads/master by this push:
     new c3a234fe99 ipv6: Fix source address with many addresses in same network
c3a234fe99 is described below

commit c3a234fe99b39ab39fde13f54808a66fc1d8ef24
Author: Petteri Aimonen <j...@git.mail.kapsi.fi>
AuthorDate: Wed Dec 13 11:06:13 2023 +0200

    ipv6: Fix source address with many addresses in same network
    
    Previously ipv6 multi-address support decided packet source
    address based on its destination. This doesn't work if NuttX
    device has multiple addresses within same subnet.
    
    Instead when a packet is a response to existing connection,
    the source address should be based on the destination address
    used in the received packet.
---
 include/nuttx/net/netdev.h  | 14 +++++++++++---
 net/icmpv6/icmpv6_input.c   |  6 ++++--
 net/icmpv6/icmpv6_reply.c   |  2 +-
 net/inet/ipv6_getsockname.c |  2 +-
 net/netdev/netdev_ipv6.c    | 14 +++++++++++---
 net/tcp/tcp_send.c          |  4 ++--
 net/udp/udp_send.c          |  2 +-
 7 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h
index 0d35828de3..509e8e95ab 100644
--- a/include/nuttx/net/netdev.h
+++ b/include/nuttx/net/netdev.h
@@ -1062,11 +1062,19 @@ int netdev_ipv6_del(FAR struct net_driver_s *dev, const 
net_ipv6addr_t addr,
  * Name: netdev_ipv6_srcaddr/srcifaddr
  *
  * Description:
- *   Get the source IPv6 address (RFC6724).
+ *   Get the source IPv6 address (RFC6724) to use for transmitted packets.
+ *   If we are responding to a received packet, use the destination address
+ *   from that packet. If we are initiating communication, pick a local
+ *   address that best matches the destination address.
+ *
+ * Input parameters:
+ *   dev - Network device that packet is being transmitted from
+ *   dst - Address to compare against when choosing local address.
  *
  * 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.
+ *   A pointer to a net_ipv6addr_t contained in net_driver_s 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.
diff --git a/net/icmpv6/icmpv6_input.c b/net/icmpv6/icmpv6_input.c
index a9ff098261..17d9137b54 100644
--- a/net/icmpv6/icmpv6_input.c
+++ b/net/icmpv6/icmpv6_input.c
@@ -543,11 +543,13 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned 
int iplen)
          * ICMPv6 checksum before we return the packet.
          */
 
+        FAR const uint16_t *srcaddr;
+
         icmpv6->type = ICMPv6_ECHO_REPLY;
 
+        srcaddr = netdev_ipv6_srcaddr(dev, ipv6->destipaddr);
         net_ipv6addr_copy(ipv6->destipaddr, ipv6->srcipaddr);
-        net_ipv6addr_copy(ipv6->srcipaddr,
-                          netdev_ipv6_srcaddr(dev, ipv6->srcipaddr));
+        net_ipv6addr_copy(ipv6->srcipaddr, srcaddr);
 
         icmpv6->chksum = 0;
         icmpv6->chksum = ~icmpv6_chksum(dev, iplen);
diff --git a/net/icmpv6/icmpv6_reply.c b/net/icmpv6/icmpv6_reply.c
index 726b499ca4..3479d24dc5 100644
--- a/net/icmpv6/icmpv6_reply.c
+++ b/net/icmpv6/icmpv6_reply.c
@@ -172,7 +172,7 @@ 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,
-                    netdev_ipv6_srcaddr(dev, ipv6->srcipaddr),
+                    netdev_ipv6_srcaddr(dev, ipv6->destipaddr),
                     ipv6->srcipaddr, 255, 0);
 
   /* Initialize the ICMPv6 header */
diff --git a/net/inet/ipv6_getsockname.c b/net/inet/ipv6_getsockname.c
index 7ea4667e91..ac642a0ab2 100644
--- a/net/inet/ipv6_getsockname.c
+++ b/net/inet/ipv6_getsockname.c
@@ -151,7 +151,7 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct 
sockaddr *addr,
 
   outaddr->sin6_family = AF_INET6;
   net_ipv6addr_copy(outaddr->sin6_addr.in6_u.u6_addr8,
-                    netdev_ipv6_srcaddr(dev, *ripaddr));
+                    netdev_ipv6_srcaddr(dev, *lipaddr));
   *addrlen = sizeof(struct sockaddr_in6);
 
   net_unlock();
diff --git a/net/netdev/netdev_ipv6.c b/net/netdev/netdev_ipv6.c
index 67e51e871f..bb548631e0 100644
--- a/net/netdev/netdev_ipv6.c
+++ b/net/netdev/netdev_ipv6.c
@@ -220,11 +220,19 @@ int netdev_ipv6_del(FAR struct net_driver_s *dev, const 
net_ipv6addr_t addr,
  * Name: netdev_ipv6_srcaddr/srcifaddr
  *
  * Description:
- *   Get the source IPv6 address (RFC6724).
+ *   Get the source IPv6 address (RFC6724) to use for transmitted packets.
+ *   If we are responding to a received packet, use the destination address
+ *   from that packet. If we are initiating communication, pick a local
+ *   address that best matches the destination address.
+ *
+ * Input parameters:
+ *   dev - Network device that packet is being transmitted from
+ *   dst - Address to compare against when choosing local address.
  *
  * 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.
+ *   A pointer to a net_ipv6addr_t contained in net_driver_s 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.
diff --git a/net/tcp/tcp_send.c b/net/tcp/tcp_send.c
index 025994e731..d8ecf554b1 100644
--- a/net/tcp/tcp_send.c
+++ b/net/tcp/tcp_send.c
@@ -182,7 +182,7 @@ 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,
-                        netdev_ipv6_srcaddr(dev, conn->u.ipv6.raddr),
+                        netdev_ipv6_srcaddr(dev, conn->u.ipv6.laddr),
                         conn->u.ipv6.raddr,
                         conn->sconn.ttl, conn->sconn.s_tclass);
 
@@ -479,7 +479,7 @@ void tcp_reset(FAR struct net_driver_s *dev, FAR struct 
tcp_conn_s *conn)
 
       ipv6_build_header(ipv6, dev->d_len - IPv6_HDRLEN,
                         IP_PROTO_TCP,
-                        netdev_ipv6_srcaddr(dev, ipv6->srcipaddr),
+                        netdev_ipv6_srcaddr(dev, ipv6->destipaddr),
                         ipv6->srcipaddr,
                         conn ? conn->sconn.ttl : IP_TTL_DEFAULT,
                         conn ? conn->sconn.s_tos : 0);
diff --git a/net/udp/udp_send.c b/net/udp/udp_send.c
index b9c6d4d7e8..2e3180af94 100644
--- a/net/udp/udp_send.c
+++ b/net/udp/udp_send.c
@@ -149,7 +149,7 @@ 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,
-                            netdev_ipv6_srcaddr(dev, conn->u.ipv6.raddr),
+                            netdev_ipv6_srcaddr(dev, conn->u.ipv6.laddr),
                             conn->u.ipv6.raddr,
                             conn->sconn.ttl, conn->sconn.s_tclass);
 

Reply via email to