diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 7edb97ce37..daa4a82d60 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -10079,7 +10079,7 @@ _dev_ipmanual_check_ready(NMDevice *self) gboolean has_carrier; NML3CfgCheckReadyFlags flags; gboolean ready; - gboolean acd_used = FALSE; + gs_unref_array GArray *conflicts = NULL; int IS_IPv4; if (priv->ipmanual_data.state_4 != NM_DEVICE_IP_STATE_PENDING @@ -10122,8 +10122,8 @@ _dev_ipmanual_check_ready(NMDevice *self) priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d, addr_family, flags, - &acd_used); - if (acd_used) { + &conflicts); + if (conflicts) { _dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_FAILED); _dev_ip_state_check_async(self, AF_UNSPEC); } else if (ready) { diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 8f69b3ae85..d69f28b64c 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -2990,7 +2990,7 @@ nm_l3cfg_check_ready(NML3Cfg *self, const NML3ConfigData *l3cd, int addr_family, NML3CfgCheckReadyFlags flags, - gboolean *acd_used) + GArray **conflicts) { NMDedupMultiIter iter; const NMPObject *obj; @@ -2998,8 +2998,7 @@ nm_l3cfg_check_ready(NML3Cfg *self, nm_assert(NM_IS_L3CFG(self)); nm_assert_addr_family(addr_family); - - NM_SET_OUT(acd_used, FALSE); + nm_assert(!conflicts || !*conflicts); if (!l3cd) return TRUE; @@ -3019,7 +3018,13 @@ nm_l3cfg_check_ready(NML3Cfg *self, /* Still probing. Not ready. */ ready = FALSE; } else if (addr_info->state == NM_L3_ACD_ADDR_STATE_USED) { - NM_SET_OUT(acd_used, TRUE); + if (conflicts) { + if (!*conflicts) + *conflicts = g_array_new(FALSE, + FALSE, + nm_utils_addr_family_to_size(addr_family)); + g_array_append_val(*conflicts, addr_info->addr); + } } } /* we only care that we don't have ACD still pending. Otherwise we are ready, @@ -3033,6 +3038,7 @@ nm_l3cfg_check_ready(NML3Cfg *self, if (NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY)) { nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) { ObjStateData *obj_state; + gboolean dadfailed = FALSE; obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj); @@ -3049,6 +3055,32 @@ nm_l3cfg_check_ready(NML3Cfg *self, continue; } + if (obj_state->os_plobj + && NM_FLAGS_HAS(NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->os_plobj)->n_ifa_flags, + IFA_F_DADFAILED)) { + /* The address is still present with DADFAILED flag. */ + dadfailed = TRUE; + } else if (obj_state->os_nm_configured && !obj_state->os_plobj + && nm_platform_ip6_dadfailed_check( + self->priv.platform, + self->priv.ifindex, + &NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->obj)->address)) { + /* We configured the address and kernel removed it with DADFAILED flag. */ + dadfailed = TRUE; + } + + if (dadfailed) { + if (conflicts) { + if (!*conflicts) { + *conflicts = + g_array_new(FALSE, FALSE, nm_utils_addr_family_to_size(addr_family)); + } + g_array_append_val(*conflicts, + NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->obj)->address); + } + continue; + } + if (obj_state->os_plobj && NM_FLAGS_HAS(NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->os_plobj)->n_ifa_flags, IFA_F_TENTATIVE)) { diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index e0257623eb..62192d08ba 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -400,7 +400,7 @@ gboolean nm_l3cfg_check_ready(NML3Cfg *self, const NML3ConfigData *l3cd, int addr_family, NML3CfgCheckReadyFlags flags, - gboolean *acd_used); + GArray **conflicts); gboolean nm_l3cfg_has_temp_not_available_obj(NML3Cfg *self, int addr_family);