diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0aad58f7b8..8d79738302 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7207,8 +7207,12 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - if (priv->ext_ip6_config_captured) - ll_addr = nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE); + if (priv->ext_ip6_config_captured) { + ll_addr = nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED); + } if (!ll_addr) { _LOGW (LOGD_DHCP6, "can't start DHCPv6: no link-local address"); @@ -7425,7 +7429,10 @@ linklocal6_complete (NMDevice *self) nm_assert (priv->linklocal6_timeout_id); nm_assert (priv->ext_ip6_config_captured); - nm_assert (nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)); + nm_assert (nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)); nm_clear_g_source (&priv->linklocal6_timeout_id); @@ -7545,7 +7552,10 @@ linklocal6_start (NMDevice *self) nm_clear_g_source (&priv->linklocal6_timeout_id); if ( priv->ext_ip6_config_captured - && nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)) + && nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) return TRUE; connection = nm_device_get_applied_connection (self); @@ -7944,7 +7954,10 @@ ndisc_ra_timeout (NMNDisc *ndisc, NMDevice *self) * config, consider that sufficient for IPv6 success. */ if ( priv->ip6_config - && nm_ip6_config_get_address_first_nontentative (priv->ip6_config, FALSE)) + && nm_ip6_config_find_first_address (priv->ip6_config, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) nm_device_activate_schedule_ip6_config_result (self); else nm_device_activate_schedule_ip6_config_timeout (self); @@ -11538,7 +11551,10 @@ update_ip_config (NMDevice *self, int addr_family, gboolean initial) if ( addr_family == AF_INET6 && priv->linklocal6_timeout_id && priv->ext_ip6_config_captured - && nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)) { + && nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) { /* linklocal6 is ready now, do the state transition... we are also * invoked as g_idle_add, so no problems with reentrance doing it now. */ @@ -11671,16 +11687,15 @@ queued_ip6_config_change (gpointer user_data) /* Check if DAD is still pending */ if ( priv->ip6_state == IP_CONF && priv->dad6_ip6_config - && priv->ext_ip6_config_captured) { - if (!nm_ip6_config_has_any_dad_pending (priv->ext_ip6_config_captured, - priv->dad6_ip6_config)) { - _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated"); - g_clear_object (&priv->dad6_ip6_config); - _set_ip_state (self, AF_INET6, IP_DONE); - check_ip_state (self, FALSE, TRUE); - if (priv->rt6_temporary_not_available) - nm_device_activate_schedule_ip6_config_result (self); - } + && priv->ext_ip6_config_captured + && !nm_ip6_config_has_any_dad_pending (priv->ext_ip6_config_captured, + priv->dad6_ip6_config)) { + _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated"); + g_clear_object (&priv->dad6_ip6_config); + _set_ip_state (self, AF_INET6, IP_DONE); + check_ip_state (self, FALSE, TRUE); + if (priv->rt6_temporary_not_available) + nm_device_activate_schedule_ip6_config_result (self); } set_unmanaged_external_down (self, TRUE); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 883e8e00fa..5700f5e64e 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -1691,19 +1691,43 @@ nm_ip6_config_lookup_address (const NMIP6Config *self, } const NMPlatformIP6Address * -nm_ip6_config_get_address_first_nontentative (const NMIP6Config *self, gboolean linklocal) +nm_ip6_config_find_first_address (const NMIP6Config *self, + NMPlatformMatchFlags match_flag) { const NMPlatformIP6Address *addr; NMDedupMultiIter iter; g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL); - linklocal = !!linklocal; + nm_assert (!NM_FLAGS_ANY (match_flag, ~( NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY + | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); + + nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY)); + nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) { - if ( ((!!IN6_IS_ADDR_LINKLOCAL (&addr->address)) == linklocal) - && !(addr->n_ifa_flags & IFA_F_TENTATIVE)) - return addr; + + if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) + continue; + } else { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) + continue; + } + + if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_DADFAILED)) { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) + continue; + } else if ( NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TENTATIVE) + && !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) + continue; + } else { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) + continue; + } + + return addr; } return NULL; diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 882047d1c1..ef5e310520 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -149,7 +149,8 @@ void _nmtst_ip6_config_del_address (NMIP6Config *self, guint i); guint nm_ip6_config_get_num_addresses (const NMIP6Config *self); const NMPlatformIP6Address *nm_ip6_config_get_first_address (const NMIP6Config *self); const NMPlatformIP6Address *_nmtst_ip6_config_get_address (const NMIP6Config *self, guint i); -const NMPlatformIP6Address *nm_ip6_config_get_address_first_nontentative (const NMIP6Config *self, gboolean linklocal); +const NMPlatformIP6Address *nm_ip6_config_find_first_address (const NMIP6Config *self, + NMPlatformMatchFlags match_flag); gboolean nm_ip6_config_address_exists (const NMIP6Config *self, const NMPlatformIP6Address *address); const NMPlatformIP6Address *nm_ip6_config_lookup_address (const NMIP6Config *self, const struct in6_addr *addr); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 0afdb3b060..824735083a 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -171,6 +171,34 @@ typedef enum { /*< skip >*/ NM_PLATFORM_ERROR_CANT_SET_MTU, } NMPlatformError; +typedef enum { + + /* match-flags are strictly inclusive. That means, + * by default nothing is matched, but if you enable a particular + * flag, a candidate that matches passes the check. + * + * In other words: adding more flags can only extend the result + * set of matching objects. + * + * Also, the flags form partitions. Like, an address can be either of + * ADDRTYPE_NORMAL or ADDRTYPE_LINKLOCAL, but never both. Same for + * the ADDRSTATE match types. + */ + NM_PLATFORM_MATCH_WITH_NONE = 0, + + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL = (1LL << 0), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL = (1LL << 1), + NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY = NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL, + + NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL = (1LL << 2), + NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE = (1LL << 3), + NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED = (1LL << 4), + NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY = NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED, +} NMPlatformMatchFlags; + #define NM_PLATFORM_LINK_OTHER_NETNS (-1) #define __NMPlatformObject_COMMON \