diff options
Diffstat (limited to 'src/nm-policy.c')
| -rw-r--r-- | src/nm-policy.c | 556 |
1 files changed, 293 insertions, 263 deletions
diff --git a/src/nm-policy.c b/src/nm-policy.c index e56fce0b..8dfb0ab0 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -44,6 +44,7 @@ #include "nm-manager.h" #include "settings/nm-settings.h" #include "settings/nm-settings-connection.h" +#include "settings/nm-agent-manager.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" #include "nm-config.h" @@ -65,7 +66,9 @@ typedef struct { NMManager *manager; NMNetns *netns; NMFirewallManager *firewall_manager; - GSList *pending_activation_checks; + CList pending_activation_checks; + + NMAgentManager *agent_mgr; GHashTable *devices; GHashTable *pending_active_connections; @@ -312,8 +315,9 @@ device_ip6_prefix_delegated (NMDevice *device, NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); IP6PrefixDelegation *delegation = NULL; - const GSList *connections, *iter; guint i; + const CList *tmp_list; + NMActiveConnection *ac; _LOGI (LOGD_IP6, "ipv6-pd: received a prefix %s/%d from %s", nm_utils_inet6_ntop (&prefix->address, NULL), @@ -344,10 +348,10 @@ device_ip6_prefix_delegated (NMDevice *device, * so traversing it from the beginning makes it likely for newly * activated connections that have no subnet assigned to be served * first. That is a simple yet fair policy, which is good. */ - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMDevice *to_device = nm_active_connection_get_device (iter->data); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + NMDevice *to_device; + to_device = nm_active_connection_get_device (ac); if (nm_device_needs_ip6_subnet (to_device)) ip6_subnet_from_delegation (delegation, to_device); } @@ -818,25 +822,25 @@ update_system_hostname (NMPolicy *self, const char *msg) static void update_default_ac (NMPolicy *self, - NMActiveConnection *best, - void (*set_active_func)(NMActiveConnection*, gboolean)) + int addr_family, + NMActiveConnection *best) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const GSList *connections, *iter; + const CList *tmp_list; + NMActiveConnection *ac; /* Clear the 'default[6]' flag on all active connections that aren't the new * default active connection. We'll set the new default after; this ensures * we don't ever have two marked 'default[6]' simultaneously. */ - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - if (NM_ACTIVE_CONNECTION (iter->data) != best) - set_active_func (NM_ACTIVE_CONNECTION (iter->data), FALSE); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + if (ac != best) + nm_active_connection_set_default (ac, addr_family, FALSE); } /* Mark new default active connection */ if (best) - set_active_func (best, TRUE); + nm_active_connection_set_default (best, addr_family, TRUE); } static gpointer @@ -850,19 +854,19 @@ get_best_ip_config (NMPolicy *self, NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); NMDevice *device; gpointer conf; - const GSList *iter; + const CList *tmp_list; + NMActiveConnection *ac; nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - for (iter = nm_manager_get_active_connections (priv->manager); iter; iter = iter->next) { - NMActiveConnection *active = NM_ACTIVE_CONNECTION (iter->data); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { NMVpnConnection *candidate; NMVpnConnectionState vpn_state; - if (!NM_IS_VPN_CONNECTION (active)) + if (!NM_IS_VPN_CONNECTION (ac)) continue; - candidate = NM_VPN_CONNECTION (active); + candidate = NM_VPN_CONNECTION (ac); vpn_state = nm_vpn_connection_get_vpn_state (candidate); if (vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED) @@ -887,7 +891,7 @@ get_best_ip_config (NMPolicy *self, * best metric. */ NM_SET_OUT (out_device, NULL); NM_SET_OUT (out_vpn, candidate); - NM_SET_OUT (out_ac, active); + NM_SET_OUT (out_ac, ac); NM_SET_OUT (out_ip_iface, nm_vpn_connection_get_ip_iface (candidate, TRUE)); return conf; } @@ -919,26 +923,6 @@ get_best_ip_config (NMPolicy *self, } static void -update_ip4_dns (NMPolicy *self, NMDnsManager *dns_mgr) -{ - NMIP4Config *ip4_config; - const char *ip_iface = NULL; - NMVpnConnection *vpn = NULL; - NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; - - ip4_config = get_best_ip_config (self, AF_INET, &ip_iface, NULL, NULL, &vpn); - if (ip4_config) { - if (vpn) - dns_type = NM_DNS_IP_CONFIG_TYPE_VPN; - - /* Tell the DNS manager this config is preferred by re-adding it with - * a different IP config type. - */ - nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, ip4_config, dns_type); - } -} - -static void update_ip4_routing (NMPolicy *self, gboolean force_update) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); @@ -946,6 +930,8 @@ update_ip4_routing (NMPolicy *self, gboolean force_update) NMVpnConnection *vpn = NULL; NMActiveConnection *best_ac = NULL; const char *ip_iface = NULL; + const CList *tmp_list; + NMActiveConnection *ac; /* Note that we might have an IPv4 VPN tunneled over an IPv6-only device, * so we can get (vpn != NULL && best == NULL). @@ -965,23 +951,18 @@ update_ip4_routing (NMPolicy *self, gboolean force_update) return; if (best) { - const GSList *connections, *iter; - - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *active = iter->data; - - if ( NM_IS_VPN_CONNECTION (active) - && nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (active)) - && !nm_active_connection_get_device (active)) - nm_active_connection_set_device (active, best); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + if ( NM_IS_VPN_CONNECTION (ac) + && nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (ac)) + && !nm_active_connection_get_device (ac)) + nm_active_connection_set_device (ac, best); } } if (vpn) best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); - update_default_ac (self, best_ac, nm_active_connection_set_default); + update_default_ac (self, AF_INET, best_ac); if (!nm_g_object_ref_set (&priv->default_device4, best)) return; @@ -997,50 +978,28 @@ static void update_ip6_dns_delegation (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const GSList *connections, *iter; - - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMDevice *device = nm_active_connection_get_device (iter->data); + NMDevice *device; + NMActiveConnection *ac; + const CList *tmp_list; + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + device = nm_active_connection_get_device (ac); if (device && nm_device_needs_ip6_subnet (device)) nm_device_copy_ip6_dns_config (device, priv->default_device6); } } static void -update_ip6_dns (NMPolicy *self, NMDnsManager *dns_mgr) -{ - NMIP6Config *ip6_config; - const char *ip_iface = NULL; - NMVpnConnection *vpn = NULL; - NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; - - ip6_config = get_best_ip_config (self, AF_INET6, &ip_iface, NULL, NULL, &vpn); - if (ip6_config) { - if (vpn) - dns_type = NM_DNS_IP_CONFIG_TYPE_VPN; - - /* Tell the DNS manager this config is preferred by re-adding it with - * a different IP config type. - */ - nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, dns_type); - } - - update_ip6_dns_delegation (self); -} - -static void update_ip6_prefix_delegation (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const GSList *connections, *iter; + NMDevice *device; + NMActiveConnection *ac; + const CList *tmp_list; /* There's new default IPv6 connection, try to get a prefix for everyone. */ - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMDevice *device = nm_active_connection_get_device (iter->data); - + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + device = nm_active_connection_get_device (ac); if (device && nm_device_needs_ip6_subnet (device)) ip6_subnet_from_device (self, priv->default_device6, device); } @@ -1054,6 +1013,8 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) NMVpnConnection *vpn = NULL; NMActiveConnection *best_ac = NULL; const char *ip_iface = NULL; + NMActiveConnection *ac; + const CList *tmp_list; /* Note that we might have an IPv6 VPN tunneled over an IPv4-only device, * so we can get (vpn != NULL && best == NULL). @@ -1073,23 +1034,18 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) return; if (best) { - const GSList *connections, *iter; - - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *active = iter->data; - - if ( NM_IS_VPN_CONNECTION (active) - && nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (active)) - && !nm_active_connection_get_device (active)) - nm_active_connection_set_device (active, best); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + if ( NM_IS_VPN_CONNECTION (ac) + && nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (ac)) + && !nm_active_connection_get_device (ac)) + nm_active_connection_set_device (ac, best); } } if (vpn) best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); - update_default_ac (self, best_ac, nm_active_connection_set_default6); + update_default_ac (self, AF_INET6, best_ac); if (!nm_g_object_ref_set (&priv->default_device6, best)) return; @@ -1104,14 +1060,42 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) } static void +update_ip_dns (NMPolicy *self, int addr_family) +{ + gpointer ip_config; + const char *ip_iface = NULL; + NMVpnConnection *vpn = NULL; + NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; + + nm_assert_addr_family (addr_family); + + ip_config = get_best_ip_config (self, addr_family, &ip_iface, NULL, NULL, &vpn); + if (ip_config) { + if (vpn) + dns_type = NM_DNS_IP_CONFIG_TYPE_VPN; + + /* Tell the DNS manager this config is preferred by re-adding it with + * a different IP config type. + */ + nm_dns_manager_add_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, + ip_iface, + ip_config, + dns_type); + } + + if (addr_family == AF_INET6) + update_ip6_dns_delegation (self); +} + +static void update_routing_and_dns (NMPolicy *self, gboolean force_update) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); nm_dns_manager_begin_updates (priv->dns_manager, __func__); - update_ip4_dns (self, priv->dns_manager); - update_ip6_dns (self, priv->dns_manager); + update_ip_dns (self, AF_INET); + update_ip_dns (self, AF_INET6); update_ip4_routing (self, force_update); update_ip6_routing (self, force_update); @@ -1146,6 +1130,7 @@ check_activating_devices (NMPolicy *self) } typedef struct { + CList pending_lst; NMPolicy *policy; NMDevice *device; guint autoactivate_id; @@ -1154,14 +1139,10 @@ typedef struct { static void activate_data_free (ActivateData *data) { - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (data->policy); - nm_device_remove_pending_action (data->device, NM_PENDING_ACTION_AUTOACTIVATE, TRUE); - priv->pending_activation_checks = g_slist_remove (priv->pending_activation_checks, data); - + c_list_unlink_stale (&data->pending_lst); nm_clear_g_source (&data->autoactivate_id); g_object_unref (data->device); - g_slice_free (ActivateData, data); } @@ -1192,7 +1173,7 @@ pending_ac_state_changed (NMActiveConnection *ac, guint state, guint reason, NMP * loop. */ con = nm_active_connection_get_settings_connection (ac); - nm_settings_connection_autoconnect_blocked_reason_set (con, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED); + nm_settings_connection_autoconnect_blocked_reason_set (con, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, TRUE); schedule_activate_check (self, nm_active_connection_get_device (ac)); /* Cleanup */ @@ -1213,7 +1194,7 @@ auto_activate_device (NMPolicy *self, gs_free char *specific_object = NULL; gs_free NMSettingsConnection **connections = NULL; guint i, len; - GError *error = NULL; + gs_free_error GError *error = NULL; NMAuthSubject *subject; NMActiveConnection *ac; @@ -1243,9 +1224,7 @@ auto_activate_device (NMPolicy *self, NMSettingConnection *s_con; const char *permission; - if ( !nm_settings_connection_is_visible (candidate) - || nm_settings_connection_autoconnect_retries_get (candidate) == 0 - || nm_settings_connection_autoconnect_blocked_reason_get (candidate) != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) + if (nm_settings_connection_autoconnect_is_blocked (candidate)) continue; s_con = nm_connection_get_setting_connection (NM_CONNECTION (candidate)); @@ -1278,13 +1257,12 @@ auto_activate_device (NMPolicy *self, NM_ACTIVATION_TYPE_MANAGED, &error); if (!ac) { - _LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: (%d) %s", + _LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: %s", nm_settings_connection_get_id (best_connection), - error->code, error->message); - g_error_free (error); nm_settings_connection_autoconnect_blocked_reason_set (best_connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED); + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, + TRUE); schedule_activate_check (self, device); return; } @@ -1318,13 +1296,14 @@ auto_activate_device_cb (gpointer user_data) } static ActivateData * -find_pending_activation (GSList *list, NMDevice *device) +find_pending_activation (NMPolicy *self, NMDevice *device) { - GSList *iter; + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + ActivateData *data; - for (iter = list; iter; iter = g_slist_next (iter)) { - if (((ActivateData *) iter->data)->device == device) - return iter->data; + c_list_for_each_entry (data, &priv->pending_activation_checks, pending_lst) { + if (data->device == device) + return data; } return NULL; } @@ -1422,48 +1401,56 @@ hostname_changed (NMHostnameManager *hostname_manager, GParamSpec *pspec, gpoint update_system_hostname (self, "hostname changed"); } -static void -reset_autoconnect_all (NMPolicy *self, NMDevice *device) +static gboolean +reset_autoconnect_all (NMPolicy *self, + NMDevice *device, /* if present, only reset connections compatible with @device */ + gboolean only_no_secrets) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - gs_free NMSettingsConnection **connections = NULL; + NMSettingsConnection *const*connections = NULL; guint i; + gboolean changed; - if (device) { - _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections on %s", - nm_device_get_iface (device)); - } else - _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections"); + _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections%s%s%s", + device ? " on " : "", + device ? nm_device_get_iface (device) : "", + only_no_secrets ? " (only clear no-secrets flag)" : ""); - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *connection = connections[i]; - if (!device || nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) { - nm_settings_connection_autoconnect_retries_reset (connection); - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); - } - } -} - -static void -reset_autoconnect_for_failed_secrets (NMPolicy *self) -{ - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - gs_free NMSettingsConnection **connections = NULL; - guint i; - - _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections with failed secrets"); - - connections = nm_settings_get_connections_sorted (priv->settings, NULL); - for (i = 0; connections[i]; i++) { - NMSettingsConnection *connection = connections[i]; + if ( device + && !nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) + continue; - if (nm_settings_connection_autoconnect_blocked_reason_get (connection) == NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS) { + if (only_no_secrets) { + /* we only reset the no-secrets blocked flag. */ + if (nm_settings_connection_autoconnect_blocked_reason_set (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, + FALSE)) { + /* maybe the connection is still blocked afterwards for other reasons + * and in the larger picture nothing changed. But it's too complicated + * to find out exactly. Just assume, something changed to be sure. */ + if (!nm_settings_connection_autoconnect_is_blocked (connection)) + changed = TRUE; + } + } else { + /* we reset the tries-count and any blocked-reason */ + if (nm_settings_connection_autoconnect_retries_get (connection) == 0) + changed = TRUE; nm_settings_connection_autoconnect_retries_reset (connection); - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); + + if (nm_settings_connection_autoconnect_blocked_reason_set (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL + & ~NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, + FALSE)) { + if (!nm_settings_connection_autoconnect_is_blocked (connection)) + changed = TRUE; + } } } + return changed; } static void @@ -1478,7 +1465,7 @@ sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) /* Reset retries on all connections so they'll checked on wakeup */ if (sleeping || !enabled) - reset_autoconnect_all (self, NULL); + reset_autoconnect_all (self, NULL, FALSE); } static void @@ -1486,7 +1473,8 @@ schedule_activate_check (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); ActivateData *data; - const GSList *active_connections, *iter; + NMActiveConnection *ac; + const CList *tmp_list; if (nm_manager_get_state (priv->manager) == NM_STATE_ASLEEP) return; @@ -1494,12 +1482,11 @@ schedule_activate_check (NMPolicy *self, NMDevice *device) if (!nm_device_autoconnect_allowed (device)) return; - if (find_pending_activation (priv->pending_activation_checks, device)) + if (find_pending_activation (self, 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) + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + if (nm_active_connection_get_device (ac) == device) return; } @@ -1509,18 +1496,7 @@ schedule_activate_check (NMPolicy *self, NMDevice *device) data->policy = self; data->device = g_object_ref (device); data->autoactivate_id = g_idle_add (auto_activate_device_cb, data); - priv->pending_activation_checks = g_slist_append (priv->pending_activation_checks, data); -} - -static void -clear_pending_activate_check (NMPolicy *self, NMDevice *device) -{ - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - ActivateData *data; - - data = find_pending_activation (priv->pending_activation_checks, device); - if (data && data->autoactivate_id) - activate_data_free (data); + c_list_link_tail (&priv->pending_activation_checks, &data->pending_lst); } static gboolean @@ -1528,7 +1504,7 @@ reset_connections_retries (gpointer user_data) { NMPolicy *self = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - gs_free NMSettingsConnection **connections = NULL; + NMSettingsConnection *const*connections = NULL; guint i; gint32 con_stamp, min_stamp, now; gboolean changed = FALSE; @@ -1537,11 +1513,11 @@ reset_connections_retries (gpointer user_data) min_stamp = 0; now = nm_utils_get_monotonic_timestamp_s (); - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *connection = connections[i]; - con_stamp = nm_settings_connection_autoconnect_blocked_until_get (connection); + con_stamp = nm_settings_connection_autoconnect_retries_blocked_until (connection); if (con_stamp == 0) continue; @@ -1564,6 +1540,29 @@ reset_connections_retries (gpointer user_data) } static void +_connection_autoconnect_retries_set (NMPolicy *self, + NMSettingsConnection *connection, + int tries) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + + nm_assert (NM_IS_SETTINGS_CONNECTION (connection)); + nm_assert (tries >= 0); + + nm_settings_connection_autoconnect_retries_set (connection, tries); + + if (tries == 0) { + /* Schedule a handler to reset retries count */ + if (!priv->reset_retries_id) { + gint32 retry_time = nm_settings_connection_autoconnect_retries_blocked_until (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, self); + } + } +} + +static void activate_slave_connections (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); @@ -1571,7 +1570,8 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) guint i; NMActRequest *req; gboolean internal_activation = FALSE; - gs_free NMSettingsConnection **connections = NULL; + NMSettingsConnection *const*connections; + gboolean changed; master_device = nm_device_get_iface (device); g_assert (master_device); @@ -1595,38 +1595,37 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) internal_activation = subject && nm_auth_subject_is_internal (subject); } - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + changed = FALSE; + connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { - NMConnection *slave; + NMSettingsConnection *connection = connections[i]; NMSettingConnection *s_slave_con; const char *slave_master; - slave = NM_CONNECTION (connections[i]); - - s_slave_con = nm_connection_get_setting_connection (slave); - g_assert (s_slave_con); + s_slave_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); slave_master = nm_setting_connection_get_master (s_slave_con); if (!slave_master) continue; + if (!NM_IN_STRSET (slave_master, master_device, + master_uuid_applied, + master_uuid_settings)) + continue; - if ( nm_streq0 (slave_master, master_device) - || nm_streq0 (slave_master, master_uuid_applied) - || nm_streq0 (slave_master, master_uuid_settings)) { - NMSettingsConnection *settings = NM_SETTINGS_CONNECTION (slave); - NMSettingsAutoconnectBlockedReason reason; - - if (!internal_activation) - nm_settings_connection_autoconnect_retries_reset (settings); - - reason = nm_settings_connection_autoconnect_blocked_reason_get (settings); - if (reason == NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED) { - reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE; - nm_settings_connection_autoconnect_blocked_reason_set (settings, reason); - } + if (!internal_activation) { + if (nm_settings_connection_autoconnect_retries_get (connection) == 0) + changed = TRUE; + nm_settings_connection_autoconnect_retries_reset (connection); + } + if (nm_settings_connection_autoconnect_blocked_reason_set (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, + FALSE)) { + if (!nm_settings_connection_autoconnect_is_blocked (connection)) + changed = TRUE; } } - schedule_activate_all (self); + if (changed) + schedule_activate_all (self); } static gboolean @@ -1711,9 +1710,7 @@ device_state_changed (NMDevice *device, NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); NMActiveConnection *ac; - NMSettingsConnection *connection = nm_device_get_settings_connection (device); - const char *ip_iface = nm_device_get_ip_iface (device); NMIP4Config *ip4_config; NMIP6Config *ip6_config; @@ -1734,7 +1731,8 @@ device_state_changed (NMDevice *device, */ if (connection) { nm_settings_connection_autoconnect_blocked_reason_set (connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED); + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, + TRUE); } break; default: @@ -1749,36 +1747,40 @@ device_state_changed (NMDevice *device, if ( connection && old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_ACTIVATED) { + gboolean block_no_secrets = FALSE; int tries; + guint64 con_v; - tries = nm_settings_connection_autoconnect_retries_get (connection); if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_NO_SECRETS) { + /* we want to block the connection from auto-connect if it failed due to no-secrets. + * However, if a secret-agent registered, since the connection made the last + * secret-request, we do not block it. The new secret-agent might not yet + * been consulted, and it may be able to provide the secrets. + * + * We detect this by using a version-id of the agent-manager, which increments + * whenever new agents register. */ + con_v = nm_settings_connection_get_last_secret_agent_version_id (connection); + if ( con_v == 0 + || con_v != nm_agent_manager_get_agent_version_id (priv->agent_mgr)) + block_no_secrets = TRUE; + } + + if (block_no_secrets) { _LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets", nm_settings_connection_get_id (connection)); - - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS); - } else if (tries != 0) { + nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, TRUE); + } else { + tries = nm_settings_connection_autoconnect_retries_get (connection); if (tries > 0) { _LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left", - nm_settings_connection_get_id (connection), tries); - nm_settings_connection_autoconnect_retries_set (connection, --tries); - } else { + nm_settings_connection_get_id (connection), tries - 1); + _connection_autoconnect_retries_set (self, connection, tries - 1); + } else if (tries != 0) { _LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; infinite tries left", nm_settings_connection_get_id (connection)); } } - if (nm_settings_connection_autoconnect_retries_get (connection) == 0) { - _LOGI (LOGD_DEVICE, "disabling autoconnect for connection '%s'.", - nm_settings_connection_get_id (connection)); - /* Schedule a handler to reset retries count */ - if (!priv->reset_retries_id) { - gint32 retry_time = nm_settings_connection_autoconnect_blocked_until_get (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, self); - } - } nm_connection_clear_secrets (NM_CONNECTION (connection)); } break; @@ -1800,10 +1802,10 @@ device_state_changed (NMDevice *device, ip4_config = nm_device_get_ip4_config (device); if (ip4_config) - nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); ip6_config = nm_device_get_ip6_config (device); if (ip6_config) - nm_dns_manager_add_ip6_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); update_routing_and_dns (self, FALSE); @@ -1815,13 +1817,25 @@ device_state_changed (NMDevice *device, update_routing_and_dns (self, FALSE); break; case NM_DEVICE_STATE_DEACTIVATING: - if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_USER_REQUESTED) { - if (connection) { - /* The connection was deactivated, so block just this connection */ - _LOGD (LOGD_DEVICE, "blocking autoconnect of connection '%s' by user request", - nm_settings_connection_get_id (connection)); - nm_settings_connection_autoconnect_blocked_reason_set (connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST); + if (connection) { + NMSettingsAutoconnectBlockedReason blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE; + + switch (nm_device_state_reason_check (reason)) { + case NM_DEVICE_STATE_REASON_USER_REQUESTED: + blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST; + break; + case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED: + blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED; + break; + default: + break; + } + if (blocked_reason != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) { + _LOGD (LOGD_DEVICE, "blocking autoconnect of connection '%s': %s", + nm_settings_connection_get_id (connection), + NM_UTILS_LOOKUP_STR (nm_device_state_reason_to_str, + nm_device_state_reason_check (reason))); + nm_settings_connection_autoconnect_blocked_reason_set (connection, blocked_reason, TRUE); } } ip6_remove_device_prefix_delegations (self, device); @@ -1832,7 +1846,7 @@ device_state_changed (NMDevice *device, */ if ( nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CARRIER && old_state == NM_DEVICE_STATE_UNAVAILABLE) - reset_autoconnect_all (self, device); + reset_autoconnect_all (self, device, FALSE); if (old_state > NM_DEVICE_STATE_DISCONNECTED) update_routing_and_dns (self, FALSE); @@ -1858,7 +1872,7 @@ device_state_changed (NMDevice *device, case NM_DEVICE_STATE_IP_CONFIG: /* We must have secrets if we got here. */ if (connection) - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); + nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL, FALSE); break; case NM_DEVICE_STATE_SECONDARIES: if (connection) @@ -1903,17 +1917,17 @@ device_ip4_config_changed (NMDevice *device, if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { if (old_config) - nm_dns_manager_remove_ip4_config (priv->dns_manager, old_config); + nm_dns_manager_remove_ip_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); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); } - update_ip4_dns (self, priv->dns_manager); + update_ip_dns (self, AF_INET); update_ip4_routing (self, TRUE); update_system_hostname (self, "ip4 conf"); } else { /* Old configs get removed immediately */ if (old_config) - nm_dns_manager_remove_ip4_config (priv->dns_manager, old_config); + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -1939,17 +1953,17 @@ device_ip6_config_changed (NMDevice *device, if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { if (old_config) - nm_dns_manager_remove_ip6_config (priv->dns_manager, old_config); + nm_dns_manager_remove_ip_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); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); } - update_ip6_dns (self, priv->dns_manager); + update_ip_dns (self, AF_INET6); update_ip6_routing (self, TRUE); update_system_hostname (self, "ip6 conf"); } else { /* Old configs get removed immediately */ if (old_config) - nm_dns_manager_remove_ip6_config (priv->dns_manager, old_config); + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -2021,13 +2035,16 @@ device_removed (NMManager *manager, NMDevice *device, gpointer user_data) { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); + ActivateData *data; /* XXX is this needed? The delegations are cleaned up * on transition to deactivated too. */ ip6_remove_device_prefix_delegations (self, device); /* Clear any idle callbacks for this device */ - clear_pending_activate_check (self, device); + data = find_pending_activation (self, device); + if (data && data->autoactivate_id) + activate_data_free (data); if (g_hash_table_remove (priv->devices, device)) devices_list_unregister (self, device); @@ -2055,11 +2072,11 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn) ip4_config = nm_vpn_connection_get_ip4_config (vpn); if (ip4_config) - nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_VPN); + nm_dns_manager_add_ip_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 (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_VPN); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_VPN); update_routing_and_dns (self, TRUE); @@ -2078,13 +2095,13 @@ vpn_connection_deactivated (NMPolicy *self, NMVpnConnection *vpn) 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 (priv->dns_manager, ip4_config); + nm_dns_manager_remove_ip_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 (priv->dns_manager, ip6_config); + nm_dns_manager_remove_ip_config (priv->dns_manager, ip6_config); } update_routing_and_dns (self, TRUE); @@ -2317,19 +2334,21 @@ connection_updated (NMSettings *settings, } static void -_deactivate_if_active (NMManager *manager, NMSettingsConnection *connection) +_deactivate_if_active (NMPolicy *self, NMSettingsConnection *connection) { - const GSList *active, *iter; + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + NMActiveConnection *ac; + const CList *tmp_list; + GError *error = NULL; + + nm_assert (NM_IS_SETTINGS_CONNECTION (connection)); - active = nm_manager_get_active_connections (manager); - for (iter = active; iter; iter = g_slist_next (iter)) { - NMActiveConnection *ac = iter->data; + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { NMActiveConnectionState state = nm_active_connection_get_state (ac); - GError *error = NULL; - if (nm_active_connection_get_settings_connection (ac) == connection && - (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { - if (!nm_manager_deactivate_connection (manager, + if ( nm_active_connection_get_settings_connection (ac) == connection + && (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { + if (!nm_manager_deactivate_connection (priv->manager, ac, NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, &error)) { @@ -2349,22 +2368,25 @@ connection_removed (NMSettings *settings, gpointer user_data) { NMPolicyPrivate *priv = user_data; + NMPolicy *self = _PRIV_TO_SELF (priv); - _deactivate_if_active (priv->manager, connection); + _deactivate_if_active (self, connection); } static void -connection_visibility_changed (NMSettings *settings, - NMSettingsConnection *connection, - gpointer user_data) +connection_flags_changed (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data) { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); - if (nm_settings_connection_is_visible (connection)) - schedule_activate_all (self); - else - _deactivate_if_active (priv->manager, connection); + if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) { + if (!nm_settings_connection_autoconnect_is_blocked (connection)) + schedule_activate_all (self); + } else + _deactivate_if_active (self, connection); } static void @@ -2372,15 +2394,14 @@ secret_agent_registered (NMSettings *settings, NMSecretAgent *agent, gpointer user_data) { - NMPolicyPrivate *priv = user_data; - NMPolicy *self = _PRIV_TO_SELF (priv); + NMPolicy *self = 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_autoconnect_for_failed_secrets (self); - schedule_activate_all (self); + if (reset_autoconnect_all (self, NULL, TRUE)) + schedule_activate_all (self); } NMDevice * @@ -2476,6 +2497,8 @@ nm_policy_init (NMPolicy *self) NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); const char *hostname_mode; + c_list_init (&priv->pending_activation_checks); + priv->netns = g_object_ref (nm_netns_get ()); priv->hostname_manager = g_object_ref (nm_hostname_manager_get ()); @@ -2516,6 +2539,8 @@ constructed (GObject *object) _LOGT (LOGD_DNS, "hostname-original: set to %s%s%s", NM_PRINT_FMT_QUOTE_STRING (priv->orig_hostname)); + priv->agent_mgr = g_object_ref (nm_agent_manager_get ()); + priv->firewall_manager = g_object_ref (nm_firewall_manager_get ()); g_signal_connect (priv->firewall_manager, NM_FIREWALL_MANAGER_STATE_CHANGED, G_CALLBACK (firewall_state_changed), self); @@ -2536,11 +2561,12 @@ constructed (GObject *object) g_signal_connect (priv->manager, NM_MANAGER_ACTIVE_CONNECTION_ADDED, (GCallback) active_connection_added, priv); g_signal_connect (priv->manager, NM_MANAGER_ACTIVE_CONNECTION_REMOVED, (GCallback) active_connection_removed, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, (GCallback) connection_added, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, (GCallback) connection_updated, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, (GCallback) connection_removed, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, (GCallback) connection_visibility_changed, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_AGENT_REGISTERED, (GCallback) secret_agent_registered, priv); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, (GCallback) connection_added, priv); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, (GCallback) connection_updated, priv); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, (GCallback) connection_removed, priv); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED, (GCallback) connection_flags_changed, priv); + + g_signal_connect (priv->agent_mgr, NM_AGENT_MANAGER_AGENT_REGISTERED, G_CALLBACK (secret_agent_registered), self); G_OBJECT_CLASS (nm_policy_parent_class)->constructed (object); @@ -2564,9 +2590,9 @@ dispose (GObject *object) { NMPolicy *self = NM_POLICY (object); NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const GSList *connections; GHashTableIter h_iter; NMDevice *device; + ActivateData *data, *data_safe; nm_clear_g_cancellable (&priv->lookup.cancellable); g_clear_object (&priv->lookup.addr); @@ -2578,8 +2604,8 @@ dispose (GObject *object) nm_clear_g_object (&priv->activating_device6); g_clear_pointer (&priv->pending_active_connections, g_hash_table_unref); - while (priv->pending_activation_checks) - activate_data_free (priv->pending_activation_checks->data); + c_list_for_each_entry_safe (data, data_safe, &priv->pending_activation_checks, pending_lst) + activate_data_free (data); g_slist_free_full (priv->pending_secondaries, (GDestroyNotify) pending_secondary_data_free); priv->pending_secondaries = NULL; @@ -2589,6 +2615,11 @@ dispose (GObject *object) g_clear_object (&priv->firewall_manager); } + if (priv->agent_mgr) { + g_signal_handlers_disconnect_by_func (priv->agent_mgr, secret_agent_registered, self); + g_clear_object (&priv->agent_mgr); + } + if (priv->dns_manager) { nm_clear_g_signal_handler (priv->dns_manager, &priv->config_changed_id); g_clear_object (&priv->dns_manager); @@ -2604,8 +2635,7 @@ dispose (GObject *object) * will have called active_connection_removed() and thus we don't need * to clean anything up. Assert that this is TRUE. */ - connections = nm_manager_get_active_connections (priv->manager); - g_assert (connections == NULL); + nm_assert (c_list_is_empty (nm_manager_get_active_connections (priv->manager))); nm_clear_g_source (&priv->reset_retries_id); nm_clear_g_source (&priv->schedule_activate_all_id); |