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.
This commit is contained in:
Petteri Aimonen 2023-12-13 11:06:13 +02:00 committed by Xiang Xiao
parent 73ceb049af
commit c3a234fe99
7 changed files with 31 additions and 13 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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 */

View File

@ -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();

View File

@ -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.

View File

@ -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);

View File

@ -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);