diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 18f78faf06..7d58e29684 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -1270,8 +1270,6 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) struct rtnl_route *rtnlroute; struct nl_addr *nldest, *nlgateway; struct in6_addr *dest, *gateway; - gboolean defgw_set = FALSE; - struct in6_addr defgw; uint32_t metric; NMIP6Route *ip6route; int i; @@ -1321,11 +1319,9 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) gateway = nl_addr_get_binary_addr (nlgateway); if (rtnl_route_get_dst_len (rtnlroute) == 0) { - /* Default gateway route; don't add to normal routes but to each address */ - if (!defgw_set) { - memcpy (&defgw, gateway, sizeof (defgw)); - defgw_set = TRUE; - } + /* Default gateway route; cache the router's address for later */ + if (!nm_ip6_config_get_defgw (config)) + nm_ip6_config_set_defgw (config, gateway); continue; } @@ -1348,6 +1344,8 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) /* Add addresses */ for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) { + const struct in6_addr *defgw; + if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; @@ -1360,8 +1358,9 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr)); nm_ip6_address_set_address (ip6addr, addr); nm_ip6_config_take_address (config, ip6addr); - if (defgw_set) - nm_ip6_address_set_gateway (ip6addr, &defgw); + defgw = nm_ip6_config_get_defgw (config); + if (defgw) + nm_ip6_address_set_gateway (ip6addr, defgw); } /* Add DNS servers */ diff --git a/src/nm-device.c b/src/nm-device.c index 02509e7015..b6359a7c7a 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1794,6 +1794,10 @@ merge_ip6_configs (NMIP6Config *dst, NMIP6Config *src) for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++) nm_ip6_config_add_nameserver (dst, nm_ip6_config_get_nameserver (src, i)); + /* default gateway */ + if (!nm_ip6_config_get_defgw (dst)) + nm_ip6_config_set_defgw (dst, nm_ip6_config_get_defgw (src)); + /* routes */ for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i)); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 0429e30b26..2fab486383 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -53,6 +53,8 @@ typedef struct { GPtrArray *domains; GPtrArray *searches; + gboolean defgw_set; + struct in6_addr defgw; GSList *routes; gboolean never_default; @@ -244,6 +246,30 @@ void nm_ip6_config_reset_nameservers (NMIP6Config *config) g_array_remove_range (priv->nameservers, 0, priv->nameservers->len); } +void +nm_ip6_config_set_defgw (NMIP6Config *config, const struct in6_addr *defgw) +{ + NMIP6ConfigPrivate *priv; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + if (defgw) + memcpy (&priv->defgw, defgw, sizeof (priv->defgw)); + priv->defgw_set = !!defgw; +} + +const struct in6_addr * +nm_ip6_config_get_defgw (NMIP6Config *config) +{ + NMIP6ConfigPrivate *priv; + + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + return priv->defgw_set ? &priv->defgw : NULL; +} + void nm_ip6_config_take_route (NMIP6Config *config, NMIP6Route *route) { @@ -659,6 +685,7 @@ nm_ip6_config_init (NMIP6Config *config) priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr)); priv->domains = g_ptr_array_sized_new (3); priv->searches = g_ptr_array_sized_new (3); + priv->defgw_set = FALSE; } static void diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 1e75a121c8..bc87430cfc 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -67,6 +67,9 @@ const struct in6_addr *nm_ip6_config_get_nameserver (NMIP6Config *config, g guint32 nm_ip6_config_get_num_nameservers (NMIP6Config *config); void nm_ip6_config_reset_nameservers (NMIP6Config *config); +void nm_ip6_config_set_defgw (NMIP6Config *config, const struct in6_addr *defgw); +const struct in6_addr *nm_ip6_config_get_defgw (NMIP6Config *config); + void nm_ip6_config_take_route (NMIP6Config *config, NMIP6Route *route); void nm_ip6_config_add_route (NMIP6Config *config, NMIP6Route *route); void nm_ip6_config_replace_route (NMIP6Config *config, guint32 i, NMIP6Route *new_route); diff --git a/src/nm-policy.c b/src/nm-policy.c index 26b24f92ed..5420bdf3f8 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -648,7 +648,12 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update) g_assert (ip6_config); addr = nm_ip6_config_get_address (ip6_config, 0); - nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_address_get_gateway (addr)); + if (memcmp (nm_ip6_address_get_gateway (addr)->s6_addr, in6addr_any.s6_addr, sizeof (in6addr_any.s6_addr)) != 0) + nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_address_get_gateway (addr)); + else if (nm_ip6_config_get_defgw (ip6_config)) + nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_config_get_defgw (ip6_config)); + else + nm_log_dbg (LOGD_IP6, "missing default IPv6 route"); dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; }