diff options
author | Thomas Haller <thaller@redhat.com> | 2017-11-27 15:50:38 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-11-27 15:50:38 +0100 |
commit | 2c3dccfd28f207cfce5b81ac27960c50a4d25bfe (patch) | |
tree | df292c313ebe01760ba2a66afed5a5c9ef6251a4 | |
parent | 1e572ebf87b44513f5c4ede266f7c2b8113b3cb6 (diff) | |
parent | e2c8ef45ac9fba8d4f5722ab10831bf42085a110 (diff) | |
download | NetworkManager-2c3dccfd28f207cfce5b81ac27960c50a4d25bfe.tar.gz |
core: merge branch 'th/user-block-autoconnect-rh1401515'
Related: https://bugzilla.redhat.com/show_bug.cgi?id=1401515
https://bugzilla.gnome.org/show_bug.cgi?id=790571
-rw-r--r-- | src/devices/nm-device.c | 2 | ||||
-rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 4 | ||||
-rw-r--r-- | src/nm-act-request.c | 12 | ||||
-rw-r--r-- | src/nm-active-connection.c | 63 | ||||
-rw-r--r-- | src/nm-active-connection.h | 14 | ||||
-rw-r--r-- | src/nm-checkpoint.c | 14 | ||||
-rw-r--r-- | src/nm-config-data.c | 24 | ||||
-rw-r--r-- | src/nm-config-data.h | 2 | ||||
-rw-r--r-- | src/nm-config.h | 1 | ||||
-rw-r--r-- | src/nm-manager.c | 220 | ||||
-rw-r--r-- | src/nm-manager.h | 15 | ||||
-rw-r--r-- | src/nm-policy.c | 433 | ||||
-rw-r--r-- | src/settings/nm-agent-manager.c | 16 | ||||
-rw-r--r-- | src/settings/nm-agent-manager.h | 4 | ||||
-rw-r--r-- | src/settings/nm-secret-agent.c | 7 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.c | 392 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.h | 55 | ||||
-rw-r--r-- | src/settings/nm-settings.c | 63 | ||||
-rw-r--r-- | src/settings/nm-settings.h | 8 | ||||
-rw-r--r-- | src/vpn/nm-vpn-connection.c | 4 |
20 files changed, 720 insertions, 633 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f8c2adfd19..f1643ea772 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -12446,7 +12446,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) nm_assert (priv->needs_ip6_subnet == FALSE); if (priv->act_request) { - nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE); + nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), AF_INET, FALSE); priv->master_ready_handled = FALSE; nm_clear_g_signal_handler (priv->act_request, &priv->master_ready_id); diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index b13ae2c77e..bf021095a5 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -1428,8 +1428,8 @@ build_hidden_probe_list (NMDeviceWifi *self) connections = nm_settings_get_connections_clone (nm_device_get_settings ((NMDevice *) self), &len, - hidden_filter_func, - NULL); + hidden_filter_func, NULL, + NULL, NULL); if (!connections[0]) return NULL; diff --git a/src/nm-act-request.c b/src/nm-act-request.c index 25a1dd9b4f..164f44d2cf 100644 --- a/src/nm-act-request.c +++ b/src/nm-act-request.c @@ -96,7 +96,7 @@ struct _NMActRequestGetSecretsCallId { NMActRequest *self; NMActRequestSecretsFunc callback; gpointer callback_data; - NMSettingsConnectionCallId call_id; + NMSettingsConnectionCallId *call_id; bool has_ref; }; @@ -113,7 +113,7 @@ _get_secrets_call_id_free (NMActRequestGetSecretsCallId *call_id) static void get_secrets_cb (NMSettingsConnection *connection, - NMSettingsConnectionCallId call_id_s, + NMSettingsConnectionCallId *call_id_s, const char *agent_username, const char *setting_name, GError *error, @@ -172,7 +172,7 @@ nm_act_request_get_secrets (NMActRequest *self, { NMActRequestPrivate *priv; NMActRequestGetSecretsCallId *call_id; - NMSettingsConnectionCallId call_id_s; + NMSettingsConnectionCallId *call_id_s; NMSettingsConnection *settings_connection; NMConnection *applied_connection; const char *hints[2] = { hint, NULL }; @@ -454,10 +454,8 @@ device_state_changed (NMActiveConnection *active, } if ( ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED - || ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) { - nm_active_connection_set_default (active, FALSE); - nm_active_connection_set_default6 (active, FALSE); - } + || ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) + nm_active_connection_set_default (active, AF_UNSPEC, FALSE); nm_active_connection_set_state (active, ac_state, ac_state_reason); } diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 002f11f7e9..c27f6548eb 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -494,53 +494,46 @@ nm_active_connection_set_specific_object (NMActiveConnection *self, } void -nm_active_connection_set_default (NMActiveConnection *self, gboolean is_default) +nm_active_connection_set_default (NMActiveConnection *self, + int addr_family, + gboolean is_default) { NMActiveConnectionPrivate *priv; g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); + nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6)); is_default = !!is_default; priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (priv->is_default == is_default) - return; - - priv->is_default = is_default; - _notify (self, PROP_DEFAULT); + if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) { + if (priv->is_default != is_default) { + priv->is_default = is_default; + _notify (self, PROP_DEFAULT); + } + } + if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) { + if (priv->is_default6 != is_default) { + priv->is_default6 = is_default; + _notify (self, PROP_DEFAULT6); + } + } } gboolean -nm_active_connection_get_default (NMActiveConnection *self) -{ - g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); - - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default; -} - -void -nm_active_connection_set_default6 (NMActiveConnection *self, gboolean is_default6) +nm_active_connection_get_default (NMActiveConnection *self, int addr_family) { NMActiveConnectionPrivate *priv; - g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); - - is_default6 = !!is_default6; - - priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (priv->is_default6 == is_default6) - return; - - priv->is_default6 = is_default6; - _notify (self, PROP_DEFAULT6); -} - -gboolean -nm_active_connection_get_default6 (NMActiveConnection *self) -{ g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); + nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default6; + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + switch (addr_family) { + case AF_INET: return priv->is_default; + case AF_INET6: return priv->is_default6; + default: return priv->is_default || priv->is_default6; + } } NMAuthSubject * @@ -1263,10 +1256,10 @@ set_property (GObject *object, guint prop_id, priv->specific_object = g_strdup (tmp); break; case PROP_DEFAULT: - priv->is_default = !!g_value_get_boolean (value); + priv->is_default = g_value_get_boolean (value); break; case PROP_DEFAULT6: - priv->is_default6 = !!g_value_get_boolean (value); + priv->is_default6 = g_value_get_boolean (value); break; case PROP_VPN: priv->vpn = g_value_get_boolean (value); @@ -1289,6 +1282,8 @@ nm_active_connection_init (NMActiveConnection *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate); self->_priv = priv; + c_list_init (&self->active_connections_lst); + _LOGT ("creating"); priv->activation_type = NM_ACTIVATION_TYPE_MANAGED; @@ -1331,6 +1326,8 @@ dispose (GObject *object) NMActiveConnection *self = NM_ACTIVE_CONNECTION (object); NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + nm_assert (!c_list_is_linked (&self->active_connections_lst)); + _LOGD ("disposing"); if (priv->chain) { diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 5562b42f07..5ede2b04ff 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -24,6 +24,8 @@ #include "nm-exported-object.h" #include "nm-connection.h" +#include "nm-utils/c-list.h" + #define NM_TYPE_ACTIVE_CONNECTION (nm_active_connection_get_type ()) #define NM_ACTIVE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnection)) #define NM_ACTIVE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionClass)) @@ -71,6 +73,10 @@ struct _NMActiveConnectionPrivate; struct _NMActiveConnection { NMExportedObject parent; struct _NMActiveConnectionPrivate *_priv; + + /* active connection can be tracked in a list by NMManager. This is + * the list node. */ + CList active_connections_lst; }; typedef struct { @@ -131,14 +137,10 @@ void nm_active_connection_set_specific_object (NMActiveConnection *self const char *specific_object); void nm_active_connection_set_default (NMActiveConnection *self, + int addr_family, gboolean is_default); -gboolean nm_active_connection_get_default (NMActiveConnection *self); - -void nm_active_connection_set_default6 (NMActiveConnection *self, - gboolean is_default6); - -gboolean nm_active_connection_get_default6 (NMActiveConnection *self); +gboolean nm_active_connection_get_default (NMActiveConnection *self, int addr_family); NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *self); diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index 54b577642e..af56bf26e6 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -125,10 +125,10 @@ find_settings_connection (NMCheckpoint *self, gboolean *need_activation) { NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); - const GSList *active_connections, *iter; - NMActiveConnection *active = NULL; + NMActiveConnection *active; NMSettingsConnection *connection; const char *uuid, *ac_uuid; + const CList *tmp_clist; *need_activation = FALSE; *need_update = FALSE; @@ -149,9 +149,7 @@ find_settings_connection (NMCheckpoint *self, } /* ... is active, ... */ - active_connections = nm_manager_get_active_connections (priv->manager); - for (iter = active_connections; iter; iter = g_slist_next (iter)) { - active = iter->data; + nm_manager_for_each_active_connection (priv->manager, active, tmp_clist) { ac_uuid = nm_settings_connection_get_uuid (nm_active_connection_get_settings_connection (active)); if (nm_streq (uuid, ac_uuid)) { _LOGT ("rollback: connection %s is active", uuid); @@ -159,7 +157,7 @@ find_settings_connection (NMCheckpoint *self, } } - if (!iter) { + if (!active) { _LOGT ("rollback: connection %s is not active", uuid); *need_activation = TRUE; return connection; @@ -335,7 +333,9 @@ next_dev: guint i; g_return_val_if_fail (priv->connection_uuids, NULL); - list = nm_settings_get_connections_sorted (nm_settings_get (), NULL); + list = nm_settings_get_connections_clone (nm_settings_get (), NULL, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; list[i]; i++) { con = list[i]; diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 5b06e00a16..00e5c635b5 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -95,6 +95,8 @@ typedef struct { guint interval; } connectivity; + int autoconnect_retries_default; + struct { char **arr; GSList *specs; @@ -275,6 +277,14 @@ nm_config_data_get_connectivity_response (const NMConfigData *self) return NM_CONFIG_DATA_GET_PRIVATE (self)->connectivity.response; } +int +nm_config_data_get_autoconnect_retries_default (const NMConfigData *self) +{ + g_return_val_if_fail (self, FALSE); + + return NM_CONFIG_DATA_GET_PRIVATE (self)->autoconnect_retries_default; +} + const char *const* nm_config_data_get_no_auto_default (const NMConfigData *self) { @@ -1527,7 +1537,7 @@ constructed (GObject *object) { NMConfigData *self = NM_CONFIG_DATA (object); NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self); - char *interval; + char *str; priv->keyfile = _merge_keyfiles (priv->keyfile_user, priv->keyfile_intern); @@ -1538,13 +1548,15 @@ constructed (GObject *object) priv->connectivity.uri = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", NULL)); priv->connectivity.response = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", NULL); + str = nm_config_keyfile_get_value (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_AUTOCONNECT_RETRIES_DEFAULT, NM_CONFIG_GET_VALUE_NONE); + priv->autoconnect_retries_default = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXINT32, 4); + g_free (str); + /* On missing config value, fallback to 300. On invalid value, disable connectivity checking by setting * the interval to zero. */ - interval = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", NULL); - priv->connectivity.interval = interval - ? _nm_utils_ascii_str_to_int64 (interval, 10, 0, G_MAXUINT, 0) - : NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL; - g_free (interval); + str = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", NULL); + priv->connectivity.interval = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT, NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL); + g_free (str); priv->dns_mode = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "dns", NULL)); priv->rc_manager = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "rc-manager", NULL)); diff --git a/src/nm-config-data.h b/src/nm-config-data.h index 3efe4259d5..3092a87f6c 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -165,6 +165,8 @@ const char *nm_config_data_get_connectivity_uri (const NMConfigData *config_data guint nm_config_data_get_connectivity_interval (const NMConfigData *config_data); const char *nm_config_data_get_connectivity_response (const NMConfigData *config_data); +int nm_config_data_get_autoconnect_retries_default (const NMConfigData *config_data); + const char *const*nm_config_data_get_no_auto_default (const NMConfigData *config_data); gboolean nm_config_data_get_no_auto_default_for_device (const NMConfigData *self, NMDevice *device); diff --git a/src/nm-config.h b/src/nm-config.h index 47e929884c..17912185f7 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -60,6 +60,7 @@ #define NM_CONFIG_KEYFILE_GROUP_IFNET "ifnet" #define NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT "auth-polkit" +#define NM_CONFIG_KEYFILE_KEY_MAIN_AUTOCONNECT_RETRIES_DEFAULT "autoconnect-retries-default" #define NM_CONFIG_KEYFILE_KEY_MAIN_DHCP "dhcp" #define NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG "debug" #define NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE "hostname-mode" diff --git a/src/nm-manager.c b/src/nm-manager.c index 1ab6e39e01..d4d4ba610c 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -114,7 +114,7 @@ typedef struct { GArray *capabilities; - GSList *active_connections; + CList active_connections_lst_head; GSList *authorizing_connections; guint ac_cleanup_id; NMActiveConnection *primary_connection; @@ -314,39 +314,38 @@ static gboolean active_connection_remove (NMManager *self, NMActiveConnection *active) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gboolean notify = nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active)); - GSList *found; - - /* FIXME: switch to a GList for faster removal */ - found = g_slist_find (priv->active_connections, active); - if (found) { - NMSettingsConnection *connection; - - priv->active_connections = g_slist_remove (priv->active_connections, active); - g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active); - g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self); - g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self); - g_signal_handlers_disconnect_by_func (active, active_connection_parent_active, self); - - if ( (connection = nm_active_connection_get_settings_connection (active)) - && nm_settings_connection_get_volatile (connection)) - g_object_ref (connection); - else - connection = NULL; + NMSettingsConnection *connection; + gboolean notify; - nm_exported_object_clear_and_unexport (&active); + nm_assert (NM_IS_ACTIVE_CONNECTION (active)); + nm_assert (c_list_contains (&priv->active_connections_lst_head, &active->active_connections_lst)); - if (connection) { - if (nm_settings_has_connection (priv->settings, connection)) { - _LOGD (LOGD_DEVICE, "assumed connection disconnected. Deleting generated connection '%s' (%s)", - nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); - nm_settings_connection_delete (connection, NULL); - } - g_object_unref (connection); + notify = nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active)); + + c_list_unlink_init (&active->active_connections_lst); + g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active); + g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self); + g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self); + g_signal_handlers_disconnect_by_func (active, active_connection_parent_active, self); + + if ( (connection = nm_active_connection_get_settings_connection (active)) + && nm_settings_connection_get_volatile (connection)) + g_object_ref (connection); + else + connection = NULL; + + nm_exported_object_clear_and_unexport (&active); + + if (connection) { + if (nm_settings_has_connection (priv->settings, connection)) { + _LOGD (LOGD_DEVICE, "assumed connection disconnected. Deleting generated connection '%s' (%s)", + nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); + nm_settings_connection_delete (connection, NULL); } + g_object_unref (connection); } - return found && notify; + return notify; } static gboolean @@ -354,16 +353,12 @@ _active_connection_cleanup (gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; + NMActiveConnection *ac, *ac_safe; priv->ac_cleanup_id = 0; g_object_freeze_notify (G_OBJECT (self)); - iter = priv->active_connections; - while (iter) { - NMActiveConnection *ac = iter->data; - - iter = iter->next; + c_list_for_each_entry_safe (ac, ac_safe, &priv->active_connections_lst_head, active_connections_lst) { if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { if (active_connection_remove (self, ac)) _notify (self, PROP_ACTIVE_CONNECTIONS); @@ -421,10 +416,11 @@ active_connection_add (NMManager *self, NMActiveConnection *active) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - g_return_if_fail (g_slist_find (priv->active_connections, active) == FALSE); + nm_assert (NM_IS_ACTIVE_CONNECTION (active)); + nm_assert (!c_list_is_linked (&active->active_connections_lst)); - priv->active_connections = g_slist_prepend (priv->active_connections, - g_object_ref (active)); + c_list_link_front (&priv->active_connections_lst_head, &active->active_connections_lst); + g_object_ref (active); g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE, @@ -446,10 +442,10 @@ active_connection_add (NMManager *self, NMActiveConnection *active) _notify (self, PROP_ACTIVE_CONNECTIONS); } -const GSList * +const CList * nm_manager_get_active_connections (NMManager *manager) { - return NM_MANAGER_GET_PRIVATE (manager)->active_connections; + return &NM_MANAGER_GET_PRIVATE (manager)->active_connections_lst_head; } static NMActiveConnection * @@ -458,16 +454,12 @@ active_connection_find_first (NMManager *self, const char *uuid, NMActiveConnectionState max_state) { - NMManagerPrivate *priv; - GSList *iter; - - g_return_val_if_fail (NM_IS_MANAGER (self), NULL); - g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMActiveConnection *ac; - priv = NM_MANAGER_GET_PRIVATE (self); + nm_assert (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection)); - for (iter = priv->active_connections; iter; iter = iter->next) { - NMActiveConnection *ac = iter->data; + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { NMSettingsConnection *con; con = nm_active_connection_get_settings_connection (ac); @@ -511,42 +503,29 @@ _get_activatable_connections_filter (NMSettings *settings, return !active_connection_find_first (user_data, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); } -/* Filter out connections that are already active. - * nm_settings_get_connections_sorted() returns sorted list. We need to preserve the - * order so that we didn't change auto-activation order (recent timestamps - * are first). - * Caller is responsible for freeing the returned list with g_slist_free(). - */ NMSettingsConnection ** nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, gboolean sort) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - NMSettingsConnection **connections; - guint len; - connections = nm_settings_get_connections_clone (priv->settings, &len, - _get_activatable_connections_filter, - manager); - if (sort && len > 1) - g_qsort_with_data (connections, len, sizeof (connections[0]), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); - NM_SET_OUT (out_len, len); - return connections; + return nm_settings_get_connections_clone (priv->settings, out_len, + _get_activatable_connections_filter, + manager, + sort ? nm_settings_connection_cmp_autoconnect_priority_p_with_data : NULL, + NULL); } static NMActiveConnection * active_connection_get_by_path (NMManager *manager, const char *path) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *iter; - - g_return_val_if_fail (manager != NULL, NULL); - g_return_val_if_fail (path != NULL, NULL); + NMActiveConnection *ac; - for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *candidate = iter->data; + nm_assert (path); - if (g_strcmp0 (path, nm_exported_object_get_path (NM_EXPORTED_OBJECT (candidate))) == 0) - return candidate; + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { + if (nm_streq0 (path, nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac)))) + return ac; } return NULL; } @@ -828,16 +807,14 @@ find_best_device_state (NMManager *manager) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); NMState best_state = NM_STATE_DISCONNECTED; - GSList *iter; + NMActiveConnection *ac; - for (iter = priv->active_connections; iter; iter = iter->next) { - NMActiveConnection *ac = NM_ACTIVE_CONNECTION (iter->data); + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { NMActiveConnectionState ac_state = nm_active_connection_get_state (ac); switch (ac_state) { case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: - if ( nm_active_connection_get_default (ac) - || nm_active_connection_get_default6 (ac)) { + if (nm_active_connection_get_default (ac, AF_UNSPEC)) { if (priv->connectivity_state == NM_CONNECTIVITY_FULL) return NM_STATE_CONNECTED_GLOBAL; @@ -1392,7 +1369,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) } /* Create backing resources if the device has any autoconnect connections */ - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections_clone (priv->settings, NULL, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) { NMConnection *candidate = NM_CONNECTION (connections[i]); NMSettingConnection *s_con; @@ -1436,7 +1415,9 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device) g_return_if_fail (device); - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections_clone (priv->settings, NULL, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) { NMConnection *candidate = NM_CONNECTION (connections[i]); gs_free_error GError *error = NULL; @@ -3022,7 +3003,9 @@ find_slaves (NMManager *manager, * even if a slave was already active, it might be deactivated during * master reactivation. */ - all_connections = nm_settings_get_connections_sorted (priv->settings, &n_all_connections); + all_connections = nm_settings_get_connections_clone (priv->settings, &n_all_connections, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; i < n_all_connections; i++) { NMSettingsConnection *master_connection = NULL; NMDevice *master_device = NULL, *slave_device; @@ -3628,11 +3611,11 @@ _internal_activation_auth_done (NMActiveConnection *active, gpointer user_data1, gpointer user_data2) { + _nm_unused gs_unref_object NMActiveConnection *active_to_free = active; NMManager *self = user_data1; NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMActiveConnection *candidate; - GError *error = NULL; - GSList *iter; + NMActiveConnection *ac; + gs_free_error GError *error = NULL; priv->authorizing_connections = g_slist_remove (priv->authorizing_connections, active); @@ -3641,12 +3624,12 @@ _internal_activation_auth_done (NMActiveConnection *active, * detect a duplicate if the existing active connection is undergoing * authorization in impl_manager_activate_connection(). */ - if (success && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))) { - for (iter = priv->active_connections; iter; iter = iter->next) { - candidate = iter->data; - if ( nm_active_connection_get_device (candidate) == nm_active_connection_get_device (active) - && nm_active_connection_get_settings_connection (candidate) == nm_active_connection_get_settings_connection (active) - && NM_IN_SET (nm_active_connection_get_state (candidate), + if ( success + && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))) { + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { + if ( nm_active_connection_get_device (ac) == nm_active_connection_get_device (active) + && nm_active_connection_get_settings_connection (ac) == nm_active_connection_get_settings_connection (active) + && NM_IN_SET (nm_active_connection_get_state (ac), NM_ACTIVE_CONNECTION_STATE_ACTIVATING, NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { g_set_error (&error, @@ -3661,16 +3644,12 @@ _internal_activation_auth_done (NMActiveConnection *active, } if (success) { - if (_internal_activate_generic (self, active, &error)) { - g_object_unref (active); + if (_internal_activate_generic (self, active, &error)) return; - } } - g_assert (error_desc || error); + nm_assert (error_desc || error); _internal_activation_failed (self, active, error_desc ? error_desc : error->message); - g_object_unref (active); - g_clear_error (&error); } /** @@ -4167,7 +4146,9 @@ impl_manager_add_and_activate_connection (NMManager *self, gs_free NMSettingsConnection **connections = NULL; guint i, len; - connections = nm_settings_get_connections_sorted (priv->settings, &len); + connections = nm_settings_get_connections_clone (priv->settings, &len, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); all_connections = NULL; for (i = len; i > 0; ) { i--; @@ -5226,7 +5207,9 @@ nm_manager_start (NMManager *self, GError **error) * connection-added signals thus devices have to be created manually. */ _LOGD (LOGD_CORE, "creating virtual devices..."); - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections_clone (priv->settings, NULL, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) connection_changed (self, NM_CONNECTION (connections[i])); @@ -5990,19 +5973,15 @@ periodic_update_active_connection_timestamps (gpointer user_data) { NMManager *manager = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *iter; - - for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *ac = iter->data; - NMSettingsConnection *connection; + NMActiveConnection *ac; + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - connection = nm_active_connection_get_settings_connection (ac); - nm_settings_connection_update_timestamp (connection, (guint64) time (NULL), FALSE); + nm_settings_connection_update_timestamp (nm_active_connection_get_settings_connection (ac), + (guint64) time (NULL), FALSE); } } - - return TRUE; + return G_SOURCE_CONTINUE; } static void @@ -6164,6 +6143,7 @@ nm_manager_init (NMManager *self) GFile *file; c_list_init (&priv->link_cb_lst); + c_list_init (&priv->active_connections_lst_head); priv->platform = g_object_ref (NM_PLATFORM_GET); @@ -6252,6 +6232,10 @@ get_property (GObject *object, guint prop_id, const NMGlobalDnsConfig *dns_config; const char *type; char **strv; + const char *path; + NMActiveConnection *ac; + GPtrArray *ptrarr; + gboolean vbool; switch (prop_id) { case PROP_VERSION: @@ -6291,7 +6275,14 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, FALSE); break; case PROP_ACTIVE_CONNECTIONS: - nm_utils_g_value_set_object_path_array (value, priv->active_connections, NULL, NULL); + ptrarr = g_ptr_array_new (); + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac)); + if (path) + g_ptr_array_add (ptrarr, g_strdup (path)); + } + g_ptr_array_add (ptrarr, NULL); + g_value_take_boxed (value, g_ptr_array_free (ptrarr, FALSE)); break; case PROP_CONNECTIVITY: g_value_set_uint (value, priv->connectivity_state); @@ -6302,15 +6293,11 @@ get_property (GObject *object, guint prop_id, break; case PROP_CONNECTIVITY_CHECK_ENABLED: #if WITH_CONCHECK - { - NMConnectivity *connectivity; - - connectivity = nm_connectivity_get (); - g_value_set_boolean (value, nm_connectivity_check_enabled (connectivity)); - } + vbool = nm_connectivity_check_enabled (nm_connectivity_get ()); #else - g_value_set_boolean (value, FALSE); + vbool = FALSE; #endif + g_value_set_boolean (value, FALSE); break; case PROP_PRIMARY_CONNECTION: nm_utils_g_value_set_object_path (value, priv->primary_connection); @@ -6415,6 +6402,7 @@ dispose (GObject *object) NMManager *self = NM_MANAGER (object); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); CList *iter, *iter_safe; + NMActiveConnection *ac, *ac_safe; g_signal_handlers_disconnect_by_func (priv->platform, G_CALLBACK (platform_link_cb), @@ -6448,9 +6436,9 @@ dispose (GObject *object) nm_clear_g_source (&priv->ac_cleanup_id); - while (priv->active_connections) - active_connection_remove (self, NM_ACTIVE_CONNECTION (priv->active_connections->data)); - g_clear_pointer (&priv->active_connections, g_slist_free); + c_list_for_each_entry_safe (ac, ac_safe, &priv->active_connections_lst_head, active_connections_lst) + active_connection_remove (self, ac); + nm_assert (c_list_is_empty (&priv->active_connections_lst_head)); g_clear_object (&priv->primary_connection); g_clear_object (&priv->activating_connection); diff --git a/src/nm-manager.h b/src/nm-manager.h index b4ec7b2688..d52b2655de 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -24,6 +24,7 @@ #include "nm-exported-object.h" #include "settings/nm-settings-connection.h" +#include "nm-utils/c-list.h" #define NM_TYPE_MANAGER (nm_manager_get_type ()) #define NM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MANAGER, NMManager)) @@ -85,7 +86,19 @@ gboolean nm_manager_start (NMManager *manager, GError **error); void nm_manager_stop (NMManager *manager); NMState nm_manager_get_state (NMManager *manager); -const GSList *nm_manager_get_active_connections (NMManager *manager); +const CList * nm_manager_get_active_connections (NMManager *manager); + +#define nm_manager_for_each_active_connection(manager, iter, tmp_list) \ + for (tmp_list = nm_manager_get_active_connections (manager), \ + iter = c_list_entry (tmp_list->next, NMActiveConnection, active_connections_lst); \ + ({ \ + gboolean _has_next = (&iter->active_connections_lst != tmp_list); \ + \ + if (!_has_next) \ + iter = NULL; \ + _has_next; \ + }); \ + iter = c_list_entry (iter->active_connections_lst.next, NMActiveConnection, active_connections_lst)) NMSettingsConnection **nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, diff --git a/src/nm-policy.c b/src/nm-policy.c index 7353d635af..6b46ed1469 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; } @@ -926,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). @@ -945,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; @@ -977,12 +978,12 @@ 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); } @@ -992,13 +993,13 @@ 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); } @@ -1012,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). @@ -1031,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; @@ -1132,6 +1130,7 @@ check_activating_devices (NMPolicy *self) } typedef struct { + CList pending_lst; NMPolicy *policy; NMDevice *device; guint autoactivate_id; @@ -1140,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 (&data->pending_lst); nm_clear_g_source (&data->autoactivate_id); g_object_unref (data->device); - g_slice_free (ActivateData, data); } @@ -1178,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 */ @@ -1199,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; @@ -1230,8 +1225,7 @@ auto_activate_device (NMPolicy *self, 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) + || nm_settings_connection_autoconnect_is_blocked (candidate)) continue; s_con = nm_connection_get_setting_connection (NM_CONNECTION (candidate)); @@ -1264,13 +1258,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; } @@ -1304,13 +1297,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; } @@ -1408,48 +1402,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 @@ -1463,8 +1465,10 @@ sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) g_object_get (G_OBJECT (manager), NM_MANAGER_NETWORKING_ENABLED, &enabled, NULL); /* Reset retries on all connections so they'll checked on wakeup */ - if (sleeping || !enabled) - reset_autoconnect_all (self, NULL); + if (sleeping || !enabled) { + if (reset_autoconnect_all (self, NULL, FALSE)) + schedule_activate_all (self); + } } static void @@ -1472,7 +1476,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; @@ -1480,12 +1485,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; } @@ -1495,18 +1499,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 @@ -1514,7 +1507,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; @@ -1523,11 +1516,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; @@ -1550,6 +1543,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); @@ -1557,7 +1573,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); @@ -1581,38 +1598,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 @@ -1718,7 +1734,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: @@ -1733,36 +1750,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; @@ -1799,22 +1820,25 @@ device_state_changed (NMDevice *device, update_routing_and_dns (self, FALSE); break; case NM_DEVICE_STATE_DEACTIVATING: - if (NM_IN_SET (nm_device_state_reason_check (reason), - NM_DEVICE_STATE_REASON_USER_REQUESTED, - NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED)) { - if (connection) { - NMSettingsAutoconnectBlockedReason blocked_reason; + if (connection) { + NMSettingsAutoconnectBlockedReason blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE; - /* The connection was deactivated, so block just this connection */ + 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))); - if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_USER_REQUESTED) - blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST; - else - blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED; - nm_settings_connection_autoconnect_blocked_reason_set (connection, blocked_reason); + nm_settings_connection_autoconnect_blocked_reason_set (connection, blocked_reason, TRUE); } } ip6_remove_device_prefix_delegations (self, device); @@ -1825,7 +1849,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); @@ -1851,7 +1875,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) @@ -2014,13 +2038,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); @@ -2310,19 +2337,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; - active = nm_manager_get_active_connections (manager); - for (iter = active; iter; iter = g_slist_next (iter)) { - NMActiveConnection *ac = iter->data; + nm_assert (NM_IS_SETTINGS_CONNECTION (connection)); + + 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)) { @@ -2341,9 +2370,7 @@ connection_removed (NMSettings *settings, NMSettingsConnection *connection, gpointer user_data) { - NMPolicyPrivate *priv = user_data; - - _deactivate_if_active (priv->manager, connection); + _deactivate_if_active (user_data, connection); } static void @@ -2357,7 +2384,7 @@ connection_visibility_changed (NMSettings *settings, if (nm_settings_connection_is_visible (connection)) schedule_activate_all (self); else - _deactivate_if_active (priv->manager, connection); + _deactivate_if_active (self, connection); } static void @@ -2365,15 +2392,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 * @@ -2469,6 +2495,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 ()); @@ -2509,6 +2537,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); @@ -2533,7 +2563,8 @@ constructed (GObject *object) 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->agent_mgr, NM_AGENT_MANAGER_AGENT_REGISTERED, G_CALLBACK (secret_agent_registered), self); G_OBJECT_CLASS (nm_policy_parent_class)->constructed (object); @@ -2557,9 +2588,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); @@ -2571,8 +2602,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; @@ -2582,6 +2613,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); @@ -2597,8 +2633,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); diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 42df9a62a7..345d6e6611 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -62,6 +62,8 @@ typedef struct { GHashTable *agents; CList requests; + + guint64 agent_version_id; } NMAgentManagerPrivate; struct _NMAgentManager { @@ -137,6 +139,16 @@ static gboolean _con_get_try_complete_early (Request *req); /*****************************************************************************/ +guint64 +nm_agent_manager_get_agent_version_id (NMAgentManager *self) +{ + g_return_val_if_fail (NM_IS_AGENT_MANAGER (self), 0); + + return NM_AGENT_MANAGER_GET_PRIVATE (self)->agent_version_id; +} + +/*****************************************************************************/ + typedef enum { REQUEST_TYPE_INVALID, REQUEST_TYPE_CON_GET, @@ -336,6 +348,7 @@ agent_register_permissions_done (NMAuthChain *chain, if (result == NM_AUTH_CALL_RESULT_YES) nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, TRUE); + priv->agent_version_id += 1; sender = nm_secret_agent_get_dbus_owner (agent); g_hash_table_insert (priv->agents, g_strdup (sender), agent); _LOGD (agent, "agent registered"); @@ -1558,6 +1571,7 @@ nm_agent_manager_init (NMAgentManager *self) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + priv->agent_version_id = 1; c_list_init (&priv->requests); priv->agents = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref); } @@ -1627,7 +1641,7 @@ nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) object_class->dispose = dispose; signals[AGENT_REGISTERED] = - g_signal_new ("agent-registered", + g_signal_new (NM_AGENT_MANAGER_AGENT_REGISTERED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h index c2a2ec1d8f..f6845818dd 100644 --- a/src/settings/nm-agent-manager.h +++ b/src/settings/nm-agent-manager.h @@ -33,6 +33,8 @@ #define NM_IS_AGENT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AGENT_MANAGER)) #define NM_AGENT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManagerClass)) +#define NM_AGENT_MANAGER_AGENT_REGISTERED "agent-registered" + typedef struct _NMAgentManagerCallId *NMAgentManagerCallId; typedef struct _NMAgentManagerClass NMAgentManagerClass; @@ -41,6 +43,8 @@ GType nm_agent_manager_get_type (void); NMAgentManager *nm_agent_manager_get (void); +guint64 nm_agent_manager_get_agent_version_id (NMAgentManager *self); + /* If no agent fulfilled the secrets request, agent_dbus_owner will be NULL */ typedef void (*NMAgentSecretsResultFunc) (NMAgentManager *manager, NMAgentManagerCallId call_id, diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index 99b955ed4a..5cb0ce4538 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -50,16 +50,13 @@ typedef struct { char *owner_username; char *dbus_owner; NMSecretAgentCapabilities capabilities; - GSList *permissions; - NMDBusSecretAgent *proxy; NMBusManager *bus_mgr; GDBusConnection *connection; - gboolean connection_is_private; - gulong on_disconnected_id; - CList requests; + gulong on_disconnected_id; + bool connection_is_private:1; } NMSecretAgentPrivate; struct _NMSecretAgent { diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 1185aef905..ec73174a4d 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -25,6 +25,8 @@ #include <string.h> +#include "nm-utils/c-list.h" + #include "nm-common-macros.h" #include "nm-config.h" #include "nm-config-data.h" @@ -42,9 +44,8 @@ #define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps" #define SETTINGS_SEEN_BSSIDS_FILE NMSTATEDIR "/seen-bssids" -#define AUTOCONNECT_RETRIES_UNSET -2 -#define AUTOCONNECT_RETRIES_FOREVER -1 -#define AUTOCONNECT_RETRIES_DEFAULT 4 +#define AUTOCONNECT_RETRIES_UNSET -2 +#define AUTOCONNECT_RETRIES_FOREVER -1 #define AUTOCONNECT_RESET_RETRIES_TIMER 300 /*****************************************************************************/ @@ -84,11 +85,11 @@ typedef struct _NMSettingsConnectionPrivate { bool timestamp_set:1; - NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:3; + NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:4; GSList *pending_auths; /* List of pending authentication requests */ - GSList *get_secret_requests; /* in-progress secrets requests */ + CList call_ids_lst_head; /* in-progress secrets requests */ /* Caches secrets from on-disk connections; were they not cached any * call to nm_connection_clear_secrets() wipes them out and we'd have @@ -105,13 +106,17 @@ typedef struct _NMSettingsConnectionPrivate { */ NMConnection *agent_secrets; - guint64 timestamp; /* Up-to-date timestamp of connection use */ + char *filename; + GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */ + guint64 timestamp; /* Up-to-date timestamp of connection use */ + + guint64 last_secret_agent_version_id; + int autoconnect_retries; - gint32 autoconnect_blocked_until; + gint32 autoconnect_retries_blocked_until; - char *filename; } NMSettingsConnectionPrivate; G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_EXPORTED_OBJECT, @@ -170,6 +175,16 @@ nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection * /*****************************************************************************/ +guint64 +nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *self) +{ + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), 0); + + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->last_secret_agent_version_id; +} + +/*****************************************************************************/ + /* Return TRUE to keep, FALSE to drop */ typedef gboolean (*ForEachSecretFunc) (NMSettingSecretFlags flags, gpointer user_data); @@ -795,18 +810,19 @@ nm_settings_connection_delete (NMSettingsConnection *self, typedef enum { - GET_SECRETS_INFO_TYPE_REQ, - GET_SECRETS_INFO_TYPE_IDLE, -} GetSecretsInfoType; + CALL_ID_TYPE_REQ, + CALL_ID_TYPE_IDLE, +} CallIdType; struct _NMSettingsConnectionCallId { NMSettingsConnection *self; + CList call_ids_lst; gboolean had_applied_connection; NMConnection *applied_connection; NMSettingsConnectionSecretsFunc callback; gpointer callback_data; - GetSecretsInfoType type; + CallIdType type; union { struct { NMAgentManagerCallId id; @@ -818,59 +834,36 @@ struct _NMSettingsConnectionCallId { } t; }; -typedef struct _NMSettingsConnectionCallId GetSecretsInfo; - -static GetSecretsInfo * -_get_secrets_info_new (NMSettingsConnection *self, - NMConnection *applied_connection, - NMSettingsConnectionSecretsFunc callback, - gpointer callback_data) -{ - GetSecretsInfo *info; - - info = g_slice_new0 (GetSecretsInfo); - - info->self = self; - if (applied_connection) { - info->had_applied_connection = TRUE; - info->applied_connection = applied_connection; - g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &info->applied_connection); - } - info->callback = callback; - info->callback_data = callback_data; - - return info; -} - static void -_get_secrets_info_callback (GetSecretsInfo *info, +_get_secrets_info_callback (NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error) { - if (info->callback) { - info->callback (info->self, - info, - agent_username, - setting_name, - error, - info->callback_data); + if (call_id->callback) { + call_id->callback (call_id->self, + call_id, + agent_username, + setting_name, + error, + call_id->callback_data); } } static void -_get_secrets_info_free (GetSecretsInfo *info) +_get_secrets_info_free (NMSettingsConnectionCallId *call_id) { - g_return_if_fail (info && info->self); + g_return_if_fail (call_id && call_id->self); + nm_assert (!c_list_is_linked (&call_id->call_ids_lst)); - if (info->applied_connection) - g_object_remove_weak_pointer (G_OBJECT (info->applied_connection), (gpointer *) &info->applied_connection); + if (call_id->applied_connection) + g_object_remove_weak_pointer (G_OBJECT (call_id->applied_connection), (gpointer *) &call_id->applied_connection); - if (info->type == GET_SECRETS_INFO_TYPE_IDLE) - g_clear_error (&info->t.idle.error); + if (call_id->type == CALL_ID_TYPE_IDLE) + g_clear_error (&call_id->t.idle.error); - memset (info, 0, sizeof (*info)); - g_slice_free (GetSecretsInfo, info); + memset (call_id, 0, sizeof (*call_id)); + g_slice_free (NMSettingsConnectionCallId, call_id); } static gboolean @@ -907,7 +900,7 @@ secret_is_system_owned (NMSettingSecretFlags flags, static void get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ - GetSecretsInfo *info, /* only needed for logging */ + NMSettingsConnectionCallId *call_id, /* only needed for logging */ NMConnection *connection, const char *agent_dbus_owner, gboolean agent_has_modify, @@ -930,7 +923,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) secrets returned from agent %s", setting_name, - info, + call_id, agent_dbus_owner); } @@ -949,7 +942,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) interaction forbidden but agent %s returned system secrets", setting_name, - info, + call_id, agent_dbus_owner); } @@ -961,7 +954,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) agent failed to authenticate but provided system secrets", setting_name, - info); + call_id); } cmp_flags->required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED; @@ -971,7 +964,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) existing secrets returned", setting_name, - info); + call_id); } } @@ -1023,7 +1016,7 @@ get_secrets_done_cb (NMAgentManager *manager, GError *error, gpointer user_data) { - GetSecretsInfo *info = user_data; + NMSettingsConnectionCallId *call_id = user_data; NMSettingsConnection *self; NMSettingsConnectionPrivate *priv; NMConnection *applied_connection; @@ -1035,36 +1028,36 @@ get_secrets_done_cb (NMAgentManager *manager, if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - self = info->self; + self = call_id->self; g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (g_slist_find (priv->get_secret_requests, info)); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + c_list_unlink_init (&call_id->call_ids_lst); if (error) { _LOGD ("(%s:%p) secrets request error: %s", - setting_name, info, error->message); + setting_name, call_id, error->message); - _get_secrets_info_callback (info, NULL, setting_name, error); + _get_secrets_info_callback (call_id, NULL, setting_name, error); goto out; } - if ( info->had_applied_connection - && !info->applied_connection) { + if ( call_id->had_applied_connection + && !call_id->applied_connection) { g_set_error_literal (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "Applied connection deleted since requesting secrets"); - _get_secrets_info_callback (info, NULL, setting_name, local); + _get_secrets_info_callback (call_id, NULL, setting_name, local); goto out; } - if ( info->had_applied_connection - && !nm_settings_connection_has_unmodified_applied_connection (self, info->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) { + if ( call_id->had_applied_connection + && !nm_settings_connection_has_unmodified_applied_connection (self, call_id->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) { g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "The connection was modified since activation"); - _get_secrets_info_callback (info, NULL, setting_name, local); + _get_secrets_info_callback (call_id, NULL, setting_name, local); goto out; } @@ -1072,12 +1065,12 @@ get_secrets_done_cb (NMAgentManager *manager, g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "Connection didn't have requested setting '%s'.", setting_name); - _get_secrets_info_callback (info, NULL, setting_name, local); + _get_secrets_info_callback (call_id, NULL, setting_name, local); goto out; } get_cmp_flags (self, - info, + call_id, NM_CONNECTION (self), agent_dbus_owner, agent_has_modify, @@ -1089,7 +1082,7 @@ get_secrets_done_cb (NMAgentManager *manager, _LOGD ("(%s:%p) secrets request completed", setting_name, - info); + call_id); dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); @@ -1119,7 +1112,7 @@ get_secrets_done_cb (NMAgentManager *manager, if (agent_had_system) { _LOGD ("(%s:%p) saving new secrets to backing storage", setting_name, - info); + call_id); nm_settings_connection_commit_changes (self, NULL, @@ -1128,27 +1121,27 @@ get_secrets_done_cb (NMAgentManager *manager, } else { _LOGD ("(%s:%p) new agent secrets processed", setting_name, - info); + call_id); } } else { _LOGD ("(%s:%p) failed to update with agent secrets: %s", setting_name, - info, + call_id, local->message); } g_variant_unref (filtered_secrets); } else { _LOGD ("(%s:%p) failed to update with existing secrets: %s", setting_name, - info, + call_id, local->message); } - applied_connection = info->applied_connection; + applied_connection = call_id->applied_connection; if (applied_connection) { get_cmp_flags (self, - info, + call_id, applied_connection, agent_dbus_owner, agent_has_modify, @@ -1169,31 +1162,31 @@ get_secrets_done_cb (NMAgentManager *manager, } } - _get_secrets_info_callback (info, agent_username, setting_name, local); + _get_secrets_info_callback (call_id, agent_username, setting_name, local); g_clear_error (&local); if (dict) g_variant_unref (dict); out: - _get_secrets_info_free (info); + _get_secrets_info_free (call_id); } static gboolean -get_secrets_idle_cb (GetSecretsInfo *info) +get_secrets_idle_cb (NMSettingsConnectionCallId *call_id) { NMSettingsConnectionPrivate *priv; - g_return_val_if_fail (info && NM_IS_SETTINGS_CONNECTION (info->self), G_SOURCE_REMOVE); + g_return_val_if_fail (call_id && NM_IS_SETTINGS_CONNECTION (call_id->self), G_SOURCE_REMOVE); - priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (info->self); + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (call_id->self); - g_return_val_if_fail (g_slist_find (priv->get_secret_requests, info), G_SOURCE_REMOVE); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + c_list_unlink_init (&call_id->call_ids_lst); - _get_secrets_info_callback (info, NULL, NULL, info->t.idle.error); + _get_secrets_info_callback (call_id, NULL, NULL, call_id->t.idle.error); - _get_secrets_info_free (info); + _get_secrets_info_free (call_id); return G_SOURCE_REMOVE; } @@ -1222,7 +1215,7 @@ get_secrets_idle_cb (GetSecretsInfo *info) * * Returns: a call ID which may be used to cancel the ongoing secrets request. **/ -NMSettingsConnectionCallId +NMSettingsConnectionCallId * nm_settings_connection_get_secrets (NMSettingsConnection *self, NMConnection *applied_connection, NMAuthSubject *subject, @@ -1236,7 +1229,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, GVariant *existing_secrets; NMAgentManagerCallId call_id_a; gs_free char *joined_hints = NULL; - GetSecretsInfo *info; + NMSettingsConnectionCallId *call_id; GError *local = NULL; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NULL); @@ -1244,12 +1237,16 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, || ( NM_IS_CONNECTION (applied_connection) && (((NMConnection *) self) != applied_connection)), NULL); - info = _get_secrets_info_new (self, - applied_connection, - callback, - callback_data); - - priv->get_secret_requests = g_slist_append (priv->get_secret_requests, info); + call_id = g_slice_new0 (NMSettingsConnectionCallId); + call_id->self = self; + if (applied_connection) { + call_id->had_applied_connection = TRUE; + call_id->applied_connection = applied_connection; + g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &call_id->applied_connection); + } + call_id->callback = callback; + call_id->callback_data = callback_data; + c_list_link_tail (&priv->call_ids_lst_head, &call_id->call_ids_lst); /* Use priv->secrets to work around the fact that nm_connection_clear_secrets() * will clear secrets on this object's settings. @@ -1278,6 +1275,14 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, existing_secrets = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); if (existing_secrets) g_variant_ref_sink (existing_secrets); + + /* we remember the current version-id of the secret-agents. The version-id is strictly increasing, + * as new agents register the number. We know hence, that this request was made against a certain + * set of secret-agents. + * If after making this request a new secret-agent registeres, the version-id increases. + * Then we know that the this request probably did not yet include the latest secret-agent. */ + priv->last_secret_agent_version_id = nm_agent_manager_get_agent_version_id (priv->agent_mgr); + call_id_a = nm_agent_manager_get_secrets (priv->agent_mgr, nm_connection_get_path (NM_CONNECTION (self)), NM_CONNECTION (self), @@ -1287,7 +1292,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, flags, hints, get_secrets_done_cb, - info); + call_id); g_assert (call_id_a); if (existing_secrets) g_variant_unref (existing_secrets); @@ -1299,45 +1304,44 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, (hints && hints[0]) ? (joined_hints = g_strjoinv (",", (char **) hints)) : "(none)"); if (call_id_a) { - info->type = GET_SECRETS_INFO_TYPE_REQ; - info->t.req.id = call_id_a; + call_id->type = CALL_ID_TYPE_REQ; + call_id->t.req.id = call_id_a; } else { schedule_dummy: - info->type = GET_SECRETS_INFO_TYPE_IDLE; - g_propagate_error (&info->t.idle.error, local); - info->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, info); + call_id->type = CALL_ID_TYPE_IDLE; + g_propagate_error (&call_id->t.idle.error, local); + call_id->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, call_id); } - return info; + return call_id; } static void _get_secrets_cancel (NMSettingsConnection *self, - GetSecretsInfo *info, + NMSettingsConnectionCallId *call_id, gboolean is_disposing) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); gs_free_error GError *error = NULL; - if (!g_slist_find (priv->get_secret_requests, info)) - g_return_if_reached (); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + c_list_unlink_init (&call_id->call_ids_lst); - if (info->type == GET_SECRETS_INFO_TYPE_REQ) - nm_agent_manager_cancel_secrets (priv->agent_mgr, info->t.req.id); + if (call_id->type == CALL_ID_TYPE_REQ) + nm_agent_manager_cancel_secrets (priv->agent_mgr, call_id->t.req.id); else - g_source_remove (info->t.idle.id); + g_source_remove (call_id->t.idle.id); nm_utils_error_set_cancelled (&error, is_disposing, "NMSettingsConnection"); - _get_secrets_info_callback (info, NULL, NULL, error); + _get_secrets_info_callback (call_id, NULL, NULL, error); - _get_secrets_info_free (info); + _get_secrets_info_free (call_id); } void nm_settings_connection_cancel_secrets (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id) + NMSettingsConnectionCallId *call_id) { _LOGD ("(%p) secrets canceled", call_id); @@ -1656,8 +1660,7 @@ update_complete (NMSettingsConnection *self, g_clear_object (&info->agent_mgr); g_clear_object (&info->new_settings); g_free (info->audit_args); - memset (info, 0, sizeof (*info)); - g_free (info); + g_slice_free (UpdateInfo, info); } static void @@ -1832,7 +1835,7 @@ settings_connection_update_helper (NMSettingsConnection *self, goto error; } - info = g_malloc0 (sizeof (*info)); + info = g_slice_new0 (UpdateInfo); info->context = context; info->agent_mgr = g_object_ref (priv->agent_mgr); info->subject = subject; @@ -1951,7 +1954,7 @@ out_err: static void dbus_get_agent_secrets_cb (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id, + NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error, @@ -2533,6 +2536,54 @@ nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *self) /*****************************************************************************/ +static int +_autoconnect_retries_initial (NMSettingsConnection *self) +{ + NMSettingConnection *s_con; + int retries = -1; + + s_con = nm_connection_get_setting_connection ((NMConnection *) self); + if (s_con) + retries = nm_setting_connection_get_autoconnect_retries (s_con); + + /* -1 means 'default' */ + if (retries == -1) + retries = nm_config_data_get_autoconnect_retries_default (NM_CONFIG_GET_DATA); + + /* 0 means 'forever', which is translated to a retry count of -1 */ + if (retries == 0) + retries = AUTOCONNECT_RETRIES_FOREVER; + + nm_assert (retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0); + return retries; +} + +static void +_autoconnect_retries_set (NMSettingsConnection *self, + int retries, + gboolean is_reset) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + g_return_if_fail (retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0); + + if (priv->autoconnect_retries != retries) { + _LOGT ("autoconnect: retries set %d%s", retries, + is_reset ? " (reset)" : ""); + priv->autoconnect_retries = retries; + } + + if (retries) + priv->autoconnect_retries_blocked_until = 0; + else { + /* XXX: the blocked time must be identical for all connections, otherwise + * the tracking of resetting the retry count in NMPolicy needs adjustment + * in _connection_autoconnect_retries_set() (as it would need to re-evaluate + * the next-timeout everytime a connection gets blocked). */ + priv->autoconnect_retries_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER; + } +} + /** * nm_settings_connection_autoconnect_retries_get: * @self: the settings connection @@ -2547,30 +2598,10 @@ nm_settings_connection_autoconnect_retries_get (NMSettingsConnection *self) NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); if (G_UNLIKELY (priv->autoconnect_retries == AUTOCONNECT_RETRIES_UNSET)) { - NMSettingConnection *s_con; - int retries = -1; - - s_con = nm_connection_get_setting_connection ((NMConnection *) self); - if (s_con) - retries = nm_setting_connection_get_autoconnect_retries (s_con); - - /* -1 means 'default' */ - if (retries == -1) { - retries = nm_config_data_get_value_int64 (NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_GROUP_MAIN, - "autoconnect-retries-default", - 10, 0, G_MAXINT32, - AUTOCONNECT_RETRIES_DEFAULT); - } - - /* 0 means 'forever', which is translated to a retry count of -1 */ - if (retries == 0) - retries = AUTOCONNECT_RETRIES_FOREVER; - - _LOGT ("autoconnect-retries: init %d", retries); - priv->autoconnect_retries = retries; + _autoconnect_retries_set (self, + _autoconnect_retries_initial (self), + TRUE); } - return priv->autoconnect_retries; } @@ -2578,51 +2609,71 @@ void nm_settings_connection_autoconnect_retries_set (NMSettingsConnection *self, int retries) { - NMSettingsConnectionPrivate *priv; - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); - nm_assert (retries == AUTOCONNECT_RETRIES_UNSET || retries >= 0); - - priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + g_return_if_fail (retries >= 0); - if (priv->autoconnect_retries != retries) { - _LOGT ("autoconnect-retries: set %d", retries); - priv->autoconnect_retries = retries; - } - if (retries) - priv->autoconnect_blocked_until = 0; - else - priv->autoconnect_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER; + _autoconnect_retries_set (self, retries, FALSE); } void nm_settings_connection_autoconnect_retries_reset (NMSettingsConnection *self) { - nm_settings_connection_autoconnect_retries_set (self, AUTOCONNECT_RETRIES_UNSET); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); + + _autoconnect_retries_set (self, + _autoconnect_retries_initial (self), + TRUE); } gint32 -nm_settings_connection_autoconnect_blocked_until_get (NMSettingsConnection *self) +nm_settings_connection_autoconnect_retries_blocked_until (NMSettingsConnection *self) { - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_until; + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_retries_blocked_until; } +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_autoconnect_blocked_reason_to_string, NMSettingsAutoconnectBlockedReason, + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, "user-request"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, "failed"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, "no-secrets"), +); + NMSettingsAutoconnectBlockedReason -nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self) +nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self, NMSettingsAutoconnectBlockedReason mask) { - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason; + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason & (mask ?: NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL); } -void -nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self, - NMSettingsAutoconnectBlockedReason reason) +gboolean +nm_settings_connection_autoconnect_blocked_reason_set_full (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask, + NMSettingsAutoconnectBlockedReason value) { - g_return_if_fail (NM_IN_SET (reason, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS)); - NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason = reason; + NMSettingsAutoconnectBlockedReason v; + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + char buf[100]; + + nm_assert (mask); + nm_assert (!NM_FLAGS_ANY (value, ~mask)); + + v = priv->autoconnect_blocked_reason; + v = (v & ~mask) | (value & mask); + + if (priv->autoconnect_blocked_reason == v) + return FALSE; + + _LOGT ("autoconnect: blocked reason: %s", _autoconnect_blocked_reason_to_string (v, buf, sizeof (buf))); + priv->autoconnect_blocked_reason = v; + return TRUE; +} + +gboolean +nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + return !priv->autoconnect_blocked_reason + && priv->autoconnect_retries != 0; } /*****************************************************************************/ @@ -2771,17 +2822,14 @@ dispose (GObject *object) { NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMSettingsConnectionCallId *call_id, *call_id_safe; _LOGD ("disposing"); /* Cancel in-progress secrets requests */ if (priv->agent_mgr) { - while (priv->get_secret_requests) { - GetSecretsInfo *info = priv->get_secret_requests->data; - - _get_secrets_cancel (self, info, TRUE); - g_return_if_fail (!priv->get_secret_requests || (info != priv->get_secret_requests->data)); - } + c_list_for_each_entry_safe (call_id, call_id_safe, &priv->call_ids_lst_head, call_ids_lst) + _get_secrets_cancel (self, call_id, TRUE); } /* Disconnect handlers. diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index 7a9e383259..3672bc08c1 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -84,13 +84,18 @@ typedef enum { /*< skip >*/ typedef enum { NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE = 0, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST = 1, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED = 2, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = 3, + + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST = (1LL << 0), + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED = (1LL << 1), + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = (1LL << 2), + + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL = ( NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST + | NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED + | NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS), } NMSettingsAutoconnectBlockedReason; struct _NMSettingsConnectionCallId; -typedef struct _NMSettingsConnectionCallId *NMSettingsConnectionCallId; +typedef struct _NMSettingsConnectionCallId NMSettingsConnectionCallId; typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass; @@ -120,6 +125,8 @@ struct _NMSettingsConnectionClass { GType nm_settings_connection_get_type (void); +guint64 nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *self); + gboolean nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self, NMConnection *applied_connection, NMSettingCompareFlags compare_flage); @@ -150,7 +157,7 @@ gboolean nm_settings_connection_delete (NMSettingsConnection *self, GError **error); typedef void (*NMSettingsConnectionSecretsFunc) (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id, + NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error, @@ -162,17 +169,17 @@ gboolean nm_settings_connection_new_secrets (NMSettingsConnection *self, GVariant *secrets, GError **error); -NMSettingsConnectionCallId nm_settings_connection_get_secrets (NMSettingsConnection *self, - NMConnection *applied_connection, - NMAuthSubject *subject, - const char *setting_name, - NMSecretAgentGetSecretsFlags flags, - const char *const*hints, - NMSettingsConnectionSecretsFunc callback, - gpointer callback_data); +NMSettingsConnectionCallId *nm_settings_connection_get_secrets (NMSettingsConnection *self, + NMConnection *applied_connection, + NMAuthSubject *subject, + const char *setting_name, + NMSecretAgentGetSecretsFlags flags, + const char *const*hints, + NMSettingsConnectionSecretsFunc callback, + gpointer callback_data); void nm_settings_connection_cancel_secrets (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id); + NMSettingsConnectionCallId *call_id); gboolean nm_settings_connection_is_visible (NMSettingsConnection *self); @@ -218,11 +225,23 @@ void nm_settings_connection_autoconnect_retries_set (NMSettingsConnection *self, int retries); void nm_settings_connection_autoconnect_retries_reset (NMSettingsConnection *self); -gint32 nm_settings_connection_autoconnect_blocked_until_get (NMSettingsConnection *self); +gint32 nm_settings_connection_autoconnect_retries_blocked_until (NMSettingsConnection *self); + +NMSettingsAutoconnectBlockedReason nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask); +gboolean nm_settings_connection_autoconnect_blocked_reason_set_full (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask, + NMSettingsAutoconnectBlockedReason value); + +static inline gboolean +nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask, + gboolean set) +{ + return nm_settings_connection_autoconnect_blocked_reason_set_full (self, mask, set ? mask : NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); +} -NMSettingsAutoconnectBlockedReason nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self); -void nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self, - NMSettingsAutoconnectBlockedReason reason); +gboolean nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self); gboolean nm_settings_connection_get_nm_generated (NMSettingsConnection *self); gboolean nm_settings_connection_get_volatile (NMSettingsConnection *self); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 4eeee31554..081997058f 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -128,7 +128,6 @@ enum { CONNECTION_UPDATED, CONNECTION_REMOVED, CONNECTION_VISIBILITY_CHANGED, - AGENT_REGISTERED, NEW_CONNECTION, /* exported, not used internally */ LAST_SIGNAL }; @@ -431,6 +430,9 @@ nm_settings_get_connections (NMSettings *self, guint *out_len) * @out_len: (allow-none): optional output argument * @func: caller-supplied function for filtering connections * @func_data: caller-supplied data passed to @func + * @sort_compare_func: (allow-none): optional function pointer for + * sorting the returned list. + * @sort_data: user data for @sort_compare_func. * * Returns: (transfer container) (element-type NMSettingsConnection): * an NULL terminated array of #NMSettingsConnection objects that were @@ -443,7 +445,9 @@ NMSettingsConnection ** nm_settings_get_connections_clone (NMSettings *self, guint *out_len, NMSettingsConnectionFilterFunc func, - gpointer func_data) + gpointer func_data, + GCompareDataFunc sort_compare_func, + gpointer sort_data) { NMSettingsConnection *const*list_cached; NMSettingsConnection **list; @@ -471,31 +475,15 @@ nm_settings_get_connections_clone (NMSettings *self, } else memcpy (list, list_cached, sizeof (list[0]) * ((gsize) len + 1)); + if ( len > 1 + && sort_compare_func) { + g_qsort_with_data (list, len, sizeof (NMSettingsConnection *), + sort_compare_func, sort_data); + } NM_SET_OUT (out_len, len); return list; } -/* Returns a list of NMSettingsConnections. - * The list is sorted in the order suitable for auto-connecting, i.e. - * first go connections with autoconnect=yes and most recent timestamp. - * Caller must free the list with g_free(), but not the list items. - */ -NMSettingsConnection ** -nm_settings_get_connections_sorted (NMSettings *self, guint *out_len) -{ - NMSettingsConnection **connections; - guint len; - - g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); - - connections = nm_settings_get_connections_clone (self, &len, NULL, NULL); - if (len > 1) - g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); - - NM_SET_OUT (out_len, len); - return connections; -} - NMSettingsConnection * nm_settings_get_connection_by_path (NMSettings *self, const char *path) { @@ -889,18 +877,6 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_object_unref (connection); } -static void -secret_agent_registered (NMAgentManager *agent_mgr, - NMSecretAgent *agent, - gpointer user_data) -{ - /* Re-emit for listeners like NMPolicy */ - g_signal_emit (NM_SETTINGS (user_data), - signals[AGENT_REGISTERED], - 0, - agent); -} - #define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect" #define NM_OPENCONNECT_KEY_GATEWAY "gateway" #define NM_OPENCONNECT_KEY_COOKIE "cookie" @@ -1899,16 +1875,8 @@ nm_settings_init (NMSettings *self) priv->connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); - /* Hold a reference to the agent manager so it stays alive; the only - * other holders are NMSettingsConnection objects which are often - * transient, and we don't want the agent manager to get destroyed and - * recreated often. - */ priv->agent_mgr = g_object_ref (nm_agent_manager_get ()); - priv->config = g_object_ref (nm_config_get ()); - - g_signal_connect (priv->agent_mgr, "agent-registered", G_CALLBACK (secret_agent_registered), self); } NMSettings * @@ -2033,15 +2001,6 @@ nm_settings_class_init (NMSettingsClass *class) g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); - signals[AGENT_REGISTERED] = - g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT); - - signals[NEW_CONNECTION] = g_signal_new ("new-connection", G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index eede76b029..cbd8afa9c3 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -47,7 +47,6 @@ #define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED "connection-updated" #define NM_SETTINGS_SIGNAL_CONNECTION_REMOVED "connection-removed" #define NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED "connection-visibility-changed" -#define NM_SETTINGS_SIGNAL_AGENT_REGISTERED "agent-registered" /** * NMConnectionFilterFunc: @@ -100,10 +99,9 @@ NMSettingsConnection *const* nm_settings_get_connections (NMSettings *settings, NMSettingsConnection **nm_settings_get_connections_clone (NMSettings *self, guint *out_len, NMSettingsConnectionFilterFunc func, - gpointer func_data); - -NMSettingsConnection **nm_settings_get_connections_sorted (NMSettings *self, - guint *out_len); + gpointer func_data, + GCompareDataFunc sort_compare_func, + gpointer sort_data); NMSettingsConnection *nm_settings_add_connection (NMSettings *settings, NMConnection *connection, diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index e441bbd051..6c600c46a6 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -103,7 +103,7 @@ typedef struct { gboolean service_can_persist; gboolean connection_can_persist; - NMSettingsConnectionCallId secrets_id; + NMSettingsConnectionCallId *secrets_id; SecretsReq secrets_idx; char *username; @@ -2571,7 +2571,7 @@ plugin_new_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da static void get_secrets_cb (NMSettingsConnection *connection, - NMSettingsConnectionCallId call_id, + NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error, |