From dfdce13cee3a1b7611aefa447c6417517ec0fffe Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 30 Jan 2016 19:43:18 +0100 Subject: [PATCH 1/4] core: add nm_ip6_config_new_cloned() function --- src/nm-ip6-config.c | 16 ++++++++++++++-- src/nm-ip6-config.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 61209d452d..8a70ab663c 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -77,6 +77,18 @@ nm_ip6_config_new (int ifindex) NULL); } +NMIP6Config * +nm_ip6_config_new_cloned (const NMIP6Config *src) +{ + NMIP6Config *new; + + g_return_val_if_fail (NM_IS_IP6_CONFIG (src), NULL); + + new = nm_ip6_config_new (nm_ip6_config_get_ifindex (src)); + nm_ip6_config_replace (new, src, NULL); + return new; +} + int nm_ip6_config_get_ifindex (const NMIP6Config *config) { @@ -962,8 +974,8 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev const NMPlatformIP6Address *dst_addr, *src_addr; const NMPlatformIP6Route *dst_route, *src_route; - g_return_val_if_fail (src != NULL, FALSE); - g_return_val_if_fail (dst != NULL, FALSE); + g_return_val_if_fail (NM_IS_IP6_CONFIG (src), FALSE); + g_return_val_if_fail (NM_IS_IP6_CONFIG (dst), FALSE); g_return_val_if_fail (src != dst, FALSE); #if NM_MORE_ASSERTS diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 3ee8370163..759e7790ea 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -66,6 +66,7 @@ GType nm_ip6_config_get_type (void); NMIP6Config * nm_ip6_config_new (int ifindex); +NMIP6Config * nm_ip6_config_new_cloned (const NMIP6Config *src); int nm_ip6_config_get_ifindex (const NMIP6Config *config); From 5ff8decb8fd94b541cfd3bfd8d00eaecd7c28f51 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 30 Jan 2016 21:37:22 +0100 Subject: [PATCH 2/4] device: add ext_ip6_config_captured to remember the last-read platform configuration ext_ip6_config gets modified to only contain items that are configured externally, not by internal choice. --- src/devices/nm-device.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 026fe92354..720fbe2f28 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -335,6 +335,7 @@ typedef struct _NMDevicePrivate { NMIP6Config * con_ip6_config; /* config from the setting */ NMIP6Config * wwan_ip6_config; NMIP6Config * ext_ip6_config; /* Stuff added outside NM */ + NMIP6Config * ext_ip6_config_captured; /* Configuration captured from platform. */ GSList * vpn6_configs; /* VPNs which use this device */ gboolean nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */ guint32 ip6_mtu; @@ -8684,7 +8685,6 @@ update_ip6_config (NMDevice *self, gboolean initial) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int ifindex; - gboolean linklocal6_just_completed = FALSE; gboolean capture_resolv_conf; NMDnsManagerResolvConfMode resolv_conf_mode; @@ -8697,12 +8697,11 @@ update_ip6_config (NMDevice *self, gboolean initial) /* IPv6 */ g_clear_object (&priv->ext_ip6_config); - priv->ext_ip6_config = nm_ip6_config_capture (ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - if (priv->ext_ip6_config) { + g_clear_object (&priv->ext_ip6_config_captured); + priv->ext_ip6_config_captured = nm_ip6_config_capture (ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + if (priv->ext_ip6_config_captured) { - /* Check this before modifying ext_ip6_config */ - linklocal6_just_completed = priv->linklocal6_timeout_id && - have_ip6_address (priv->ext_ip6_config, TRUE); + priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured); /* This function was called upon external changes. Remove the configuration * (addresses,routes) that is no longer present externally from the internal @@ -8734,7 +8733,9 @@ update_ip6_config (NMDevice *self, gboolean initial) ip6_config_merge_and_apply (self, FALSE, NULL); } - if (linklocal6_just_completed) { + if ( priv->linklocal6_timeout_id + && priv->ext_ip6_config_captured + && have_ip6_address (priv->ext_ip6_config_captured, TRUE)) { /* linklocal6 is ready now, do the state transition... we are also * invoked as g_idle_add, so no problems with reentrance doing it now. */ @@ -9648,6 +9649,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) g_clear_object (&priv->con_ip6_config); g_clear_object (&priv->ac_ip6_config); g_clear_object (&priv->ext_ip6_config); + g_clear_object (&priv->ext_ip6_config_captured); g_clear_object (&priv->wwan_ip6_config); g_clear_object (&priv->ip6_config); From 9ff161b2a1b0d4a63f91d326050ae1b8906b7b1b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 30 Jan 2016 22:28:23 +0100 Subject: [PATCH 3/4] device: move have_ip6_address() to nm_ip6_config_get_address_first_nontentative() --- src/devices/nm-device.c | 30 ++++-------------------------- src/nm-ip6-config.c | 23 +++++++++++++++++++++++ src/nm-ip6-config.h | 2 +- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 720fbe2f28..2a5ae8ad00 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -405,7 +405,6 @@ static void nm_device_slave_notify_enslave (NMDevice *self, gboolean success); static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason); static gboolean addrconf6_start_with_link_ready (NMDevice *self); -static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection); static NMActStageReturn linklocal6_start (NMDevice *self); static void _carrier_wait_check_queued_act_request (NMDevice *self); @@ -5397,27 +5396,6 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release) /******************************************/ -static gboolean -have_ip6_address (const NMIP6Config *ip6_config, gboolean linklocal) -{ - guint i; - - if (!ip6_config) - return FALSE; - - linklocal = !!linklocal; - - for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) { - const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ip6_config, i); - - if ((IN6_IS_ADDR_LINKLOCAL (&addr->address) == linklocal) && - !(addr->flags & IFA_F_TENTATIVE)) - return TRUE; - } - - return FALSE; -} - static void linklocal6_cleanup (NMDevice *self) { @@ -5451,7 +5429,7 @@ linklocal6_complete (NMDevice *self) const char *method; g_assert (priv->linklocal6_timeout_id); - g_assert (have_ip6_address (priv->ip6_config, TRUE)); + g_assert (nm_ip6_config_get_address_first_nontentative (priv->ip6_config, TRUE)); linklocal6_cleanup (self); @@ -5568,7 +5546,7 @@ linklocal6_start (NMDevice *self) linklocal6_cleanup (self); - if (have_ip6_address (priv->ip6_config, TRUE)) + if (nm_ip6_config_get_address_first_nontentative (priv->ip6_config, TRUE)) return NM_ACT_STAGE_RETURN_FINISH; connection = nm_device_get_applied_connection (self); @@ -5803,7 +5781,7 @@ rdisc_ra_timeout (NMRDisc *rdisc, NMDevice *self) * IPv6 configuration, like manual IPv6 addresses or external IPv6 * config, consider that sufficient for IPv6 success. */ - if (have_ip6_address (priv->ip6_config, FALSE)) + if (nm_ip6_config_get_address_first_nontentative (priv->ip6_config, FALSE)) nm_device_activate_schedule_ip6_config_result (self); else nm_device_activate_schedule_ip6_config_timeout (self); @@ -8735,7 +8713,7 @@ update_ip6_config (NMDevice *self, gboolean initial) if ( priv->linklocal6_timeout_id && priv->ext_ip6_config_captured - && have_ip6_address (priv->ext_ip6_config_captured, TRUE)) { + && nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)) { /* linklocal6 is ready now, do the state transition... we are also * invoked as g_idle_add, so no problems with reentrance doing it now. */ diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 8a70ab663c..b6f534c36e 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -1362,6 +1362,29 @@ nm_ip6_config_address_exists (const NMIP6Config *config, return _addresses_get_index (config, needle) >= 0; } +const NMPlatformIP6Address * +nm_ip6_config_get_address_first_nontentative (const NMIP6Config *config, gboolean linklocal) +{ + NMIP6ConfigPrivate *priv; + guint i; + + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + linklocal = !!linklocal; + + for (i = 0; i < priv->addresses->len; i++) { + const NMPlatformIP6Address *addr = &g_array_index (priv->addresses, NMPlatformIP6Address, i); + + if ( ((!!IN6_IS_ADDR_LINKLOCAL (&addr->address)) == linklocal) + && !(addr->flags & IFA_F_TENTATIVE)) + return addr; + } + + return NULL; +} + /******************************************************************/ void diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 759e7790ea..5ca64ac372 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -97,10 +97,10 @@ void nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address void nm_ip6_config_del_address (NMIP6Config *config, guint i); guint nm_ip6_config_get_num_addresses (const NMIP6Config *config); const NMPlatformIP6Address *nm_ip6_config_get_address (const NMIP6Config *config, guint i); +const NMPlatformIP6Address *nm_ip6_config_get_address_first_nontentative (const NMIP6Config *config, gboolean linklocal); gboolean nm_ip6_config_address_exists (const NMIP6Config *config, const NMPlatformIP6Address *address); gboolean nm_ip6_config_addresses_sort (NMIP6Config *config, NMSettingIP6ConfigPrivacy use_temporary); - /* Routes */ void nm_ip6_config_reset_routes (NMIP6Config *config); void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *route); From 118a75fcde0ce0ee80d07fa6570f55e2e780895c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 30 Jan 2016 22:31:37 +0100 Subject: [PATCH 4/4] device: check ext_ip6_config_captured for ll_addr in dhcp6_start_with_link_ready() We should not check ip6_config for the link local address because ip6_config contains the merged settings we want to configure, not the addresses that are actually configured on the device. Check ext_ip6_config_captured for that. Also, reuse nm_ip6_config_get_address_first_nontentative() which only takes an address after it survived DAD. --- src/devices/nm-device.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 2a5ae8ad00..712c9d90e6 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5284,9 +5284,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) GByteArray *tmp = NULL; const guint8 *hw_addr; size_t hw_addr_len = 0; - const struct in6_addr *ll_addr = NULL; - NMIP6Config *ip6_config; - int i; + const NMPlatformIP6Address *ll_addr = NULL; g_assert (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); @@ -5298,22 +5296,16 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) g_byte_array_append (tmp, hw_addr, hw_addr_len); } - ip6_config = priv->ip6_config; - for (i = 0; ip6_config && i < nm_ip6_config_get_num_addresses (ip6_config); i++) { - const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ip6_config, i); + if (priv->ext_ip6_config_captured) + ll_addr = nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE); - if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { - ll_addr = &addr->address; - break; - } - } g_return_val_if_fail (ll_addr, FALSE); priv->dhcp6_client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), nm_device_get_ip_iface (self), nm_device_get_ip_ifindex (self), tmp, - ll_addr, + &ll_addr->address, nm_connection_get_uuid (connection), nm_device_get_ip6_route_metric (self), nm_setting_ip_config_get_dhcp_send_hostname (s_ip6),