diff options
author | Dan Williams <dcbw@redhat.com> | 2014-11-14 16:04:44 -0600 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2014-11-17 09:52:12 -0600 |
commit | d1295b12e9f802867edef57ee02c87495df1683e (patch) | |
tree | 46996a812d6c3050fe3a5e94bfe8a9a5ba813018 | |
parent | 45bfb653f35584aa50a2a1575aa64953c33cd48b (diff) | |
download | NetworkManager-d1295b12e9f802867edef57ee02c87495df1683e.tar.gz |
dhcp: wait for an IPv6LL address before starting DHCPv6 (bgo #740147)
For ipv6.method=dhcp NM was not waiting for an IPv6LL address, which
caused the DHCP client to exit early because it had no local address
to bind to.
https://bugzilla.gnome.org/show_bug.cgi?id=740147
-rw-r--r-- | src/devices/nm-device.c | 128 |
1 files changed, 66 insertions, 62 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 43c36b8e5d..59fc4bb03b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -327,6 +327,8 @@ 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 gboolean nm_device_get_default_unmanaged (NMDevice *self); @@ -3279,14 +3281,14 @@ dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release) priv->dhcp6_state_sigid = 0; } - nm_device_remove_pending_action (self, PENDING_ACTION_DHCP6, FALSE); - if (stop) nm_dhcp_client_stop (priv->dhcp6_client, release); g_clear_object (&priv->dhcp6_client); } + nm_device_remove_pending_action (self, PENDING_ACTION_DHCP6, FALSE); + if (priv->dhcp6_config) { g_clear_object (&priv->dhcp6_config); g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG); @@ -3528,38 +3530,19 @@ dhcp6_state_changed (NMDhcpClient *client, } } -static NMActStageReturn -dhcp6_start (NMDevice *self, - NMConnection *connection, - guint32 dhcp_opt, - NMDeviceStateReason *reason) +static gboolean +dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) { - NMSettingIPConfig *s_ip6; NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + NMSettingIPConfig *s_ip6; GByteArray *tmp = NULL; const guint8 *hw_addr; size_t hw_addr_len = 0; - if (!connection) { - connection = nm_device_get_connection (self); - g_assert (connection); - } - + g_assert (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - /* Clear old exported DHCP options */ - if (priv->dhcp6_config) - g_object_unref (priv->dhcp6_config); - priv->dhcp6_config = nm_dhcp6_config_new (); - - g_warn_if_fail (priv->dhcp6_ip6_config == NULL); - if (priv->dhcp6_ip6_config) { - g_object_unref (priv->dhcp6_ip6_config); - priv->dhcp6_ip6_config = NULL; - } - hw_addr = nm_platform_link_get_address (nm_device_get_ip_ifindex (self), &hw_addr_len); if (hw_addr_len) { tmp = g_byte_array_sized_new (hw_addr_len); @@ -3576,7 +3559,7 @@ dhcp6_start (NMDevice *self, nm_setting_ip_config_get_dhcp_hostname (s_ip6), priv->dhcp_timeout, priv->dhcp_anycast_address, - (dhcp_opt == NM_RDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, + (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6))); if (tmp) g_byte_array_free (tmp, TRUE); @@ -3586,29 +3569,57 @@ dhcp6_start (NMDevice *self, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (dhcp6_state_changed), self); + } - s_ip6 = nm_connection_get_setting_ip6_config (connection); - if (!nm_setting_ip_config_get_may_fail (s_ip6) || - !strcmp (nm_setting_ip_config_get_method (s_ip6), NM_SETTING_IP6_CONFIG_METHOD_DHCP)) - nm_device_add_pending_action (self, PENDING_ACTION_DHCP6, TRUE); + return !!priv->dhcp6_client; +} - /* DHCP devices will be notified by the DHCP manager when stuff happens */ - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { +static gboolean +dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *connection; + NMSettingIPConfig *s_ip6; + + g_clear_object (&priv->dhcp6_config); + priv->dhcp6_config = nm_dhcp6_config_new (); + + g_warn_if_fail (priv->dhcp6_ip6_config == NULL); + g_clear_object (&priv->dhcp6_ip6_config); + + connection = nm_device_get_connection (self); + g_assert (connection); + s_ip6 = nm_connection_get_setting_ip6_config (connection); + if (!nm_setting_ip_config_get_may_fail (s_ip6) || + !strcmp (nm_setting_ip_config_get_method (s_ip6), NM_SETTING_IP6_CONFIG_METHOD_DHCP)) + nm_device_add_pending_action (self, PENDING_ACTION_DHCP6, TRUE); + + if (wait_for_ll) { + NMActStageReturn ret; + + /* ensure link local is ready... */ + ret = linklocal6_start (self); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + /* success; wait for the LL address to show up */ + return TRUE; + } + + /* success; already have the LL address; kick off DHCP */ + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + } + + if (!dhcp6_start_with_link_ready (self, connection)) { *reason = NM_DEVICE_STATE_REASON_DHCP_START_FAILED; - ret = NM_ACT_STAGE_RETURN_FAILURE; + return FALSE; } - return ret; + return TRUE; } gboolean nm_device_dhcp6_renew (NMDevice *self, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActStageReturn ret; - NMDeviceStateReason reason; - NMConnection *connection; g_return_val_if_fail (priv->dhcp6_client != NULL, FALSE); @@ -3617,13 +3628,8 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release) /* Terminate old DHCP instance and release the old lease */ dhcp6_cleanup (self, TRUE, release); - connection = nm_device_get_connection (self); - g_assert (connection); - /* Start DHCP again on the interface */ - ret = dhcp6_start (self, connection, priv->dhcp6_mode, &reason); - - return (ret != NM_ACT_STAGE_RETURN_FAILURE); + return dhcp6_start (self, FALSE, NULL); } /******************************************/ @@ -3695,6 +3701,11 @@ linklocal6_complete (NMDevice *self) /* Time out IPv6 instead of failing the entire activation */ nm_device_activate_schedule_ip6_config_timeout (self); } + } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { + if (!dhcp6_start_with_link_ready (self, connection)) { + /* Time out IPv6 instead of failing the entire activation */ + nm_device_activate_schedule_ip6_config_timeout (self); + } } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) nm_device_activate_schedule_ip6_config_result (self); else @@ -3825,9 +3836,7 @@ static void rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; int i; - NMDeviceStateReason reason; static int system_support = -1; guint ifa_flags = 0x00; @@ -3853,8 +3862,6 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) } g_return_if_fail (priv->act_request); - connection = nm_device_get_connection (self); - g_assert (connection); if (!priv->ac_ip6_config) priv->ac_ip6_config = nm_ip6_config_new (); @@ -3948,24 +3955,17 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) dhcp6_cleanup (self, TRUE, TRUE); priv->dhcp6_mode = rdisc->dhcp_level; + if (priv->dhcp6_mode != NM_RDISC_DHCP_LEVEL_NONE) { + NMDeviceStateReason reason; - switch (priv->dhcp6_mode) { - case NM_RDISC_DHCP_LEVEL_NONE: - break; - default: _LOGI (LOGD_DEVICE | LOGD_DHCP6, "Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6" " as requested by IPv6 router..."); - switch (dhcp6_start (self, connection, priv->dhcp6_mode, &reason)) { - case NM_ACT_STAGE_RETURN_SUCCESS: - g_warn_if_reached (); - break; - case NM_ACT_STAGE_RETURN_POSTPONE: - return; - default: - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); - return; + if (!dhcp6_start (self, FALSE, &reason)) { + if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED) + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); } + return; } } @@ -4353,7 +4353,11 @@ act_stage3_ip6_config_start (NMDevice *self, } } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_MANAGED; - ret = dhcp6_start (self, connection, priv->dhcp6_mode, reason); + if (!dhcp6_start (self, TRUE, reason)) { + /* IPv6 might be disabled; allow IPv4 to proceed */ + ret = NM_ACT_STAGE_RETURN_STOP; + } else + ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) == 0) { /* New blank config */ *out_config = nm_ip6_config_new (); |