summaryrefslogtreecommitdiff
path: root/src/rdisc/nm-lndp-rdisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rdisc/nm-lndp-rdisc.c')
-rw-r--r--src/rdisc/nm-lndp-rdisc.c84
1 files changed, 61 insertions, 23 deletions
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;
}