diff options
| author | Michael Biebl <biebl@debian.org> | 2016-01-20 16:26:51 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2016-01-20 16:26:51 +0100 |
| commit | 494f296a3baab08522617b24b1f126d8f9a17502 (patch) | |
| tree | c8ef32fb0dd1c4ff35a0b38e787abb58692de0cd /src/rdisc/nm-rdisc.c | |
| parent | 54f6333410ffd570e62717d9e77c5c987175e397 (diff) | |
Imported Upstream version 1.1.90 upstream/1.1.90
Diffstat (limited to 'src/rdisc/nm-rdisc.c')
| -rw-r--r-- | src/rdisc/nm-rdisc.c | 196 |
1 files changed, 135 insertions, 61 deletions
diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c index a73ab7d0..6133ae28 100644 --- a/src/rdisc/nm-rdisc.c +++ b/src/rdisc/nm-rdisc.c @@ -27,10 +27,12 @@ #include "nm-rdisc.h" #include "nm-rdisc-private.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-utils.h" -#define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__) +#include <nm-setting-ip6-config.h> + +#define _NMLOG_PREFIX_NAME "rdisc" typedef struct { int solicitations_left; @@ -38,6 +40,7 @@ typedef struct { gint64 last_rs; guint ra_timeout_id; /* first RA timeout */ guint timeout_id; /* prefix/dns/etc lifetime timeout */ + char *last_send_rs_error; } NMRDiscPrivate; #define NM_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_RDISC, NMRDiscPrivate)) @@ -87,11 +90,63 @@ nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new) return !!new->lifetime; } +/** + * complete_address: + * @rdisc: the #NMRDisc + * @addr: the #NMRDiscAddress + * + * Adds the host part to the address that has network part set. + * If the address already has a host part, add a different host part + * if possible (this is useful in case DAD failed). + * + * Can fail if a different address can not be generated (DAD failure + * for an EUI-64 address or DAD counter overflow). + * + * Returns: %TRUE if the address could be completed, %FALSE otherwise. + **/ +static gboolean +complete_address (NMRDisc *rdisc, NMRDiscAddress *addr) +{ + GError *error = NULL; + + if (rdisc->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { + if (!nm_utils_ipv6_addr_set_stable_privacy (&addr->address, + rdisc->ifname, + rdisc->uuid, + addr->dad_counter++, + &error)) { + _LOGW ("complete-address: failed to generate an stable-privacy address: %s", + error->message); + g_clear_error (&error); + return FALSE; + } + _LOGD ("complete-address: using an stable-privacy address"); + return TRUE; + } + + if (!rdisc->iid.id) { + _LOGW ("complete-address: can't generate an EUI-64 address: no interface identifier"); + return FALSE; + } + + if (addr->address.s6_addr32[2] == 0x0 && addr->address.s6_addr32[3] == 0x0) { + _LOGD ("complete-address: adding an EUI-64 address"); + nm_utils_ipv6_addr_set_interface_identfier (&addr->address, rdisc->iid); + return TRUE; + } + + _LOGW ("complete-address: can't generate a new EUI-64 address"); + return FALSE; +} + gboolean -nm_rdisc_add_address (NMRDisc *rdisc, const NMRDiscAddress *new) +nm_rdisc_complete_and_add_address (NMRDisc *rdisc, NMRDiscAddress *new) { int i; + if (!complete_address (rdisc, new)) + return FALSE; + for (i = 0; i < rdisc->addresses->len; i++) { NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i); @@ -219,28 +274,6 @@ nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new) /******************************************************************/ -static void -clear_ra_timeout (NMRDisc *rdisc) -{ - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - - if (priv->ra_timeout_id) { - g_source_remove (priv->ra_timeout_id); - priv->ra_timeout_id = 0; - } -} - -static void -clear_rs_timeout (NMRDisc *rdisc) -{ - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - - if (priv->send_rs_id) { - g_source_remove (priv->send_rs_id); - priv->send_rs_id = 0; - } -} - /** * nm_rdisc_set_iid: * @rdisc: the #NMRDisc @@ -255,7 +288,10 @@ clear_rs_timeout (NMRDisc *rdisc) * the old identifier are removed. The caller should ensure the addresses * will be reset by soliciting router advertisements. * - * Returns: %TRUE if the token was changed, %FALSE otherwise. + * In case the stable privacy addressing is used %FALSE is returned and + * addresses are left untouched. + * + * Returns: %TRUE if addresses need to be regenerated, %FALSE otherwise. **/ gboolean nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid) @@ -264,8 +300,12 @@ nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid) if (rdisc->iid.id != iid.id) { rdisc->iid = iid; + + if (rdisc->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) + return FALSE; + if (rdisc->addresses->len) { - debug ("(%s) IPv6 interface identifier changed, flushing addresses", rdisc->ifname); + _LOGD ("IPv6 interface identifier changed, flushing addresses"); g_array_remove_range (rdisc->addresses, 0, rdisc->addresses->len); g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, NM_RDISC_CONFIG_ADDRESSES); } @@ -280,21 +320,34 @@ send_rs (NMRDisc *rdisc) { NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc); NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); + GError *error = NULL; - debug ("(%s): sending router solicitation", rdisc->ifname); - - if (klass->send_rs (rdisc)) + if (klass->send_rs (rdisc, &error)) { + _LOGD ("router solicitation sent"); priv->solicitations_left--; + g_clear_pointer (&priv->last_send_rs_error, g_free); + } else { + gboolean different_message; + + different_message = g_strcmp0 (priv->last_send_rs_error, error->message) != 0; + _NMLOG (different_message ? LOGL_WARN : LOGL_DEBUG, + "failure sending router solicitation: %s", error->message); + if (different_message) { + g_clear_pointer (&priv->last_send_rs_error, g_free); + priv->last_send_rs_error = g_strdup (error->message); + } + g_clear_error (&error); + } priv->last_rs = nm_utils_get_monotonic_timestamp_s (); if (priv->solicitations_left > 0) { - debug ("(%s): scheduling router solicitation retry in %d seconds.", - rdisc->ifname, rdisc->rtr_solicitation_interval); + _LOGD ("scheduling router solicitation retry in %d seconds.", + 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); + _LOGD ("did not receive a router advertisement after %d solicitations.", + rdisc->rtr_solicitations); priv->send_rs_id = 0; } @@ -312,8 +365,8 @@ solicit (NMRDisc *rdisc) priv->solicitations_left = rdisc->rtr_solicitations; next = CLAMP (priv->last_rs + rdisc->rtr_solicitation_interval - now, 0, G_MAXINT32); - debug ("(%s): scheduling explicit router solicitation request in %" G_GINT64_FORMAT " seconds.", - rdisc->ifname, next); + _LOGD ("scheduling explicit router solicitation request in %" G_GINT64_FORMAT " seconds.", + next); priv->send_rs_id = g_timeout_add_seconds ((guint32) next, (GSourceFunc) send_rs, rdisc); } } @@ -337,12 +390,12 @@ nm_rdisc_start (NMRDisc *rdisc) g_assert (klass->start); - debug ("(%s): starting router discovery: %d", rdisc->ifname, rdisc->ifindex); + _LOGD ("starting router discovery: %d", rdisc->ifindex); - clear_ra_timeout (rdisc); + nm_clear_g_source (&priv->ra_timeout_id); 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); + _LOGD ("scheduling RA timeout in %d seconds", ra_wait_secs); if (klass->start) klass->start (rdisc); @@ -350,6 +403,28 @@ nm_rdisc_start (NMRDisc *rdisc) solicit (rdisc); } +void +nm_rdisc_dad_failed (NMRDisc *rdisc, struct in6_addr *address) +{ + int i; + gboolean changed = FALSE; + + for (i = 0; i < rdisc->addresses->len; i++) { + NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i); + + if (!IN6_ARE_ADDR_EQUAL (&item->address, address)) + continue; + + _LOGD ("DAD failed for discovered address %s", nm_utils_inet6_ntop (address, NULL)); + if (!complete_address (rdisc, item)) + g_array_remove_index (rdisc->addresses, i--); + changed = TRUE; + } + + if (changed) + g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, NM_RDISC_CONFIG_ADDRESSES); +} + #define CONFIG_MAP_MAX_STR 7 static void @@ -394,27 +469,27 @@ config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed) char changedstr[CONFIG_MAP_MAX_STR]; char addrstr[INET6_ADDRSTRLEN]; - if (nm_logging_enabled (LOGL_DEBUG, LOGD_IP6)) { + if (_LOGD_ENABLED ()) { config_map_to_string (changed, changedstr); - debug ("(%s): router discovery configuration changed [%s]:", rdisc->ifname, changedstr); - debug (" dhcp-level %s", dhcp_level_to_string (rdisc->dhcp_level)); + _LOGD ("router discovery configuration changed [%s]:", changedstr); + _LOGD (" dhcp-level %s", dhcp_level_to_string (rdisc->dhcp_level)); for (i = 0; i < rdisc->gateways->len; i++) { NMRDiscGateway *gateway = &g_array_index (rdisc->gateways, NMRDiscGateway, i); inet_ntop (AF_INET6, &gateway->address, addrstr, sizeof (addrstr)); - debug (" gateway %s pref %d exp %u", addrstr, gateway->preference, expiry (gateway)); + _LOGD (" gateway %s pref %d exp %u", addrstr, gateway->preference, expiry (gateway)); } for (i = 0; i < rdisc->addresses->len; i++) { NMRDiscAddress *address = &g_array_index (rdisc->addresses, NMRDiscAddress, i); inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr)); - debug (" address %s exp %u", addrstr, expiry (address)); + _LOGD (" address %s exp %u", addrstr, expiry (address)); } for (i = 0; i < rdisc->routes->len; i++) { NMRDiscRoute *route = &g_array_index (rdisc->routes, NMRDiscRoute, i); inet_ntop (AF_INET6, &route->network, addrstr, sizeof (addrstr)); - debug (" route %s/%d via %s pref %d exp %u", addrstr, route->plen, + _LOGD (" route %s/%d via %s pref %d exp %u", addrstr, route->plen, nm_utils_inet6_ntop (&route->gateway, NULL), route->preference, expiry (route)); } @@ -422,12 +497,12 @@ config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed) NMRDiscDNSServer *dns_server = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i); inet_ntop (AF_INET6, &dns_server->address, addrstr, sizeof (addrstr)); - debug (" dns_server %s exp %u", addrstr, expiry (dns_server)); + _LOGD (" dns_server %s exp %u", addrstr, expiry (dns_server)); } for (i = 0; i < rdisc->dns_domains->len; i++) { NMRDiscDNSDomain *dns_domain = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i); - debug (" dns_domain %s exp %u", dns_domain->domain, expiry (dns_domain)); + _LOGD (" dns_domain %s exp %u", dns_domain->domain, expiry (dns_domain)); } } } @@ -548,10 +623,7 @@ check_timestamps (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) guint32 never = G_MAXINT32; guint32 nextevent = never; - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + nm_clear_g_source (&priv->timeout_id); clean_gateways (rdisc, now, &changed, &nextevent); clean_addresses (rdisc, now, &changed, &nextevent); @@ -564,8 +636,8 @@ check_timestamps (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) if (nextevent != never) { g_return_if_fail (nextevent > now); - debug ("(%s): scheduling next now/lifetime check: %u seconds", - rdisc->ifname, nextevent - now); + _LOGD ("scheduling next now/lifetime check: %u seconds", + nextevent - now); priv->timeout_id = g_timeout_add_seconds (nextevent - now, timeout_cb, rdisc); } } @@ -581,8 +653,11 @@ timeout_cb (gpointer user_data) void nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) { - clear_ra_timeout (rdisc); - clear_rs_timeout (rdisc); + NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); + + nm_clear_g_source (&priv->ra_timeout_id); + nm_clear_g_source (&priv->send_rs_id); + g_clear_pointer (&priv->last_send_rs_error, g_free); check_timestamps (rdisc, now, changed); } @@ -619,13 +694,11 @@ dispose (GObject *object) NMRDisc *rdisc = NM_RDISC (object); NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - clear_ra_timeout (rdisc); - clear_rs_timeout (rdisc); + nm_clear_g_source (&priv->ra_timeout_id); + nm_clear_g_source (&priv->send_rs_id); + g_clear_pointer (&priv->last_send_rs_error, g_free); - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + nm_clear_g_source (&priv->timeout_id); G_OBJECT_CLASS (nm_rdisc_parent_class)->dispose (object); } @@ -636,6 +709,7 @@ finalize (GObject *object) NMRDisc *rdisc = NM_RDISC (object); g_free (rdisc->ifname); + g_free (rdisc->uuid); g_array_unref (rdisc->gateways); g_array_unref (rdisc->addresses); g_array_unref (rdisc->routes); |