From 5fad262b9f78786a214a2bdc464c90ad4e65138b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 9 Dec 2013 09:33:13 +0100 Subject: [PATCH] ethernet: add reconnect delay for PPPoE connections (rh #1023503) Attempting an immediate reconnect if the peer terminates the connection sometimes results in the peer not being ready to negotiate a new connection, while a short delay allows the peer to correctly tear down the old connection and get listen for a new one. Introduce a short delay when activating a PPPoE connection if a PPPoE connection was recently deactivated. https://bugzilla.redhat.com/show_bug.cgi?id=1023503 https://bugzilla.redhat.com/show_bug.cgi?id=602265 Rebased to master by jklimes. --- src/devices/nm-device-ethernet.c | 67 +++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 062134b54a..c3dcd7614d 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2012 Red Hat, Inc. + * Copyright (C) 2005 - 2013 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -66,8 +66,12 @@ G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE) #define WIRED_SECRETS_TRIES "wired-secrets-tries" +#define PPPOE_RECONNECT_DELAY 7 + #define NM_ETHERNET_ERROR (nm_ethernet_error_quark ()) +static NMSetting *device_get_setting (NMDevice *device, GType setting_type); + typedef struct Supplicant { NMSupplicantManager *mgr; NMSupplicantInterface *iface; @@ -99,6 +103,8 @@ typedef struct { /* PPPoE */ NMPPPManager *ppp_manager; NMIP4Config *pending_ip4_config; + time_t last_pppoe_time; + guint pppoe_wait_id; } NMDeviceEthernetPrivate; enum { @@ -272,15 +278,10 @@ device_state_changed (NMDevice *device, NMDeviceState old_state, NMDeviceStateReason reason) { - switch (new_state) { - case NM_DEVICE_STATE_ACTIVATED: - case NM_DEVICE_STATE_FAILED: - case NM_DEVICE_STATE_DISCONNECTED: + if ( new_state == NM_DEVICE_STATE_ACTIVATED + || new_state == NM_DEVICE_STATE_FAILED + || new_state == NM_DEVICE_STATE_DISCONNECTED) clear_secrets_tries (device); - break; - default: - break; - } } static void @@ -891,10 +892,24 @@ supplicant_interface_init (NMDeviceEthernet *self) return TRUE; } +static gboolean +pppoe_reconnect_delay (gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); + + priv->pppoe_wait_id = 0; + nm_log_info (LOGD_DEVICE, "(%s) PPPoE reconnect delay complete, resuming connection...", + nm_device_get_iface (device)); + nm_device_activate_schedule_stage2_device_config (device); + return FALSE; +} + static NMActStageReturn act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMActRequest *req; NMSettingWired *s_wired; const GByteArray *cloned_mac; @@ -914,6 +929,26 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) if (cloned_mac && (cloned_mac->len == ETH_ALEN)) nm_device_set_hw_addr (dev, cloned_mac->data, "set", LOGD_ETHER); } + + /* If we're re-activating a PPPoE connection a short while after + * a previous PPPoE connection was torn down, wait a bit to allow the + * remote side to handle the disconnection. Otherwise the peer may + * get confused and fail to negotiate the new connection. (rh #1023503) + */ + if (priv->last_pppoe_time) { + time_t delay = time (NULL) - priv->last_pppoe_time; + + if (delay < PPPOE_RECONNECT_DELAY && device_get_setting (dev, NM_TYPE_SETTING_PPPOE)) { + nm_log_info (LOGD_DEVICE, "(%s) delaying PPPoE reconnect to ensure peer is ready...", + nm_device_get_iface (dev)); + g_assert (!priv->pppoe_wait_id); + priv->pppoe_wait_id = g_timeout_add_seconds (delay, + pppoe_reconnect_delay, + self); + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else + priv->last_pppoe_time = 0; + } } return ret; @@ -1141,6 +1176,11 @@ deactivate (NMDevice *device) /* Clear wired secrets tries when deactivating */ clear_secrets_tries (device); + if (priv->pppoe_wait_id) { + g_source_remove (priv->pppoe_wait_id); + priv->pppoe_wait_id = 0; + } + if (priv->pending_ip4_config) { g_object_unref (priv->pending_ip4_config); priv->pending_ip4_config = NULL; @@ -1164,6 +1204,10 @@ deactivate (NMDevice *device) } } + /* Set last PPPoE connection time */ + if (device_get_setting (device, NM_TYPE_SETTING_PPPOE)) + NM_DEVICE_ETHERNET_GET_PRIVATE (device)->last_pppoe_time = time (NULL); + /* Reset MAC address back to initial address */ nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_ETHER); } @@ -1347,6 +1391,11 @@ dispose (GObject *object) g_free (priv->subchan3); g_free (priv->subchannels); + if (priv->pppoe_wait_id) { + g_source_remove (priv->pppoe_wait_id); + priv->pppoe_wait_id = 0; + } + G_OBJECT_CLASS (nm_device_ethernet_parent_class)->dispose (object); }