From b372ba67d92663b03f5d445655d702a55668e7b0 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 12 Feb 2025 12:46:02 +0100 Subject: [PATCH 1/3] net: ipv6: Fix neighbor registration based on received RA message When Router Advertisement with Source Link-Layer Address option is received, host should register a new neighbor marked as STALE (RFC 4861, ch. 6.3.4). This behavior was broken however, because we always added a new neighbor in INCOMPLETE state before processing SLLA option. In result, the entry was not updated to the STALE state, and a redundant Neighbor Solicitation was sent. Fix this by moving the code responsible for adding neighbor in INCOMPLETE state after options processing, and only as a fallback behavior if the SLLA option was not present. Signed-off-by: Robert Lubos (cherry picked from commit fce53922ef20c242b5f97e7e239078fca0456de4) --- subsys/net/ip/ipv6_nbr.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index bace919c3cbd2..6825ebdacf524 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -2559,12 +2559,6 @@ static int handle_ra_input(struct net_icmp_ctx *ctx, nd_opt_hdr = (struct net_icmpv6_nd_opt_hdr *) net_pkt_get_data(pkt, &nd_access); - /* Add neighbor cache entry using link local address, regardless of link layer address - * presence in Router Advertisement. - */ - nbr = net_ipv6_nbr_add(net_pkt_iface(pkt), (struct in6_addr *)NET_IPV6_HDR(pkt)->src, NULL, - true, NET_IPV6_NBR_STATE_INCOMPLETE); - while (nd_opt_hdr) { net_pkt_acknowledge_data(pkt, &nd_access); @@ -2665,6 +2659,15 @@ static int handle_ra_input(struct net_icmp_ctx *ctx, net_pkt_get_data(pkt, &nd_access); } + if (nbr == NULL) { + /* Add neighbor cache entry using link local address, regardless + * of link layer address presence in Router Advertisement. + */ + nbr = net_ipv6_nbr_add(net_pkt_iface(pkt), + (struct in6_addr *)NET_IPV6_HDR(pkt)->src, + NULL, true, NET_IPV6_NBR_STATE_INCOMPLETE); + } + router = net_if_ipv6_router_lookup(net_pkt_iface(pkt), (struct in6_addr *)ip_hdr->src); if (router) { From f654fb71d9e0c06c7c0201928e8b3de626d480cc Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 12 Feb 2025 12:55:48 +0100 Subject: [PATCH 2/3] net: ipv6: Send Neighbor Solicitations in PROBE state as unicast According to RFC 4861, ch. 7.3.3: "Upon entering the PROBE state, a node sends a unicast Neighbor Solicitation message to the neighbor using the cached link-layer address." Zephyr's implementation was not compliant with behavior, as instead of sending a unicast probe for reachability confirmation, it was sending a multicast packet instead. This commit fixes it. Signed-off-by: Robert Lubos (cherry picked from commit 8cd213e84612430738ad884400e1f69030fbd514) --- subsys/net/ip/ipv6_nbr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 6825ebdacf524..2fd8ceb182a97 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -1549,7 +1549,7 @@ static void ipv6_nd_reachable_timeout(struct k_work *work) data->ns_count); ret = net_ipv6_send_ns(nbr->iface, NULL, NULL, - NULL, &data->addr, + &data->addr, &data->addr, false); if (ret < 0) { NET_DBG("Cannot send NS (%d)", ret); From f4e19481f1f97adb4dfd850c388f596ced196e99 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 12 Feb 2025 13:08:41 +0100 Subject: [PATCH 3/3] net: ipv6: Fix Neighbor Advertisement processing w/o TLLA option According to RFC 4861, ch. 7.2.5: "If the Override flag is set, or the supplied link-layer address is the same as that in the cache, or no Target Link-Layer Address option was supplied, the received advertisement MUST update the Neighbor Cache entry as follows ... If the Solicited flag is set, the state of the entry MUST be set to REACHABLE" This indicates that Target Link-Layer Address option does not need to be present in the received solicited Neighbor Advertisement to confirm reachability. Therefore remove `tllao_offset` variable check from the if condition responsible for updating cache entry. No further changes in the logic are required because if TLLA option is missing, `lladdr_changed` will be set to false, so no LL address will be updated. Signed-off-by: Robert Lubos (cherry picked from commit 02c153c8b1898c21f55f5dc6d890f1534a227123) --- subsys/net/ip/ipv6_nbr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 2fd8ceb182a97..73ec23b4c54fb 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -1727,7 +1727,7 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, if (na_hdr->flags & NET_ICMPV6_NA_FLAG_OVERRIDE || (!(na_hdr->flags & NET_ICMPV6_NA_FLAG_OVERRIDE) && - tllao_offset && !lladdr_changed)) { + !lladdr_changed)) { if (lladdr_changed) { dbg_update_neighbor_lladdr_raw(