From 6d8a636563b0ddbf2b484473210bf3bcf41b47a7 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 9 Feb 2018 13:19:49 +0100 Subject: [PATCH] device: fix IPv6 DAD to re-check whether address really failed DAD In device_ipx_changed() we remember the addresses for which it appears that DAD failed. Later, on an idle handler, we process them during queued_ip6_config_change(). Note that nm_plaform_ip6_address_sync() might very well decide to remove some or all addresses and re-add them immidiately later. It might do so, to get the address priority/ordering right. At that point, we already emit platform signals that the device disappeared, and track them in dad6_failed_addrs. Hence, later during queued_ip6_config_change() we must check again whether the address is really not there and not still doing DAD. Otherwise, we wrongly claim that DAD failed and remove the address, generate a new one, and the same issue might happen again. --- src/devices/nm-device.c | 20 +++++++++++++++++--- src/platform/nmp-object.h | 10 ++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index c08b93ebb6..8b99fc0ba8 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -11529,6 +11529,7 @@ queued_ip6_config_change (gpointer user_data) NMDevicePrivate *priv; GSList *iter; gboolean need_ipv6ll = FALSE; + NMPlatform *platform; g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); @@ -11555,11 +11556,24 @@ queued_ip6_config_change (gpointer user_data) } else update_ip_config (self, AF_INET6, FALSE); - if (priv->state < NM_DEVICE_STATE_DEACTIVATING - && nm_platform_link_get (nm_device_get_platform (self), priv->ifindex)) { + if ( priv->state < NM_DEVICE_STATE_DEACTIVATING + && (platform = nm_device_get_platform (self)) + && nm_platform_link_get (platform, priv->ifindex)) { /* Handle DAD failures */ for (iter = priv->dad6_failed_addrs; iter; iter = iter->next) { - const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS (iter->data); + const NMPObject *obj = iter->data; + const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS (obj); + const NMPlatformIP6Address *addr2; + + addr2 = NMP_OBJECT_CAST_IP6_ADDRESS (nm_platform_lookup_obj (platform, + NMP_CACHE_ID_TYPE_OBJECT_TYPE, + obj)); + if ( addr2 + && ( NM_FLAGS_HAS (addr2->n_ifa_flags, IFA_F_SECONDARY) + || !NM_FLAGS_HAS (addr2->n_ifa_flags, IFA_F_DADFAILED))) { + /* the address still/again exists and is not in DADFAILED state. Skip it. */ + continue; + } _LOGI (LOGD_IP6, "ipv6: duplicate address check failed for the %s address", nm_platform_ip6_address_to_string (addr, NULL, 0)); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 8414c1a57f..8c36e2e3d4 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -730,6 +730,16 @@ const NMDedupMultiEntry *nm_platform_lookup_entry (NMPlatform *platform, NMPCacheIdType cache_id_type, const NMPObject *obj); +static inline const NMPObject * +nm_platform_lookup_obj (NMPlatform *platform, + NMPCacheIdType cache_id_type, + const NMPObject *obj) +{ + return nm_dedup_multi_entry_get_obj (nm_platform_lookup_entry (platform, + cache_id_type, + obj)); +} + static inline const NMDedupMultiHeadEntry * nm_platform_lookup_obj_type (NMPlatform *platform, NMPObjectType obj_type)