diff options
Diffstat (limited to 'src/nm-policy.c')
| -rw-r--r-- | src/nm-policy.c | 1232 |
1 files changed, 614 insertions, 618 deletions
diff --git a/src/nm-policy.c b/src/nm-policy.c index f95caf93..d46aca04 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -25,23 +25,24 @@ #include <errno.h> #include <netdb.h> +#include <gio/gio.h> + #include "nm-policy.h" #include "NetworkManagerUtils.h" -#include "nm-wifi-ap.h" #include "nm-activation-request.h" #include "nm-logging.h" #include "nm-device.h" #include "nm-dbus-manager.h" #include "nm-setting-ip4-config.h" #include "nm-setting-connection.h" -#include "nm-system.h" +#include "nm-platform.h" #include "nm-dns-manager.h" #include "nm-vpn-manager.h" -#include "nm-policy-hostname.h" #include "nm-manager-auth.h" #include "nm-firewall-manager.h" #include "nm-dispatcher.h" #include "nm-utils.h" +#include "nm-glib-compat.h" typedef struct { NMManager *manager; @@ -61,9 +62,9 @@ typedef struct { NMDevice *default_device4, *activating_device4; NMDevice *default_device6, *activating_device6; - HostnameThread *lookup; - guint32 lookup_ipv4_addr; /* IPv4 for reverse lookup */ - struct in6_addr *lookup_ipv6_addr; /* IPv6 for reverse lookup */ + GResolver *resolver; + GInetAddress *lookup_addr; + GCancellable *lookup_cancellable; NMDnsManager *dns_manager; gulong config_changed_id; @@ -87,12 +88,6 @@ enum { PROP_ACTIVATING_IP6_DEVICE }; -#define RETRIES_TAG "autoconnect-retries" -#define RETRIES_DEFAULT 4 -#define RESET_RETRIES_TIMESTAMP_TAG "reset-retries-timestamp-tag" -#define RESET_RETRIES_TIMER 300 -#define FAILURE_REASON_TAG "failure-reason" - static void schedule_activate_all (NMPolicy *policy); @@ -100,22 +95,18 @@ static NMDevice * get_best_ip4_device (NMPolicy *self, gboolean fully_activated) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *devices, *iter; + const GSList *iter; NMDevice *best = NULL; int best_prio = G_MAXINT; - devices = nm_manager_get_devices (priv->manager); - for (iter = devices; iter; iter = g_slist_next (iter)) { + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); NMDeviceType devtype = nm_device_get_device_type (dev); NMDeviceState state = nm_device_get_state (dev); NMActRequest *req; NMConnection *connection; - NMIP4Config *ip4_config; NMSettingIP4Config *s_ip4; int prio; - guint i; - gboolean can_default = FALSE; const char *method = NULL; if ( state <= NM_DEVICE_STATE_DISCONNECTED @@ -125,44 +116,38 @@ get_best_ip4_device (NMPolicy *self, gboolean fully_activated) if (fully_activated && state < NM_DEVICE_STATE_SECONDARIES) continue; - ip4_config = nm_device_get_ip4_config (dev); - if (ip4_config) { - /* Make sure at least one of this device's IP addresses has a gateway */ - for (i = 0; i < nm_ip4_config_get_num_addresses (ip4_config); i++) { - NMIP4Address *addr; + if (fully_activated) { + NMIP4Config *ip4_config; - addr = nm_ip4_config_get_address (ip4_config, i); - if (nm_ip4_address_get_gateway (addr)) { - can_default = TRUE; - break; - } - } + ip4_config = nm_device_get_ip4_config (dev); + if (!ip4_config) + continue; - if (!can_default && (devtype != NM_DEVICE_TYPE_MODEM)) + /* Make sure the device has a gateway */ + if (!nm_ip4_config_get_gateway (ip4_config) && (devtype != NM_DEVICE_TYPE_MODEM)) continue; /* 'never-default' devices can't ever be the default */ if (nm_ip4_config_get_never_default (ip4_config)) continue; - } else if (fully_activated) - continue; + } req = nm_device_get_act_request (dev); g_assert (req); connection = nm_act_request_get_connection (req); g_assert (connection); - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4) { - /* Never set the default route through an IPv4LL-addressed device */ - method = nm_setting_ip4_config_get_method (s_ip4); - if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) - continue; + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); + /* If IPv4 is disabled or link-local-only, it can't be the default */ + if ( !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) + || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) + continue; - /* 'never-default' devices can't ever be the default */ - if (nm_setting_ip4_config_get_never_default (s_ip4)) - continue; - } + /* 'never-default' devices can't ever be the default */ + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + if (nm_setting_ip4_config_get_never_default (s_ip4)) + continue; prio = nm_device_get_priority (dev); if ( prio < best_prio @@ -194,22 +179,18 @@ static NMDevice * get_best_ip6_device (NMPolicy *self, gboolean fully_activated) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *devices, *iter; + const GSList *iter; NMDevice *best = NULL; int best_prio = G_MAXINT; - devices = nm_manager_get_devices (priv->manager); - for (iter = devices; iter; iter = g_slist_next (iter)) { + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); NMDeviceType devtype = nm_device_get_device_type (dev); NMDeviceState state = nm_device_get_state (dev); NMActRequest *req; NMConnection *connection; - NMIP6Config *ip6_config; NMSettingIP6Config *s_ip6; int prio; - guint i; - gboolean can_default = FALSE; const char *method = NULL; if ( state <= NM_DEVICE_STATE_DISCONNECTED @@ -219,40 +200,34 @@ get_best_ip6_device (NMPolicy *self, gboolean fully_activated) if (fully_activated && state < NM_DEVICE_STATE_SECONDARIES) continue; - ip6_config = nm_device_get_ip6_config (dev); - if (ip6_config) { - for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) { - NMIP6Address *addr; + if (fully_activated) { + NMIP6Config *ip6_config; - addr = nm_ip6_config_get_address (ip6_config, i); - if (nm_ip6_address_get_gateway (addr)) { - can_default = TRUE; - break; - } - } + ip6_config = nm_device_get_ip6_config (dev); + if (!ip6_config) + continue; - if (!can_default && (devtype != NM_DEVICE_TYPE_MODEM)) + if (!nm_ip6_config_get_gateway (ip6_config) && (devtype != NM_DEVICE_TYPE_MODEM)) continue; if (nm_ip6_config_get_never_default (ip6_config)) continue; - } else if (fully_activated) - continue; + } req = nm_device_get_act_request (dev); g_assert (req); connection = nm_act_request_get_connection (req); g_assert (connection); - s_ip6 = nm_connection_get_setting_ip6_config (connection); - if (s_ip6) { - method = nm_setting_ip6_config_get_method (s_ip6); - if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) - continue; + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); + if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) + || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) + continue; - if (nm_setting_ip6_config_get_never_default (s_ip6)) - continue; - } + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + if (nm_setting_ip6_config_get_never_default (s_ip6)) + continue; prio = nm_device_get_priority (dev); if ( prio < best_prio @@ -280,6 +255,43 @@ get_best_ip6_device (NMPolicy *self, gboolean fully_activated) return best; } +#define FALLBACK_HOSTNAME4 "localhost.localdomain" + +static gboolean +set_system_hostname (const char *new_hostname, const char *msg) +{ + char old_hostname[HOST_NAME_MAX + 1]; + const char *name; + int ret; + + if (new_hostname) + g_warn_if_fail (strlen (new_hostname)); + + old_hostname[HOST_NAME_MAX] = '\0'; + errno = 0; + ret = gethostname (old_hostname, HOST_NAME_MAX); + if (ret != 0) { + nm_log_warn (LOGD_DNS, "couldn't get the system hostname: (%d) %s", + errno, strerror (errno)); + } else { + /* Don't set the hostname if it isn't actually changing */ + if ( (new_hostname && !strcmp (old_hostname, new_hostname)) + || (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME4))) + return FALSE; + } + + name = (new_hostname && strlen (new_hostname)) ? new_hostname : FALLBACK_HOSTNAME4; + + nm_log_info (LOGD_DNS, "Setting system hostname to '%s' (%s)", name, msg); + ret = sethostname (name, strlen (name)); + if (ret != 0) { + nm_log_warn (LOGD_DNS, "couldn't set the system hostname to '%s': (%d) %s", + name, errno, strerror (errno)); + } + + return (ret == 0); +} + static void _set_hostname (NMPolicy *policy, const char *new_hostname, @@ -293,14 +305,11 @@ _set_hostname (NMPolicy *policy, * there was no valid hostname to start with. */ - /* Clear lookup adresses if we have a hostname, so that we didn't - * restart reverse lookup thread later. + /* Clear lookup adresses if we have a hostname, so that we don't + * restart the reverse lookup thread later. */ - if (new_hostname) { - priv->lookup_ipv4_addr = 0; - g_free (priv->lookup_ipv6_addr); - priv->lookup_ipv6_addr = NULL; - } + if (new_hostname) + g_clear_object (&priv->lookup_addr); /* Don't change the hostname or update DNS this is the first time we're * trying to change the hostname, and it's not actually changing. @@ -322,32 +331,35 @@ _set_hostname (NMPolicy *policy, nm_dns_manager_set_hostname (priv->dns_manager, priv->cur_hostname); - if (nm_policy_set_system_hostname (priv->cur_hostname, msg)) - nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL); + if (set_system_hostname (priv->cur_hostname, msg)) + nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL); } static void -lookup_callback (HostnameThread *thread, - int result, - const char *hostname, +lookup_callback (GObject *source, + GAsyncResult *result, gpointer user_data) { NMPolicy *policy = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - char *msg; - - /* Update the hostname if the calling lookup thread is the in-progress one */ - if (!hostname_thread_is_dead (thread) && (thread == priv->lookup)) { - priv->lookup = NULL; - if (!hostname) { - /* Fall back to localhost.localdomain */ - msg = g_strdup_printf ("address lookup failed: %d", result); - _set_hostname (policy, NULL, msg); - g_free (msg); - } else - _set_hostname (policy, hostname, "from address lookup"); + const char *hostname; + GError *error = NULL; + + hostname = g_resolver_lookup_by_address_finish (G_RESOLVER (source), result, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* Don't touch policy; it may have been freed already */ + g_error_free (error); + return; } - hostname_thread_free (thread); + + if (hostname) + _set_hostname (policy, hostname, "from address lookup"); + else { + _set_hostname (policy, NULL, error->message); + g_error_free (error); + } + + g_clear_object (&priv->lookup_cancellable); } static void @@ -356,12 +368,14 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6) NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); char *configured_hostname = NULL; const char *dhcp_hostname, *p; + NMIP4Config *ip4_config; + NMIP6Config *ip6_config; g_return_if_fail (policy != NULL); - if (priv->lookup) { - hostname_thread_kill (priv->lookup); - priv->lookup = NULL; + if (priv->lookup_cancellable) { + g_cancellable_cancel (priv->lookup_cancellable); + g_clear_object (&priv->lookup_cancellable); } /* Hostname precedence order: @@ -446,51 +460,32 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6) /* No configured hostname, no automatically determined hostname, and no * bootup hostname. Start reverse DNS of the current IPv4 or IPv6 address. */ - if (best4) { - NMIP4Config *ip4_config; - NMIP4Address *addr4; - - ip4_config = nm_device_get_ip4_config (best4); - if ( !ip4_config - || (nm_ip4_config_get_num_nameservers (ip4_config) == 0) - || (nm_ip4_config_get_num_addresses (ip4_config) == 0)) { - /* No valid IP4 config (!!); fall back to localhost.localdomain */ - _set_hostname (policy, NULL, "no IPv4 config"); - return; - } + ip4_config = best4 ? nm_device_get_ip4_config (best4) : NULL; + ip6_config = best6 ? nm_device_get_ip6_config (best6) : NULL; - addr4 = nm_ip4_config_get_address (ip4_config, 0); - g_assert (addr4); /* checked for > 1 address above */ + if (ip4_config && nm_ip4_config_get_num_addresses (ip4_config) > 0) { + const NMPlatformIP4Address *addr4; - /* Start the hostname lookup thread */ - priv->lookup_ipv4_addr = nm_ip4_address_get_address (addr4); - priv->lookup = hostname4_thread_new (priv->lookup_ipv4_addr, lookup_callback, policy); - } else if (best6) { - NMIP6Config *ip6_config; - NMIP6Address *addr6; - - ip6_config = nm_device_get_ip6_config (best6); - if ( !ip6_config - || (nm_ip6_config_get_num_nameservers (ip6_config) == 0) - || (nm_ip6_config_get_num_addresses (ip6_config) == 0)) { - /* No valid IP6 config (!!); fall back to localhost.localdomain */ - _set_hostname (policy, NULL, "no IPv6 config"); - return; - } + addr4 = nm_ip4_config_get_address (ip4_config, 0); + priv->lookup_addr = g_inet_address_new_from_bytes ((guint8 *) &addr4->address, + G_SOCKET_FAMILY_IPV4); + } else if (ip6_config && nm_ip6_config_get_num_addresses (ip6_config) > 0) { + const NMPlatformIP6Address *addr6; addr6 = nm_ip6_config_get_address (ip6_config, 0); - g_assert (addr6); /* checked for > 1 address above */ - - /* Start the hostname lookup thread */ - priv->lookup_ipv6_addr = g_malloc0 (sizeof (struct in6_addr)); - memcpy (priv->lookup_ipv6_addr, nm_ip6_address_get_address (addr6), sizeof (struct in6_addr)); - priv->lookup = hostname6_thread_new (priv->lookup_ipv6_addr, lookup_callback, policy); + priv->lookup_addr = g_inet_address_new_from_bytes ((guint8 *) &addr6->address, + G_SOCKET_FAMILY_IPV6); + } else { + /* No valid IP config; fall back to localhost.localdomain */ + _set_hostname (policy, NULL, "no IP config"); + return; } - if (!priv->lookup) { - /* Fall back to 'localhost.localdomain' */ - _set_hostname (policy, NULL, "error starting hostname thread"); - } + priv->lookup_cancellable = g_cancellable_new (); + g_resolver_lookup_by_address_async (priv->resolver, + priv->lookup_addr, + priv->lookup_cancellable, + lookup_callback, policy); } static void @@ -564,7 +559,7 @@ get_best_ip4_config (NMPolicy *policy, /* Check the user's preference from the NMConnection */ s_ip4 = nm_connection_get_setting_ip4_config (tmp); - if (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4)) + if (nm_setting_ip4_config_get_never_default (s_ip4)) continue; } @@ -627,15 +622,14 @@ static void update_ip4_routing (NMPolicy *policy, gboolean force_update) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - NMDevice *best = NULL, *parent, *default_device; + NMDevice *best = NULL, *default_device; NMConnection *connection = NULL; NMVPNConnection *vpn = NULL; NMActiveConnection *best_ac = NULL; - NMIP4Config *ip4_config = NULL, *parent_ip4; + NMIP4Config *ip4_config = NULL; const char *ip_iface = NULL; int ip_ifindex = -1; - guint32 gw_addr = 0, parent_mss; - guint32 i; + guint32 gw_addr = 0; /* Note that we might have an IPv4 VPN tunneled over an IPv6-only device, * so we can get (vpn != NULL && best == NULL). @@ -656,35 +650,50 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update) if (!force_update && best && (best == priv->default_device4)) return; - /* We set the default route to the first gateway we find. If we don't find - * a gateway (WWAN, point-to-point, etc) then we just use 0.0.0.0 - */ - for (i = 0; i < nm_ip4_config_get_num_addresses (ip4_config); i++) { - NMIP4Address *addr; + gw_addr = nm_ip4_config_get_gateway (ip4_config); - addr = nm_ip4_config_get_address (ip4_config, i); - if (nm_ip4_address_get_gateway (addr)) { - gw_addr = nm_ip4_address_get_gateway (addr); - break; + if (vpn) { + NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); + int parent_ifindex = nm_device_get_ip_ifindex (parent); + NMIP4Config *parent_ip4 = nm_device_get_ip4_config (parent); + guint32 parent_mss = parent_ip4 ? nm_ip4_config_get_mss (parent_ip4) : 0; + in_addr_t int_gw = nm_vpn_connection_get_ip4_internal_gateway (vpn); + int mss = nm_ip4_config_get_mss (ip4_config); + + /* If no VPN interface, use the parent interface */ + if (ip_ifindex <= 0) + ip_ifindex = parent_ifindex; + + if (!nm_platform_ip4_route_add (ip_ifindex, NM_PLATFORM_SOURCE_VPN, + 0, 0, int_gw, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) { + (void) nm_platform_ip4_route_add (parent_ifindex, NM_PLATFORM_SOURCE_VPN, + gw_addr, 32, 0, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, parent_mss); + if (!nm_platform_ip4_route_add (ip_ifindex, NM_PLATFORM_SOURCE_VPN, + 0, 0, int_gw, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) + nm_log_err (LOGD_IP4 | LOGD_VPN, "Failed to set default route."); } - } - if (vpn) { - parent = nm_vpn_connection_get_parent_device (vpn); - parent_ip4 = nm_device_get_ip4_config (parent); - parent_mss = parent_ip4 ? nm_ip4_config_get_mss (parent_ip4) : 0; - - nm_system_replace_default_ip4_route_vpn (ip_ifindex, - gw_addr, - nm_vpn_connection_get_ip4_internal_gateway (vpn), - nm_ip4_config_get_mss (ip4_config), - nm_device_get_ip_ifindex (parent), - parent_mss); - default_device = parent; + default_device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); } else { - nm_system_replace_default_ip4_route (ip_ifindex, - gw_addr, - nm_ip4_config_get_mss (ip4_config)); + int mss = nm_ip4_config_get_mss (ip4_config); + + g_assert (ip_iface); + if (!nm_platform_ip4_route_add (ip_ifindex, NM_PLATFORM_SOURCE_USER, + 0, 0, gw_addr, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) { + (void) nm_platform_ip4_route_add (ip_ifindex, NM_PLATFORM_SOURCE_USER, + gw_addr, 32, 0, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss); + if (!nm_platform_ip4_route_add (ip_ifindex, NM_PLATFORM_SOURCE_USER, + 0, 0, gw_addr, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) { + nm_log_err (LOGD_IP4, "Failed to set default route."); + } + } + default_device = best; } @@ -748,7 +757,7 @@ get_best_ip6_config (NMPolicy *policy, /* Check the user's preference from the NMConnection */ s_ip6 = nm_connection_get_setting_ip6_config (tmp); - if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6)) + if (nm_setting_ip6_config_get_never_default (s_ip6)) continue; } @@ -811,15 +820,13 @@ static void update_ip6_routing (NMPolicy *policy, gboolean force_update) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - NMDevice *best = NULL, *parent, *default_device6; + NMDevice *best = NULL, *default_device6; NMConnection *connection = NULL; NMVPNConnection *vpn = NULL; NMActiveConnection *best_ac = NULL; - NMIP6Config *ip6_config = NULL, *parent_ip6; + NMIP6Config *ip6_config = NULL; const char *ip_iface = NULL; int ip_ifindex = -1; - guint32 parent_mss; - guint32 i; const struct in6_addr *gw_addr; /* Note that we might have an IPv6 VPN tunneled over an IPv4-only device, @@ -844,41 +851,54 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update) /* If no better gateway is found, use ::; not all configurations will * have a gateway, especially WWAN/Point-to-Point connections. */ - gw_addr = &in6addr_any; - - /* Look for a gateway paired with one of the addresses */ - for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) { - NMIP6Address *addr; + gw_addr = nm_ip6_config_get_gateway (ip6_config); + if (!gw_addr) + gw_addr = &in6addr_any; - addr = nm_ip6_config_get_address (ip6_config, i); - if (nm_ip6_address_get_gateway (addr)) { - gw_addr = nm_ip6_address_get_gateway (addr); - break; + if (vpn) { + NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); + int parent_ifindex = nm_device_get_ip_ifindex (parent); + NMIP6Config *parent_ip6 = nm_device_get_ip6_config (parent); + guint32 parent_mss = parent_ip6 ? nm_ip6_config_get_mss (parent_ip6) : 0; + const struct in6_addr *int_gw = nm_vpn_connection_get_ip6_internal_gateway (vpn); + int mss = nm_ip6_config_get_mss (ip6_config); + + if (!int_gw) + int_gw = &in6addr_any; + + /* If no VPN interface, use the parent interface */ + if (ip_ifindex <= 0) + ip_ifindex = parent_ifindex; + + if (!nm_platform_ip6_route_add (ip_ifindex, NM_PLATFORM_SOURCE_VPN, + in6addr_any, 0, *int_gw, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) { + (void) nm_platform_ip6_route_add (parent_ifindex, NM_PLATFORM_SOURCE_VPN, + *gw_addr, 128, in6addr_any, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, parent_mss); + if (!nm_platform_ip6_route_add (ip_ifindex, NM_PLATFORM_SOURCE_VPN, + in6addr_any, 0, *int_gw, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) { + nm_log_err (LOGD_IP6 | LOGD_VPN, "Failed to set default route."); + } } - } - - /* If we don't find a paired gateway, try the generic IPv6 gateway */ - if ( IN6_IS_ADDR_UNSPECIFIED (gw_addr) - && nm_ip6_config_get_gateway (ip6_config)) - gw_addr = nm_ip6_config_get_gateway (ip6_config); - if (vpn) { - parent = nm_vpn_connection_get_parent_device (vpn); - parent_ip6 = nm_device_get_ip6_config (parent); - parent_mss = parent_ip6 ? nm_ip6_config_get_mss (parent_ip6) : 0; - - nm_system_replace_default_ip6_route_vpn (ip_ifindex, - gw_addr, - nm_vpn_connection_get_ip6_internal_gateway (vpn), - nm_ip6_config_get_mss (ip6_config), - nm_device_get_ip_ifindex (parent), - parent_mss); - default_device6 = parent; + default_device6 = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); } else { - if (gw_addr) - nm_system_replace_default_ip6_route (ip_ifindex, gw_addr); - else - nm_log_dbg (LOGD_IP6, "missing default IPv6 gateway"); + int mss = nm_ip6_config_get_mss (ip6_config); + + if (!nm_platform_ip6_route_add (ip_ifindex, NM_PLATFORM_SOURCE_USER, + in6addr_any, 0, *gw_addr, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) { + (void) nm_platform_ip6_route_add (ip_ifindex, NM_PLATFORM_SOURCE_USER, + *gw_addr, 128, in6addr_any, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss); + if (!nm_platform_ip6_route_add (ip_ifindex, NM_PLATFORM_SOURCE_USER, + in6addr_any, 0, *gw_addr, + NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) + nm_log_err (LOGD_IP6, "Failed to set default route."); + } + default_device6 = best; } @@ -898,13 +918,11 @@ static void update_routing_and_dns (NMPolicy *policy, gboolean force_update) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - NMDnsManager *mgr; - mgr = nm_dns_manager_get (NULL); - nm_dns_manager_begin_updates (mgr, __func__); + nm_dns_manager_begin_updates (priv->dns_manager, __func__); - update_ip4_dns (policy, mgr); - update_ip6_dns (policy, mgr); + update_ip4_dns (policy, priv->dns_manager); + update_ip6_dns (policy, priv->dns_manager); update_ip4_routing (policy, force_update); update_ip6_routing (policy, force_update); @@ -912,8 +930,7 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) /* Update the system hostname */ update_system_hostname (policy, priv->default_device4, priv->default_device6); - nm_dns_manager_end_updates (mgr, __func__); - g_object_unref (mgr); + nm_dns_manager_end_updates (priv->dns_manager, __func__); } static void @@ -940,33 +957,23 @@ check_activating_devices (NMPolicy *policy) g_object_thaw_notify (object); } -static void -set_connection_auto_retries (NMConnection *connection, guint retries) -{ - /* add +1 so that the tag still exists if the # retries is 0 */ - g_object_set_data (G_OBJECT (connection), RETRIES_TAG, GUINT_TO_POINTER (retries + 1)); -} - -static guint32 -get_connection_auto_retries (NMConnection *connection) -{ - /* subtract 1 to handle the +1 from set_connection_auto_retries() */ - return GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), RETRIES_TAG)) - 1; -} - typedef struct { NMPolicy *policy; NMDevice *device; - guint id; + guint autoactivate_id; } ActivateData; static void activate_data_free (ActivateData *data) { - if (data->id) - g_source_remove (data->id); + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (data->policy); + + nm_device_remove_pending_action (data->device, "autoactivate", TRUE); + priv->pending_activation_checks = g_slist_remove (priv->pending_activation_checks, data); + + if (data->autoactivate_id) + g_source_remove (data->autoactivate_id); g_object_unref (data->device); - memset (data, 0, sizeof (*data)); g_free (data); } @@ -984,8 +991,7 @@ auto_activate_device (gpointer user_data) policy = data->policy; priv = NM_POLICY_GET_PRIVATE (policy); - data->id = 0; - priv->pending_activation_checks = g_slist_remove (priv->pending_activation_checks, data); + data->autoactivate_id = 0; // FIXME: if a device is already activating (or activated) with a connection // but another connection now overrides the current one for that device, @@ -994,47 +1000,32 @@ auto_activate_device (gpointer user_data) if (nm_device_get_act_request (data->device)) goto out; - iter = connections = nm_settings_get_connections (priv->settings); + iter = connections = nm_manager_get_activatable_connections (priv->manager); /* Remove connections that shouldn't be auto-activated */ while (iter) { NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (iter->data); - gboolean remove_it = FALSE; - const char *permission; /* Grab next item before we possibly delete the current item */ iter = g_slist_next (iter); - /* Ignore connections that were tried too many times or are not visible - * to any logged-in users. Also ignore shared wifi connections for - * which no user has the shared wifi permission. - */ - if ( get_connection_auto_retries (NM_CONNECTION (candidate)) == 0 - || nm_settings_connection_is_visible (candidate) == FALSE) - remove_it = TRUE; - else { - permission = nm_utils_get_shared_wifi_permission (NM_CONNECTION (candidate)); - if (permission) { - if (nm_settings_connection_check_permission (candidate, permission) == FALSE) - remove_it = TRUE; - } - } - - if (remove_it) + if (!nm_settings_connection_can_autoconnect (candidate)) connections = g_slist_remove (connections, candidate); } best_connection = nm_device_get_best_auto_connection (data->device, connections, &specific_object); if (best_connection) { GError *error = NULL; + NMAuthSubject *subject; nm_log_info (LOGD_DEVICE, "Auto-activating connection '%s'.", nm_connection_get_id (best_connection)); + subject = nm_auth_subject_new_internal (); if (!nm_manager_activate_connection (priv->manager, best_connection, specific_object, - nm_device_get_path (data->device), - NULL, + data->device, + subject, &error)) { nm_log_info (LOGD_DEVICE, "Connection '%s' auto-activation failed: (%d) %s", nm_connection_get_id (best_connection), @@ -1042,28 +1033,14 @@ auto_activate_device (gpointer user_data) error ? error->message : "(none)"); g_error_free (error); } + g_object_unref (subject); } g_slist_free (connections); out: activate_data_free (data); - return FALSE; -} - -static ActivateData * -activate_data_new (NMPolicy *policy, NMDevice *device, guint delay_seconds) -{ - ActivateData *data; - - data = g_malloc0 (sizeof (ActivateData)); - data->policy = policy; - data->device = g_object_ref (device); - if (delay_seconds > 0) - data->id = g_timeout_add_seconds (delay_seconds, auto_activate_device, data); - else - data->id = g_idle_add (auto_activate_device, data); - return data; + return G_SOURCE_REMOVE; } static ActivateData * @@ -1100,7 +1077,7 @@ static void pending_secondary_data_free (PendingSecondaryData *data) { g_object_unref (data->device); - nm_utils_slist_free (data->secondaries, g_free); + g_slist_free_full (data->secondaries, g_object_unref); memset (data, 0, sizeof (*data)); g_free (data); } @@ -1111,51 +1088,50 @@ process_secondaries (NMPolicy *policy, gboolean connected) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - NMDevice *device = NULL; - const char *ac_path; GSList *iter, *iter2; - nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' %s; active path '%s'", - nm_active_connection_get_name (active), - connected ? "SUCCEEDED" : "FAILED", - nm_active_connection_get_path (active)); - - ac_path = nm_active_connection_get_path (active); - - if (NM_IS_VPN_CONNECTION (active)) - device = nm_vpn_connection_get_parent_device (NM_VPN_CONNECTION (active)); - + /* Loop through devices waiting for secondary connections to activate */ for (iter = priv->pending_secondaries; iter; iter = g_slist_next (iter)) { PendingSecondaryData *secondary_data = (PendingSecondaryData *) iter->data; NMDevice *item_device = secondary_data->device; - if (!device || item_device == device) { - for (iter2 = secondary_data->secondaries; iter2; iter2 = g_slist_next (iter2)) { - char *list_ac_path = (char *) iter2->data; - - if (g_strcmp0 (ac_path, list_ac_path) == 0) { - if (connected) { - /* Secondary connection activated */ - secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, list_ac_path); - g_free (list_ac_path); - if (!secondary_data->secondaries) { - /* None secondary UUID remained -> remove the secondary data item */ - priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); - pending_secondary_data_free (secondary_data); - nm_device_state_changed (item_device, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE); - return; - } - } else { - /* Secondary connection failed -> do not watch other connections */ - priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); - pending_secondary_data_free (secondary_data); - nm_device_state_changed (item_device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED); - return; - } + /* Look for 'active' in each device's secondary connections list */ + for (iter2 = secondary_data->secondaries; iter2; iter2 = g_slist_next (iter2)) { + NMActiveConnection *secondary_active = NM_ACTIVE_CONNECTION (iter2->data); + + if (active != secondary_active) + continue; + + if (connected) { + nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' SUCCEEDED; active path '%s'", + nm_active_connection_get_id (active), + nm_active_connection_get_path (active)); + + /* Secondary connection activated */ + secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, secondary_active); + g_object_unref (secondary_active); + if (!secondary_data->secondaries) { + /* No secondary UUID remained -> remove the secondary data item */ + priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); + pending_secondary_data_free (secondary_data); + if (nm_device_get_state (item_device) == NM_DEVICE_STATE_SECONDARIES) + nm_device_state_changed (item_device, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE); + break; } + } else { + nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' FAILED; active path '%s'", + nm_active_connection_get_id (active), + nm_active_connection_get_path (active)); + + /* Secondary connection failed -> do not watch other connections */ + priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); + pending_secondary_data_free (secondary_data); + if ( nm_device_get_state (item_device) == NM_DEVICE_STATE_SECONDARIES + || nm_device_get_state (item_device) == NM_DEVICE_STATE_ACTIVATED) + nm_device_state_changed (item_device, NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED); + break; } - return; } } } @@ -1172,42 +1148,76 @@ hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) } static void -reset_retries_all (NMSettings *settings, NMDevice *device) +reset_autoconnect_all (NMPolicy *policy, NMDevice *device) { + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); GSList *connections, *iter; - GError *error = NULL; - connections = nm_settings_get_connections (settings); + if (device) { + nm_log_dbg (LOGD_DEVICE, "Re-enabling autoconnect for all connections on %s", + nm_device_get_iface (device)); + } else + nm_log_dbg (LOGD_DEVICE, "Re-enabling autoconnect for all connections"); + + connections = nm_settings_get_connections (priv->settings); for (iter = connections; iter; iter = g_slist_next (iter)) { - if (!device || nm_device_check_connection_compatible (device, iter->data, &error)) - set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT); - g_clear_error (&error); + if (!device || nm_device_check_connection_compatible (device, iter->data)) { + nm_settings_connection_reset_autoconnect_retries (iter->data); + nm_settings_connection_set_autoconnect_blocked_reason (iter->data, NM_DEVICE_STATE_REASON_NONE); + } } g_slist_free (connections); } static void -reset_retries_for_failed_secrets (NMSettings *settings) +reset_autoconnect_for_failed_secrets (NMPolicy *policy) { + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); GSList *connections, *iter; - connections = nm_settings_get_connections (settings); + nm_log_dbg (LOGD_DEVICE, "Re-enabling autoconnect for all connections with failed secrets"); + + connections = nm_settings_get_connections (priv->settings); for (iter = connections; iter; iter = g_slist_next (iter)) { - NMDeviceStateReason reason = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (iter->data), FAILURE_REASON_TAG)); + NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (iter->data); - if (reason == NM_DEVICE_STATE_REASON_NO_SECRETS) { - set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT); - g_object_set_data (G_OBJECT (iter->data), FAILURE_REASON_TAG, GUINT_TO_POINTER (0)); + if (nm_settings_connection_get_autoconnect_blocked_reason (connection) == NM_DEVICE_STATE_REASON_NO_SECRETS) { + nm_settings_connection_reset_autoconnect_retries (connection); + nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NONE); } } g_slist_free (connections); } static void +block_autoconnect_for_device (NMPolicy *policy, NMDevice *device) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); + GSList *connections, *iter; + + nm_log_dbg (LOGD_DEVICE, "Blocking autoconnect for all connections on %s", + nm_device_get_iface (device)); + + /* NMDevice keeps its own autoconnect-able-ness state; we only need to + * explicitly block connections for software devices, where the NMDevice + * might be destroyed and recreated later. + */ + if (!nm_device_is_software (device)) + return; + + connections = nm_settings_get_connections (priv->settings); + for (iter = connections; iter; iter = g_slist_next (iter)) { + if (nm_device_check_connection_compatible (device, iter->data)) { + nm_settings_connection_set_autoconnect_blocked_reason (NM_SETTINGS_CONNECTION (iter->data), + NM_DEVICE_STATE_REASON_USER_REQUESTED); + } + } +} + +static void sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) { NMPolicy *policy = user_data; - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); gboolean sleeping = FALSE, enabled = FALSE; g_object_get (G_OBJECT (manager), NM_MANAGER_SLEEPING, &sleeping, NULL); @@ -1215,34 +1225,52 @@ sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) /* Reset retries on all connections so they'll checked on wakeup */ if (sleeping || !enabled) - reset_retries_all (priv->settings, NULL); + reset_autoconnect_all (policy, NULL); } static void -schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds) +schedule_activate_check (NMPolicy *policy, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); ActivateData *data; - NMDeviceState state; + const GSList *active_connections, *iter; if (nm_manager_get_state (priv->manager) == NM_STATE_ASLEEP) return; - state = nm_device_get_state (device); - if (state < NM_DEVICE_STATE_DISCONNECTED) - return; - if (!nm_device_get_enabled (device)) return; if (!nm_device_autoconnect_allowed (device)) return; - /* Schedule an auto-activation if there isn't one already for this device */ - if (find_pending_activation (priv->pending_activation_checks, device) == NULL) { - data = activate_data_new (policy, device, delay_seconds); - priv->pending_activation_checks = g_slist_append (priv->pending_activation_checks, data); + if (find_pending_activation (priv->pending_activation_checks, device)) + return; + + active_connections = nm_manager_get_active_connections (priv->manager); + for (iter = active_connections; iter; iter = iter->next) { + if (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (iter->data)) == device) + return; } + + nm_device_add_pending_action (device, "autoactivate", TRUE); + + data = g_malloc0 (sizeof (ActivateData)); + data->policy = policy; + data->device = g_object_ref (device); + data->autoactivate_id = g_idle_add (auto_activate_device, data); + priv->pending_activation_checks = g_slist_append (priv->pending_activation_checks, data); +} + +static void +clear_pending_activate_check (NMPolicy *policy, NMDevice *device) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); + ActivateData *data; + + data = find_pending_activation (priv->pending_activation_checks, device); + if (data && data->autoactivate_id) + activate_data_free (data); } static gboolean @@ -1251,31 +1279,32 @@ reset_connections_retries (gpointer user_data) NMPolicy *policy = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); GSList *connections, *iter; - time_t con_stamp, min_stamp, now; + gint32 con_stamp, min_stamp, now; gboolean changed = FALSE; priv->reset_retries_id = 0; - min_stamp = now = time (NULL); + min_stamp = 0; + now = nm_utils_get_monotonic_timestamp_s (); connections = nm_settings_get_connections (priv->settings); for (iter = connections; iter; iter = g_slist_next (iter)) { - con_stamp = GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (iter->data), RESET_RETRIES_TIMESTAMP_TAG)); + NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (iter->data); + + con_stamp = nm_settings_connection_get_autoconnect_retry_time (connection); if (con_stamp == 0) continue; - if (con_stamp + RESET_RETRIES_TIMER <= now) { - set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT); - g_object_set_data (G_OBJECT (iter->data), RESET_RETRIES_TIMESTAMP_TAG, GSIZE_TO_POINTER (0)); + + if (con_stamp <= now) { + nm_settings_connection_reset_autoconnect_retries (connection); changed = TRUE; - continue; - } - if (con_stamp < min_stamp) + } else if (min_stamp == 0 || min_stamp > con_stamp) min_stamp = con_stamp; } g_slist_free (connections); /* Schedule the handler again if there are some stamps left */ - if (min_stamp != now) - priv->reset_retries_id = g_timeout_add_seconds (RESET_RETRIES_TIMER - (now - min_stamp), reset_connections_retries, policy); + if (min_stamp != 0) + priv->reset_retries_id = g_timeout_add_seconds (min_stamp - now, reset_connections_retries, policy); /* If anything changed, try to activate the newly re-enabled connections */ if (changed) @@ -1287,29 +1316,37 @@ reset_connections_retries (gpointer user_data) static void schedule_activate_all (NMPolicy *policy); static void -activate_slave_connections (NMPolicy *policy, NMConnection *connection, - NMDevice *device) +activate_slave_connections (NMPolicy *policy, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - const char *master_device; + const char *master_device, *master_uuid = NULL; GSList *connections, *iter; + NMActRequest *req; master_device = nm_device_get_iface (device); g_assert (master_device); + req = nm_device_get_act_request (device); + if (req) + master_uuid = nm_active_connection_get_uuid (NM_ACTIVE_CONNECTION (req)); + connections = nm_settings_get_connections (priv->settings); for (iter = connections; iter; iter = g_slist_next (iter)) { NMConnection *slave; NMSettingConnection *s_slave_con; + const char *slave_master; slave = NM_CONNECTION (iter->data); g_assert (slave); s_slave_con = nm_connection_get_setting_connection (slave); g_assert (s_slave_con); + slave_master = nm_setting_connection_get_master (s_slave_con); + if (!slave_master) + continue; - if (!g_strcmp0 (nm_setting_connection_get_master (s_slave_con), master_device)) - set_connection_auto_retries (slave, RETRIES_DEFAULT); + if (!g_strcmp0 (slave_master, master_device) || !g_strcmp0 (slave_master, master_uuid)) + nm_settings_connection_reset_autoconnect_retries (NM_SETTINGS_CONNECTION (slave)); } g_slist_free (connections); @@ -1337,46 +1374,52 @@ activate_secondary_connections (NMPolicy *policy, for (i = 0; i < nm_setting_connection_get_num_secondaries (s_con); i++) { const char *sec_uuid = nm_setting_connection_get_secondary (s_con, i); + NMActRequest *req; settings_con = nm_settings_get_connection_by_uuid (priv->settings, sec_uuid); - if (settings_con) { - NMActRequest *req = nm_device_get_act_request (device); - g_assert (req); - - nm_log_dbg (LOGD_DEVICE, "Activating secondary connection '%s (%s)' for base connection '%s (%s)'", - nm_connection_get_id (NM_CONNECTION (settings_con)), sec_uuid, - nm_connection_get_id (connection), nm_connection_get_uuid (connection)); - ac = nm_manager_activate_connection (priv->manager, - NM_CONNECTION (settings_con), - nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req)), - nm_device_get_path (device), - nm_act_request_get_dbus_sender (req), - &error); - if (ac) { - secondary_ac_list = g_slist_append (secondary_ac_list, - g_strdup (nm_active_connection_get_path (ac))); - } else { - nm_log_warn (LOGD_DEVICE, "Secondary connection '%s' auto-activation failed: (%d) %s", - sec_uuid, - error ? error->code : 0, - (error && error->message) ? error->message : "unknown"); - g_clear_error (&error); - success = FALSE; - break; - } - } else { + if (!settings_con) { nm_log_warn (LOGD_DEVICE, "Secondary connection '%s' auto-activation failed: The connection doesn't exist.", sec_uuid); success = FALSE; break; } + if (!nm_connection_is_type (NM_CONNECTION (settings_con), NM_SETTING_VPN_SETTING_NAME)) { + nm_log_warn (LOGD_DEVICE, "Secondary connection '%s (%s)' auto-activation failed: The connection is not a VPN.", + nm_connection_get_id (NM_CONNECTION (settings_con)), sec_uuid); + success = FALSE; + break; + } + + req = nm_device_get_act_request (device); + g_assert (req); + + nm_log_dbg (LOGD_DEVICE, "Activating secondary connection '%s (%s)' for base connection '%s (%s)'", + nm_connection_get_id (NM_CONNECTION (settings_con)), sec_uuid, + nm_connection_get_id (connection), nm_connection_get_uuid (connection)); + ac = nm_manager_activate_connection (priv->manager, + NM_CONNECTION (settings_con), + nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req)), + device, + nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)), + &error); + if (ac) + secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac)); + else { + nm_log_warn (LOGD_DEVICE, "Secondary connection '%s (%s)' auto-activation failed: (%d) %s", + nm_connection_get_id (NM_CONNECTION (settings_con)), sec_uuid, + error ? error->code : 0, + (error && error->message) ? error->message : "unknown"); + g_clear_error (&error); + success = FALSE; + break; + } } if (success && secondary_ac_list != NULL) { secondary_data = pending_secondary_data_new (device, secondary_ac_list); priv->pending_secondaries = g_slist_append (priv->pending_secondaries, secondary_data); } else - nm_utils_slist_free (secondary_ac_list, g_free); + g_slist_free_full (secondary_ac_list, g_object_unref); return success; } @@ -1390,14 +1433,11 @@ device_state_changed (NMDevice *device, { NMPolicy *policy = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - NMConnection *connection = nm_device_get_connection (device); + NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (nm_device_get_connection (device)); const char *ip_iface = nm_device_get_ip_iface (device); NMIP4Config *ip4_config; NMIP6Config *ip6_config; - NMSettingConnection *s_con; - - if (connection) - g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (0)); + NMSettingConnection *s_con = NULL; switch (new_state) { case NM_DEVICE_STATE_FAILED: @@ -1407,47 +1447,42 @@ device_state_changed (NMDevice *device, if ( connection && old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_ACTIVATED) { - guint32 tries = get_connection_auto_retries (connection); + guint32 tries = nm_settings_connection_get_autoconnect_retries (connection); if (reason == NM_DEVICE_STATE_REASON_NO_SECRETS) { - /* If the connection couldn't get the secrets it needed (ex because - * the user canceled, or no secrets exist), there's no point in - * automatically retrying because it's just going to fail anyway. - */ - set_connection_auto_retries (connection, 0); - - /* Mark the connection as failed due to missing secrets so that we can reset - * RETRIES_TAG and automatically re-try when an secret agent registers. - */ - g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (NM_DEVICE_STATE_REASON_NO_SECRETS)); + nm_log_dbg (LOGD_DEVICE, "Connection '%s' now blocked from autoconnect due to no secrets", + nm_connection_get_id (NM_CONNECTION (connection))); + + nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NO_SECRETS); } else if (tries > 0) { - /* Otherwise if it's a random failure, just decrease the number - * of automatic retries so that the connection gets tried again - * if it still has a retry count. - */ - set_connection_auto_retries (connection, tries - 1); + nm_log_dbg (LOGD_DEVICE, "Connection '%s' failed to autoconnect; %d tries left", + nm_connection_get_id (NM_CONNECTION (connection)), tries); + nm_settings_connection_set_autoconnect_retries (connection, tries - 1); } - if (get_connection_auto_retries (connection) == 0) { - nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid.", nm_connection_get_id (connection)); + if (nm_settings_connection_get_autoconnect_retries (connection) == 0) { + nm_log_info (LOGD_DEVICE, "Disabling autoconnect for connection '%s'.", + nm_connection_get_id (NM_CONNECTION (connection))); /* Schedule a handler to reset retries count */ - g_object_set_data (G_OBJECT (connection), RESET_RETRIES_TIMESTAMP_TAG, GSIZE_TO_POINTER ((gsize) time (NULL))); - if (!priv->reset_retries_id) - priv->reset_retries_id = g_timeout_add_seconds (RESET_RETRIES_TIMER, reset_connections_retries, policy); + if (!priv->reset_retries_id) { + gint32 retry_time = nm_settings_connection_get_autoconnect_retry_time (connection); + + g_warn_if_fail (retry_time != 0); + priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - nm_utils_get_monotonic_timestamp_s ()), reset_connections_retries, policy); + } } - nm_connection_clear_secrets (connection); + nm_connection_clear_secrets (NM_CONNECTION (connection)); } - schedule_activate_check (policy, device, 3); break; case NM_DEVICE_STATE_ACTIVATED: if (connection) { /* Reset auto retries back to default since connection was successful */ - set_connection_auto_retries (connection, RETRIES_DEFAULT); + nm_settings_connection_reset_autoconnect_retries (connection); /* And clear secrets so they will always be requested from the * settings service when the next connection is made. */ - nm_connection_clear_secrets (connection); + nm_connection_clear_secrets (NM_CONNECTION (connection)); } /* Add device's new IPv4 and IPv6 configs to DNS */ @@ -1470,32 +1505,55 @@ device_state_changed (NMDevice *device, if (old_state > NM_DEVICE_STATE_DISCONNECTED) update_routing_and_dns (policy, FALSE); break; + case NM_DEVICE_STATE_DEACTIVATING: + if (reason == NM_DEVICE_STATE_REASON_USER_REQUESTED) { + if (!nm_device_get_autoconnect (device)) { + /* The device was disconnected; block all connections on it */ + block_autoconnect_for_device (policy, device); + } else { + if (connection) { + /* The connection was deactivated, so block just this connection */ + nm_log_dbg (LOGD_DEVICE, "Blocking autoconnect of connection '%s' by user request", + nm_connection_get_id (NM_CONNECTION (connection))); + nm_settings_connection_set_autoconnect_blocked_reason (connection, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + } + } + } + break; case NM_DEVICE_STATE_DISCONNECTED: - /* Reset RETRIES_TAG when carrier on. If cable was unplugged - * and plugged again, we should try to reconnect */ + /* Reset retry counts for a device's connections when carrier on; if cable + * was unplugged and plugged in again, we should try to reconnect. + */ if (reason == NM_DEVICE_STATE_REASON_CARRIER && old_state == NM_DEVICE_STATE_UNAVAILABLE) - reset_retries_all (priv->settings, device); + reset_autoconnect_all (policy, device); if (old_state > NM_DEVICE_STATE_DISCONNECTED) update_routing_and_dns (policy, FALSE); /* Device is now available for auto-activation */ - schedule_activate_check (policy, device, 0); + schedule_activate_check (policy, device); break; case NM_DEVICE_STATE_PREPARE: /* Reset auto-connect retries of all slaves and schedule them for * activation. */ - activate_slave_connections (policy, connection, device); + activate_slave_connections (policy, device); + break; + case NM_DEVICE_STATE_IP_CONFIG: + /* We must have secrets if we got here. */ + if (connection) + nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NONE); break; case NM_DEVICE_STATE_SECONDARIES: - s_con = nm_connection_get_setting_connection (connection); + if (connection) + s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); if (s_con && nm_setting_connection_get_num_secondaries (s_con) > 0) { /* Make routes and DNS up-to-date before activating dependent connections */ update_routing_and_dns (policy, FALSE); /* Activate secondary (VPN) connections */ - if (!activate_secondary_connections (policy, connection, device)) + if (!activate_secondary_connections (policy, NM_CONNECTION (connection), device)) nm_device_queue_state (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED); } else @@ -1519,27 +1577,26 @@ device_ip4_config_changed (NMDevice *device, NMPolicy *policy = user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); const char *ip_iface = nm_device_get_ip_iface (device); - NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL; nm_dns_manager_begin_updates (priv->dns_manager, __func__); - /* Old configs get removed immediately */ - if (old_config) - nm_dns_manager_remove_ip4_config (priv->dns_manager, old_config); - /* Ignore IP config changes while the device is activating, because we'll * catch all the changes when the device moves to ACTIVATED state. * Prevents unecessary changes to DNS information. */ if (!nm_device_is_activating (device)) { - if (new_config) - nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + if (old_config != new_config) { + if (old_config) + nm_dns_manager_remove_ip4_config (priv->dns_manager, old_config); + if (new_config) + nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + } update_ip4_dns (policy, priv->dns_manager); - - /* Only change routing if something actually changed */ - diff = nm_ip4_config_diff (new_config, old_config); - if (diff & (NM_IP4_COMPARE_FLAG_ADDRESSES | NM_IP4_COMPARE_FLAG_PTP_ADDRESS | NM_IP4_COMPARE_FLAG_ROUTES)) - update_ip4_routing (policy, TRUE); + update_ip4_routing (policy, TRUE); + } else { + /* Old configs get removed immediately */ + if (old_config) + nm_dns_manager_remove_ip4_config (priv->dns_manager, old_config); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -1554,27 +1611,26 @@ device_ip6_config_changed (NMDevice *device, NMPolicy *policy = user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); const char *ip_iface = nm_device_get_ip_iface (device); - NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL; nm_dns_manager_begin_updates (priv->dns_manager, __func__); - /* Old configs get removed immediately */ - if (old_config) - nm_dns_manager_remove_ip6_config (priv->dns_manager, old_config); - /* Ignore IP config changes while the device is activating, because we'll * catch all the changes when the device moves to ACTIVATED state. * Prevents unecessary changes to DNS information. */ if (!nm_device_is_activating (device)) { - if (new_config) - nm_dns_manager_add_ip6_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + if (old_config != new_config) { + if (old_config) + nm_dns_manager_remove_ip6_config (priv->dns_manager, old_config); + if (new_config) + nm_dns_manager_add_ip6_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + } update_ip6_dns (policy, priv->dns_manager); - - /* Only change routing if something actually changed */ - diff = nm_ip6_config_diff (new_config, old_config); - if (diff & (NM_IP6_COMPARE_FLAG_ADDRESSES | NM_IP6_COMPARE_FLAG_PTP_ADDRESS | NM_IP6_COMPARE_FLAG_ROUTES)) - update_ip6_routing (policy, TRUE); + update_ip6_routing (policy, TRUE); + } else { + /* Old configs get removed immediately */ + if (old_config) + nm_dns_manager_remove_ip6_config (priv->dns_manager, old_config); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -1586,25 +1642,13 @@ device_autoconnect_changed (NMDevice *device, gpointer user_data) { if (nm_device_get_autoconnect (device)) - schedule_activate_check ((NMPolicy *) user_data, device, 0); + schedule_activate_check ((NMPolicy *) user_data, device); } static void -wireless_networks_changed (NMDevice *device, GObject *ap, gpointer user_data) +device_recheck_auto_activate (NMDevice *device, gpointer user_data) { - schedule_activate_check ((NMPolicy *) user_data, device, 0); -} - -static void -nsps_changed (NMDevice *device, GObject *nsp, gpointer user_data) -{ - schedule_activate_check ((NMPolicy *) user_data, device, 0); -} - -static void -modem_enabled_changed (NMDevice *device, gpointer user_data) -{ - schedule_activate_check ((NMPolicy *) (user_data), device, 0); + schedule_activate_check (NM_POLICY (user_data), device); } typedef struct { @@ -1613,14 +1657,21 @@ typedef struct { } DeviceSignalId; static void -_connect_device_signal (NMPolicy *policy, NMDevice *device, const char *name, gpointer callback) +_connect_device_signal (NMPolicy *policy, + NMDevice *device, + const char *name, + gpointer callback, + gboolean after) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); DeviceSignalId *data; data = g_slice_new0 (DeviceSignalId); g_assert (data); - data->id = g_signal_connect (device, name, callback, policy); + if (after) + data->id = g_signal_connect_after (device, name, callback, policy); + else + data->id = g_signal_connect (device, name, callback, policy); data->device = device; priv->dev_ids = g_slist_prepend (priv->dev_ids, data); } @@ -1630,26 +1681,12 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data) { NMPolicy *policy = (NMPolicy *) user_data; - _connect_device_signal (policy, device, "state-changed", device_state_changed); - _connect_device_signal (policy, device, NM_DEVICE_IP4_CONFIG_CHANGED, device_ip4_config_changed); - _connect_device_signal (policy, device, NM_DEVICE_IP6_CONFIG_CHANGED, device_ip6_config_changed); - _connect_device_signal (policy, device, "notify::" NM_DEVICE_AUTOCONNECT, device_autoconnect_changed); - - switch (nm_device_get_device_type (device)) { - case NM_DEVICE_TYPE_WIFI: - _connect_device_signal (policy, device, "access-point-added", wireless_networks_changed); - _connect_device_signal (policy, device, "access-point-removed", wireless_networks_changed); - break; - case NM_DEVICE_TYPE_WIMAX: - _connect_device_signal (policy, device, "nsp-added", nsps_changed); - _connect_device_signal (policy, device, "nsp-removed", nsps_changed); - break; - case NM_DEVICE_TYPE_MODEM: - _connect_device_signal (policy, device, "enable-changed", modem_enabled_changed); - break; - default: - break; - } + /* Connect state-changed with _after, so that the handler is invoked after other handlers. */ + _connect_device_signal (policy, device, "state-changed", device_state_changed, TRUE); + _connect_device_signal (policy, device, NM_DEVICE_IP4_CONFIG_CHANGED, device_ip4_config_changed, FALSE); + _connect_device_signal (policy, device, NM_DEVICE_IP6_CONFIG_CHANGED, device_ip6_config_changed, FALSE); + _connect_device_signal (policy, device, "notify::" NM_DEVICE_AUTOCONNECT, device_autoconnect_changed, FALSE); + _connect_device_signal (policy, device, NM_DEVICE_RECHECK_AUTO_ACTIVATE, device_recheck_auto_activate, FALSE); } static void @@ -1657,15 +1694,10 @@ device_removed (NMManager *manager, NMDevice *device, gpointer user_data) { NMPolicy *policy = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - ActivateData *tmp; GSList *iter; /* Clear any idle callbacks for this device */ - tmp = find_pending_activation (priv->pending_activation_checks, device); - if (tmp) { - priv->pending_activation_checks = g_slist_remove (priv->pending_activation_checks, tmp); - activate_data_free (tmp); - } + clear_pending_activate_check (policy, device); /* Clear any signal handlers for this device */ iter = priv->dev_ids; @@ -1691,13 +1723,12 @@ device_removed (NMManager *manager, NMDevice *device, gpointer user_data) static void vpn_connection_activated (NMPolicy *policy, NMVPNConnection *vpn) { - NMDnsManager *mgr; + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); NMIP4Config *ip4_config; NMIP6Config *ip6_config; const char *ip_iface; - mgr = nm_dns_manager_get (NULL); - nm_dns_manager_begin_updates (mgr, __func__); + nm_dns_manager_begin_updates (priv->dns_manager, __func__); ip_iface = nm_vpn_connection_get_ip_iface (vpn); @@ -1705,81 +1736,58 @@ vpn_connection_activated (NMPolicy *policy, NMVPNConnection *vpn) ip4_config = nm_vpn_connection_get_ip4_config (vpn); if (ip4_config) - nm_dns_manager_add_ip4_config (mgr, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_VPN); + nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_VPN); ip6_config = nm_vpn_connection_get_ip6_config (vpn); if (ip6_config) - nm_dns_manager_add_ip6_config (mgr, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_VPN); + nm_dns_manager_add_ip6_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_VPN); update_routing_and_dns (policy, TRUE); - nm_dns_manager_end_updates (mgr, __func__); - - process_secondaries (policy, NM_ACTIVE_CONNECTION (vpn), TRUE); + nm_dns_manager_end_updates (priv->dns_manager, __func__); } static void vpn_connection_deactivated (NMPolicy *policy, NMVPNConnection *vpn) { - NMDnsManager *mgr; - NMIP4Config *ip4_config, *parent_ip4 = NULL; - NMIP6Config *ip6_config, *parent_ip6 = NULL; - const char *ip_iface; - NMDevice *parent; - - mgr = nm_dns_manager_get (NULL); - nm_dns_manager_begin_updates (mgr, __func__); + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); + NMIP4Config *ip4_config; + NMIP6Config *ip6_config; - ip_iface = nm_vpn_connection_get_ip_iface (vpn); - parent = nm_vpn_connection_get_parent_device (vpn); + nm_dns_manager_begin_updates (priv->dns_manager, __func__); ip4_config = nm_vpn_connection_get_ip4_config (vpn); if (ip4_config) { /* Remove the VPN connection's IP4 config from DNS */ - nm_dns_manager_remove_ip4_config (mgr, ip4_config); - - /* Re-apply routes and addresses of the VPN connection's parent interface, - * which the VPN might have overridden. - */ - if (parent) { - parent_ip4 = nm_device_get_ip4_config (parent); - if (parent_ip4) { - if (!nm_system_apply_ip4_config (nm_device_get_ip_ifindex (parent), - parent_ip4, - nm_device_get_priority (parent), - NM_IP4_COMPARE_FLAG_ADDRESSES | NM_IP4_COMPARE_FLAG_ROUTES)) { - nm_log_err (LOGD_VPN, "failed to re-apply VPN parent device IPv4 addresses and routes."); - } - } - } + nm_dns_manager_remove_ip4_config (priv->dns_manager, ip4_config); } ip6_config = nm_vpn_connection_get_ip6_config (vpn); if (ip6_config) { /* Remove the VPN connection's IP6 config from DNS */ - nm_dns_manager_remove_ip6_config (mgr, ip6_config); - - /* Re-apply routes and addresses of the VPN connection's parent interface, - * which the VPN might have overridden. - */ - if (parent) { - parent_ip6 = nm_device_get_ip6_config (parent); - if (parent_ip6) { - if (!nm_system_apply_ip6_config (nm_device_get_ip_ifindex (parent), - parent_ip6, - nm_device_get_priority (parent), - NM_IP6_COMPARE_FLAG_ADDRESSES | NM_IP6_COMPARE_FLAG_ROUTES)) { - nm_log_err (LOGD_VPN, "failed to re-apply VPN parent device IPv6 addresses and routes."); - } - } - } + nm_dns_manager_remove_ip6_config (priv->dns_manager, ip6_config); } update_routing_and_dns (policy, TRUE); - nm_dns_manager_end_updates (mgr, __func__); + nm_dns_manager_end_updates (priv->dns_manager, __func__); +} - process_secondaries (policy, NM_ACTIVE_CONNECTION (vpn), FALSE); +static void +vpn_connection_state_changed (NMVPNConnection *vpn, + NMVPNConnectionState new_state, + NMVPNConnectionState old_state, + NMVPNConnectionStateReason reason, + NMPolicy *policy) +{ + if (new_state == NM_VPN_CONNECTION_STATE_ACTIVATED) + vpn_connection_activated (policy, vpn); + else if (new_state >= NM_VPN_CONNECTION_STATE_FAILED) { + /* Only clean up IP/DNS if the connection ever got past IP_CONFIG */ + if (old_state >= NM_VPN_CONNECTION_STATE_IP_CONFIG_GET && + old_state <= NM_VPN_CONNECTION_STATE_ACTIVATED) + vpn_connection_deactivated (policy, vpn); + } } static void @@ -1787,18 +1795,12 @@ active_connection_state_changed (NMActiveConnection *active, GParamSpec *pspec, NMPolicy *policy) { - switch (nm_active_connection_get_state (active)) { - case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: - if (NM_IS_VPN_CONNECTION (active)) - vpn_connection_activated (policy, NM_VPN_CONNECTION (active)); - break; - case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED: - if (NM_IS_VPN_CONNECTION (active)) - vpn_connection_deactivated (policy, NM_VPN_CONNECTION (active)); - break; - default: - break; - } + NMActiveConnectionState state = nm_active_connection_get_state (active); + + if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) + process_secondaries (policy, active, TRUE); + else if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) + process_secondaries (policy, active, FALSE); } static void @@ -1806,7 +1808,13 @@ active_connection_added (NMManager *manager, NMActiveConnection *active, gpointer user_data) { - NMPolicy *policy = (NMPolicy *) user_data; + NMPolicy *policy = NM_POLICY (user_data); + + if (NM_IS_VPN_CONNECTION (active)) { + g_signal_connect (active, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED, + G_CALLBACK (vpn_connection_state_changed), + policy); + } g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE, G_CALLBACK (active_connection_state_changed), @@ -1818,9 +1826,14 @@ active_connection_removed (NMManager *manager, NMActiveConnection *active, gpointer user_data) { + NMPolicy *policy = NM_POLICY (user_data); + + g_signal_handlers_disconnect_by_func (active, + vpn_connection_state_changed, + policy); g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, - (NMPolicy *) user_data); + policy); } /**************************************************************************/ @@ -1829,33 +1842,20 @@ static void schedule_activate_all (NMPolicy *policy) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - GSList *iter, *devices; + const GSList *iter; - devices = nm_manager_get_devices (priv->manager); - for (iter = devices; iter; iter = g_slist_next (iter)) - schedule_activate_check (policy, NM_DEVICE (iter->data), 0); + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) + schedule_activate_check (policy, NM_DEVICE (iter->data)); } static void connection_added (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *connection, gpointer user_data) { - set_connection_auto_retries (connection, RETRIES_DEFAULT); - schedule_activate_all ((NMPolicy *) user_data); -} - -static void -connections_loaded (NMSettings *settings, gpointer user_data) -{ - // FIXME: "connections-loaded" signal is emmitted *before* we connect to it - // in nm_policy_new(). So this function is never called. Currently we work around - // that by calling reset_retries_all() in nm_policy_new() - - /* Initialize connections' auto-retries */ - reset_retries_all (settings, NULL); + NMPolicy *policy = NM_POLICY (user_data); - schedule_activate_all ((NMPolicy *) user_data); + schedule_activate_all (policy); } static void @@ -1875,11 +1875,10 @@ firewall_update_zone (NMPolicy *policy, NMConnection *connection) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); NMSettingConnection *s_con = nm_connection_get_setting_connection (connection); - GSList *iter, *devices; + const GSList *iter; - devices = nm_manager_get_devices (priv->manager); /* find dev with passed connection and change zone its interface belongs to */ - for (iter = devices; iter; iter = g_slist_next (iter)) { + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); if ( (nm_device_get_connection (dev) == connection) @@ -1902,20 +1901,22 @@ firewall_started (NMFirewallManager *manager, NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); NMConnection *connection; NMSettingConnection *s_con; - GSList *iter, *devices; + const GSList *iter; - devices = nm_manager_get_devices (priv->manager); /* add interface of each device to correct zone */ - for (iter = devices; iter; iter = g_slist_next (iter)) { + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); connection = nm_device_get_connection (dev); + if (!connection) + continue; + s_con = nm_connection_get_setting_connection (connection); if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) { nm_firewall_manager_add_or_change_zone (priv->fw_manager, nm_device_get_ip_iface (dev), nm_setting_connection_get_zone (s_con), - TRUE, /* add zone */ + FALSE, /* still change zone */ add_or_change_zone_cb, g_object_ref (dev)); } @@ -1934,29 +1935,23 @@ dns_config_changed (NMDnsManager *dns_manager, gpointer user_data) */ /* Stop a lookup thread if any. */ - if (priv->lookup) { - hostname_thread_kill (priv->lookup); - priv->lookup = NULL; + if (priv->lookup_cancellable) { + g_cancellable_cancel (priv->lookup_cancellable); + g_clear_object (&priv->lookup_cancellable); } /* Re-start the hostname lookup thread if we don't have hostname yet. */ - if (priv->lookup_ipv4_addr) { - char buf[INET_ADDRSTRLEN]; - struct in_addr addr = { .s_addr = priv->lookup_ipv4_addr }; - - if (!inet_ntop (AF_INET, &addr, buf, sizeof (buf))) - strcpy (buf, "(unknown)"); - nm_log_dbg (LOGD_DNS, "restarting IPv4 reverse-lookup thread for address %s'", buf); - - priv->lookup = hostname4_thread_new (priv->lookup_ipv4_addr, lookup_callback, policy); - } else if (priv->lookup_ipv6_addr) { - char buf[INET6_ADDRSTRLEN]; - - if (!inet_ntop (AF_INET6, priv->lookup_ipv6_addr, buf, sizeof (buf))) - strcpy (buf, "(unknown)"); - nm_log_dbg (LOGD_DNS, "restarting IPv6 reverse-lookup thread for address %s'", buf); - - priv->lookup = hostname6_thread_new (priv->lookup_ipv6_addr, lookup_callback, policy); + if (priv->lookup_addr) { + char *str = g_inet_address_to_string (priv->lookup_addr); + + nm_log_dbg (LOGD_DNS, "restarting reverse-lookup thread for address %s", str); + g_free (str); + + priv->lookup_cancellable = g_cancellable_new (); + g_resolver_lookup_by_address_async (priv->resolver, + priv->lookup_addr, + priv->lookup_cancellable, + lookup_callback, policy); } } @@ -1969,13 +1964,19 @@ connection_updated (NMSettings *settings, firewall_update_zone (policy, connection); - /* Reset auto retries back to default since connection was updated */ - set_connection_auto_retries (connection, RETRIES_DEFAULT); - schedule_activate_all (policy); } static void +connection_updated_by_user (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data) +{ + /* Reset auto retries back to default since connection was updated */ + nm_settings_connection_reset_autoconnect_retries (connection); +} + +static void _deactivate_if_active (NMManager *manager, NMConnection *connection) { const GSList *active, *iter; @@ -2032,12 +2033,14 @@ secret_agent_registered (NMSettings *settings, NMSecretAgent *agent, gpointer user_data) { + NMPolicy *policy = NM_POLICY (user_data); + /* The registered secret agent may provide some missing secrets. Thus we * reset retries count here and schedule activation, so that the * connections failed due to missing secrets may re-try auto-connection. */ - reset_retries_for_failed_secrets (settings); - schedule_activate_all ((NMPolicy *) user_data); + reset_autoconnect_for_failed_secrets (policy); + schedule_activate_all (policy); } static void @@ -2094,9 +2097,12 @@ nm_policy_new (NMManager *manager, NMSettings *settings) G_CALLBACK (firewall_started), policy); priv->fw_started_id = id; - priv->dns_manager = nm_dns_manager_get (NULL); + priv->dns_manager = nm_dns_manager_get (); + nm_dns_manager_set_initial_hostname (priv->dns_manager, priv->orig_hostname); priv->config_changed_id = g_signal_connect (priv->dns_manager, "config-changed", - G_CALLBACK (dns_config_changed), policy); + G_CALLBACK (dns_config_changed), policy); + + priv->resolver = g_resolver_get_default (); _connect_manager_signal (policy, "state-changed", global_state_changed); _connect_manager_signal (policy, "notify::" NM_MANAGER_HOSTNAME, hostname_changed); @@ -2107,17 +2113,14 @@ nm_policy_new (NMManager *manager, NMSettings *settings) _connect_manager_signal (policy, NM_MANAGER_ACTIVE_CONNECTION_ADDED, active_connection_added); _connect_manager_signal (policy, NM_MANAGER_ACTIVE_CONNECTION_REMOVED, active_connection_removed); - _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTIONS_LOADED, connections_loaded); _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, connection_added); _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, connection_updated); + _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER, connection_updated_by_user); _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, connection_removed); _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, connection_visibility_changed); _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_AGENT_REGISTERED, secret_agent_registered); - /* Initialize connections' auto-retries */ - reset_retries_all (priv->settings, NULL); - initialized = TRUE; return policy; } @@ -2184,17 +2187,16 @@ dispose (GObject *object) NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); const GSList *connections, *iter; - /* Tell any existing hostname lookup thread to die, it'll get cleaned up - * by the lookup thread callback. - */ - if (priv->lookup) { - hostname_thread_kill (priv->lookup); - priv->lookup = NULL; + /* Tell any existing hostname lookup thread to die. */ + if (priv->lookup_cancellable) { + g_cancellable_cancel (priv->lookup_cancellable); + g_clear_object (&priv->lookup_cancellable); } - g_free (priv->lookup_ipv6_addr); + g_clear_object (&priv->lookup_addr); + g_clear_object (&priv->resolver); - g_slist_free_full (priv->pending_activation_checks, (GDestroyNotify) activate_data_free); - priv->pending_activation_checks = NULL; + while (priv->pending_activation_checks) + activate_data_free (priv->pending_activation_checks->data); g_slist_free_full (priv->pending_secondaries, (GDestroyNotify) pending_secondary_data_free); priv->pending_secondaries = NULL; @@ -2207,19 +2209,16 @@ dispose (GObject *object) if (priv->dns_manager) { g_signal_handler_disconnect (priv->dns_manager, priv->config_changed_id); - g_object_unref (priv->dns_manager); priv->dns_manager = NULL; } for (iter = priv->manager_ids; iter; iter = g_slist_next (iter)) g_signal_handler_disconnect (priv->manager, GPOINTER_TO_UINT (iter->data)); - g_slist_free (priv->manager_ids); - priv->manager_ids = NULL; + g_clear_pointer (&priv->manager_ids, g_slist_free); for (iter = priv->settings_ids; iter; iter = g_slist_next (iter)) g_signal_handler_disconnect (priv->settings, GPOINTER_TO_UINT (iter->data)); - g_slist_free (priv->settings_ids); - priv->settings_ids = NULL; + g_clear_pointer (&priv->settings_ids, g_slist_free); for (iter = priv->dev_ids; iter; iter = g_slist_next (iter)) { DeviceSignalId *data = iter->data; @@ -2227,8 +2226,7 @@ dispose (GObject *object) g_signal_handler_disconnect (data->device, data->id); g_slice_free (DeviceSignalId, data); } - g_slist_free (priv->dev_ids); - priv->dev_ids = NULL; + g_clear_pointer (&priv->dev_ids, g_slist_free); /* The manager should have disposed of ActiveConnections already, which * will have called active_connection_removed() and thus we don't need @@ -2242,10 +2240,8 @@ dispose (GObject *object) priv->reset_retries_id = 0; } - g_free (priv->orig_hostname); - priv->orig_hostname = NULL; - g_free (priv->cur_hostname); - priv->cur_hostname = NULL; + g_clear_pointer (&priv->orig_hostname, g_free); + g_clear_pointer (&priv->cur_hostname, g_free); g_clear_object (&priv->settings); |