wired: defer carrier-off events while connected by a few seconds

Don't immediately tear down an active wired connection when the carrier
flips to off, but wait a few seconds for it to come back before breaking
the user's network.
This commit is contained in:
Dan Williams 2009-09-28 14:12:09 -07:00
parent 4f6eef9e77
commit 963d055abf

View file

@ -110,6 +110,7 @@ typedef struct {
NMNetlinkMonitor * monitor;
gulong link_connected_id;
gulong link_disconnected_id;
guint carrier_action_defer_id;
Supplicant supplicant;
guint supplicant_timeout_id;
@ -174,7 +175,41 @@ nm_ethernet_error_get_type (void)
}
static void
set_carrier (NMDeviceEthernet *self, const gboolean carrier)
carrier_action_defer_clear (NMDeviceEthernet *self)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
if (priv->carrier_action_defer_id) {
g_source_remove (priv->carrier_action_defer_id);
priv->carrier_action_defer_id = 0;
}
}
static gboolean
carrier_action_defer_cb (gpointer user_data)
{
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
NMDeviceState state;
priv->carrier_action_defer_id = 0;
state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
if (state == NM_DEVICE_STATE_UNAVAILABLE) {
if (priv->carrier)
nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
if (!priv->carrier)
nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER);
}
return FALSE;
}
static void
set_carrier (NMDeviceEthernet *self,
const gboolean carrier,
const gboolean defer_action)
{
NMDeviceEthernetPrivate *priv;
NMDeviceState state;
@ -185,18 +220,23 @@ set_carrier (NMDeviceEthernet *self, const gboolean carrier)
if (priv->carrier == carrier)
return;
/* Clear any previous deferred action */
carrier_action_defer_clear (self);
priv->carrier = carrier;
g_object_notify (G_OBJECT (self), NM_DEVICE_ETHERNET_CARRIER);
state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
nm_info ("(%s): carrier now %s (device state %d)", nm_device_get_iface (NM_DEVICE (self)), carrier ? "ON" : "OFF", state);
if (state == NM_DEVICE_STATE_UNAVAILABLE) {
if (carrier)
nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
if (!carrier)
nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER);
}
nm_info ("(%s): carrier now %s (device state %d%s)",
nm_device_get_iface (NM_DEVICE (self)),
carrier ? "ON" : "OFF",
state,
defer_action ? ", deferring action for 4 seconds" : "");
if (defer_action)
priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self);
else
carrier_action_defer_cb (self);
}
static void
@ -216,7 +256,7 @@ carrier_on (NMNetlinkMonitor *monitor,
if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
return;
set_carrier (NM_DEVICE_ETHERNET (device), TRUE);
set_carrier (self, TRUE, FALSE);
}
}
@ -232,12 +272,23 @@ carrier_off (NMNetlinkMonitor *monitor,
/* Make sure signal is for us */
if (idx == priv->ifindex) {
NMDeviceState state;
gboolean defer = FALSE;
/* Ignore spurious netlink messages */
caps = nm_device_get_capabilities (device);
if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
return;
set_carrier (NM_DEVICE_ETHERNET (device), FALSE);
/* Defer carrier-off event actions while connected by a few seconds
* so that tripping over a cable, power-cycling a switch, or breaking
* off the RJ45 locking tab isn't so catastrophic.
*/
state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
if (state > NM_DEVICE_STATE_DISCONNECTED)
defer = TRUE;
set_carrier (self, FALSE, defer);
}
}
@ -287,6 +338,10 @@ constructor (GType type,
} else
priv->carrier = !!(ifflags & IFF_LOWER_UP);
nm_info ("(%s): carrier is %s",
nm_device_get_iface (NM_DEVICE (self)),
priv->carrier ? "ON" : "OFF");
/* Request link state again just in case an error occurred getting the
* initial link state.
*/
@ -1675,6 +1730,8 @@ dispose (GObject *object)
priv->link_disconnected_id = 0;
}
carrier_action_defer_clear (self);
if (priv->monitor) {
g_object_unref (priv->monitor);
priv->monitor = NULL;