From c3a234fe99b39ab39fde13f54808a66fc1d8ef24 Mon Sep 17 00:00:00 2001 From: Petteri Aimonen Date: Wed, 13 Dec 2023 11:06:13 +0200 Subject: [PATCH] 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);