diff options
author | Andrew Zaborowski <andrew.zaborowski@intel.com> | 2022-09-20 15:32:00 +0200 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2022-09-20 10:04:02 -0500 |
commit | b1b130fe5d52eae5f81a4a20fb1221a6b968bcfd (patch) | |
tree | b60ae08c35d230acedf5b5b5219646227bf53e4b | |
parent | abeb8590791b1985447aed112348475c7761f17f (diff) |
icmp6,netconfig: Skip SLLAO if RS sent from optimistic address
Make sure we don't include the Source Link-Local Address Option in our
Router Solicitations until the source link-local address completes DAD.
Extand the recently added l_icmp6_client_set_link_local_address() with a
parameter to tell us whether the address is optimistic. Don't change
the l_dhcp6_client_set_link_local_address signature to avoid breaking
existing users.
-rw-r--r-- | ell/dhcp6.c | 2 | ||||
-rw-r--r-- | ell/icmp6.c | 29 | ||||
-rw-r--r-- | ell/icmp6.h | 3 | ||||
-rw-r--r-- | ell/netconfig.c | 30 |
4 files changed, 50 insertions, 14 deletions
diff --git a/ell/dhcp6.c b/ell/dhcp6.c index e234eb0b..2792ff29 100644 --- a/ell/dhcp6.c +++ b/ell/dhcp6.c @@ -1623,7 +1623,7 @@ LIB_EXPORT bool l_dhcp6_client_set_link_local_address( return false; if (!client->nora) - l_icmp6_client_set_link_local_address(client->icmp6, ll); + l_icmp6_client_set_link_local_address(client->icmp6, ll, false); return true; } diff --git a/ell/icmp6.c b/ell/icmp6.c index 5ddc494d..f087ba3e 100644 --- a/ell/icmp6.c +++ b/ell/icmp6.c @@ -206,7 +206,8 @@ static uint16_t icmp6_checksum(const struct iovec *iov, unsigned int iov_len) static int icmp6_send_router_solicitation(int s, int ifindex, const uint8_t src_mac[static 6], - const struct in6_addr *src_ip) + const struct in6_addr *src_ip, + bool src_ip_optimistic) { struct nd_router_solicit rs = { .nd_rs_type = ND_ROUTER_SOLICIT, @@ -247,11 +248,17 @@ static int icmp6_send_router_solicitation(int s, int ifindex, memcpy(&ip_hdr.ip6_src, src_ip, 16); - if (l_memeqzero(src_ip, 16)) { + if (l_memeqzero(src_ip, 16) || src_ip_optimistic) { /* - * radvd will discard and warn about RSs from the unspecified - * address with the SLLAO, omit that option by dropping the - * last two iov buffers. + * RFC 4429 Section 3.2: "A node MUST NOT send a Router + * Solicitation with a SLLAO from an Optimistic Address. + * Router Solicitations SHOULD be sent from a non-Optimistic + * or the Unspecified Address; however, they MAY be sent from + * an Optimistic Address as long as the SLLAO is not included." + * + * Additionally radvd will also discard and warn about RSs + * from the unspecified address with the SLLAO. Omit that + * option by dropping the last two iov buffers. */ msg.msg_iovlen -= 2; ip_hdr.ip6_plen = htons(ntohs(ip_hdr.ip6_plen) - rs_sllao_size); @@ -347,6 +354,7 @@ struct l_icmp6_client { uint64_t retransmit_time; struct l_io *io; struct in6_addr src_ip; + bool src_ip_optimistic; struct l_icmp6_router *ra; struct l_netlink *rtnl; @@ -547,7 +555,8 @@ static void icmp6_client_timeout_send(struct l_timeout *timeout, r = icmp6_send_router_solicitation(l_io_get_fd(client->io), client->ifindex, client->mac, - &client->src_ip); + &client->src_ip, + client->src_ip_optimistic); if (r < 0) { CLIENT_DEBUG("Error sending Router Solicitation: %s", strerror(-r)); @@ -766,7 +775,7 @@ LIB_EXPORT bool l_icmp6_client_set_route_priority( LIB_EXPORT bool l_icmp6_client_set_link_local_address( struct l_icmp6_client *client, - const char *ll) + const char *ll, bool optimistic) { if (unlikely(!client)) return false; @@ -777,7 +786,11 @@ LIB_EXPORT bool l_icmp6_client_set_link_local_address( * is fine. Once we have a confirmed link-local address we use that * as the source address. */ - return inet_pton(AF_INET6, ll, &client->src_ip) == 1; + if (inet_pton(AF_INET6, ll, &client->src_ip) != 1) + return false; + + client->src_ip_optimistic = optimistic; + return true; } struct l_icmp6_router *_icmp6_router_new() diff --git a/ell/icmp6.h b/ell/icmp6.h index ffbb8a80..ad3d661e 100644 --- a/ell/icmp6.h +++ b/ell/icmp6.h @@ -66,7 +66,8 @@ bool l_icmp6_client_set_rtnl(struct l_icmp6_client *client, bool l_icmp6_client_set_route_priority(struct l_icmp6_client *client, uint32_t priority); bool l_icmp6_client_set_link_local_address(struct l_icmp6_client *client, - const char *ll); + const char *ll, + bool optimistic); char *l_icmp6_router_get_address(const struct l_icmp6_router *r); bool l_icmp6_router_get_managed(const struct l_icmp6_router *r); diff --git a/ell/netconfig.c b/ell/netconfig.c index 765703b2..c558cade 100644 --- a/ell/netconfig.c +++ b/ell/netconfig.c @@ -93,6 +93,7 @@ struct l_netconfig { unsigned int orig_optimistic_dad; uint8_t mac[ETH_ALEN]; struct l_timeout *ra_timeout; + bool have_lla; enum { NETCONFIG_V6_METHOD_UNSET, NETCONFIG_V6_METHOD_DHCP, @@ -702,7 +703,7 @@ static bool netconfig_check_start_dhcp6(struct l_netconfig *nc) return true; /* Don't start DHCPv6 while waiting for the link-local address */ - if (l_queue_find(addr_wait_list, netconfig_match, nc)) + if (!nc->have_lla) return true; return l_dhcp6_client_start(nc->dhcp6_client); @@ -1844,6 +1845,7 @@ static void netconfig_ifaddr_ipv6_added(struct l_netconfig *nc, { struct in6_addr in6; _auto_(l_free) char *ip = NULL; + bool new_lla; if ((ifa->ifa_flags & IFA_F_TENTATIVE) && !(ifa->ifa_flags & IFA_F_OPTIMISTIC)) @@ -1858,16 +1860,28 @@ static void netconfig_ifaddr_ipv6_added(struct l_netconfig *nc, if (!IN6_IS_ADDR_LINKLOCAL(&in6)) return; - netconfig_addr_wait_unregister(nc, true); + new_lla = !nc->have_lla; + nc->have_lla = true; + + if (!(ifa->ifa_flags & IFA_F_TENTATIVE)) + netconfig_addr_wait_unregister(nc, true); + else if (nc->ifaddr6_dump_cmd_id) { + struct l_netlink *rtnl = l_rtnl_get(); + unsigned int cmd_id = nc->ifaddr6_dump_cmd_id; + + nc->ifaddr6_dump_cmd_id = 0; + l_netlink_cancel(rtnl, cmd_id); + } l_dhcp6_client_set_link_local_address(nc->dhcp6_client, ip); - l_icmp6_client_set_link_local_address(nc->icmp6_client, ip); + l_icmp6_client_set_link_local_address(nc->icmp6_client, ip, + !!(ifa->ifa_flags & IFA_F_OPTIMISTIC)); /* * Only now that we have a link-local address see if we can start * actual DHCPv6 setup. */ - if (netconfig_check_start_dhcp6(nc)) + if (new_lla && netconfig_check_start_dhcp6(nc)) return; netconfig_emit_event(nc, AF_INET6, L_NETCONFIG_EVENT_FAILED); @@ -2022,6 +2036,13 @@ configure_ipv6: * before we start the dump, instead of after it ends, to eliminate * the possibility of missing an RTM_NEWADDR between the end of * the dump command and registering for the events. + * + * We stay on that list until we receive a non-tentative LL address. + * Note that we may set .have_lla earlier, specifically when we + * receive a tentative LL address that is also optimistic. We will + * however stay on addr_wait_list because we want to notify + * l_icmp6_client again when the LL address completes DAD and becomes + * non-tentative. */ if (!addr_wait_list) { addr_wait_list = l_queue_new(); @@ -2041,6 +2062,7 @@ configure_ipv6: goto unregister; l_queue_push_tail(addr_wait_list, netconfig); + netconfig->have_lla = false; if (!l_net_get_mac_address(netconfig->ifindex, netconfig->mac)) goto unregister; |