diff options
| author | Michael Biebl <biebl@debian.org> | 2015-05-05 17:48:57 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2015-05-05 17:48:57 +0200 |
| commit | f408e27bccfacf347605a8d98649975a68f38a17 (patch) | |
| tree | 654fd6695c31511baf919b1c0870d119a352ed75 /src/rdisc/nm-lndp-rdisc.c | |
| parent | 2c032d8f1c6292c1338a615e6ec40252889ba85c (diff) | |
Imported Upstream version 1.0.2 upstream/1.0.2
Diffstat (limited to 'src/rdisc/nm-lndp-rdisc.c')
| -rw-r--r-- | src/rdisc/nm-lndp-rdisc.c | 468 |
1 files changed, 50 insertions, 418 deletions
diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c index ff1bd33d..cadbfdfa 100644 --- a/src/rdisc/nm-lndp-rdisc.c +++ b/src/rdisc/nm-lndp-rdisc.c @@ -27,6 +27,7 @@ #include <ndp.h> #include "nm-lndp-rdisc.h" +#include "nm-rdisc-private.h" #include "NetworkManagerUtils.h" #include "nm-logging.h" @@ -39,13 +40,9 @@ typedef struct { struct ndp *ndp; - guint send_rs_id; GIOChannel *event_channel; guint event_id; - guint timeout_id; /* prefix/dns/etc lifetime timeout */ guint ra_timeout_id; /* first RA timeout */ - - int solicitations_left; } NMLNDPRDiscPrivate; #define NM_LNDP_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LNDP_RDISC, NMLNDPRDiscPrivate)) @@ -54,185 +51,6 @@ G_DEFINE_TYPE (NMLNDPRDisc, nm_lndp_rdisc, NM_TYPE_RDISC) /******************************************************************/ -static inline gint32 -ipv6_sysctl_get (const char *ifname, const char *property, gint32 defval) -{ - return nm_platform_sysctl_get_int32 (nm_utils_ip6_property_path (ifname, property), defval); -} - -NMRDisc * -nm_lndp_rdisc_new (int ifindex, const char *ifname) -{ - NMRDisc *rdisc; - NMLNDPRDiscPrivate *priv; - int error; - - rdisc = g_object_new (NM_TYPE_LNDP_RDISC, NULL); - - rdisc->ifindex = ifindex; - rdisc->ifname = g_strdup (ifname); - - rdisc->max_addresses = ipv6_sysctl_get (ifname, "max_addresses", - NM_RDISC_MAX_ADDRESSES_DEFAULT); - rdisc->rtr_solicitations = ipv6_sysctl_get (ifname, "router_solicitations", - NM_RDISC_RTR_SOLICITATIONS_DEFAULT); - rdisc->rtr_solicitation_interval = ipv6_sysctl_get (ifname, "router_solicitation_interval", - NM_RDISC_RTR_SOLICITATION_INTERVAL_DEFAULT); - - priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); - error = ndp_open (&priv->ndp); - if (error != 0) { - g_object_unref (rdisc); - debug ("(%s): error creating socket for NDP; errno=%d", ifname, -error); - return NULL; - } - return rdisc; -} - -static gboolean -add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new) -{ - int i; - - for (i = 0; i < rdisc->gateways->len; i++) { - NMRDiscGateway *item = &g_array_index (rdisc->gateways, NMRDiscGateway, i); - - if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { - if (item->preference != new->preference) { - g_array_remove_index (rdisc->gateways, i--); - continue; - } - memcpy (item, new, sizeof (*new)); - return FALSE; - } - - /* Put before less preferable gateways. */ - if (item->preference < new->preference) - break; - } - - g_array_insert_val (rdisc->gateways, i, *new); - return TRUE; -} - -static gboolean -add_address (NMRDisc *rdisc, const NMRDiscAddress *new) -{ - int i; - - for (i = 0; i < rdisc->addresses->len; i++) { - NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i); - - if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { - gboolean changed = item->timestamp + item->lifetime != new->timestamp + new->lifetime || - item->timestamp + item->preferred != new->timestamp + new->preferred; - - *item = *new; - return changed; - } - } - - /* we create at most max_addresses autoconf addresses. This is different from - * what the kernel does, because it considers *all* addresses (including - * static and other temporary addresses). - **/ - if (rdisc->max_addresses && rdisc->addresses->len >= rdisc->max_addresses) - return FALSE; - - g_array_insert_val (rdisc->addresses, i, *new); - return TRUE; -} - -static gboolean -add_route (NMRDisc *rdisc, const NMRDiscRoute *new) -{ - int i; - - for (i = 0; i < rdisc->routes->len; i++) { - NMRDiscRoute *item = &g_array_index (rdisc->routes, NMRDiscRoute, i); - - if (IN6_ARE_ADDR_EQUAL (&item->network, &new->network) && item->plen == new->plen) { - if (item->preference != new->preference) { - g_array_remove_index (rdisc->routes, i--); - continue; - } - memcpy (item, new, sizeof (*new)); - return FALSE; - } - - /* Put before less preferable routes. */ - if (item->preference < new->preference) - break; - } - - g_array_insert_val (rdisc->routes, i, *new); - return TRUE; -} - -static gboolean -add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new) -{ - int i; - - for (i = 0; i < rdisc->dns_servers->len; i++) { - NMRDiscDNSServer *item = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i); - - if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { - gboolean changed; - - if (new->lifetime == 0) { - g_array_remove_index (rdisc->dns_servers, i); - return TRUE; - } - - changed = (item->timestamp != new->timestamp || - item->lifetime != new->lifetime); - if (changed) { - item->timestamp = new->timestamp; - item->lifetime = new->lifetime; - } - return changed; - } - } - - g_array_insert_val (rdisc->dns_servers, i, *new); - return TRUE; -} - -/* Copies new->domain if 'new' is added to the dns_domains list */ -static gboolean -add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new) -{ - NMRDiscDNSDomain *item; - int i; - - for (i = 0; i < rdisc->dns_domains->len; i++) { - item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i); - - if (!g_strcmp0 (item->domain, new->domain)) { - gboolean changed; - - if (new->lifetime == 0) { - g_array_remove_index (rdisc->dns_domains, i); - return TRUE; - } - - changed = (item->timestamp != new->timestamp || - item->lifetime != new->lifetime); - if (changed) { - item->timestamp = new->timestamp; - item->lifetime = new->lifetime; - } - return changed; - } - } - - g_array_insert_val (rdisc->dns_domains, i, *new); - item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i); - item->domain = g_strdup (new->domain); - return TRUE; -} - static gboolean send_rs (NMRDisc *rdisc) { @@ -244,185 +62,12 @@ send_rs (NMRDisc *rdisc) g_assert (!error); ndp_msg_ifindex_set (msg, rdisc->ifindex); - debug ("(%s): sending router solicitation", rdisc->ifname); - error = ndp_msg_send (priv->ndp, msg); - if (error) - error ("(%s): cannot send router solicitation: %d.", rdisc->ifname, error); - else - priv->solicitations_left--; - ndp_msg_destroy (msg); - - if (priv->solicitations_left > 0) { - debug ("(%s): scheduling router solicitation retry in %d seconds.", - rdisc->ifname, rdisc->rtr_solicitation_interval); - priv->send_rs_id = g_timeout_add_seconds (rdisc->rtr_solicitation_interval, - (GSourceFunc) send_rs, rdisc); - } else { - debug ("(%s): did not receive a router advertisement after %d solicitations.", - rdisc->ifname, rdisc->rtr_solicitations); - priv->send_rs_id = 0; - } - - return G_SOURCE_REMOVE; -} - -static void -solicit (NMRDisc *rdisc) -{ - NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); - - if (!priv->send_rs_id) { - debug ("(%s): scheduling router solicitation.", rdisc->ifname); - priv->send_rs_id = g_idle_add ((GSourceFunc) send_rs, rdisc); - priv->solicitations_left = rdisc->rtr_solicitations; - } -} - -static void -clean_gateways (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) -{ - int i; - - for (i = 0; i < rdisc->gateways->len; i++) { - NMRDiscGateway *item = &g_array_index (rdisc->gateways, NMRDiscGateway, i); - guint64 expiry = (guint64) item->timestamp + item->lifetime; - - if (item->lifetime == G_MAXUINT32) - continue; - - if (now >= expiry) { - g_array_remove_index (rdisc->gateways, i--); - *changed |= NM_RDISC_CONFIG_GATEWAYS; - } else if (*nextevent > expiry) - *nextevent = expiry; - } -} - -static void -clean_addresses (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) -{ - int i; - - for (i = 0; i < rdisc->addresses->len; i++) { - NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i); - guint64 expiry = (guint64) item->timestamp + item->lifetime; - - if (item->lifetime == G_MAXUINT32) - continue; - - if (now >= expiry) { - g_array_remove_index (rdisc->addresses, i--); - *changed |= NM_RDISC_CONFIG_ADDRESSES; - } else if (*nextevent > expiry) - *nextevent = expiry; - } -} - -static void -clean_routes (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) -{ - int i; - - for (i = 0; i < rdisc->routes->len; i++) { - NMRDiscRoute *item = &g_array_index (rdisc->routes, NMRDiscRoute, i); - guint64 expiry = (guint64) item->timestamp + item->lifetime; - - if (item->lifetime == G_MAXUINT32) - continue; - - if (now >= expiry) { - g_array_remove_index (rdisc->routes, i--); - *changed |= NM_RDISC_CONFIG_ROUTES; - } else if (*nextevent > expiry) - *nextevent = expiry; - } -} - -static void -clean_dns_servers (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) -{ - int i; - - for (i = 0; i < rdisc->dns_servers->len; i++) { - NMRDiscDNSServer *item = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i); - guint64 expiry = (guint64) item->timestamp + item->lifetime; - guint64 refresh = (guint64) item->timestamp + item->lifetime / 2; - - if (item->lifetime == G_MAXUINT32) - continue; - - if (now >= expiry) { - g_array_remove_index (rdisc->dns_servers, i--); - *changed |= NM_RDISC_CONFIG_DNS_SERVERS; - } else if (now >= refresh) - solicit (rdisc); - else if (*nextevent > refresh) - *nextevent = refresh; - } -} - -static void -clean_dns_domains (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) -{ - int i; - - for (i = 0; i < rdisc->dns_domains->len; i++) { - NMRDiscDNSDomain *item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i); - guint64 expiry = (guint64) item->timestamp + item->lifetime; - guint64 refresh = (guint64) item->timestamp + item->lifetime / 2; - - if (item->lifetime == G_MAXUINT32) - continue; - - if (now >= expiry) { - g_free (item->domain); - g_array_remove_index (rdisc->dns_domains, i--); - *changed |= NM_RDISC_CONFIG_DNS_DOMAINS; - } else if (now >= refresh) - solicit (rdisc); - else if (*nextevent > refresh) - *nextevent = refresh; - } -} - -static gboolean timeout_cb (gpointer user_data); - -static void -check_timestamps (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) -{ - NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); - /* Use a magic date in the distant future (~68 years) */ - guint32 never = G_MAXINT32; - guint32 nextevent = never; - - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } - - clean_gateways (rdisc, now, &changed, &nextevent); - clean_addresses (rdisc, now, &changed, &nextevent); - clean_routes (rdisc, now, &changed, &nextevent); - clean_dns_servers (rdisc, now, &changed, &nextevent); - clean_dns_domains (rdisc, now, &changed, &nextevent); - - if (changed) - g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, changed); - - if (nextevent != never) { - g_return_if_fail (nextevent > now); - debug ("(%s): scheduling next now/lifetime check: %u seconds", - rdisc->ifname, nextevent - now); - priv->timeout_id = g_timeout_add_seconds (nextevent - now, timeout_cb, rdisc); + if (error) { + error ("(%s): cannot send router solicitation: %d.", rdisc->ifname, error); + return FALSE; } -} - -static gboolean -timeout_cb (gpointer user_data) -{ - check_timestamps (user_data, nm_utils_get_monotonic_timestamp_s (), 0); return TRUE; } @@ -442,28 +87,6 @@ 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) { @@ -488,9 +111,6 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) */ debug ("(%s): received router advertisement at %u", rdisc->ifname, now); - clear_ra_timeout (NM_LNDP_RDISC (rdisc)); - clear_rs_timeout (NM_LNDP_RDISC (rdisc)); - /* DHCP level: * * The problem with DHCP level is what to do if subsequent @@ -524,7 +144,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) gateway.timestamp = now; gateway.lifetime = ndp_msgra_router_lifetime (msgra); gateway.preference = translate_preference (ndp_msgra_route_preference (msgra)); - if (add_gateway (rdisc, &gateway)) + if (nm_rdisc_add_gateway (rdisc, &gateway)) changed |= NM_RDISC_CONFIG_GATEWAYS; /* Addresses & Routes */ @@ -539,7 +159,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) route.timestamp = now; if (ndp_msg_opt_prefix_flag_on_link (msg, offset)) { route.lifetime = ndp_msg_opt_prefix_valid_time (msg, offset); - if (add_route (rdisc, &route)) + if (nm_rdisc_add_route (rdisc, &route)) changed |= NM_RDISC_CONFIG_ROUTES; } @@ -557,7 +177,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) /* Add the Interface Identifier to the lower 64 bits */ nm_utils_ipv6_addr_set_interface_identfier (&address.address, rdisc->iid); - if (add_address (rdisc, &address)) + if (nm_rdisc_add_address (rdisc, &address)) changed |= NM_RDISC_CONFIG_ADDRESSES; } } @@ -573,7 +193,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) route.timestamp = now; route.lifetime = ndp_msg_opt_route_lifetime (msg, offset); route.preference = translate_preference (ndp_msg_opt_route_preference (msg, offset)); - if (add_route (rdisc, &route)) + if (nm_rdisc_add_route (rdisc, &route)) changed |= NM_RDISC_CONFIG_ROUTES; } @@ -596,7 +216,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) */ if (dns_server.lifetime && dns_server.lifetime < 7200) dns_server.lifetime = 7200; - if (add_dns_server (rdisc, &dns_server)) + if (nm_rdisc_add_dns_server (rdisc, &dns_server)) changed |= NM_RDISC_CONFIG_DNS_SERVERS; } } @@ -618,7 +238,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) */ if (dns_domain.lifetime && dns_domain.lifetime < 7200) dns_domain.lifetime = 7200; - if (add_dns_domain (rdisc, &dns_domain)) + if (nm_rdisc_add_dns_domain (rdisc, &dns_domain)) changed |= NM_RDISC_CONFIG_DNS_DOMAINS; } } @@ -644,8 +264,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) } } - check_timestamps (rdisc, now, changed); - + nm_rdisc_ra_received (rdisc, now, changed); return 0; } @@ -659,41 +278,58 @@ event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc) return G_SOURCE_CONTINUE; } -static gboolean -rdisc_ra_timeout_cb (gpointer user_data) -{ - NMLNDPRDisc *rdisc = NM_LNDP_RDISC (user_data); - NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); - - priv->ra_timeout_id = 0; - g_signal_emit_by_name (rdisc, NM_RDISC_RA_TIMEOUT); - return G_SOURCE_REMOVE; -} - static void 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 */ event_ready (priv->event_channel, 0, rdisc); ndp_msgrcv_handler_register (priv->ndp, receive_ra, NDP_MSG_RA, rdisc->ifindex, rdisc); - solicit (rdisc); } /******************************************************************/ +static inline gint32 +ipv6_sysctl_get (const char *ifname, const char *property, gint32 defval) +{ + return nm_platform_sysctl_get_int32 (nm_utils_ip6_property_path (ifname, property), defval); +} + +NMRDisc * +nm_lndp_rdisc_new (int ifindex, const char *ifname) +{ + NMRDisc *rdisc; + NMLNDPRDiscPrivate *priv; + int error; + + rdisc = g_object_new (NM_TYPE_LNDP_RDISC, NULL); + + rdisc->ifindex = ifindex; + rdisc->ifname = g_strdup (ifname); + + rdisc->max_addresses = ipv6_sysctl_get (ifname, "max_addresses", + NM_RDISC_MAX_ADDRESSES_DEFAULT); + rdisc->rtr_solicitations = ipv6_sysctl_get (ifname, "router_solicitations", + NM_RDISC_RTR_SOLICITATIONS_DEFAULT); + rdisc->rtr_solicitation_interval = ipv6_sysctl_get (ifname, "router_solicitation_interval", + NM_RDISC_RTR_SOLICITATION_INTERVAL_DEFAULT); + + priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); + error = ndp_open (&priv->ndp); + if (error != 0) { + g_object_unref (rdisc); + debug ("(%s): error creating socket for NDP; errno=%d", ifname, -error); + return NULL; + } + return rdisc; +} + static void nm_lndp_rdisc_init (NMLNDPRDisc *lndp_rdisc) { @@ -705,14 +341,6 @@ dispose (GObject *object) NMLNDPRDisc *rdisc = NM_LNDP_RDISC (object); NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); - clear_rs_timeout (rdisc); - clear_ra_timeout (rdisc); - - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } - if (priv->event_id) { g_source_remove (priv->event_id); priv->event_id = 0; @@ -720,9 +348,12 @@ dispose (GObject *object) g_clear_pointer (&priv->event_channel, g_io_channel_unref); if (priv->ndp) { + ndp_msgrcv_handler_unregister (priv->ndp, receive_ra, NDP_MSG_RA, NM_RDISC (rdisc)->ifindex, rdisc); ndp_close (priv->ndp); priv->ndp = NULL; } + + G_OBJECT_CLASS (nm_lndp_rdisc_parent_class)->dispose (object); } static void @@ -735,4 +366,5 @@ nm_lndp_rdisc_class_init (NMLNDPRDiscClass *klass) object_class->dispose = dispose; rdisc_class->start = start; + rdisc_class->send_rs = send_rs; } |