From d98bfc3e49b55ad560907241cbd7e184cf7aac0a Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Thu, 10 Aug 2023 11:43:27 +0800 Subject: [PATCH] net/icmpv6: Fix `icmpv6_neighbor` for link-local address The netdev of link-local address cannot be auto decided, and the link-local address should always be reguarded as address on local network. The problem we met: When using `icmpv6_autoconfig` with multiple netdev, the `icmpv6_neighbor` may take out wrong netdev with ip address already set, then it may send solicitation with wrong address (`dev->d_ipv6draddr`) on wrong device, and regard the link-local address as conflict (because `dev->d_ipv6draddr` exists on this network). Signed-off-by: Zhe Weng --- net/icmpv6/icmpv6.h | 7 +++++-- net/icmpv6/icmpv6_autoconfig.c | 2 +- net/icmpv6/icmpv6_neighbor.c | 15 +++++++++++---- net/icmpv6/icmpv6_sendmsg.c | 2 +- net/sixlowpan/sixlowpan_tcpsend.c | 2 +- net/sixlowpan/sixlowpan_udpsend.c | 2 +- net/tcp/tcp_conn.c | 2 +- net/tcp/tcp_send_buffered.c | 2 +- net/tcp/tcp_send_unbuffered.c | 2 +- net/tcp/tcp_sendfile.c | 2 +- net/udp/udp_sendto_buffered.c | 2 +- net/udp/udp_sendto_unbuffered.c | 2 +- 12 files changed, 26 insertions(+), 16 deletions(-) diff --git a/net/icmpv6/icmpv6.h b/net/icmpv6/icmpv6.h index 8e00f8b356..c90c3722b1 100644 --- a/net/icmpv6/icmpv6.h +++ b/net/icmpv6/icmpv6.h @@ -205,6 +205,8 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen); * ICMPv6 Neighbor Advertisement. * * Input Parameters: + * dev The suggested device driver structure to do the solicitation, + * can be NULL for auto decision, must set for link-local ipaddr. * ipaddr The IPv6 address to be queried. * * Returned Value: @@ -221,9 +223,10 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen); ****************************************************************************/ #ifdef CONFIG_NET_ICMPv6_NEIGHBOR -int icmpv6_neighbor(const net_ipv6addr_t ipaddr); +int icmpv6_neighbor(FAR struct net_driver_s *dev, + const net_ipv6addr_t ipaddr); #else -# define icmpv6_neighbor(i) (0) +# define icmpv6_neighbor(d,i) (0) #endif /**************************************************************************** diff --git a/net/icmpv6/icmpv6_autoconfig.c b/net/icmpv6/icmpv6_autoconfig.c index 1b2939b8dd..dfc87e6777 100644 --- a/net/icmpv6/icmpv6_autoconfig.c +++ b/net/icmpv6/icmpv6_autoconfig.c @@ -332,7 +332,7 @@ int icmpv6_autoconfig(FAR struct net_driver_s *dev) * method must be employed. */ - ret = icmpv6_neighbor(lladdr); + ret = icmpv6_neighbor(dev, lladdr); if (ret >= 0) { /* Hmmm... someone else responded to our Neighbor Solicitation. We diff --git a/net/icmpv6/icmpv6_neighbor.c b/net/icmpv6/icmpv6_neighbor.c index 62c42c25ac..c7274d4fa8 100644 --- a/net/icmpv6/icmpv6_neighbor.c +++ b/net/icmpv6/icmpv6_neighbor.c @@ -161,6 +161,8 @@ static uint16_t icmpv6_neighbor_eventhandler(FAR struct net_driver_s *dev, * ICMPv6 Neighbor Advertisement. * * Input Parameters: + * dev The suggested device driver structure to do the solicitation, + * can be NULL for auto decision, must set for link-local ipaddr. * ipaddr The IPv6 address to be queried. * * Returned Value: @@ -176,9 +178,9 @@ static uint16_t icmpv6_neighbor_eventhandler(FAR struct net_driver_s *dev, * ****************************************************************************/ -int icmpv6_neighbor(const net_ipv6addr_t ipaddr) +int icmpv6_neighbor(FAR struct net_driver_s *dev, + const net_ipv6addr_t ipaddr) { - FAR struct net_driver_s *dev; struct icmpv6_notify_s notify; struct icmpv6_neighbor_s state; net_ipv6addr_t lookup; @@ -202,7 +204,11 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr) /* Get the device that can route this request */ - dev = netdev_findby_ripv6addr(g_ipv6_unspecaddr, ipaddr); + if (!dev) + { + dev = netdev_findby_ripv6addr(g_ipv6_unspecaddr, ipaddr); + } + if (!dev) { nerr("ERROR: Unreachable: %08lx\n", (unsigned long)ipaddr); @@ -212,7 +218,8 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr) /* Check if the destination address is on the local network. */ - if (net_ipv6addr_maskcmp(ipaddr, dev->d_ipv6addr, dev->d_ipv6netmask)) + if (net_ipv6addr_maskcmp(ipaddr, dev->d_ipv6addr, dev->d_ipv6netmask) || + net_is_addr_linklocal(ipaddr)) { /* Yes.. use the input address for the lookup */ diff --git a/net/icmpv6/icmpv6_sendmsg.c b/net/icmpv6/icmpv6_sendmsg.c index 17f7d064bd..13ccc2b938 100644 --- a/net/icmpv6/icmpv6_sendmsg.c +++ b/net/icmpv6/icmpv6_sendmsg.c @@ -338,7 +338,7 @@ ssize_t icmpv6_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, #ifdef CONFIG_NET_ICMPv6_NEIGHBOR /* Make sure that the IP address mapping is in the Neighbor Table */ - ret = icmpv6_neighbor(inaddr->sin6_addr.s6_addr16); + ret = icmpv6_neighbor(dev, inaddr->sin6_addr.s6_addr16); if (ret < 0) { nerr("ERROR: Not reachable\n"); diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index 649de5675c..0ec02c726d 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -774,7 +774,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, #ifdef CONFIG_NET_ICMPv6_NEIGHBOR /* Make sure that the IP address mapping is in the Neighbor Table */ - ret = icmpv6_neighbor(conn->u.ipv6.raddr); + ret = icmpv6_neighbor(dev, conn->u.ipv6.raddr); if (ret < 0) { nerr("ERROR: Not reachable\n"); diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index d10dc5801c..da04df9439 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -213,7 +213,7 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, #ifdef CONFIG_NET_ICMPv6_NEIGHBOR /* Make sure that the IP address mapping is in the Neighbor Table */ - ret = icmpv6_neighbor(to6->sin6_addr.in6_u.u6_addr16); + ret = icmpv6_neighbor(dev, to6->sin6_addr.in6_u.u6_addr16); if (ret < 0) { nerr("ERROR: Not reachable\n"); diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index 1e9319022f..7bdeb5a357 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -1494,7 +1494,7 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr) { /* Make sure that the IP address mapping is in the Neighbor Table */ - ret = icmpv6_neighbor(conn->u.ipv6.raddr); + ret = icmpv6_neighbor(NULL, conn->u.ipv6.raddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c index 614c675ea5..fec4c97ab1 100644 --- a/net/tcp/tcp_send_buffered.c +++ b/net/tcp/tcp_send_buffered.c @@ -1299,7 +1299,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, { /* Make sure that the IP address mapping is in the Neighbor Table */ - ret = icmpv6_neighbor(conn->u.ipv6.raddr); + ret = icmpv6_neighbor(NULL, conn->u.ipv6.raddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c index 2c40af0d31..c01c3c5a26 100644 --- a/net/tcp/tcp_send_unbuffered.c +++ b/net/tcp/tcp_send_unbuffered.c @@ -525,7 +525,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, { /* Make sure that the IP address mapping is in the Neighbor Table */ - ret = icmpv6_neighbor(conn->u.ipv6.raddr); + ret = icmpv6_neighbor(NULL, conn->u.ipv6.raddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ diff --git a/net/tcp/tcp_sendfile.c b/net/tcp/tcp_sendfile.c index b5a6a67107..0cbac05fb1 100644 --- a/net/tcp/tcp_sendfile.c +++ b/net/tcp/tcp_sendfile.c @@ -450,7 +450,7 @@ ssize_t tcp_sendfile(FAR struct socket *psock, FAR struct file *infile, { /* Make sure that the IP address mapping is in the Neighbor Table */ - ret = icmpv6_neighbor(conn->u.ipv6.raddr); + ret = icmpv6_neighbor(NULL, conn->u.ipv6.raddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ diff --git a/net/udp/udp_sendto_buffered.c b/net/udp/udp_sendto_buffered.c index 211a53aa77..4d87e42b55 100644 --- a/net/udp/udp_sendto_buffered.c +++ b/net/udp/udp_sendto_buffered.c @@ -651,7 +651,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, /* Make sure that the IP address mapping is in the Neighbor Table */ - ret = icmpv6_neighbor(destipaddr); + ret = icmpv6_neighbor(NULL, destipaddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ diff --git a/net/udp/udp_sendto_unbuffered.c b/net/udp/udp_sendto_unbuffered.c index 6d182f1393..cba199d4b6 100644 --- a/net/udp/udp_sendto_unbuffered.c +++ b/net/udp/udp_sendto_unbuffered.c @@ -382,7 +382,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, /* Make sure that the IP address mapping is in the Neighbor Table */ - ret = icmpv6_neighbor(destipaddr); + ret = icmpv6_neighbor(NULL, destipaddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */