summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-08-13 09:40:08 -0500
committerDan Williams <dcbw@redhat.com>2014-08-29 16:03:36 -0500
commit7c9d4e8f5a0f4d64ae0ec218928ca2641ae7e9c9 (patch)
tree38d2be09e2c0582208e9ecadffc2092e52b27081
parentbc18992dd8fbbc1ce5e0c3ca6a6e13b62ae93d91 (diff)
downloadNetworkManager-7c9d4e8f5a0f4d64ae0ec218928ca2641ae7e9c9.tar.gz
rdisc: add RA wait timeout
Add an advisory timeout when waiting for router advertisements so we can fail IPv6 addressing attempts when no router advertisement has been received.
-rw-r--r--src/devices/nm-device.c46
-rw-r--r--src/rdisc/nm-lndp-rdisc.c84
-rw-r--r--src/rdisc/nm-rdisc.c9
-rw-r--r--src/rdisc/nm-rdisc.h2
4 files changed, 111 insertions, 30 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 265cf938e2..7edd2a7310 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -270,7 +270,8 @@ typedef struct {
NMIP6Config * ext_ip6_config; /* Stuff added outside NM */
NMRDisc * rdisc;
- gulong rdisc_config_changed_sigid;
+ gulong rdisc_changed_id;
+ gulong rdisc_timeout_id;
NMSettingIP6ConfigPrivacy rdisc_use_tempaddr;
/* IP6 config from autoconf */
NMIP6Config * ac_ip6_config;
@@ -3591,6 +3592,21 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self)
nm_device_activate_schedule_ip6_config_result (self);
}
+static void
+rdisc_ra_timeout (NMRDisc *rdisc, NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ /* We don't want to stop listening for router advertisements completely,
+ * but instead let device activation continue activating. If an RA
+ * shows up later, we'll use it as long as the device is not disconnected.
+ */
+
+ _LOGD (LOGD_IP6, "timed out waiting for IPv6 router advertisement");
+ if (priv->ip6_state == IP_CONF)
+ nm_device_activate_schedule_ip6_config_timeout (self);
+}
+
static gboolean
addrconf6_start_with_link_ready (NMDevice *self)
{
@@ -3610,8 +3626,14 @@ addrconf6_start_with_link_ready (NMDevice *self)
nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0");
nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0");
- priv->rdisc_config_changed_sigid = g_signal_connect (priv->rdisc, NM_RDISC_CONFIG_CHANGED,
- G_CALLBACK (rdisc_config_changed), self);
+ priv->rdisc_changed_id = g_signal_connect (priv->rdisc,
+ NM_RDISC_CONFIG_CHANGED,
+ G_CALLBACK (rdisc_config_changed),
+ self);
+ priv->rdisc_timeout_id = g_signal_connect (priv->rdisc,
+ NM_RDISC_RA_TIMEOUT,
+ G_CALLBACK (rdisc_ra_timeout),
+ self);
nm_rdisc_start (priv->rdisc);
return TRUE;
}
@@ -3662,10 +3684,14 @@ addrconf6_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- if (priv->rdisc_config_changed_sigid) {
- g_signal_handler_disconnect (priv->rdisc,
- priv->rdisc_config_changed_sigid);
- priv->rdisc_config_changed_sigid = 0;
+ if (priv->rdisc_changed_id) {
+ g_signal_handler_disconnect (priv->rdisc, priv->rdisc_changed_id);
+ priv->rdisc_changed_id = 0;
+ }
+
+ if (priv->rdisc_timeout_id) {
+ g_signal_handler_disconnect (priv->rdisc, priv->rdisc_timeout_id);
+ priv->rdisc_timeout_id = 0;
}
nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE);
@@ -4647,6 +4673,12 @@ nm_device_activate_schedule_ip6_config_result (NMDevice *self)
g_return_if_fail (NM_IS_DEVICE (self));
+ /* If IP had previously failed, move it back to IP_CONF since we
+ * clearly now have configuration.
+ */
+ if (priv->ip6_state == IP_FAIL)
+ priv->ip6_state = IP_CONF;
+
activation_source_schedule (self, nm_device_activate_ip6_config_commit, AF_INET6);
_LOG (level, LOGD_DEVICE | LOGD_IP6,
diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c
index 87934e65a8..1ec8921ee9 100644
--- a/src/rdisc/nm-lndp-rdisc.c
+++ b/src/rdisc/nm-lndp-rdisc.c
@@ -40,7 +40,8 @@ typedef struct {
guint send_rs_id;
GIOChannel *event_channel;
guint event_id;
- guint timeout_id;
+ guint timeout_id; /* prefix/dns/etc lifetime timeout */
+ guint ra_timeout_id; /* first RA timeout */
int solicitations_left;
} NMLNDPRDiscPrivate;
@@ -433,11 +434,32 @@ translate_preference (enum ndp_route_preference preference)
}
}
+static void
+clear_rs_timeout (NMLNDPRDisc *rdisc)
+{
+ NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
+
+ if (priv->send_rs_id) {
+ g_source_remove (priv->send_rs_id);
+ priv->send_rs_id = 0;
+ }
+}
+
+static void
+clear_ra_timeout (NMLNDPRDisc *rdisc)
+{
+ NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
+
+ if (priv->ra_timeout_id) {
+ g_source_remove (priv->ra_timeout_id);
+ priv->ra_timeout_id = 0;
+ }
+}
+
static int
receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
{
NMRDisc *rdisc = (NMRDisc *) user_data;
- NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
NMRDiscConfigMap changed = 0;
struct ndp_msgra *msgra = ndp_msgra (msg);
NMRDiscGateway gateway;
@@ -458,10 +480,8 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
*/
debug ("(%s): received router advertisement at %u", rdisc->ifname, now);
- if (priv->send_rs_id) {
- g_source_remove (priv->send_rs_id);
- priv->send_rs_id = 0;
- }
+ clear_ra_timeout (NM_LNDP_RDISC (rdisc));
+ clear_rs_timeout (NM_LNDP_RDISC (rdisc));
/* DHCP level:
*
@@ -606,21 +626,25 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
return 0;
}
-static void
-process_events (NMRDisc *rdisc)
+static gboolean
+event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc)
{
NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
debug ("(%s): processing libndp events.", rdisc->ifname);
ndp_callall_eventfd_handler (priv->ndp);
+ return G_SOURCE_CONTINUE;
}
static gboolean
-event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc)
+rdisc_ra_timeout_cb (gpointer user_data)
{
- process_events (rdisc);
+ NMLNDPRDisc *rdisc = NM_LNDP_RDISC (user_data);
+ NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
- return TRUE;
+ priv->ra_timeout_id = 0;
+ g_signal_emit_by_name (rdisc, NM_RDISC_RA_TIMEOUT);
+ return G_SOURCE_REMOVE;
}
static void
@@ -628,14 +652,20 @@ start (NMRDisc *rdisc)
{
NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
int fd = ndp_get_eventfd (priv->ndp);
+ guint ra_wait_secs;
priv->event_channel = g_io_channel_unix_new (fd);
priv->event_id = g_io_add_watch (priv->event_channel, G_IO_IN, (GIOFunc) event_ready, rdisc);
+ clear_ra_timeout (NM_LNDP_RDISC (rdisc));
+ ra_wait_secs = CLAMP (rdisc->rtr_solicitations * rdisc->rtr_solicitation_interval, 30, 120);
+ priv->ra_timeout_id = g_timeout_add_seconds (ra_wait_secs, rdisc_ra_timeout_cb, rdisc);
+ debug ("(%s): scheduling RA timeout in %d seconds", rdisc->ifname, ra_wait_secs);
+
/* Flush any pending messages to avoid using obsolete information */
- process_events (rdisc);
+ event_ready (priv->event_channel, 0, rdisc);
- ndp_msgrcv_handler_register (priv->ndp, &receive_ra, NDP_MSG_RA, rdisc->ifindex, rdisc);
+ ndp_msgrcv_handler_register (priv->ndp, receive_ra, NDP_MSG_RA, rdisc->ifindex, rdisc);
solicit (rdisc);
}
@@ -647,21 +677,29 @@ nm_lndp_rdisc_init (NMLNDPRDisc *lndp_rdisc)
}
static void
-nm_lndp_rdisc_finalize (GObject *object)
+dispose (GObject *object)
{
- NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (object);
+ NMLNDPRDisc *rdisc = NM_LNDP_RDISC (object);
+ NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
- if (priv->send_rs_id)
- g_source_remove (priv->send_rs_id);
- if (priv->timeout_id)
+ clear_rs_timeout (rdisc);
+ clear_ra_timeout (rdisc);
+
+ if (priv->timeout_id) {
g_source_remove (priv->timeout_id);
- if (priv->event_channel)
- g_io_channel_unref (priv->event_channel);
- if (priv->event_id)
+ priv->timeout_id = 0;
+ }
+
+ if (priv->event_id) {
g_source_remove (priv->event_id);
+ priv->event_id = 0;
+ }
+ g_clear_pointer (&priv->event_channel, g_io_channel_unref);
- if (priv->ndp)
+ if (priv->ndp) {
ndp_close (priv->ndp);
+ priv->ndp = NULL;
+ }
}
static void
@@ -672,6 +710,6 @@ nm_lndp_rdisc_class_init (NMLNDPRDiscClass *klass)
g_type_class_add_private (klass, sizeof (NMLNDPRDiscPrivate));
- object_class->finalize = nm_lndp_rdisc_finalize;
+ object_class->dispose = dispose;
rdisc_class->start = start;
}
diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c
index d3dc14a194..a326e6f03f 100644
--- a/src/rdisc/nm-rdisc.c
+++ b/src/rdisc/nm-rdisc.c
@@ -32,6 +32,7 @@ G_DEFINE_TYPE (NMRDisc, nm_rdisc, G_TYPE_OBJECT)
enum {
CONFIG_CHANGED,
+ RA_TIMEOUT,
LAST_SIGNAL
};
@@ -184,4 +185,12 @@ nm_rdisc_class_init (NMRDiscClass *klass)
G_STRUCT_OFFSET (NMRDiscClass, config_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_INT);
+
+ signals[RA_TIMEOUT] = g_signal_new (
+ NM_RDISC_RA_TIMEOUT,
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMRDiscClass, ra_timeout),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
}
diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h
index 35db3c917f..f4ebc228a9 100644
--- a/src/rdisc/nm-rdisc.h
+++ b/src/rdisc/nm-rdisc.h
@@ -36,6 +36,7 @@
#define NM_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_RDISC, NMRDiscClass))
#define NM_RDISC_CONFIG_CHANGED "config-changed"
+#define NM_RDISC_RA_TIMEOUT "ra-timeout"
typedef enum {
NM_RDISC_DHCP_LEVEL_UNKNOWN,
@@ -131,6 +132,7 @@ typedef struct {
void (*start) (NMRDisc *rdisc);
void (*config_changed) (NMRDisc *rdisc, NMRDiscConfigMap changed);
+ void (*ra_timeout) (NMRDisc *rdisc);
} NMRDiscClass;
GType nm_rdisc_get_type (void);