about summary refs log tree commit diff
path: root/src/nm-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-manager.c')
-rw-r--r--src/nm-manager.c520
1 files changed, 313 insertions, 207 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 2766e86a..7f1b9a9d 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -62,41 +62,7 @@
 #include "introspection/org.freedesktop.NetworkManager.h"
 #include "introspection/org.freedesktop.NetworkManager.Device.h"
 
-static gboolean add_device (NMManager *self, NMDevice *device, GError **error);
-
-static NMActiveConnection *_new_active_connection (NMManager *self,
-                                                   NMConnection *connection,
-                                                   NMConnection *applied,
-                                                   const char *specific_object,
-                                                   NMDevice *device,
-                                                   NMAuthSubject *subject,
-                                                   NMActivationType activation_type,
-                                                   GError **error);
-
-static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
-
-static gboolean find_master (NMManager *self,
-                             NMConnection *connection,
-                             NMDevice *device,
-                             NMSettingsConnection **out_master_connection,
-                             NMDevice **out_master_device,
-                             NMActiveConnection **out_master_ac,
-                             GError **error);
-
-static void nm_manager_update_state (NMManager *manager);
-
-static void connection_changed (NMManager *self, NMConnection *connection);
-static void device_sleep_cb (NMDevice *device,
-                             GParamSpec *pspec,
-                             NMManager *self);
-
-static void settings_startup_complete_changed (NMSettings *settings,
-                                               GParamSpec *pspec,
-                                               NMManager *self);
-
-static void retry_connections_for_parent_device (NMManager *self, NMDevice *device);
-
-static NM_CACHED_QUARK_FCN ("active-connection-add-and-activate", active_connection_add_and_activate_quark)
+/*****************************************************************************/
 
 typedef struct {
 	gboolean user_enabled;
@@ -109,12 +75,56 @@ typedef struct {
 	const char *hw_prop;
 } RadioState;
 
+enum {
+	DEVICE_ADDED,
+	INTERNAL_DEVICE_ADDED,
+	DEVICE_REMOVED,
+	INTERNAL_DEVICE_REMOVED,
+	STATE_CHANGED,
+	CHECK_PERMISSIONS,
+	ACTIVE_CONNECTION_ADDED,
+	ACTIVE_CONNECTION_REMOVED,
+	CONFIGURE_QUIT,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+NM_GOBJECT_PROPERTIES_DEFINE (NMManager,
+	PROP_VERSION,
+	PROP_CAPABILITIES,
+	PROP_STATE,
+	PROP_STARTUP,
+	PROP_NETWORKING_ENABLED,
+	PROP_WIRELESS_ENABLED,
+	PROP_WIRELESS_HARDWARE_ENABLED,
+	PROP_WWAN_ENABLED,
+	PROP_WWAN_HARDWARE_ENABLED,
+	PROP_WIMAX_ENABLED,
+	PROP_WIMAX_HARDWARE_ENABLED,
+	PROP_ACTIVE_CONNECTIONS,
+	PROP_CONNECTIVITY,
+	PROP_CONNECTIVITY_CHECK_AVAILABLE,
+	PROP_CONNECTIVITY_CHECK_ENABLED,
+	PROP_PRIMARY_CONNECTION,
+	PROP_PRIMARY_CONNECTION_TYPE,
+	PROP_ACTIVATING_CONNECTION,
+	PROP_DEVICES,
+	PROP_METERED,
+	PROP_GLOBAL_DNS_CONFIGURATION,
+	PROP_ALL_DEVICES,
+
+	/* Not exported */
+	PROP_SLEEPING,
+);
+
 typedef struct {
 	NMPlatform *platform;
 
 	GArray *capabilities;
 
-	GSList *active_connections;
+	CList active_connections_lst_head;
 	GSList *authorizing_connections;
 	guint ac_cleanup_id;
 	NMActiveConnection *primary_connection;
@@ -166,6 +176,9 @@ typedef struct {
 
 	bool sleeping:1;
 	bool net_enabled:1;
+
+	guint delete_volatile_connection_idle_id;
+	CList delete_volatile_connection_lst_head;
 } NMManagerPrivate;
 
 struct _NMManager {
@@ -181,49 +194,7 @@ G_DEFINE_TYPE (NMManager, nm_manager, NM_TYPE_EXPORTED_OBJECT)
 
 #define NM_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMManager, NM_IS_MANAGER)
 
-enum {
-	DEVICE_ADDED,
-	INTERNAL_DEVICE_ADDED,
-	DEVICE_REMOVED,
-	INTERNAL_DEVICE_REMOVED,
-	STATE_CHANGED,
-	CHECK_PERMISSIONS,
-	ACTIVE_CONNECTION_ADDED,
-	ACTIVE_CONNECTION_REMOVED,
-	CONFIGURE_QUIT,
-
-	LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-NM_GOBJECT_PROPERTIES_DEFINE (NMManager,
-	PROP_VERSION,
-	PROP_CAPABILITIES,
-	PROP_STATE,
-	PROP_STARTUP,
-	PROP_NETWORKING_ENABLED,
-	PROP_WIRELESS_ENABLED,
-	PROP_WIRELESS_HARDWARE_ENABLED,
-	PROP_WWAN_ENABLED,
-	PROP_WWAN_HARDWARE_ENABLED,
-	PROP_WIMAX_ENABLED,
-	PROP_WIMAX_HARDWARE_ENABLED,
-	PROP_ACTIVE_CONNECTIONS,
-	PROP_CONNECTIVITY,
-	PROP_CONNECTIVITY_CHECK_AVAILABLE,
-	PROP_CONNECTIVITY_CHECK_ENABLED,
-	PROP_PRIMARY_CONNECTION,
-	PROP_PRIMARY_CONNECTION_TYPE,
-	PROP_ACTIVATING_CONNECTION,
-	PROP_DEVICES,
-	PROP_METERED,
-	PROP_GLOBAL_DNS_CONFIGURATION,
-	PROP_ALL_DEVICES,
-
-	/* Not exported */
-	PROP_SLEEPING,
-);
+/*****************************************************************************/
 
 NM_DEFINE_SINGLETON_INSTANCE (NMManager);
 
@@ -296,7 +267,39 @@ NM_DEFINE_SINGLETON_INSTANCE (NMManager);
 
 /*****************************************************************************/
 
-static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark)
+static gboolean add_device (NMManager *self, NMDevice *device, GError **error);
+
+static NMActiveConnection *_new_active_connection (NMManager *self,
+                                                   NMConnection *connection,
+                                                   NMConnection *applied,
+                                                   const char *specific_object,
+                                                   NMDevice *device,
+                                                   NMAuthSubject *subject,
+                                                   NMActivationType activation_type,
+                                                   GError **error);
+
+static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
+
+static gboolean find_master (NMManager *self,
+                             NMConnection *connection,
+                             NMDevice *device,
+                             NMSettingsConnection **out_master_connection,
+                             NMDevice **out_master_device,
+                             NMActiveConnection **out_master_ac,
+                             GError **error);
+
+static void nm_manager_update_state (NMManager *manager);
+
+static void connection_changed (NMManager *self, NMConnection *connection);
+static void device_sleep_cb (NMDevice *device,
+                             GParamSpec *pspec,
+                             NMManager *self);
+
+static void settings_startup_complete_changed (NMSettings *settings,
+                                               GParamSpec *pspec,
+                                               NMManager *self);
+
+static void retry_connections_for_parent_device (NMManager *self, NMDevice *device);
 
 static void active_connection_state_changed (NMActiveConnection *active,
                                              GParamSpec *pspec,
@@ -308,44 +311,68 @@ static void active_connection_parent_active (NMActiveConnection *active,
                                              NMActiveConnection *parent_ac,
                                              NMManager *self);
 
+static NMActiveConnection *active_connection_find_first (NMManager *self,
+                                                         NMSettingsConnection *settings_connection,
+                                                         const char *uuid,
+                                                         NMActiveConnectionState max_state);
+
+/*****************************************************************************/
+
+static NM_CACHED_QUARK_FCN ("active-connection-add-and-activate", active_connection_add_and_activate_quark)
+
+static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark)
+
+/*****************************************************************************/
+
+static void
+_delete_volatile_connection_do (NMManager *self,
+                                NMSettingsConnection *connection)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection),
+	                   NM_SETTINGS_CONNECTION_FLAGS_VOLATILE))
+		return;
+	if (active_connection_find_first (self,
+	                                  connection,
+	                                  NULL,
+	                                  NM_ACTIVE_CONNECTION_STATE_DEACTIVATED))
+		return;
+	if (!nm_settings_has_connection (priv->settings, connection))
+		return;
+
+	_LOGD (LOGD_DEVICE, "volatile connection disconnected. Deleting connection '%s' (%s)",
+	       nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection));
+	nm_settings_connection_delete (connection, NULL);
+}
+
 /* Returns: whether to notify D-Bus of the removal or not */
 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;
+	gs_unref_object NMSettingsConnection *connection = NULL;
+	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 (&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);
+
+	connection = nm_g_object_ref (nm_active_connection_get_settings_connection (active));
+
+	nm_exported_object_clear_and_unexport (&active);
 
-	return found && notify;
+	if (connection)
+		_delete_volatile_connection_do (self, connection);
+
+	return notify;
 }
 
 static gboolean
@@ -353,16 +380,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);
@@ -420,10 +443,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,
@@ -445,10 +469,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 *
@@ -457,16 +481,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);
@@ -505,47 +525,35 @@ _get_activatable_connections_filter (NMSettings *settings,
                                      NMSettingsConnection *connection,
                                      gpointer user_data)
 {
-	if (nm_settings_connection_get_volatile (connection))
+	if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection),
+	                  NM_SETTINGS_CONNECTION_FLAGS_VOLATILE))
 		return FALSE;
 	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;
 }
@@ -827,16 +835,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;
 
@@ -1391,7 +1397,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;
@@ -1435,7 +1443,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;
@@ -1491,6 +1501,74 @@ connection_updated_cb (NMSettings *settings,
 		connection_changed (self, connection);
 }
 
+/*****************************************************************************/
+
+typedef struct {
+	CList delete_volatile_connection_lst;
+	NMSettingsConnection *connection;
+} DeleteVolatileConnectionData;
+
+static void
+_delete_volatile_connection_all (NMManager *self, gboolean do_delete)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	CList *lst;
+	DeleteVolatileConnectionData *data;
+
+	while ((lst = c_list_first (&priv->delete_volatile_connection_lst_head))) {
+		gs_unref_object NMSettingsConnection *connection = NULL;
+
+		data = c_list_entry (lst,
+		                     DeleteVolatileConnectionData,
+		                     delete_volatile_connection_lst);
+		connection = data->connection;
+		c_list_unlink_stale (&data->delete_volatile_connection_lst);
+		g_slice_free (DeleteVolatileConnectionData, data);
+
+		if (do_delete)
+			_delete_volatile_connection_do (self, connection);
+	}
+}
+
+static gboolean
+_delete_volatile_connection_cb (gpointer user_data)
+{
+	NMManager *self = user_data;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	priv->delete_volatile_connection_idle_id = 0;
+	_delete_volatile_connection_all (self, TRUE);
+	return G_SOURCE_REMOVE;
+}
+
+static void
+connection_flags_changed (NMSettings *settings,
+                          NMSettingsConnection *connection,
+                          gpointer user_data)
+{
+	NMManager *self = user_data;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	DeleteVolatileConnectionData *data;
+
+	if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection),
+	                   NM_SETTINGS_CONNECTION_FLAGS_VOLATILE))
+		return;
+
+	if (active_connection_find_first (self, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)) {
+		/* the connection still have an active-connection. It will be purged
+		 * when the active connection(s) get(s) removed. */
+		return;
+	}
+
+	data = g_slice_new (DeleteVolatileConnectionData);
+	data->connection = g_object_ref (connection);
+	c_list_link_tail (&priv->delete_volatile_connection_lst_head, &data->delete_volatile_connection_lst);
+	if (!priv->delete_volatile_connection_idle_id)
+		priv->delete_volatile_connection_idle_id = g_idle_add (_delete_volatile_connection_cb, self);
+}
+
+/*****************************************************************************/
+
 static void
 system_unmanaged_devices_changed_cb (NMSettings *settings,
                                      GParamSpec *pspec,
@@ -1860,6 +1938,7 @@ get_existing_connection (NMManager *self,
 
 		matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections,
 		                                                             connection,
+		                                                             TRUE,
 		                                                             nm_device_has_carrier (device),
 		                                                             nm_device_get_route_metric (device, AF_INET),
 		                                                             nm_device_get_route_metric (device, AF_INET6),
@@ -1889,6 +1968,7 @@ get_existing_connection (NMManager *self,
 
 			matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection ((NMConnection *const*) connections,
 			                                                             connection,
+			                                                             FALSE,
 			                                                             nm_device_has_carrier (device),
 			                                                             nm_device_get_route_metric (device, AF_INET),
 			                                                             nm_device_get_route_metric (device, AF_INET6),
@@ -2476,7 +2556,7 @@ _platform_link_cb_idle (PlatformLinkCbData *data)
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	const NMPlatformLink *plink;
 
-	c_list_unlink (&data->lst);
+	c_list_unlink_stale (&data->lst);
 	g_slice_free (PlatformLinkCbData, data);
 
 	plink = nm_platform_link_get (priv->platform, ifindex);
@@ -3021,7 +3101,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;
@@ -3627,11 +3709,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);
 
@@ -3640,12 +3722,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,
@@ -3660,16 +3742,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);
 }
 
 /**
@@ -3894,6 +3972,9 @@ _activation_auth_done (NMActiveConnection *active,
 
 	if (success) {
 		if (_internal_activate_generic (self, active, &error)) {
+			nm_settings_connection_autoconnect_blocked_reason_set (connection,
+			                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST,
+			                                                       FALSE);
 			g_dbus_method_invocation_return_value (context,
 			                                       g_variant_new ("(o)",
 			                                       nm_exported_object_get_path (NM_EXPORTED_OBJECT (active))));
@@ -4037,10 +4118,12 @@ activation_add_done (NMSettings *settings,
 		nm_active_connection_set_settings_connection (active, new_connection);
 
 		if (_internal_activate_generic (self, active, &local)) {
-			nm_settings_connection_commit_changes (new_connection,
-			                                       NULL,
-			                                       NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED,
-			                                       NULL);
+			nm_settings_connection_update (new_connection,
+			                               NULL,
+			                               NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK,
+			                               NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED,
+			                               "add-and-activate",
+			                               NULL);
 			g_dbus_method_invocation_return_value (
 			    context,
 			    g_variant_new ("(oo)",
@@ -4166,7 +4249,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--;
@@ -4508,7 +4593,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 	waking_from_suspend = sleeping_changed && !priv->sleeping;
 
 	if (manager_sleeping (self)) {
-		_LOGI (LOGD_SUSPEND, "%s...", suspending ? "sleeping" : "disabling");
+		_LOGD (LOGD_SUSPEND, "sleep: %s...", suspending ? "sleeping" : "disabling");
 
 		/* FIXME: are there still hardware devices that need to be disabled around
 		 * suspend/resume?
@@ -4539,7 +4624,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 			}
 		}
 	} else {
-		_LOGI (LOGD_SUSPEND, "%s...", waking_from_suspend ? "waking up" : "re-enabling");
+		_LOGD (LOGD_SUSPEND, "sleep: %s...", waking_from_suspend ? "waking up" : "re-enabling");
 
 		if (waking_from_suspend) {
 			sleep_devices_clear (self);
@@ -4596,7 +4681,6 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 					       enabled ? "enabling" : "disabling",
 					       rstate->desc, rstate->hw_enabled, rstate->sw_enabled, rstate->user_enabled);
 				}
-
 				if (nm_device_get_rfkill_type (device) == rstate->rtype)
 					nm_device_set_enabled (device, enabled);
 			}
@@ -4620,7 +4704,7 @@ _internal_sleep (NMManager *self, gboolean do_sleep)
 	if (priv->sleeping == do_sleep)
 		return;
 
-	_LOGI (LOGD_SUSPEND, "%s requested (sleeping: %s  enabled: %s)",
+	_LOGI (LOGD_SUSPEND, "sleep: %s requested (sleeping: %s  enabled: %s)",
 	       do_sleep ? "sleep" : "wake",
 	       priv->sleeping ? "yes" : "no",
 	       priv->net_enabled ? "yes" : "no");
@@ -4732,7 +4816,7 @@ sleeping_cb (NMSleepMonitor *monitor, gboolean is_about_to_suspend, gpointer use
 {
 	NMManager *self = user_data;
 
-	_LOGD (LOGD_SUSPEND, "Received %s signal", is_about_to_suspend ? "sleeping" : "resuming");
+	_LOGT (LOGD_SUSPEND, "sleep: received %s signal", is_about_to_suspend ? "sleeping" : "resuming");
 	_internal_sleep (self, is_about_to_suspend);
 }
 
@@ -5225,7 +5309,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]));
 
@@ -5908,7 +5994,7 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena
 	if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) {
 		_LOGW (LOGD_RFKILL, "rfkill: (%s): failed to set killswitch device for "
 		       "non-blocking operation", desc);
-		close (fd);
+		nm_close (fd);
 		return;
 	}
 
@@ -5938,7 +6024,7 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena
 		_LOGW (LOGD_RFKILL, "rfkill: (%s): failed to change WiFi killswitch state", desc);
 	}
 
-	close (fd);
+	nm_close (fd);
 }
 
 static void
@@ -5989,19 +6075,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
@@ -6106,6 +6188,7 @@ constructed (GObject *object)
 	                  G_CALLBACK (connection_added_cb), self);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
 	                  G_CALLBACK (connection_updated_cb), self);
+	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED, G_CALLBACK (connection_flags_changed), self);
 
 	priv->hostname_manager = g_object_ref (nm_hostname_manager_get ());
 	g_signal_connect (priv->hostname_manager, "notify::" NM_HOSTNAME_MANAGER_HOSTNAME,
@@ -6163,6 +6246,8 @@ nm_manager_init (NMManager *self)
 	GFile *file;
 
 	c_list_init (&priv->link_cb_lst);
+	c_list_init (&priv->active_connections_lst_head);
+	c_list_init (&priv->delete_volatile_connection_lst_head);
 
 	priv->platform = g_object_ref (NM_PLATFORM_GET);
 
@@ -6250,7 +6335,10 @@ get_property (GObject *object, guint prop_id,
 	NMConfigData *config_data;
 	const NMGlobalDnsConfig *dns_config;
 	const char *type;
-	NMConnectivity *connectivity;
+	const char *path;
+	NMActiveConnection *ac;
+	GPtrArray *ptrarr;
+	gboolean vbool;
 
 	switch (prop_id) {
 	case PROP_VERSION:
@@ -6290,7 +6378,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);
@@ -6300,8 +6395,12 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_boolean (value, nm_config_data_get_connectivity_uri (config_data) != NULL);
 		break;
 	case PROP_CONNECTIVITY_CHECK_ENABLED:
-		connectivity = nm_connectivity_get ();
-		g_value_set_boolean (value, nm_connectivity_check_enabled (connectivity));
+#if WITH_CONCHECK
+		vbool = nm_connectivity_check_enabled (nm_connectivity_get ());
+#else
+		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);
@@ -6400,6 +6499,12 @@ dispose (GObject *object)
 	NMManager *self = NM_MANAGER (object);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	CList *iter, *iter_safe;
+	NMActiveConnection *ac, *ac_safe;
+
+	nm_clear_g_source (&priv->delete_volatile_connection_idle_id);
+	_delete_volatile_connection_all (self, FALSE);
+	nm_assert (!priv->delete_volatile_connection_idle_id);
+	nm_assert (c_list_is_empty (&priv->delete_volatile_connection_lst_head));
 
 	g_signal_handlers_disconnect_by_func (priv->platform,
 	                                      G_CALLBACK (platform_link_cb),
@@ -6408,7 +6513,7 @@ dispose (GObject *object)
 		PlatformLinkCbData *data = c_list_entry (iter, PlatformLinkCbData, lst);
 
 		g_source_remove (data->idle_id);
-		c_list_unlink (iter);
+		c_list_unlink_stale (iter);
 		g_slice_free (PlatformLinkCbData, data);
 	}
 
@@ -6433,9 +6538,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);
 
@@ -6455,6 +6560,7 @@ dispose (GObject *object)
 		g_signal_handlers_disconnect_by_func (priv->settings, system_unmanaged_devices_changed_cb, self);
 		g_signal_handlers_disconnect_by_func (priv->settings, connection_added_cb, self);
 		g_signal_handlers_disconnect_by_func (priv->settings, connection_updated_cb, self);
+		g_signal_handlers_disconnect_by_func (priv->settings, connection_flags_changed, self);
 		g_clear_object (&priv->settings);
 	}