summary refs log tree commit diff
path: root/src/settings
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-12-18 18:29:24 +0100
committerMichael Biebl <biebl@debian.org>2019-12-18 18:29:24 +0100
commit28028b26b3371756811e95d894f709f4b1207c00 (patch)
tree6fe7316fd743b51042db47601a8ef8814b3134ac /src/settings
parente22609983008e1a669196ad64ba3a59ae8c76e0d (diff)
New upstream version 1.22.0 upstream/1.22.0
Diffstat (limited to 'src/settings')
-rw-r--r--src/settings/nm-agent-manager.c51
-rw-r--r--src/settings/nm-agent-manager.h18
-rw-r--r--src/settings/nm-secret-agent.c743
-rw-r--r--src/settings/nm-secret-agent.h24
-rw-r--r--src/settings/nm-settings-connection.c22
-rw-r--r--src/settings/nm-settings-connection.h22
-rw-r--r--src/settings/nm-settings-plugin.c18
-rw-r--r--src/settings/nm-settings-plugin.h18
-rw-r--r--src/settings/nm-settings-storage.c18
-rw-r--r--src/settings/nm-settings-storage.h18
-rw-r--r--src/settings/nm-settings-utils.c18
-rw-r--r--src/settings/nm-settings-utils.h18
-rw-r--r--src/settings/nm-settings.c67
-rw-r--r--src/settings/nm-settings.h23
-rw-r--r--src/settings/plugins/ifcfg-rh/meson.build37
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-common.h20
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c19
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.h19
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c609
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h18
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c18
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.h18
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c20
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h20
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c47
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h18
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.c41
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.h30
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/meson.build5
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk-adhoc1
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp9
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes4
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c73
-rw-r--r--src/settings/plugins/ifupdown/meson.build29
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c21
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h21
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-parser.c21
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-parser.h21
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-plugin.c23
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-plugin.h21
-rw-r--r--src/settings/plugins/ifupdown/tests/meson.build3
-rw-r--r--src/settings/plugins/ifupdown/tests/test-ifupdown.c105
-rw-r--r--src/settings/plugins/ifupdown/tests/test22-duplicate-stanzas8
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-plugin.c55
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-plugin.h18
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-reader.c18
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-reader.h18
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-storage.c18
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-storage.h18
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-utils.c52
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-utils.h32
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-writer.c33
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-writer.h18
-rw-r--r--src/settings/plugins/keyfile/tests/meson.build3
-rw-r--r--src/settings/plugins/keyfile/tests/test-keyfile-settings.c20
55 files changed, 1054 insertions, 1626 deletions
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index db0e021c..ecca0eb3 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -1,19 +1,5 @@
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2010 - 2013 Red Hat, Inc.
  */
 
@@ -93,13 +79,13 @@ NM_DEFINE_SINGLETON_GETTER (NMAgentManager, nm_agent_manager_get, NM_TYPE_AGENT_
             if (!(self)) \
                 g_snprintf (__prefix1, sizeof (__prefix1), "%s%s", ""_NMLOG_PREFIX_NAME"", "[]"); \
             else if ((self) != singleton_instance) \
-                g_snprintf (__prefix1, sizeof (__prefix1), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \
+                g_snprintf (__prefix1, sizeof (__prefix1), "%s["NM_HASH_OBFUSCATE_PTR_FMT"]", ""_NMLOG_PREFIX_NAME"", NM_HASH_OBFUSCATE_PTR (self)); \
             else \
                 g_strlcpy (__prefix1, _NMLOG_PREFIX_NAME, sizeof (__prefix1)); \
             if (__agent) { \
                 g_snprintf (__prefix2, sizeof (__prefix2), \
-                            ": req[%p, %s]", \
-                            __agent, \
+                            ": agent["NM_HASH_OBFUSCATE_PTR_FMT",%s]", \
+                            NM_HASH_OBFUSCATE_PTR (__agent), \
                             nm_secret_agent_get_description (__agent)); \
             } else \
                 __prefix2[0] = '\0'; \
@@ -109,9 +95,9 @@ NM_DEFINE_SINGLETON_GETTER (NMAgentManager, nm_agent_manager_get, NM_TYPE_AGENT_
         } \
     } G_STMT_END
 
-#define LOG_REQ_FMT          "[%p/%s%s%s%s%s%s]"
+#define LOG_REQ_FMT          "["NM_HASH_OBFUSCATE_PTR_FMT"/%s%s%s%s%s%s]"
 #define LOG_REQ_ARG(req) \
-	(req), \
+	NM_HASH_OBFUSCATE_PTR (req), \
 	NM_PRINT_FMT_QUOTE_STRING ((req)->detail), \
 	NM_PRINT_FMT_QUOTED (((req)->request_type == REQUEST_TYPE_CON_GET) && (req)->con.get.setting_name, \
 	                     "/\"", (req)->con.get.setting_name, "\"", \
@@ -539,12 +525,10 @@ request_free (Request *req)
 	if (req->idle_id)
 		g_source_remove (req->idle_id);
 
-	if (req->current && req->current_call_id) {
-		/* cancel-secrets invokes the done-callback synchronously -- in which case
-		 * the handler just return.
-		 * Hence, we can proceed to free @req... */
-		nm_secret_agent_cancel_secrets (req->current, req->current_call_id);
-	}
+	/* cancel-secrets invokes the done-callback synchronously -- in which case
+	 * the handler just return.
+	 * Hence, we can proceed to free @req... */
+	nm_secret_agent_cancel_call (req->current, req->current_call_id);
 
 	g_object_unref (req->subject);
 
@@ -742,12 +726,9 @@ request_next_agent (Request *req)
 
 	self = req->self;
 
-	if (req->current) {
-		if (req->current_call_id)
-			nm_secret_agent_cancel_secrets (req->current, req->current_call_id);
-		g_clear_object (&req->current);
-	}
+	nm_secret_agent_cancel_call (req->current, req->current_call_id);
 	nm_assert (!req->current_call_id);
+	g_clear_object (&req->current);
 
 	if (req->pending) {
 		/* Send the request to the next agent */
@@ -882,10 +863,8 @@ _con_get_request_done (NMSecretAgent *agent,
 			req_complete_error (req, error);
 			g_error_free (error);
 		} else {
-			if (req->current_call_id) {
-				/* Tell the failed agent we're no longer interested. */
-				nm_secret_agent_cancel_secrets (req->current, req->current_call_id);
-			}
+			/* Tell the failed agent we're no longer interested. */
+			nm_secret_agent_cancel_call (req->current, req->current_call_id);
 
 			/* Try the next agent */
 			request_next_agent (req);
diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h
index 949ab6bc..5200d241 100644
--- a/src/settings/nm-agent-manager.h
+++ b/src/settings/nm-agent-manager.h
@@ -1,19 +1,5 @@
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2010 - 2011 Red Hat, Inc.
  */
 
diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c
index 2aa1476d..74bd9b2f 100644
--- a/src/settings/nm-secret-agent.c
+++ b/src/settings/nm-secret-agent.c
@@ -1,19 +1,5 @@
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2010 - 2011 Red Hat, Inc.
  */
 
@@ -24,9 +10,9 @@
 #include <sys/types.h>
 #include <pwd.h>
 
+#include "nm-glib-aux/nm-c-list.h"
 #include "nm-glib-aux/nm-dbus-aux.h"
 #include "nm-dbus-interface.h"
-#include "nm-dbus-manager.h"
 #include "nm-core-internal.h"
 #include "nm-auth-subject.h"
 #include "nm-simple-connection.h"
@@ -35,30 +21,32 @@
 
 /*****************************************************************************/
 
+#define METHOD_GET_SECRETS        "GetSecrets"
+#define METHOD_CANCEL_GET_SECRETS "CancelGetSecrets"
+#define METHOD_SAVE_SECRETS       "SaveSecrets"
+#define METHOD_DELETE_SECRETS     "DeleteSecrets"
+
 enum {
 	DISCONNECTED,
 
 	LAST_SIGNAL
 };
+
 static guint signals[LAST_SIGNAL] = { 0 };
 
 typedef struct {
+	CList permissions;
 	char *description;
 	NMAuthSubject *subject;
 	char *identifier;
 	char *owner_username;
 	char *dbus_owner;
-	NMSecretAgentCapabilities capabilities;
-	GSList *permissions;
-	GDBusProxy *proxy;
-	NMDBusManager *bus_mgr;
-	GDBusConnection *connection;
+	GDBusConnection *dbus_connection;
+	GCancellable *name_owner_cancellable;
 	CList requests;
-	union {
-		gulong obj_signal;
-		guint dbus_signal;
-	} on_disconnected_id;
-	bool connection_is_private:1;
+	NMSecretAgentCapabilities capabilities;
+	guint name_owner_changed_id;
+	bool shutdown_wait_obj_registered:1;
 } NMSecretAgentPrivate;
 
 struct _NMSecretAgent {
@@ -81,25 +69,51 @@ G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT)
 #define _NMLOG(level, ...) \
     G_STMT_START { \
         if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \
-            char __prefix[32]; \
+            char _prefix[64]; \
             \
-            if ((self)) \
-                g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \
-            else \
-                g_strlcpy (__prefix, _NMLOG_PREFIX_NAME, sizeof (__prefix)); \
-            _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \
+            if ((self)) { \
+                g_snprintf (_prefix, \
+                            sizeof (_prefix), \
+                            _NMLOG_PREFIX_NAME"["NM_HASH_OBFUSCATE_PTR_FMT"]", \
+                            NM_HASH_OBFUSCATE_PTR (self)); \
+            } else \
+                g_strlcpy (_prefix, _NMLOG_PREFIX_NAME, sizeof (_prefix)); \
+            \
+            _nm_log ((level), \
+                     (_NMLOG_DOMAIN), \
+                     0, \
+                     NULL, \
+                     NULL, \
                      "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
-                     __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+                     _prefix \
+                     _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
         } \
     } G_STMT_END
 
-#define LOG_REQ_FMT          "req[%p,%s,%s%s%s%s]"
-#define LOG_REQ_ARG(req)     (req), (req)->dbus_command, NM_PRINT_FMT_QUOTE_STRING ((req)->path), ((req)->cancellable ? "" : " (cancelled)")
+#define _NMLOG2(level, call_id, ...) \
+    G_STMT_START { \
+        NMSecretAgentCallId *const _call_id = (call_id); \
+        \
+        nm_assert (_call_id); \
+        \
+        nm_log ((level), \
+                (_NMLOG_DOMAIN), \
+                NULL, \
+                NULL, \
+                "%s["NM_HASH_OBFUSCATE_PTR_FMT"] request ["NM_HASH_OBFUSCATE_PTR_FMT",%s,%s%s%s%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+                _NMLOG_PREFIX_NAME, \
+                NM_HASH_OBFUSCATE_PTR (_call_id->self), \
+                NM_HASH_OBFUSCATE_PTR (_call_id), \
+                _call_id->method_name, \
+                NM_PRINT_FMT_QUOTE_STRING (_call_id->path), \
+                (_call_id->cancellable ? "" : " (cancelled)") \
+                _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+    } G_STMT_END
 
 /*****************************************************************************/
 
 NM_UTILS_FLAGS2STR_DEFINE_STATIC (_capabilities_to_string, NMSecretAgentCapabilities,
-	NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_NONE, "none"),
+	NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_NONE,      "none"),
 	NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, "vpn-hints"),
 );
 
@@ -107,69 +121,100 @@ NM_UTILS_FLAGS2STR_DEFINE_STATIC (_capabilities_to_string, NMSecretAgentCapabili
 
 struct _NMSecretAgentCallId {
 	CList lst;
-	NMSecretAgent *agent;
+	NMSecretAgent *self;
 	GCancellable *cancellable;
 	char *path;
-	const char *dbus_command;
+	const char *method_name;
 	char *setting_name;
-	gboolean is_get_secrets;
 	NMSecretAgentCallback callback;
 	gpointer callback_data;
 };
 
 static NMSecretAgentCallId *
-request_new (NMSecretAgent *self,
-             const char *dbus_command, /* this must be a static string. */
-             const char *path,
-             const char *setting_name,
-             NMSecretAgentCallback callback,
-             gpointer callback_data)
+_call_id_new (NMSecretAgent *self,
+              const char *method_name, /* this must be a static string. */
+              const char *path,
+              const char *setting_name,
+              NMSecretAgentCallback callback,
+              gpointer callback_data)
 {
-	NMSecretAgentCallId *r;
-
-	r = g_slice_new0 (NMSecretAgentCallId);
-	r->agent = self;
-	r->path = g_strdup (path);
-	r->setting_name = g_strdup (setting_name);
-	r->dbus_command = dbus_command,
-	r->callback = callback;
-	r->callback_data = callback_data;
-	r->cancellable = g_cancellable_new ();
-	c_list_link_tail (&NM_SECRET_AGENT_GET_PRIVATE (self)->requests,
-	                  &r->lst);
-	_LOGt ("request "LOG_REQ_FMT": created", LOG_REQ_ARG (r));
-	return r;
+	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
+	NMSecretAgentCallId *call_id;
+
+	call_id = g_slice_new (NMSecretAgentCallId);
+	*call_id = (NMSecretAgentCallId) {
+		.self              = g_object_ref (self),
+		.path              = g_strdup (path),
+		.setting_name      = g_strdup (setting_name),
+		.method_name       = method_name,
+		.callback          = callback,
+		.callback_data     = callback_data,
+		.cancellable       = g_cancellable_new (),
+	};
+	c_list_link_tail (&priv->requests, &call_id->lst);
+
+	_LOG2T (call_id, "new request...");
+
+	if (!priv->shutdown_wait_obj_registered) {
+		/* self has async requests (that keep self alive). As long as
+		 * we have pending requests, shutdown is blocked. */
+		priv->shutdown_wait_obj_registered = TRUE;
+		nm_shutdown_wait_obj_register_object (G_OBJECT (self), "secret-agent");
+	}
+
+	return call_id;
 }
-#define request_new(self,dbus_command,path,setting_name,callback,callback_data) request_new(self,""dbus_command"",path,setting_name,callback,callback_data)
+
+#define _call_id_new(self, method_name, path, setting_name, callback, callback_data) _call_id_new(self, ""method_name"", path, setting_name, callback, callback_data)
 
 static void
-request_free (NMSecretAgentCallId *r)
+_call_id_free (NMSecretAgentCallId *call_id)
 {
-	NMSecretAgent *self = r->agent;
-
-	_LOGt ("request "LOG_REQ_FMT": destroyed", LOG_REQ_ARG (r));
-	c_list_unlink_stale (&r->lst);
-	g_free (r->path);
-	g_free (r->setting_name);
-	if (r->cancellable)
-		g_object_unref (r->cancellable);
-	g_slice_free (NMSecretAgentCallId, r);
+	c_list_unlink_stale (&call_id->lst);
+	g_free (call_id->path);
+	g_free (call_id->setting_name);
+	nm_g_object_unref (call_id->cancellable);
+	g_object_unref (call_id->self);
+	nm_g_slice_free (call_id);
 }
 
-static gboolean
-request_check_return (NMSecretAgentCallId *r)
+static void
+_call_id_invoke_callback (NMSecretAgentCallId *call_id,
+                          GVariant *secrets,
+                          GError *error,
+                          gboolean cancelled,
+                          gboolean free_call_id)
 {
-	if (!r->cancellable)
-		return FALSE;
+	gs_free_error GError *error_cancelled = NULL;
 
-	g_return_val_if_fail (NM_IS_SECRET_AGENT (r->agent), FALSE);
+	nm_assert (call_id);
+	nm_assert (!c_list_is_empty (&call_id->lst));
 
-	nm_assert (c_list_contains (&NM_SECRET_AGENT_GET_PRIVATE (r->agent)->requests,
-	                            &r->lst));
+	c_list_unlink (&call_id->lst);
 
-	c_list_unlink (&r->lst);
+	if (cancelled) {
+		nm_assert (!secrets);
+		nm_assert (!error);
+		if (call_id->callback) {
+			nm_utils_error_set_cancelled (&error_cancelled, FALSE, "NMSecretAgent");
+			error = error_cancelled;
+		}
+		_LOG2T (call_id, "cancelled");
+	} else if (error) {
+		nm_assert (!secrets);
+		_LOG2T (call_id, "completed with failure: %s", error->message);
+	} else {
+		nm_assert (   !secrets
+		           || g_variant_is_of_type (secrets, G_VARIANT_TYPE ("a{sa{sv}}")));
+		nm_assert ((!!secrets) == nm_streq0 (call_id->method_name, METHOD_GET_SECRETS));
+		_LOG2T (call_id, "completed successfully");
+	}
+
+	if (call_id->callback)
+		call_id->callback (call_id->self, call_id, secrets, error, call_id->callback_data);
 
-	return TRUE;
+	if (free_call_id)
+		_call_id_free (call_id);
 }
 
 /*****************************************************************************/
@@ -200,6 +245,8 @@ nm_secret_agent_get_description (NMSecretAgent *agent)
 	return priv->description;
 }
 
+/*****************************************************************************/
+
 const char *
 nm_secret_agent_get_dbus_owner (NMSecretAgent *agent)
 {
@@ -256,6 +303,8 @@ nm_secret_agent_get_subject (NMSecretAgent *agent)
 	return NM_SECRET_AGENT_GET_PRIVATE (agent)->subject;
 }
 
+/*****************************************************************************/
+
 /**
  * nm_secret_agent_add_permission:
  * @agent: A #NMSecretAgent.
@@ -269,31 +318,25 @@ nm_secret_agent_add_permission (NMSecretAgent *agent,
                                 gboolean allowed)
 {
 	NMSecretAgentPrivate *priv;
-	GSList *iter;
+	NMCListElem *elem;
 
 	g_return_if_fail (agent != NULL);
 	g_return_if_fail (permission != NULL);
 
 	priv = NM_SECRET_AGENT_GET_PRIVATE (agent);
 
-	/* Check if the permission is already in the list */
-	for (iter = priv->permissions; iter; iter = g_slist_next (iter)) {
-		if (g_strcmp0 (permission, iter->data) == 0) {
-			/* If the permission is no longer allowed, remove it from the
-			 * list.  If it is now allowed, do nothing since it's already
-			 * in the list.
-			 */
-			if (allowed == FALSE) {
-				g_free (iter->data);
-				priv->permissions = g_slist_delete_link (priv->permissions, iter);
-			}
-			return;
-		}
+	elem = nm_c_list_elem_find_first (&priv->permissions, p, nm_streq (p, permission));
+
+	if (elem) {
+		if (!allowed)
+			nm_c_list_elem_free_full (elem, g_free);
+		return;
 	}
 
-	/* New permission that's allowed */
-	if (allowed)
-		priv->permissions = g_slist_prepend (priv->permissions, g_strdup (permission));
+	if (allowed) {
+		c_list_link_tail (&priv->permissions,
+		                  &nm_c_list_elem_new_stale (g_strdup (permission))->lst);
+	}
 }
 
 /**
@@ -310,51 +353,48 @@ nm_secret_agent_add_permission (NMSecretAgent *agent,
 gboolean
 nm_secret_agent_has_permission (NMSecretAgent *agent, const char *permission)
 {
-	NMSecretAgentPrivate *priv;
-	GSList *iter;
-
 	g_return_val_if_fail (agent != NULL, FALSE);
 	g_return_val_if_fail (permission != NULL, FALSE);
 
-	priv = NM_SECRET_AGENT_GET_PRIVATE (agent);
-
-	/* Check if the permission is already in the list */
-	for (iter = priv->permissions; iter; iter = g_slist_next (iter)) {
-		if (g_strcmp0 (permission, iter->data) == 0)
-			return TRUE;
-	}
-	return FALSE;
+	return !!nm_c_list_elem_find_first (&NM_SECRET_AGENT_GET_PRIVATE (agent)->permissions,
+	                                    p, nm_streq (p, permission));
 }
 
 /*****************************************************************************/
 
 static void
-get_callback (GObject *proxy,
-              GAsyncResult *result,
-              gpointer user_data)
+_dbus_call_cb (GObject *source,
+               GAsyncResult *result,
+               gpointer user_data)
 {
-	NMSecretAgentCallId *r = user_data;
-
-	if (request_check_return (r)) {
-		NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent);
-		gs_free_error GError *error = NULL;
-		gs_unref_variant GVariant *ret = NULL;
-		gs_unref_variant GVariant *secrets = NULL;
-
-		ret = _nm_dbus_proxy_call_finish (priv->proxy, result, G_VARIANT_TYPE ("(a{sa{sv}})"), &error);
-		if (!ret)
-			g_dbus_error_strip_remote_error (error);
-		else {
+	NMSecretAgentCallId *call_id;
+	gs_unref_variant GVariant *ret = NULL;
+	gs_unref_variant GVariant *secrets = NULL;
+	gs_free_error GError *error = NULL;
+
+	ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
+
+	if (   !ret
+	    && nm_utils_error_is_cancelled (error, FALSE))
+		return;
+
+	call_id = user_data;
+
+	if (!ret)
+		g_dbus_error_strip_remote_error (error);
+	else {
+		if (nm_streq (call_id->method_name, METHOD_GET_SECRETS)) {
 			g_variant_get (ret,
 			               "(@a{sa{sv}})",
 			               &secrets);
 		}
-		r->callback (r->agent, r, secrets, error, r->callback_data);
 	}
 
-	request_free (r);
+	_call_id_invoke_callback (call_id, secrets, error, FALSE, TRUE);
 }
 
+/*****************************************************************************/
+
 NMSecretAgentCallId *
 nm_secret_agent_get_secrets (NMSecretAgent *self,
                              const char *path,
@@ -367,160 +407,139 @@ nm_secret_agent_get_secrets (NMSecretAgent *self,
 {
 	NMSecretAgentPrivate *priv;
 	GVariant *dict;
-	NMSecretAgentCallId *r;
+	NMSecretAgentCallId *call_id;
 
 	g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
 	g_return_val_if_fail (path && *path, NULL);
-	g_return_val_if_fail (setting_name != NULL, NULL);
+	g_return_val_if_fail (setting_name, NULL);
+	g_return_val_if_fail (callback, NULL);
 
 	priv = NM_SECRET_AGENT_GET_PRIVATE (self);
-	g_return_val_if_fail (priv->proxy != NULL, NULL);
 
 	dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
 
 	/* Mask off the private flags if present */
-	flags &= ~NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM;
-	flags &= ~NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS;
-
-	r = request_new (self, "GetSecrets", path, setting_name, callback, callback_data);
-	r->is_get_secrets = TRUE;
-
-	g_dbus_proxy_call (priv->proxy,
-	                   "GetSecrets",
-	                   g_variant_new ("(@a{sa{sv}}os^asu)",
-	                                  dict,
-	                                  path,
-	                                  setting_name,
-	                                  hints ?: NM_PTRARRAY_EMPTY (const char *),
-	                                  (guint32) flags),
-	                   G_DBUS_CALL_FLAGS_NONE,
-	                   120000,
-	                   r->cancellable,
-	                   get_callback,
-	                   r);
-
-	g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (priv->proxy), -1);
-
-	return r;
+	flags &= ~(  NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM
+	           | NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS);
+
+	call_id = _call_id_new (self, METHOD_GET_SECRETS, path, setting_name, callback, callback_data);
+
+	g_dbus_connection_call (priv->dbus_connection,
+	                        priv->dbus_owner,
+	                        NM_DBUS_PATH_SECRET_AGENT,
+	                        NM_DBUS_INTERFACE_SECRET_AGENT,
+	                        call_id->method_name,
+	                        g_variant_new ("(@a{sa{sv}}os^asu)",
+	                                       dict,
+	                                       path,
+	                                       setting_name,
+	                                       hints ?: NM_PTRARRAY_EMPTY (const char *),
+	                                       (guint32) flags),
+	                        G_VARIANT_TYPE ("(a{sa{sv}})"),
+	                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                        120000,
+	                        call_id->cancellable,
+	                        _dbus_call_cb,
+	                        call_id);
+
+	return call_id;
 }
 
 /*****************************************************************************/
 
 static void
-cancel_done (GObject *proxy, GAsyncResult *result, gpointer user_data)
+_call_cancel_cb (GObject *source,
+                 GAsyncResult *result,
+                 gpointer user_data)
 {
-	gs_free char *description = user_data;
+	NMSecretAgentCallId *call_id = user_data;
 	gs_free_error GError *error = NULL;
 	gs_unref_variant GVariant *ret = NULL;
 
-	ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, G_VARIANT_TYPE ("()"), &error);
-	if (!ret) {
-		nm_log_dbg (LOGD_AGENTS, "%s%s%s: agent failed to cancel secrets: %s",
-		            NM_PRINT_FMT_QUOTED (description, "(", description, ")", "???"),
-		            error->message);
-	}
-}
-
-static void
-do_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId *r, gboolean disposing)
-{
-	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
-	GCancellable *cancellable;
-	NMSecretAgentCallback callback;
-	gpointer callback_data;
+	ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
 
-	g_return_if_fail (r->agent == self);
-	g_return_if_fail (r->cancellable);
-
-	if (   r->is_get_secrets
-	    && priv->proxy) {
-		/* for GetSecrets call, we must cancel the request. */
-		g_dbus_proxy_call (G_DBUS_PROXY (priv->proxy),
-		                   "CancelGetSecrets",
-		                   g_variant_new ("(os)",
-		                                  r->path,
-		                                  r->setting_name),
-		                   G_DBUS_CALL_FLAGS_NONE,
-		                   -1,
-		                   NULL,
-		                   cancel_done,
-		                   g_strdup (nm_secret_agent_get_description (self)));
+	if (ret)
+		_LOG2T (call_id, "success cancelling GetSecrets");
+	else if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
+		_LOG2T (call_id, "cancelling GetSecrets no longer works as service disconnected");
+	else {
+		_LOG2T (call_id, "failed to cancel GetSecrets: %s",
+		        error->message);
 	}
 
-	cancellable = r->cancellable;
-	callback = r->callback;
-	callback_data = r->callback_data;
-
-	/* During g_cancellable_cancel() the d-bus method might return synchronously.
-	 * Clear r->cancellable first, so that it doesn't actually do anything.
-	 * After that, @r might be already freed. */
-	r->cancellable = NULL;
-	g_cancellable_cancel (cancellable);
-	g_object_unref (cancellable);
-
-	/* Don't free the request @r. It will be freed when the d-bus call returns.
-	 * Only clear r->cancellable to indicate that the request was cancelled. */
-
-	if (callback) {
-		gs_free_error GError *error = NULL;
-
-		nm_utils_error_set_cancelled (&error, disposing, "NMSecretAgent");
-		/* @r might be a dangling pointer at this point. However, that is no problem
-		 * to pass it as (opaque) call_id. */
-		callback (self, r, NULL, error, callback_data);
-	}
+	_call_id_free (call_id);
 }
 
 /**
- * nm_secret_agent_cancel_secrets:
- * @self: #NMSecretAgent instance
- * @call_id: the call id to cancel
+ * nm_secret_agent_cancel_call:
+ * @self: the #NMSecretAgent instance for the @call_id.
+ *   Maybe be %NULL if @call_id is %NULL.
+ * @call_id: (allow-none): the call id to cancel. May be %NULL for convenience,
+ *   in which case it does nothing.
  *
  * It is an error to pass an invalid @call_id or a @call_id for an operation
- * that already completed. NMSecretAgent will always invoke the callback,
- * also for cancel() and dispose().
- * In case of nm_secret_agent_cancel_secrets() this will synchronously invoke the
- * callback before nm_secret_agent_cancel_secrets() returns.
+ * that already completed. It is also an error to cancel the call from inside
+ * the callback, at that point the call is already completed.
+ * In case of nm_secret_agent_cancel_call() this will synchronously invoke the
+ * callback before nm_secret_agent_cancel_call() returns.
  */
 void
-nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId *call_id)
+nm_secret_agent_cancel_call (NMSecretAgent *self,
+                             NMSecretAgentCallId *call_id)
 {
-	NMSecretAgentCallId *r = call_id;
-
-	g_return_if_fail (NM_IS_SECRET_AGENT (self));
-	g_return_if_fail (r);
-
-	nm_assert (c_list_contains (&NM_SECRET_AGENT_GET_PRIVATE (self)->requests,
-	                            &r->lst));
-
-	c_list_unlink (&r->lst);
+	NMSecretAgentPrivate *priv;
+	gboolean free_call_id = TRUE;
 
-	do_cancel_secrets (self, r, FALSE);
-}
+	if (!call_id) {
+		/* for convenience, %NULL is accepted fine. */
+		nm_assert (!self || NM_IS_SECRET_AGENT (self));
+		return;
+	}
 
-/*****************************************************************************/
+	g_return_if_fail (NM_IS_SECRET_AGENT (call_id->self));
+	g_return_if_fail (!c_list_is_empty (&call_id->lst));
 
-static void
-agent_save_cb (GObject *proxy,
-               GAsyncResult *result,
-               gpointer user_data)
-{
-	NMSecretAgentCallId *r = user_data;
+	/* Theoretically, call-id already has a self pointer. But nm_secret_agent_cancel_call() has only
+	 * one user: NMAgentManager. And that one has the self-pointer at hand, so the only purpose of
+	 * the @self argument is to assert that we are cancelling the expected call.
+	 *
+	 * We could drop the @self argument, but that just remove an additional assert-check from
+	 * our code, without making a simplification for the only caller of this function. */
+	g_return_if_fail (self == call_id->self);
 
-	if (request_check_return (r)) {
-		gs_free_error GError *error = NULL;
-		gs_unref_variant GVariant *ret = NULL;
+	priv = NM_SECRET_AGENT_GET_PRIVATE (self);
 
-		ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, G_VARIANT_TYPE ("()"), &error);
-		if (!ret)
-			g_dbus_error_strip_remote_error (error);
-		r->callback (r->agent, r, NULL, error, r->callback_data);
+	nm_assert (c_list_contains (&priv->requests,
+	                            &call_id->lst));
+
+	nm_clear_g_cancellable (&call_id->cancellable);
+
+	if (nm_streq (call_id->method_name, METHOD_GET_SECRETS)) {
+		g_dbus_connection_call (priv->dbus_connection,
+		                        priv->dbus_owner,
+		                        NM_DBUS_PATH_SECRET_AGENT,
+		                        NM_DBUS_INTERFACE_SECRET_AGENT,
+		                        METHOD_CANCEL_GET_SECRETS,
+		                        g_variant_new ("(os)",
+		                                       call_id->path,
+		                                       call_id->setting_name),
+		                        G_VARIANT_TYPE ("()"),
+		                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
+		                        NM_SHUTDOWN_TIMEOUT_MS,
+		                        NULL, /* this operation is not cancellable. We rely on the timeout. */
+		                        _call_cancel_cb,
+		                        call_id);
+		/* we keep call-id alive, but it will be unlinked from priv->requests.
+		 * _call_cancel_cb() will finally free it later. */
+		free_call_id = FALSE;
 	}
 
-	request_free (r);
+	_call_id_invoke_callback (call_id, NULL, NULL, TRUE, free_call_id);
 }
 
+/*****************************************************************************/
+
 NMSecretAgentCallId *
 nm_secret_agent_save_secrets (NMSecretAgent *self,
                               const char *path,
@@ -530,7 +549,7 @@ nm_secret_agent_save_secrets (NMSecretAgent *self,
 {
 	NMSecretAgentPrivate *priv;
 	GVariant *dict;
-	NMSecretAgentCallId *r;
+	NMSecretAgentCallId *call_id;
 
 	g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
@@ -541,43 +560,28 @@ nm_secret_agent_save_secrets (NMSecretAgent *self,
 	/* Caller should have ensured that only agent-owned secrets exist in 'connection' */
 	dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
 
-	r = request_new (self, "SaveSecrets", path, NULL, callback, callback_data);
-	g_dbus_proxy_call (priv->proxy,
-	                   "SaveSecrets",
-	                   g_variant_new ("(@a{sa{sv}}o)",
-	                                  dict,
-	                                  path),
-	                   G_DBUS_CALL_FLAGS_NONE,
-	                   -1,
-	                   NULL, /* cancelling the request does *not* cancel the D-Bus call. */
-	                   agent_save_cb,
-	                   r);
-
-	return r;
+	call_id = _call_id_new (self, METHOD_SAVE_SECRETS, path, NULL, callback, callback_data);
+
+	g_dbus_connection_call (priv->dbus_connection,
+	                        priv->dbus_owner,
+	                        NM_DBUS_PATH_SECRET_AGENT,
+	                        NM_DBUS_INTERFACE_SECRET_AGENT,
+	                        call_id->method_name,
+	                        g_variant_new ("(@a{sa{sv}}o)",
+	                                       dict,
+	                                       path),
+	                        G_VARIANT_TYPE ("()"),
+	                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                        60000,
+	                        call_id->cancellable,
+	                        _dbus_call_cb,
+	                        call_id);
+
+	return call_id;
 }
 
 /*****************************************************************************/
 
-static void
-agent_delete_cb (GObject *proxy,
-                 GAsyncResult *result,
-                 gpointer user_data)
-{
-	NMSecretAgentCallId *r = user_data;
-
-	if (request_check_return (r)) {
-		gs_free_error GError *error = NULL;
-		gs_unref_variant GVariant *ret = NULL;
-
-		ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, G_VARIANT_TYPE ("()"), &error);
-		if (!ret)
-			g_dbus_error_strip_remote_error (error);
-		r->callback (r->agent, r, NULL, error, r->callback_data);
-	}
-
-	request_free (r);
-}
-
 NMSecretAgentCallId *
 nm_secret_agent_delete_secrets (NMSecretAgent *self,
                                 const char *path,
@@ -587,7 +591,7 @@ nm_secret_agent_delete_secrets (NMSecretAgent *self,
 {
 	NMSecretAgentPrivate *priv;
 	GVariant *dict;
-	NMSecretAgentCallId *r;
+	NMSecretAgentCallId *call_id;
 
 	g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
@@ -598,81 +602,90 @@ nm_secret_agent_delete_secrets (NMSecretAgent *self,
 	/* No secrets sent; agents must be smart enough to track secrets using the UUID or something */
 	dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_NO_SECRETS);
 
-	r = request_new (self, "DeleteSecrets", path, NULL, callback, callback_data);
-	g_dbus_proxy_call (priv->proxy,
-	                   "DeleteSecrets",
-	                   g_variant_new ("(@a{sa{sv}}o)",
-	                                  dict,
-	                                  path),
-	                   G_DBUS_CALL_FLAGS_NONE,
-	                   -1,
-	                   NULL, /* cancelling the request does *not* cancel the D-Bus call. */
-	                   agent_delete_cb,
-	                   r);
-	return r;
+	call_id = _call_id_new (self, METHOD_DELETE_SECRETS, path, NULL, callback, callback_data);
+
+	g_dbus_connection_call (priv->dbus_connection,
+	                        priv->dbus_owner,
+	                        NM_DBUS_PATH_SECRET_AGENT,
+	                        NM_DBUS_INTERFACE_SECRET_AGENT,
+	                        call_id->method_name,
+	                        g_variant_new ("(@a{sa{sv}}o)",
+	                                       dict,
+	                                       path),
+	                        G_VARIANT_TYPE ("()"),
+	                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                        60000,
+	                        call_id->cancellable,
+	                        _dbus_call_cb,
+	                        call_id);
+	return call_id;
 }
 
 /*****************************************************************************/
 
 static void
-_on_disconnected_cleanup (NMSecretAgentPrivate *priv)
+name_owner_changed (NMSecretAgent *self,
+                    const char *owner)
 {
-	if (priv->connection_is_private) {
-		nm_clear_g_signal_handler (priv->bus_mgr,
-		                           &priv->on_disconnected_id.obj_signal);
-	} else {
-		nm_clear_g_dbus_connection_signal (priv->connection,
-		                                   &priv->on_disconnected_id.dbus_signal);
-	}
+	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
 
-	g_clear_object (&priv->connection);
-	g_clear_object (&priv->proxy);
-	g_clear_object (&priv->bus_mgr);
-}
+	nm_assert (!priv->name_owner_cancellable);
 
-static void
-_on_disconnected_private_connection (NMDBusManager *mgr,
-                                     GDBusConnection *connection,
-                                     NMSecretAgent *self)
-{
-	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
+	owner = nm_str_not_empty (owner);
+
+	_LOGT ("name-owner-changed: %s%s%s",
+	       NM_PRINT_FMT_QUOTED (owner, "has ", owner, "", "disconnected"));
 
-	if (priv->connection != connection)
+	if (owner)
 		return;
 
-	_LOGt ("private connection disconnected");
+	nm_clear_g_dbus_connection_signal (priv->dbus_connection,
+	                                   &priv->name_owner_changed_id);
 
-	_on_disconnected_cleanup (priv);
 	g_signal_emit (self, signals[DISCONNECTED], 0);
 }
 
 static void
-_on_disconnected_name_owner_changed (GDBusConnection *connection,
-                                     const char       *sender_name,
-                                     const char       *object_path,
-                                     const char       *interface_name,
-                                     const char       *signal_name,
-                                     GVariant         *parameters,
-                                     gpointer          user_data)
+name_owner_changed_cb (GDBusConnection *dbus_connection,
+                       const char       *sender_name,
+                       const char       *object_path,
+                       const char       *interface_name,
+                       const char       *signal_name,
+                       GVariant         *parameters,
+                       gpointer          user_data)
 {
 	NMSecretAgent *self = NM_SECRET_AGENT (user_data);
-	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
-	const char *old_owner = NULL, *new_owner = NULL;
+	const char *new_owner = NULL;
+
+	if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) {
+		g_variant_get (parameters,
+		               "(&s&s&s)",
+		               NULL,
+		               NULL,
+		               &new_owner);
+	}
 
-	g_variant_get (parameters,
-	               "(&s&s&s)",
-	               NULL,
-	               &old_owner,
-	               &new_owner);
+	nm_clear_g_cancellable (&NM_SECRET_AGENT_GET_PRIVATE (self)->name_owner_cancellable);
 
-	_LOGt ("name-owner-changed: %s%s%s => %s%s%s",
-	       NM_PRINT_FMT_QUOTE_STRING (old_owner),
-	       NM_PRINT_FMT_QUOTE_STRING (new_owner));
+	name_owner_changed (self, new_owner);
+}
 
-	if (!*new_owner) {
-		_on_disconnected_cleanup (priv);
-		g_signal_emit (self, signals[DISCONNECTED], 0);
-	}
+static void
+get_name_owner_cb (const char *name_owner,
+                   GError *error,
+                   gpointer user_data)
+{
+	NMSecretAgent *self;
+
+	if (   !name_owner
+	    && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+
+	self = user_data;
+
+	g_clear_object (&NM_SECRET_AGENT_GET_PRIVATE (self)->name_owner_cancellable);
+
+	name_owner_changed (self, name_owner);
 }
 
 /*****************************************************************************/
@@ -692,16 +705,16 @@ nm_secret_agent_new (GDBusMethodInvocation *context,
 	char buf_subject[64];
 	char buf_caps[150];
 	gulong uid;
-	GDBusConnection *connection;
+	GDBusConnection *dbus_connection;
 
 	g_return_val_if_fail (context != NULL, NULL);
 	g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
 	g_return_val_if_fail (nm_auth_subject_is_unix_process (subject), NULL);
 	g_return_val_if_fail (identifier != NULL, NULL);
 
-	connection = g_dbus_method_invocation_get_connection (context);
+	dbus_connection = g_dbus_method_invocation_get_connection (context);
 
-	g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+	g_return_val_if_fail (G_IS_DBUS_CONNECTION (dbus_connection), NULL);
 
 	uid = nm_auth_subject_get_unix_process_uid (subject);
 
@@ -715,16 +728,13 @@ nm_secret_agent_new (GDBusMethodInvocation *context,
 
 	priv = NM_SECRET_AGENT_GET_PRIVATE (self);
 
-	priv->bus_mgr = g_object_ref (nm_dbus_manager_get ());
-	priv->connection = g_object_ref (connection);
-	priv->connection_is_private = !!nm_dbus_manager_connection_get_private_name (priv->bus_mgr, connection);
+	priv->dbus_connection = g_object_ref (dbus_connection);
 
-	_LOGt ("constructed: %s, owner=%s%s%s (%s), private-connection=%d, unique-name=%s%s%s, capabilities=%s",
+	_LOGT ("constructed: %s, owner=%s%s%s (%s), unique-name=%s%s%s, capabilities=%s",
 	       (description = _create_description (dbus_owner, identifier, uid)),
 	       NM_PRINT_FMT_QUOTE_STRING (owner_username),
 	       nm_auth_subject_to_string (subject, buf_subject, sizeof (buf_subject)),
-	       priv->connection_is_private,
-	       NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->connection)),
+	       NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->dbus_connection)),
 	       _capabilities_to_string (capabilities, buf_caps, sizeof (buf_caps)));
 
 	priv->identifier = g_strdup (identifier);
@@ -734,27 +744,19 @@ nm_secret_agent_new (GDBusMethodInvocation *context,
 	priv->capabilities = capabilities;
 	priv->subject = g_object_ref (subject);
 
-	priv->proxy = nm_dbus_manager_new_proxy (priv->bus_mgr,
-	                                         priv->connection,
-	                                         G_TYPE_DBUS_PROXY,
-	                                         priv->dbus_owner,
-	                                         NM_DBUS_PATH_SECRET_AGENT,
-	                                         NM_DBUS_INTERFACE_SECRET_AGENT);
-
-	/* we cannot subscribe to notify::g-name-owner because that doesn't work
-	 * for unique names and it doesn't work for private connections. */
-	if (priv->connection_is_private) {
-		priv->on_disconnected_id.obj_signal = g_signal_connect (priv->bus_mgr,
-		                                                        NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED,
-		                                                        G_CALLBACK (_on_disconnected_private_connection),
-		                                                        self);
-	} else {
-		priv->on_disconnected_id.dbus_signal = nm_dbus_connection_signal_subscribe_name_owner_changed (priv->connection,
-		                                                                                               priv->dbus_owner,
-		                                                                                               _on_disconnected_name_owner_changed,
-		                                                                                               self,
-		                                                                                               NULL);
-	}
+	priv->name_owner_changed_id = nm_dbus_connection_signal_subscribe_name_owner_changed (priv->dbus_connection,
+	                                                                                      priv->dbus_owner,
+	                                                                                      name_owner_changed_cb,
+	                                                                                      self,
+	                                                                                      NULL);
+
+	priv->name_owner_cancellable = g_cancellable_new ();
+	nm_dbus_connection_call_get_name_owner (priv->dbus_connection,
+	                                        priv->dbus_owner,
+	                                        -1,
+	                                        priv->name_owner_cancellable,
+	                                        get_name_owner_cb,
+	                                        self);
 
 	return self;
 }
@@ -764,6 +766,7 @@ nm_secret_agent_init (NMSecretAgent *self)
 {
 	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
 
+	c_list_init (&priv->permissions);
 	c_list_init (&priv->requests);
 }
 
@@ -772,18 +775,13 @@ dispose (GObject *object)
 {
 	NMSecretAgent *self = NM_SECRET_AGENT (object);
 	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
-	CList *iter;
 
-again:
-	c_list_for_each (iter, &priv->requests) {
-		c_list_unlink (iter);
-		do_cancel_secrets (self, c_list_entry (iter, NMSecretAgentCallId, lst), TRUE);
-		goto again;
-	}
+	nm_assert (c_list_is_empty (&priv->requests));
 
-	_on_disconnected_cleanup (priv);
+	nm_clear_g_dbus_connection_signal (priv->dbus_connection,
+	                                   &priv->name_owner_changed_id);
 
-	g_clear_object (&priv->subject);
+	nm_clear_g_cancellable (&priv->name_owner_cancellable);
 
 	G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object);
 }
@@ -799,11 +797,15 @@ finalize (GObject *object)
 	g_free (priv->owner_username);
 	g_free (priv->dbus_owner);
 
-	g_slist_free_full (priv->permissions, g_free);
+	nm_c_list_elem_free_all (&priv->permissions, g_free);
+
+	g_clear_object (&priv->subject);
+
+	g_clear_object (&priv->dbus_connection);
 
 	G_OBJECT_CLASS (nm_secret_agent_parent_class)->finalize (object);
 
-	_LOGt ("finalized");
+	_LOGT ("finalized");
 }
 
 static void
@@ -823,4 +825,3 @@ nm_secret_agent_class_init (NMSecretAgentClass *config_class)
 	                  g_cclosure_marshal_VOID__VOID,
 	                  G_TYPE_NONE, 0);
 }
-
diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h
index 209a1009..ea86e432 100644
--- a/src/settings/nm-secret-agent.h
+++ b/src/settings/nm-secret-agent.h
@@ -1,19 +1,5 @@
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2010 - 2011 Red Hat, Inc.
  */
 
@@ -79,9 +65,6 @@ NMSecretAgentCallId *nm_secret_agent_get_secrets (NMSecretAgent *agent,
                                                   NMSecretAgentCallback callback,
                                                   gpointer callback_data);
 
-void        nm_secret_agent_cancel_secrets (NMSecretAgent *agent,
-                                            NMSecretAgentCallId *call_id);
-
 NMSecretAgentCallId *nm_secret_agent_save_secrets (NMSecretAgent *agent,
                                                    const char *path,
                                                    NMConnection *connection,
@@ -94,4 +77,7 @@ NMSecretAgentCallId *nm_secret_agent_delete_secrets (NMSecretAgent *agent,
                                                      NMSecretAgentCallback callback,
                                                      gpointer callback_data);
 
+void nm_secret_agent_cancel_call (NMSecretAgent *self,
+                                  NMSecretAgentCallId *call_id);
+
 #endif /* __NETWORKMANAGER_SECRET_AGENT_H__ */
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index ed0cb8e8..ccbab807 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -1,21 +1,7 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2008 Novell, Inc.
- * Copyright 2008 - 2014 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2008 Novell, Inc.
+ * Copyright (C) 2008 - 2014 Red Hat, Inc.
  */
 
 #include "nm-default.h"
diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h
index 61d5c246..dfc3786c 100644
--- a/src/settings/nm-settings-connection.h
+++ b/src/settings/nm-settings-connection.h
@@ -1,21 +1,7 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2008 Novell, Inc.
- * (C) Copyright 2008 - 2013 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2008 Novell, Inc.
+ * Copyright (C) 2008 - 2013 Red Hat, Inc.
  */
 
 #ifndef __NETWORKMANAGER_SETTINGS_CONNECTION_H__
diff --git a/src/settings/nm-settings-plugin.c b/src/settings/nm-settings-plugin.c
index 09010931..630532ef 100644
--- a/src/settings/nm-settings-plugin.c
+++ b/src/settings/nm-settings-plugin.c
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2007 - 2018 Red Hat, Inc.
  * Copyright (C) 2008 Novell, Inc.
  */
diff --git a/src/settings/nm-settings-plugin.h b/src/settings/nm-settings-plugin.h
index 4df3472e..d27429db 100644
--- a/src/settings/nm-settings-plugin.h
+++ b/src/settings/nm-settings-plugin.h
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2007 - 2018 Red Hat, Inc.
  * Copyright (C) 2008 Novell, Inc.
  */
diff --git a/src/settings/nm-settings-storage.c b/src/settings/nm-settings-storage.c
index 935b5b48..483773f6 100644
--- a/src/settings/nm-settings-storage.c
+++ b/src/settings/nm-settings-storage.c
@@ -1,20 +1,6 @@
+// SPDX-License-Identifier: LGPL-2.1+
 /*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * Copyright 2018 Red Hat, Inc.
+ * Copyright (C) 2018 Red Hat, Inc.
  */
 
 #include "nm-default.h"
diff --git a/src/settings/nm-settings-storage.h b/src/settings/nm-settings-storage.h
index c43145b5..62ee8876 100644
--- a/src/settings/nm-settings-storage.h
+++ b/src/settings/nm-settings-storage.h
@@ -1,20 +1,6 @@
+// SPDX-License-Identifier: LGPL-2.1+
 /*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * Copyright 2018 Red Hat, Inc.
+ * Copyright (C) 2018 Red Hat, Inc.
  */
 
 #ifndef __NM_SETTINGS_STORAGE_H__
diff --git a/src/settings/nm-settings-utils.c b/src/settings/nm-settings-utils.c
index 0d636537..c5ec6c31 100644
--- a/src/settings/nm-settings-utils.c
+++ b/src/settings/nm-settings-utils.c
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2019 Red Hat, Inc.
  */
 
diff --git a/src/settings/nm-settings-utils.h b/src/settings/nm-settings-utils.h
index a2a22dc4..1f9a6ea1 100644
--- a/src/settings/nm-settings-utils.h
+++ b/src/settings/nm-settings-utils.h
@@ -1,20 +1,6 @@
+// SPDX-License-Identifier: LGPL-2.1+
 /*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * Copyright 2019 Red Hat, Inc.
+ * Copyright (C) 2019 Red Hat, Inc.
  */
 
 #ifndef __NM_SETTINGS_UTILS_H__
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 6529cc58..f964fb16 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -1,25 +1,10 @@
-/* NetworkManager system settings service
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Søren Sandmann <sandmann@daimi.au.dk>
  * Dan Williams <dcbw@redhat.com>
  * Tambet Ingo <tambet@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2007 - 2011 Red Hat, Inc.
- * (C) Copyright 2008 Novell, Inc.
+ * Copyright (C) 2007 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 Novell, Inc.
  */
 
 #include "nm-default.h"
@@ -2487,17 +2472,6 @@ nm_settings_add_connection_dbus (NMSettings *self,
 		goto done;
 	}
 
-	/* FIXME: The kernel doesn't support Ad-Hoc WPA connections well at this time,
-	 * and turns them into open networks.  It's been this way since at least
-	 * 2.6.30 or so; until that's fixed, disable WPA-protected Ad-Hoc networks.
-	 */
-	if (nm_utils_connection_is_adhoc_wpa (connection)) {
-		error = g_error_new_literal (NM_SETTINGS_ERROR,
-		                             NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		                             "WPA Ad-Hoc disabled due to kernel bugs");
-		goto done;
-	}
-
 	if (!nm_auth_is_subject_in_acl_set_error (connection,
 	                                          subject,
 	                                          NM_SETTINGS_ERROR,
@@ -2776,9 +2750,10 @@ impl_settings_load_connections (NMDBusObject *obj,
 		for (i = 0; i < n_entries; i++) {
 			NMSettingsPluginConnectionLoadEntry *entry = &entries[i];
 
-			if (!entry->handled)
+			if (!entry->handled) {
 				_LOGW ("load: no settings plugin could load \"%s\"", entry->filename);
-			else if (entry->error) {
+				nm_assert (!entry->error);
+			} else if (entry->error) {
 				_LOGW ("load: failure to load \"%s\": %s", entry->filename, entry->error->message);
 				g_clear_error (&entry->error);
 			} else
@@ -2847,6 +2822,7 @@ impl_settings_reload_connections (NMDBusObject *obj,
 
 	nm_audit_log_connection_op (NM_AUDIT_OP_CONNS_RELOAD, NULL, TRUE, NULL, invocation, NULL);
 
+	/* We MUST return %TRUE here, otherwise older libnm versions might misbehave. */
 	g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
 }
 
@@ -3140,9 +3116,9 @@ add_plugin (NMSettings *self,
 
 	priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin));
 
-	nm_shutdown_wait_obj_register_full (G_OBJECT (plugin),
-	                                    g_strdup_printf ("%s-settings-plugin", pname),
-	                                    TRUE);
+	nm_shutdown_wait_obj_register_object_full (plugin,
+	                                           g_strdup_printf ("%s-settings-plugin", pname),
+	                                           TRUE);
 
 	_LOGI ("Loaded settings plugin: %s (%s%s%s)",
 	       pname,
@@ -3455,14 +3431,27 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
 	 */
 	if (   !NM_DEVICE_GET_CLASS (device)->new_default_connection
 	    || !nm_device_get_managed (device, FALSE)
-	    || g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ())
-	    || have_connection_for_device (self, device)
-	    || nm_config_get_no_auto_default_for_device (priv->config, device))
+	    || g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ()))
 		return;
 
+	if (nm_config_get_no_auto_default_for_device (priv->config, device)) {
+		_LOGT ("auto-default: cannot create auto-default connection for device %s: disabled by \"no-auto-default\"",
+		       nm_device_get_iface (device));
+		return;
+	}
+
+	if (have_connection_for_device (self, device)) {
+		_LOGT ("auto-default: cannot create auto-default connection for device %s: already has a profile",
+		       nm_device_get_iface (device));
+		return;
+	}
+
 	connection = nm_device_new_default_connection (device);
-	if (!connection)
+	if (!connection) {
+		_LOGT ("auto-default: cannot create auto-default connection for device %s",
+		       nm_device_get_iface (device));
 		return;
+	}
 
 	_LOGT ("auto-default: creating in-memory connection %s (%s) for device %s",
 	       nm_connection_get_uuid (connection),
diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h
index d2bf72d6..aa7e36e0 100644
--- a/src/settings/nm-settings.h
+++ b/src/settings/nm-settings.h
@@ -1,25 +1,10 @@
-/* NetworkManager system settings service
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Søren Sandmann <sandmann@daimi.au.dk>
  * Dan Williams <dcbw@redhat.com>
  * Tambet Ingo <tambet@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2007 - 2011 Red Hat, Inc.
- * (C) Copyright 2008 Novell, Inc.
+ * Copyright (C) 2007 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 Novell, Inc.
  */
 
 #ifndef __NM_SETTINGS_H__
diff --git a/src/settings/plugins/ifcfg-rh/meson.build b/src/settings/plugins/ifcfg-rh/meson.build
index 58acdcfc..d9dd3edb 100644
--- a/src/settings/plugins/ifcfg-rh/meson.build
+++ b/src/settings/plugins/ifcfg-rh/meson.build
@@ -25,23 +25,24 @@ core_sources = files(
   'shvar.c',
 )
 
-deps = [
-  nm_dep,
-]
-
 libnms_ifcfg_rh_core = static_library(
   'nms-ifcfg-rh-core',
   sources: core_sources,
-  dependencies: deps,
+  dependencies: daemon_nm_default_dep,
+  c_args: daemon_c_flags,
 )
 
-sources = [dbus_sources] + core_sources + files('nms-ifcfg-rh-storage.c', 'nms-ifcfg-rh-plugin.c')
+sources = [dbus_sources] + core_sources + files(
+  'nms-ifcfg-rh-storage.c',
+  'nms-ifcfg-rh-plugin.c',
+)
 
 libnm_settings_plugin_ifcfg_rh = shared_module(
   'nm-settings-plugin-ifcfg-rh',
   sources: sources,
-  dependencies: deps,
-  link_with: [libnms_ifcfg_rh_core],
+  dependencies: daemon_nm_default_dep,
+  c_args: daemon_c_flags,
+  link_with: libnms_ifcfg_rh_core,
   link_args: ldflags_linker_script_settings,
   link_depends: linker_script_settings,
   install: true,
@@ -50,27 +51,17 @@ libnm_settings_plugin_ifcfg_rh = shared_module(
 
 core_plugins += libnm_settings_plugin_ifcfg_rh
 
-# FIXME: check_so_symbols replacement
-'''
-run_target(
-  'check-local-symbols-settings-ifcfg-rh',
-  command: [check_so_symbols, libnm_settings_plugin_ifcfg_rh.full_path()],
-  depends: libnm_settings_plugin_ifcfg_rh,
-)
-
-check-local-symbols-settings-ifcfg-rh: src/settings/plugins/ifcfg-rh/libnm-settings-plugin-ifcfg-rh.la
-  $(call check_so_symbols,$(builddir)/src/settings/plugins/ifcfg-rh/.libs/libnm-settings-plugin-ifcfg-rh.so)
-'''
+data = [
+  'nm-ifdown',
+  'nm-ifup',
+]
 
 install_data(
-  ['nm-ifup', 'nm-ifdown'],
+  data,
   install_dir: nm_libexecdir,
   install_mode: 'rwxr-xr-x',
 )
 
-meson.add_install_script('sh', '-c',
-                         'mkdir -p $DESTDIR/@0@/sysconfig/network-scripts'.format(nm_sysconfdir))
-
 if enable_tests
   subdir('tests')
 endif
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-common.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-common.h
index ff01fc7a..6a01a5ac 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-common.h
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-common.h
@@ -1,20 +1,6 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2008 - 2013 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2008 - 2013 Red Hat, Inc.
  */
 
 #ifndef __COMMON_H__
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
index cc4fe4ce..f57ca1a7 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
@@ -1,22 +1,7 @@
-/* NetworkManager system settings service
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Dan Williams <dcbw@redhat.com>
  * Søren Sandmann <sandmann@daimi.au.dk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
  * Copyright (C) 2007 - 2011 Red Hat, Inc.
  */
 
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.h
index 1db36083..14cadac6 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.h
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.h
@@ -1,22 +1,7 @@
-/* NetworkManager system settings service
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Dan Williams <dcbw@redhat.com>
  * Søren Sandmann <sandmann@daimi.au.dk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
  * Copyright (C) 2007 - 2008 Red Hat, Inc.
  */
 
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
index 68ebd781..a1d3236e 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
@@ -1,20 +1,6 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2008 - 2017 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2008 - 2017 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -29,6 +15,7 @@
 #include <sys/inotify.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
+#include <linux/rtnetlink.h>
 
 #include "nm-glib-aux/nm-secret-utils.h"
 #include "nm-connection.h"
@@ -753,25 +740,36 @@ parse_route_line_is_comment (const char *line)
 
 /*****************************************************************************/
 
+typedef enum {
+	PARSE_LINE_AF_FLAG_FOR_IPV4 = 0x01,
+	PARSE_LINE_AF_FLAG_FOR_IPV6 = 0x02,
+} ParseLineAFFlag;
+
 typedef struct {
 	const char *key;
 
 	/* the element is not available in this case. */
-	bool disabled:1;
+	ParseLineAFFlag disabled:3;
+
+	bool disabled_with_options_route:1;
 
 	/* whether the element is to be ignored. Ignord is different from
 	 * "disabled", because we still parse the option, but don't use it. */
-	bool ignore:1;
+	ParseLineAFFlag ignore:3;
 
 	bool int_base_16:1;
 
+	/* the type, one of PARSE_LINE_TYPE_* */
+	char type;
+
+} ParseLineInfo;
+
+typedef struct {
+
 	/* whether the command line option was found, and @v is
 	 * initialized. */
 	bool has:1;
 
-	/* the type, one of PARSE_LINE_TYPE_* */
-	char type;
-
 	union {
 		guint8 uint8;
 		guint32 uint32;
@@ -786,7 +784,7 @@ typedef struct {
 		} addr;
 	} v;
 
-} ParseLineInfo;
+} ParseLineData;
 
 enum {
 	/* route attributes */
@@ -794,6 +792,7 @@ enum {
 	PARSE_LINE_ATTR_ROUTE_SRC,
 	PARSE_LINE_ATTR_ROUTE_FROM,
 	PARSE_LINE_ATTR_ROUTE_TOS,
+	PARSE_LINE_ATTR_ROUTE_SCOPE,
 	PARSE_LINE_ATTR_ROUTE_ONLINK,
 	PARSE_LINE_ATTR_ROUTE_WINDOW,
 	PARSE_LINE_ATTR_ROUTE_CWND,
@@ -817,6 +816,7 @@ enum {
 #define PARSE_LINE_TYPE_ADDR_WITH_PREFIX  'p'
 #define PARSE_LINE_TYPE_IFNAME            'i'
 #define PARSE_LINE_TYPE_FLAG              'f'
+#define PARSE_LINE_TYPE_ROUTE_SCOPE       'S'
 
 /**
  * parse_route_line:
@@ -847,29 +847,23 @@ parse_route_line (const char *line,
                   NMIPRoute **out_route,
                   GError **error)
 {
-	nm_auto_unref_ip_route NMIPRoute *route = NULL;
-	gs_free const char **words_free = NULL;
-	const char *const*words;
-	const char *s;
-	gsize i_words;
-	guint i;
-	char buf1[256];
-	char buf2[256];
-	ParseLineInfo infos[] = {
+	static const ParseLineInfo parse_infos[] = {
 		[PARSE_LINE_ATTR_ROUTE_TABLE]     = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE,
 		                                      .type = PARSE_LINE_TYPE_UINT32, },
 		[PARSE_LINE_ATTR_ROUTE_SRC]       = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC,
 		                                      .type = PARSE_LINE_TYPE_ADDR, },
 		[PARSE_LINE_ATTR_ROUTE_FROM]      = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM,
 		                                      .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX,
-		                                      .disabled = (addr_family != AF_INET6), },
+		                                      .disabled = PARSE_LINE_AF_FLAG_FOR_IPV4, },
 		[PARSE_LINE_ATTR_ROUTE_TOS]       = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS,
 		                                      .type = PARSE_LINE_TYPE_UINT8,
 		                                      .int_base_16 = TRUE,
-		                                      .ignore = (addr_family != AF_INET), },
+		                                      .ignore = PARSE_LINE_AF_FLAG_FOR_IPV6, },
+		[PARSE_LINE_ATTR_ROUTE_SCOPE]     = { .key = NM_IP_ROUTE_ATTRIBUTE_SCOPE,
+		                                      .type = PARSE_LINE_TYPE_ROUTE_SCOPE,
+		                                      .ignore = PARSE_LINE_AF_FLAG_FOR_IPV6, },
 		[PARSE_LINE_ATTR_ROUTE_ONLINK]    = { .key = NM_IP_ROUTE_ATTRIBUTE_ONLINK,
-		                                      .type = PARSE_LINE_TYPE_FLAG,
-		                                      .ignore = (addr_family != AF_INET), },
+		                                      .type = PARSE_LINE_TYPE_FLAG, },
 		[PARSE_LINE_ATTR_ROUTE_WINDOW]    = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW,
 		                                      .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, },
 		[PARSE_LINE_ATTR_ROUTE_CWND]      = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND,
@@ -883,19 +877,31 @@ parse_route_line (const char *line,
 
 		[PARSE_LINE_ATTR_ROUTE_TO]        = { .key = "to",
 		                                      .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX,
-		                                      .disabled = (options_route != NULL), },
+		                                      .disabled_with_options_route = TRUE, },
 		[PARSE_LINE_ATTR_ROUTE_VIA]       = { .key = "via",
 		                                      .type = PARSE_LINE_TYPE_ADDR,
-		                                      .disabled = (options_route != NULL), },
+		                                      .disabled_with_options_route = TRUE, },
 		[PARSE_LINE_ATTR_ROUTE_METRIC]    = { .key = "metric",
 		                                      .type = PARSE_LINE_TYPE_UINT32,
-		                                      .disabled = (options_route != NULL), },
+		                                      .disabled_with_options_route = TRUE, },
 
 		[PARSE_LINE_ATTR_ROUTE_DEV]       = { .key = "dev",
 		                                      .type = PARSE_LINE_TYPE_IFNAME,
-		                                      .ignore = TRUE,
-		                                      .disabled = (options_route != NULL), },
+		                                      .ignore = PARSE_LINE_AF_FLAG_FOR_IPV4 | PARSE_LINE_AF_FLAG_FOR_IPV6,
+		                                      .disabled_with_options_route = TRUE, },
 	};
+	nm_auto_unref_ip_route NMIPRoute *route = NULL;
+	gs_free const char **words_free = NULL;
+	const char *const*words;
+	const char *s;
+	gsize i_words;
+	guint i;
+	char buf1[256];
+	char buf2[256];
+	ParseLineData parse_datas[G_N_ELEMENTS (parse_infos)] = { };
+	const ParseLineAFFlag af_flag =   (addr_family == AF_INET)
+	                                ? PARSE_LINE_AF_FLAG_FOR_IPV4
+	                                : PARSE_LINE_AF_FLAG_FOR_IPV6;
 
 	nm_assert (line);
 	nm_assert_addr_family (addr_family);
@@ -923,19 +929,22 @@ parse_route_line (const char *line,
 	for (i_words = 0; words[i_words]; ) {
 		const gsize i_words0 = i_words;
 		const char *const w = words[i_words0];
-		ParseLineInfo *info;
+		const ParseLineInfo *p_info;
+		ParseLineData *p_data;
 		gboolean unqualified_addr = FALSE;
 
-		for (i = 0; i < G_N_ELEMENTS (infos); i++) {
-			info = &infos[i];
+		for (i = 0; i < G_N_ELEMENTS (parse_infos); i++) {
+			p_info = &parse_infos[i];
+			p_data = &parse_datas[i];
 
-			if (info->disabled)
+			if (   (p_info->disabled & af_flag)
+			    || (p_info->disabled_with_options_route && options_route))
 				continue;
 
-			if (!nm_streq (w, info->key))
+			if (!nm_streq (w, p_info->key))
 				continue;
 
-			if (info->has) {
+			if (p_data->has) {
 				/* iproute2 for most arguments allows specifying them multiple times.
 				 * Let's not do that. */
 				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -943,8 +952,8 @@ parse_route_line (const char *line,
 				return -EINVAL;
 			}
 
-			info->has = TRUE;
-			switch (info->type) {
+			p_data->has = TRUE;
+			switch (p_info->type) {
 			case PARSE_LINE_TYPE_UINT8:
 				i_words++;
 				goto parse_line_type_uint8;
@@ -966,16 +975,22 @@ parse_route_line (const char *line,
 			case PARSE_LINE_TYPE_FLAG:
 				i_words++;
 				goto next;
+			case PARSE_LINE_TYPE_ROUTE_SCOPE:
+				i_words++;
+				goto parse_line_type_route_scope;
 			default:
 				nm_assert_not_reached ();
 			}
 		}
 
 		/* "to" is also accepted unqualified... (once) */
-		info = &infos[PARSE_LINE_ATTR_ROUTE_TO];
-		if (!info->has && !info->disabled) {
+		p_info = &parse_infos[PARSE_LINE_ATTR_ROUTE_TO];
+		p_data = &parse_datas[PARSE_LINE_ATTR_ROUTE_TO];
+		if (   !p_data->has
+		    && !(p_info->disabled & af_flag)
+		    && !(p_info->disabled_with_options_route && options_route)) {
 			unqualified_addr = TRUE;
-			info->has = TRUE;
+			p_data->has = TRUE;
 			goto parse_line_type_addr;
 		}
 
@@ -983,15 +998,44 @@ parse_route_line (const char *line,
 		             "Unrecognized argument (\"to\" is duplicate or \"%s\" is garbage)", w);
 		return -EINVAL;
 
+parse_line_type_route_scope:
+		s = words[i_words];
+		if (!s)
+			goto err_word_missing_argument;
+		if (nm_streq (s, "global"))
+			p_data->v.uint8 = RT_SCOPE_UNIVERSE;
+		else if (nm_streq (s, "nowhere"))
+			p_data->v.uint8 = RT_SCOPE_NOWHERE;
+		else if (nm_streq (s, "host"))
+			p_data->v.uint8 = RT_SCOPE_HOST;
+		else if (nm_streq (s, "link"))
+			p_data->v.uint8 = RT_SCOPE_LINK;
+		else if (nm_streq (s, "site"))
+			p_data->v.uint8 = RT_SCOPE_SITE;
+		else {
+			p_data->v.uint8 = _nm_utils_ascii_str_to_int64 (s,
+			                                                0,
+			                                                0,
+			                                                G_MAXUINT8,
+			                                                0);;
+			if (errno) {
+				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				             "Argument for \"%s\" is not a valid number", w);
+				return -EINVAL;
+			}
+		}
+		i_words++;
+		goto next;
+
 parse_line_type_uint8:
 		s = words[i_words];
 		if (!s)
 			goto err_word_missing_argument;
-		info->v.uint8 = _nm_utils_ascii_str_to_int64 (s,
-		                                              info->int_base_16 ? 16 : 10,
-		                                              0,
-		                                              G_MAXUINT8,
-		                                              0);;
+		p_data->v.uint8 = _nm_utils_ascii_str_to_int64 (s,
+		                                                p_info->int_base_16 ? 16 : 10,
+		                                                0,
+		                                                G_MAXUINT8,
+		                                                0);;
 		if (errno) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Argument for \"%s\" is not a valid number", w);
@@ -1005,17 +1049,17 @@ parse_line_type_uint32_with_lock:
 		s = words[i_words];
 		if (!s)
 			goto err_word_missing_argument;
-		if (info->type == PARSE_LINE_TYPE_UINT32_WITH_LOCK) {
+		if (p_info->type == PARSE_LINE_TYPE_UINT32_WITH_LOCK) {
 			if (nm_streq (s, "lock")) {
 				s = words[++i_words];
 				if (!s)
 					goto err_word_missing_argument;
-				info->v.uint32_with_lock.lock = TRUE;
+				p_data->v.uint32_with_lock.lock = TRUE;
 			} else
-				info->v.uint32_with_lock.lock = FALSE;
-			info->v.uint32_with_lock.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0);;
+				p_data->v.uint32_with_lock.lock = FALSE;
+			p_data->v.uint32_with_lock.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0);;
 		} else {
-			info->v.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0);
+			p_data->v.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0);
 		}
 		if (errno) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -1040,16 +1084,16 @@ parse_line_type_addr_with_prefix:
 		{
 			int prefix = -1;
 
-			if (info->type == PARSE_LINE_TYPE_ADDR) {
+			if (p_info->type == PARSE_LINE_TYPE_ADDR) {
 				if (!nm_utils_parse_inaddr_bin (addr_family,
 				                                s,
 				                                NULL,
-				                                &info->v.addr.addr)) {
-					if (   info == &infos[PARSE_LINE_ATTR_ROUTE_VIA]
+				                                &p_data->v.addr.addr)) {
+					if (   p_info == &parse_infos[PARSE_LINE_ATTR_ROUTE_VIA]
 					    && nm_streq (s, "(null)")) {
 						/* Due to a bug, would older versions of NM write "via (null)"
 						 * (rh#1452648). Workaround that, and accept it.*/
-						memset (&info->v.addr.addr, 0, sizeof (info->v.addr.addr));
+						memset (&p_data->v.addr.addr, 0, sizeof (p_data->v.addr.addr));
 					} else {
 						if (unqualified_addr) {
 							g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -1064,15 +1108,15 @@ parse_line_type_addr_with_prefix:
 					}
 				}
 			} else {
-				nm_assert (info->type == PARSE_LINE_TYPE_ADDR_WITH_PREFIX);
-				if (   info == &infos[PARSE_LINE_ATTR_ROUTE_TO]
+				nm_assert (p_info->type == PARSE_LINE_TYPE_ADDR_WITH_PREFIX);
+				if (   p_info == &parse_infos[PARSE_LINE_ATTR_ROUTE_TO]
 				    && nm_streq (s, "default")) {
-					memset (&info->v.addr.addr, 0, sizeof (info->v.addr.addr));
+					memset (&p_data->v.addr.addr, 0, sizeof (p_data->v.addr.addr));
 					prefix = 0;
 				} else if (!nm_utils_parse_inaddr_prefix_bin (addr_family,
 				                                              s,
 				                                              NULL,
-				                                              &info->v.addr.addr,
+				                                              &p_data->v.addr.addr,
 				                                              &prefix)) {
 					g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 					             "Argument for \"%s\" is not ADDR/PREFIX format", w);
@@ -1080,10 +1124,10 @@ parse_line_type_addr_with_prefix:
 				}
 			}
 			if (prefix == -1)
-				info->v.addr.has_plen = FALSE;
+				p_data->v.addr.has_plen = FALSE;
 			else {
-				info->v.addr.has_plen = TRUE;
-				info->v.addr.plen = prefix;
+				p_data->v.addr.has_plen = TRUE;
+				p_data->v.addr.plen = prefix;
 			}
 		}
 		i_words++;
@@ -1101,79 +1145,76 @@ next:
 		route = options_route;
 		nm_ip_route_ref (route);
 	} else {
-		ParseLineInfo *info_to = &infos[PARSE_LINE_ATTR_ROUTE_TO];
-		ParseLineInfo *info_via = &infos[PARSE_LINE_ATTR_ROUTE_VIA];
-		ParseLineInfo *info_metric = &infos[PARSE_LINE_ATTR_ROUTE_METRIC];
+		ParseLineData *data_to     = &parse_datas[PARSE_LINE_ATTR_ROUTE_TO];
+		ParseLineData *data_via    = &parse_datas[PARSE_LINE_ATTR_ROUTE_VIA];
+		ParseLineData *data_metric = &parse_datas[PARSE_LINE_ATTR_ROUTE_METRIC];
 		guint prefix;
 
-		if (!info_to->has) {
+		if (!data_to->has) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Missing destination prefix");
 			return -EINVAL;
 		}
 
-		prefix =   info_to->v.addr.has_plen
-		         ? info_to->v.addr.plen
+		prefix =   data_to->v.addr.has_plen
+		         ? data_to->v.addr.plen
 		         : (addr_family == AF_INET ? 32 : 128);
 
-		if (   (   (addr_family == AF_INET  && !info_to->v.addr.addr.addr4)
-		        || (addr_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED (&info_to->v.addr.addr.addr6)))
-		    && prefix == 0) {
-			/* we ignore default routes by returning -ERANGE. */
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "Ignore manual default route");
-			return -ERANGE;
-		}
-
 		route = nm_ip_route_new_binary (addr_family,
-		                                &info_to->v.addr.addr,
+		                                &data_to->v.addr.addr,
 		                                prefix,
-		                                info_via->has ? &info_via->v.addr.addr : NULL,
-		                                info_metric->has ? (gint64) info_metric->v.uint32 : (gint64) -1,
+		                                data_via->has ? &data_via->v.addr.addr : NULL,
+		                                data_metric->has ? (gint64) data_metric->v.uint32 : (gint64) -1,
 		                                error);
-		info_to->has = FALSE;
-		info_via->has = FALSE;
-		info_metric->has = FALSE;
+		data_to->has = FALSE;
+		data_via->has = FALSE;
+		data_metric->has = FALSE;
 		if (!route)
 			return -EINVAL;
 	}
 
-	for (i = 0; i < G_N_ELEMENTS (infos); i++) {
-		ParseLineInfo *info = &infos[i];
+	for (i = 0; i < G_N_ELEMENTS (parse_infos); i++) {
+		const ParseLineInfo *p_info = &parse_infos[i];
+		ParseLineData *p_data = &parse_datas[i];
 
-		if (!info->has)
+		if (!p_data->has)
 			continue;
-		if (info->ignore || info->disabled)
+
+		if (   (p_info->ignore & af_flag)
+		    || (p_info->disabled & af_flag)
+		    || (p_info->disabled_with_options_route && options_route))
 			continue;
-		switch (info->type) {
+
+		switch (p_info->type) {
 		case PARSE_LINE_TYPE_UINT8:
+		case PARSE_LINE_TYPE_ROUTE_SCOPE:
 			nm_ip_route_set_attribute (route,
-			                           info->key,
-			                           g_variant_new_byte (info->v.uint8));
+			                           p_info->key,
+			                           g_variant_new_byte (p_data->v.uint8));
 			break;
 		case PARSE_LINE_TYPE_UINT32:
 			nm_ip_route_set_attribute (route,
-			                           info->key,
-			                           g_variant_new_uint32 (info->v.uint32));
+			                           p_info->key,
+			                           g_variant_new_uint32 (p_data->v.uint32));
 			break;
 		case PARSE_LINE_TYPE_UINT32_WITH_LOCK:
-			if (info->v.uint32_with_lock.lock) {
+			if (p_data->v.uint32_with_lock.lock) {
 				nm_ip_route_set_attribute (route,
-				                           nm_sprintf_buf (buf1, "lock-%s", info->key),
+				                           nm_sprintf_buf (buf1, "lock-%s", p_info->key),
 				                           g_variant_new_boolean (TRUE));
 			}
 			nm_ip_route_set_attribute (route,
-			                           info->key,
-			                           g_variant_new_uint32 (info->v.uint32_with_lock.uint32));
+			                           p_info->key,
+			                           g_variant_new_uint32 (p_data->v.uint32_with_lock.uint32));
 			break;
 		case PARSE_LINE_TYPE_ADDR:
 		case PARSE_LINE_TYPE_ADDR_WITH_PREFIX:
 			nm_ip_route_set_attribute (route,
-			                           info->key,
+			                           p_info->key,
 			                           g_variant_new_printf ("%s%s",
-			                                                 inet_ntop (addr_family, &info->v.addr.addr, buf1, sizeof (buf1)),
-			                                                 info->v.addr.has_plen
-			                                                    ? nm_sprintf_buf (buf2, "/%u", (unsigned) info->v.addr.plen)
+			                                                 inet_ntop (addr_family, &p_data->v.addr.addr, buf1, sizeof (buf1)),
+			                                                 p_data->v.addr.has_plen
+			                                                    ? nm_sprintf_buf (buf2, "/%u", (unsigned) p_data->v.addr.plen)
 			                                                    : ""));
 			break;
 		case PARSE_LINE_TYPE_FLAG:
@@ -1182,7 +1223,7 @@ next:
 			 * of this attribute, hence, the file format cannot encode
 			 * that configuration. */
 			nm_ip_route_set_attribute (route,
-			                           info->key,
+			                           p_info->key,
 			                           g_variant_new_boolean (TRUE));
 			break;
 		default:
@@ -1244,7 +1285,7 @@ read_one_ip4_route (shvarFile *ifcfg,
 		return FALSE;
 	if (has_key) {
 		prefix = nm_utils_ip4_netmask_to_prefix (netmask);
-		if (prefix == 0 || netmask != _nm_utils_ip4_prefix_to_netmask (prefix)) {
+		if (netmask != _nm_utils_ip4_prefix_to_netmask (prefix)) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, inet_buf));
 			return FALSE;
@@ -1538,7 +1579,7 @@ make_ip4_setting (shvarFile *ifcfg,
 	gboolean has_key;
 	shvarFile *route_ifcfg;
 	gboolean never_default;
-	gint64 timeout;
+	gint64 i64;
 	int priority;
 	const char *const *item;
 	guint32 route_table;
@@ -1641,6 +1682,14 @@ make_ip4_setting (shvarFile *ifcfg,
 		              NULL);
 	}
 
+	i64 = svGetValueInt64 (ifcfg, "DHCP_HOSTNAME_FLAGS", 10, 0, G_MAXUINT32, -1);
+	if (i64 > -1) {
+		g_object_set (s_ip4,
+		              NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS,
+		              (guint) i64,
+		              NULL);
+	}
+
 	g_object_set (s_ip4,
 	              NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, svGetValueBoolean (ifcfg, "DHCP_SEND_HOSTNAME", TRUE),
 	              NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, svGetValueInt64 (ifcfg, "IPV4_DHCP_TIMEOUT", 10, 0, G_MAXINT32, 0),
@@ -1651,6 +1700,11 @@ make_ip4_setting (shvarFile *ifcfg,
 	if (v)
 		g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, v, NULL);
 
+	nm_clear_g_free (&value);
+	v = svGetValueStr (ifcfg, "DHCP_IAID", &value);
+	if (v)
+		g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_IAID, v, NULL);
+
 	/* Read static IP addresses.
 	 * Read them even for AUTO method - in this case the addresses are
 	 * added to the automatic ones. Note that this is not currently supported by
@@ -1806,14 +1860,14 @@ make_ip4_setting (shvarFile *ifcfg,
 		}
 	}
 
-	timeout = svGetValueInt64 (ifcfg, "ACD_TIMEOUT", 10, -1, NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, -2);
-	if (timeout == -2) {
-		timeout = svGetValueInt64 (ifcfg, "ARPING_WAIT", 10, -1,
-		                           NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX / 1000, -1);
-		if (timeout > 0)
-			timeout *= 1000;
+	i64 = svGetValueInt64 (ifcfg, "ACD_TIMEOUT", 10, -1, NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, -2);
+	if (i64 == -2) {
+		i64 = svGetValueInt64 (ifcfg, "ARPING_WAIT", 10, -1,
+		                       NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX / 1000, -1);
+		if (i64 > 0)
+			i64 *= 1000;
 	}
-	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, (int) timeout, NULL);
+	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, (int) i64, NULL);
 
 	return NM_SETTING (g_steal_pointer (&s_ip4));
 }
@@ -1947,6 +2001,7 @@ make_ip6_setting (shvarFile *ifcfg,
 	gs_free const char **list = NULL;
 	const char *const *iter;
 	guint32 i;
+	gint64 i64;
 	int i_val;
 	GError *local = NULL;
 	int priority;
@@ -2085,6 +2140,11 @@ make_ip6_setting (shvarFile *ifcfg,
 		g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_DHCP_DUID, v, NULL);
 
 	nm_clear_g_free (&value);
+	v = svGetValueStr (ifcfg, "DHCPV6_IAID", &value);
+	if (v)
+		g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_IAID, v, NULL);
+
+	nm_clear_g_free (&value);
 	v = svGetValueStr (ifcfg, "DHCPV6_HOSTNAME", &value);
 	/* Use DHCP_HOSTNAME as fallback if it is in FQDN format and ipv6.method is
 	 * auto or dhcp: this is required to support old ifcfg files
@@ -2102,6 +2162,15 @@ make_ip6_setting (shvarFile *ifcfg,
 	g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME,
 	              svGetValueBoolean (ifcfg, "DHCPV6_SEND_HOSTNAME", TRUE), NULL);
 
+
+	i64 = svGetValueInt64 (ifcfg, "DHCPV6_HOSTNAME_FLAGS", 10, 0, G_MAXUINT32, -1);
+	if (i64 > -1) {
+		g_object_set (s_ip6,
+		              NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS,
+		              (guint) i64,
+		              NULL);
+	}
+
 	/* Read static IP addresses.
 	 * Read them even for AUTO and DHCP methods - in this case the addresses are
 	 * added to the automatic ones. Note that this is not currently supported by
@@ -2762,7 +2831,7 @@ add_one_wep_key (shvarFile *ifcfg,
 			/* Hexadecimal WEP key */
 			if (NM_STRCHAR_ANY (value, ch, !g_ascii_isxdigit (ch))) {
 				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-				             "Invalid hexadecimal WEP key.");
+				             "Invalid hexadecimal WEP key");
 				return FALSE;
 			}
 			key = value;
@@ -2771,7 +2840,7 @@ add_one_wep_key (shvarFile *ifcfg,
 			/* ASCII key */
 			if (NM_STRCHAR_ANY (value + 2, ch, !g_ascii_isprint (ch))) {
 				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-				             "Invalid ASCII WEP key.");
+				             "Invalid ASCII WEP key");
 				return FALSE;
 			}
 
@@ -2787,7 +2856,7 @@ add_one_wep_key (shvarFile *ifcfg,
 
 	if (!key) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Invalid WEP key length.");
+		             "Invalid WEP key length");
 		return FALSE;
 	}
 
@@ -2934,7 +3003,7 @@ make_wep_setting (shvarFile *ifcfg,
 		if (auth_alg && !strcmp (auth_alg, "shared")) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "WEP Shared Key authentication is invalid for "
-			             "unencrypted connections.");
+			             "unencrypted connections");
 			return NULL;
 		}
 
@@ -2963,22 +3032,6 @@ fill_wpa_ciphers (shvarFile *ifcfg,
 
 	list = nm_utils_strsplit_set (p, " ");
 	for (iter = list; iter && *iter; iter++, i++) {
-		/* Ad-Hoc configurations cannot have pairwise ciphers, and can only
-		 * have one group cipher.  Ignore any additional group ciphers and
-		 * any pairwise ciphers specified.
-		 */
-		if (adhoc) {
-			if (group && (i > 0)) {
-				PARSE_WARNING ("ignoring group cipher '%s' (only one group cipher allowed "
-				               "in Ad-Hoc mode)", *iter);
-				continue;
-			} else if (!group) {
-				PARSE_WARNING ("ignoring pairwise cipher '%s' (pairwise not used "
-				               "in Ad-Hoc mode)", *iter);
-				continue;
-			}
-		}
-
 		if (!strcmp (*iter, "CCMP")) {
 			if (group)
 				nm_setting_wireless_security_add_group (wsec, "ccmp");
@@ -3184,6 +3237,89 @@ eap_tls_reader (const char *eap_method,
 }
 
 static gboolean
+parse_8021x_phase2_auth (shvarFile *ifcfg,
+                         shvarFile *keys_ifcfg,
+                         NMSetting8021x *s_8021x,
+                         GError **error)
+{
+	gs_free char *inner_auth = NULL;
+	gs_free char *v_free = NULL;
+	const char *v;
+	gs_free const char **list = NULL;
+	const char *const *iter;
+	guint num_auth = 0;
+	guint num_autheap = 0;
+
+	v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &v_free);
+	if (!v) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+		             "Missing IEEE_8021X_INNER_AUTH_METHODS");
+		return FALSE;
+	}
+
+	inner_auth = g_ascii_strdown (v, -1);
+	list = nm_utils_strsplit_set (inner_auth, " ");
+	for (iter = list; iter && *iter; iter++) {
+		if (NM_IN_STRSET (*iter, "pap",
+		                         "chap",
+		                         "mschap",
+		                         "mschapv2",
+		                         "gtc",
+		                         "otp",
+		                         "md5")) {
+			if (num_auth == 0) {
+				if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
+					return FALSE;
+				g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL);
+			}
+			num_auth++;
+		} else if (nm_streq (*iter, "tls")) {
+			if (num_auth == 0) {
+				if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
+					return FALSE;
+				g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, "tls", NULL);
+			}
+			num_auth++;
+		} else if (NM_IN_STRSET (*iter, "eap-md5",
+		                                "eap-mschapv2",
+		                                "eap-otp",
+		                                "eap-gtc")) {
+			if (num_autheap == 0) {
+				if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
+					return FALSE;
+				g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + NM_STRLEN ("eap-")), NULL);
+			}
+			num_autheap++;
+		} else if (nm_streq (*iter, "eap-tls")) {
+			if (num_autheap == 0) {
+				if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
+					return FALSE;
+				g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL);
+			}
+			num_autheap++;
+		} else {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'",
+			             *iter);
+			return FALSE;
+		}
+	}
+
+	if (num_auth > 1)
+		PARSE_WARNING ("Discarded extra phase2 authentication methods");
+	if (num_auth > 1)
+		PARSE_WARNING ("Discarded extra phase2 EAP authentication methods");
+
+	if (!num_auth && !num_autheap) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+		             "No phase2 authentication method found");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
 eap_peap_reader (const char *eap_method,
                  shvarFile *ifcfg,
                  shvarFile *keys_ifcfg,
@@ -3193,8 +3329,6 @@ eap_peap_reader (const char *eap_method,
 {
 	gs_free char *value = NULL;
 	const char *v;
-	gs_free const char **list = NULL;
-	const char *const *iter;
 
 	if (!_cert_set_from_ifcfg (s_8021x,
 	                           ifcfg,
@@ -3232,46 +3366,8 @@ eap_peap_reader (const char *eap_method,
 	if (v)
 		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, v, NULL);
 
-	nm_clear_g_free (&value);
-	v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &value);
-	if (!v) {
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
-		return FALSE;
-	}
-
-	/* Handle options for the inner auth method */
-	list = nm_utils_strsplit_set (v, " ");
-	iter = list;
-	if (iter) {
-		if (NM_IN_STRSET (*iter, "MSCHAPV2",
-		                         "MD5",
-		                         "GTC")) {
-			if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
-				return FALSE;
-		} else if (nm_streq (*iter, "TLS")) {
-			if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
-				return FALSE;
-		} else {
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
-			             *iter);
-			return FALSE;
-		}
-
-		{
-			gs_free char *lower = NULL;
-
-			lower = g_ascii_strdown (*iter, -1);
-			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
-		}
-	}
-
-	if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
+	if (!parse_8021x_phase2_auth (ifcfg, keys_ifcfg, s_8021x, error))
 		return FALSE;
-	}
 
 	return TRUE;
 }
@@ -3284,11 +3380,8 @@ eap_ttls_reader (const char *eap_method,
                  gboolean phase2,
                  GError **error)
 {
-	gs_free char *inner_auth = NULL;
 	gs_free char *value = NULL;
 	const char *v;
-	gs_free const char **list = NULL;
-	const char *const *iter;
 
 	if (!_cert_set_from_ifcfg (s_8021x,
 	                           ifcfg,
@@ -3308,44 +3401,8 @@ eap_ttls_reader (const char *eap_method,
 	if (v)
 		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, v, NULL);
 
-	nm_clear_g_free (&value);
-	v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &value);
-	if (!v) {
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
+	if (!parse_8021x_phase2_auth (ifcfg, keys_ifcfg, s_8021x, error))
 		return FALSE;
-	}
-
-	inner_auth = g_ascii_strdown (v, -1);
-
-	/* Handle options for the inner auth method */
-	list = nm_utils_strsplit_set (inner_auth, " ");
-	iter = list;
-	if (iter) {
-		if (NM_IN_STRSET (*iter, "mschapv2",
-		                         "mschap",
-		                         "pap",
-		                         "chap")) {
-			if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
-				return FALSE;
-			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL);
-		} else if (nm_streq (*iter, "eap-tls")) {
-			if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
-				return FALSE;
-			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL);
-		} else if (NM_IN_STRSET (*iter, "eap-mschapv2",
-		                                "eap-md5",
-		                                "eap-gtc")) {
-			if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
-				return FALSE;
-			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + NM_STRLEN ("eap-")), NULL);
-		} else {
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
-			             *iter);
-			return FALSE;
-		}
-	}
 
 	return TRUE;
 }
@@ -3358,17 +3415,13 @@ eap_fast_reader (const char *eap_method,
                  gboolean phase2,
                  GError **error)
 {
-	char *anon_ident = NULL;
-	char *pac_file = NULL;
-	char *real_pac_path = NULL;
-	char *inner_auth = NULL;
-	char *fast_provisioning = NULL;
-	char *lower;
-	gs_free const char **list = NULL;
+	gs_free char *anon_ident = NULL;
+	gs_free char *pac_file = NULL;
+	gs_free char *real_pac_path = NULL;
+	gs_free char *fast_provisioning = NULL;
 	const char *const *iter;
 	const char *pac_prov_str;
 	gboolean allow_unauth = FALSE, allow_auth = FALSE;
-	gboolean success = FALSE;
 
 	pac_file = svGetValueStr_cp (ifcfg, "IEEE_8021X_PAC_FILE");
 	if (pac_file) {
@@ -3378,10 +3431,10 @@ eap_fast_reader (const char *eap_method,
 
 	fast_provisioning = svGetValueStr_cp (ifcfg, "IEEE_8021X_FAST_PROVISIONING");
 	if (fast_provisioning) {
-		gs_free const char **list1 = NULL;
+		gs_free const char **list = NULL;
 
-		list1 = nm_utils_strsplit_set (fast_provisioning, " \t");
-		for (iter = list1; iter && *iter; iter++) {
+		list = nm_utils_strsplit_set (fast_provisioning, " \t");
+		for (iter = list; iter && *iter; iter++) {
 			if (strcmp (*iter, "allow-unauth") == 0)
 				allow_unauth = TRUE;
 			else if (strcmp (*iter, "allow-auth") == 0)
@@ -3398,56 +3451,18 @@ eap_fast_reader (const char *eap_method,
 
 	if (!pac_file && !(allow_unauth || allow_auth)) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled.");
-		goto done;
+		             "IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled");
+		return FALSE;
 	}
 
 	anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY");
 	if (anon_ident)
 		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
 
-	inner_auth = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
-	if (!inner_auth) {
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
-		goto done;
-	}
-
-	/* Handle options for the inner auth method */
-	list = nm_utils_strsplit_set (inner_auth, " ");
-	iter = list;
-	if (iter) {
-		if (   !strcmp (*iter, "MSCHAPV2")
-		    || !strcmp (*iter, "GTC")) {
-			if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
-				goto done;
-		} else {
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
-			             *iter);
-			goto done;
-		}
-
-		lower = g_ascii_strdown (*iter, -1);
-		g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
-		g_free (lower);
-	}
-
-	if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
-		goto done;
-	}
-
-	success = TRUE;
+	if (!parse_8021x_phase2_auth (ifcfg, keys_ifcfg, s_8021x, error))
+		return FALSE;
 
-done:
-	g_free (inner_auth);
-	g_free (fast_provisioning);
-	g_free (real_pac_path);
-	g_free (pac_file);
-	g_free (anon_ident);
-	return success;
+	return TRUE;
 }
 
 typedef struct {
@@ -3546,7 +3561,7 @@ fill_8021x (shvarFile *ifcfg,
 			 * used with TTLS or PEAP or whatever.
 			 */
 			if (wifi && eap->wifi_phase2_only) {
-				PARSE_WARNING ("ignored invalid IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.",
+				PARSE_WARNING ("ignored invalid IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi",
 				               lower);
 				goto next;
 			}
@@ -3564,12 +3579,12 @@ next:
 		}
 
 		if (!found)
-			PARSE_WARNING ("ignored unknown IEEE_8021X_EAP_METHOD '%s'.", lower);
+			PARSE_WARNING ("ignored unknown IEEE_8021X_EAP_METHOD '%s'", lower);
 	}
 
 	if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "No valid EAP methods found in IEEE_8021X_EAP_METHODS.");
+		             "No valid EAP methods found in IEEE_8021X_EAP_METHODS");
 		return NULL;
 	}
 
@@ -3663,8 +3678,8 @@ make_wpa_setting (shvarFile *ifcfg,
 
 	/* WPA and/or RSN */
 	if (adhoc) {
-		/* Ad-Hoc mode only supports WPA proto for now */
-		nm_setting_wireless_security_add_proto (wsec, "wpa");
+		/* Ad-Hoc mode only supports RSN proto */
+		nm_setting_wireless_security_add_proto (wsec, "rsn");
 	} else {
 		gs_free char *value2 = NULL;
 		const char *v2;
@@ -3698,9 +3713,7 @@ make_wpa_setting (shvarFile *ifcfg,
 			}
 		}
 
-		if (adhoc)
-			g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL);
-		else if (wpa_psk)
+		if (wpa_psk)
 			g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
 		else {
 			nm_assert (wpa_sae);
@@ -4145,7 +4158,7 @@ wireless_connection_from_ifcfg (const char *file,
 
 	if (!con_setting) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Failed to create connection setting.");
+		             "Failed to create connection setting");
 		g_object_unref (connection);
 		return NULL;
 	}
@@ -4664,7 +4677,7 @@ make_wired_setting (shvarFile *ifcfg,
 		g_set_error (error,
 		             NM_UTILS_ERROR,
 		             NM_UTILS_ERROR_SETTING_MISSING,
-		             "The setting is missing.");
+		             "The setting is missing");
 		return NULL;
 	}
 
@@ -4690,7 +4703,7 @@ wired_connection_from_ifcfg (const char *file,
 	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL, NULL);
 	if (!con_setting) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Failed to create connection setting.");
+		             "Failed to create connection setting");
 		g_object_unref (connection);
 		return NULL;
 	}
@@ -4768,7 +4781,7 @@ parse_infiniband_p_key (shvarFile *ifcfg,
 
 	if (!ret) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Failed to create InfiniBand setting.");
+		             "Failed to create InfiniBand setting");
 	}
 	return ret;
 }
@@ -4842,7 +4855,7 @@ infiniband_connection_from_ifcfg (const char *file,
 	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL);
 	if (!con_setting) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Failed to create connection setting.");
+		             "Failed to create connection setting");
 		g_object_unref (connection);
 		return NULL;
 	}
@@ -4946,7 +4959,7 @@ bond_connection_from_ifcfg (const char *file,
 	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BOND_SETTING_NAME, NULL, _("Bond"));
 	if (!con_setting) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Failed to create connection setting.");
+		             "Failed to create connection setting");
 		g_object_unref (connection);
 		return NULL;
 	}
@@ -5019,7 +5032,7 @@ team_connection_from_ifcfg (const char *file,
 	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_TEAM_SETTING_NAME, NULL, _("Team"));
 	if (!con_setting) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Failed to create connection setting.");
+		             "Failed to create connection setting");
 		g_object_unref (connection);
 		return NULL;
 	}
@@ -5301,7 +5314,7 @@ bridge_connection_from_ifcfg (const char *file,
 	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BRIDGE_SETTING_NAME, NULL, _("Bridge"));
 	if (!con_setting) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Failed to create connection setting.");
+		             "Failed to create connection setting");
 		g_object_unref (connection);
 		return NULL;
 	}
@@ -5469,7 +5482,7 @@ make_vlan_setting (shvarFile *ifcfg,
 	iface_name = svGetValueStr_cp (ifcfg, "DEVICE");
 	if (!iface_name && vlan_id < 0) {
 		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		                     "Missing DEVICE property; cannot determine VLAN ID.");
+		                     "Missing DEVICE property; cannot determine VLAN ID");
 		return NULL;
 	}
 
@@ -5512,7 +5525,7 @@ make_vlan_setting (shvarFile *ifcfg,
 
 	if (vlan_id < 0) {
 		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		                     "Failed to determine VLAN ID from DEVICE or VLAN_ID.");
+		                     "Failed to determine VLAN ID from DEVICE or VLAN_ID");
 		return NULL;
 	}
 	g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL);
@@ -5583,7 +5596,7 @@ vlan_connection_from_ifcfg (const char *file,
 	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_VLAN_SETTING_NAME, NULL, "Vlan");
 	if (!con_setting) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Failed to create connection setting.");
+		             "Failed to create connection setting");
 		g_object_unref (connection);
 		return NULL;
 	}
@@ -5726,7 +5739,7 @@ connection_from_file_full (const char *filename,
 	ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
 	if (!ifcfg_name) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Ignoring connection '%s' because it's not an ifcfg file.", filename);
+		             "Ignoring connection '%s' because it's not an ifcfg file", filename);
 		return NULL;
 	}
 
@@ -5804,14 +5817,14 @@ connection_from_file_full (const char *filename,
 		device = svGetValueStr_cp (main_ifcfg, "DEVICE");
 		if (!device) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "File '%s' had neither TYPE nor DEVICE keys.", filename);
+			             "File '%s' had neither TYPE nor DEVICE keys", filename);
 			return NULL;
 		}
 
 		if (!strcmp (device, "lo")) {
 			NM_SET_OUT (out_ignore_error, TRUE);
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "Ignoring loopback device config.");
+			             "Ignoring loopback device config");
 			g_free (device);
 			return NULL;
 		}
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h
index 8008e052..9319a064 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2008 Red Hat, Inc.
  */
 
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c
index 2841bedb..79101296 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c
@@ -1,19 +1,5 @@
-/* NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2018 Red Hat, Inc.
  */
 
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.h
index e1165f50..1b2b58e6 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.h
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.h
@@ -1,19 +1,5 @@
-/* NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2019 Red Hat, Inc.
  */
 
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
index cb1fc23a..ee389bd9 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
@@ -1,20 +1,6 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2008 - 2017 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2008 - 2017 Red Hat, Inc.
  */
 
 #include "nm-default.h"
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h
index 20d6f72d..035146ff 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h
@@ -1,20 +1,6 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2008 - 2017 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2008 - 2017 Red Hat, Inc.
  */
 
 #ifndef _UTILS_H_
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index 809d3769..d33845c2 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -1,20 +1,6 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2009 - 2015 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2009 - 2015 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -305,6 +291,7 @@ write_blobs (GHashTable *blobs, GError **error)
 		                                 (const char *) g_bytes_get_data (blob, NULL),
 		                                 g_bytes_get_size (blob),
 		                                 0600,
+		                                 NULL,
 		                                 &write_error)) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
 			             "Could not write certificate to file \"%s\": %s",
@@ -588,7 +575,7 @@ write_wireless_security_setting (NMConnection *connection,
 		svUnsetValue (ifcfg, "KEY_MGMT");
 		wep = TRUE;
 		*no_8021x = TRUE;
-	} else if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) {
+	} else if (!strcmp (key_mgmt, "wpa-psk")) {
 		svSetValueStr (ifcfg, "KEY_MGMT", "WPA-PSK");
 		wpa = TRUE;
 		*no_8021x = TRUE;
@@ -1943,7 +1930,7 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
 		 * it into an interface name, so that legacy tooling is not confused. */
 		if (!nm_utils_get_testing ()) {
 			/* This is conditional for easier testing. */
-			master_iface = nm_manager_iface_for_uuid (nm_manager_get (), master);
+			master_iface = nm_manager_iface_for_uuid (NM_MANAGER_GET, master);
 		}
 		if (!master_iface) {
 			master_iface = master;
@@ -2097,6 +2084,8 @@ get_route_attributes_string (NMIPRoute *route, int family)
 				/* we also have a corresponding attribute with the numeric value. The
 				 * lock setting is handled above. */
 			}
+		} else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SCOPE)) {
+			g_string_append_printf (str, "%s %u", names[i], (unsigned) g_variant_get_byte (attr));
 		} else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TOS)) {
 			g_string_append_printf (str, "%s 0x%02x", names[i], (unsigned) g_variant_get_byte (attr));
 		} else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TABLE)) {
@@ -2449,6 +2438,7 @@ write_ip4_setting (NMConnection *connection,
 	GString *searches;
 	const char *method = NULL;
 	gboolean has_netmask;
+	NMDhcpHostnameFlags flags;
 
 	NM_SET_OUT (out_route_content_svformat, NULL);
 	NM_SET_OUT (out_route_content, NULL);
@@ -2609,6 +2599,12 @@ write_ip4_setting (NMConnection *connection,
 	value = nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4));
 	svSetValueStr (ifcfg, "DHCP_FQDN", value);
 
+	flags = nm_setting_ip_config_get_dhcp_hostname_flags (s_ip4);
+	svSetValueInt64_cond (ifcfg,
+	                      "DHCP_HOSTNAME_FLAGS",
+	                      flags != NM_DHCP_HOSTNAME_FLAG_NONE,
+	                      flags);
+
 	/* Missing DHCP_SEND_HOSTNAME means TRUE, and we prefer not write it explicitly
 	 * in that case, because it is NM-specific variable
 	 */
@@ -2618,6 +2614,9 @@ write_ip4_setting (NMConnection *connection,
 	value = nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4));
 	svSetValueStr (ifcfg, "DHCP_CLIENT_ID", value);
 
+	value = nm_setting_ip_config_get_dhcp_iaid (s_ip4);
+	svSetValueStr (ifcfg, "DHCP_IAID", value);
+
 	timeout = nm_setting_ip_config_get_dhcp_timeout (s_ip4);
 	svSetValueInt64_cond (ifcfg,
 	                      "IPV4_DHCP_TIMEOUT",
@@ -2752,6 +2751,7 @@ write_ip4_aliases (NMConnection *connection, const char *base_ifcfg_path)
 static void
 write_ip6_setting_dhcp_hostname (NMSettingIPConfig *s_ip6, shvarFile *ifcfg)
 {
+	NMDhcpHostnameFlags flags;
 	const char *hostname;
 
 	hostname = nm_setting_ip_config_get_dhcp_hostname (s_ip6);
@@ -2764,6 +2764,12 @@ write_ip6_setting_dhcp_hostname (NMSettingIPConfig *s_ip6, shvarFile *ifcfg)
 		svUnsetValue (ifcfg, "DHCPV6_SEND_HOSTNAME");
 	else
 		svSetValueStr (ifcfg, "DHCPV6_SEND_HOSTNAME", "no");
+
+	flags = nm_setting_ip_config_get_dhcp_hostname_flags (s_ip6);
+	svSetValueInt64_cond (ifcfg,
+	                      "DHCPV6_HOSTNAME_FLAGS",
+	                      flags != NM_DHCP_HOSTNAME_FLAG_NONE,
+	                      flags);
 }
 
 static gboolean
@@ -2796,6 +2802,7 @@ write_ip6_setting (NMConnection *connection,
 		svUnsetValue (ifcfg, "IPV6_AUTOCONF");
 		svUnsetValue (ifcfg, "DHCPV6C");
 		svUnsetValue (ifcfg, "DHCPv6_DUID");
+		svUnsetValue (ifcfg, "DHCPv6_IAID");
 		svUnsetValue (ifcfg, "DHCPV6_HOSTNAME");
 		svUnsetValue (ifcfg, "DHCPV6_SEND_HOSTNAME");
 		svUnsetValue (ifcfg, "IPV6_DEFROUTE");
@@ -2845,6 +2852,8 @@ write_ip6_setting (NMConnection *connection,
 
 	svSetValueStr (ifcfg, "DHCPV6_DUID",
 	               nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6)));
+	svSetValueStr (ifcfg, "DHCPV6_IAID",
+	               nm_setting_ip_config_get_dhcp_iaid (s_ip6));
 
 	write_ip6_setting_dhcp_hostname (s_ip6, ifcfg);
 
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h
index 0902daee..c4903a46 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2009 Red Hat, Inc.
  */
 
diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
index d4bc71f3..16b2dd37 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/settings/plugins/ifcfg-rh/shvar.c
@@ -1,25 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- * shvar.c
- *
- * Implementation of non-destructively reading/writing files containing
- * only shell variable declarations and full-line comments.
- *
- * Copyright 1999,2000 Red Hat, Inc.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+ * Copyright (C) 1999, 2000 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -790,7 +771,7 @@ svOpenFileInternal (const char *name, gboolean create, GError **error)
 	shvarFile *s;
 	gboolean closefd = FALSE;
 	int errsv = 0;
-	char *arena;
+	gs_free char *arena = NULL;
 	const char *p, *q;
 	gs_free_error GError *local = NULL;
 	nm_auto_close int fd = -1;
@@ -816,13 +797,14 @@ svOpenFileInternal (const char *name, gboolean create, GError **error)
 		return NULL;
 	}
 
-	if (nm_utils_fd_get_contents (closefd ? nm_steal_fd (&fd) : fd,
-	                              closefd,
-	                              10 * 1024 * 1024,
-	                              NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
-	                              &arena,
-	                              NULL,
-	                              &local) < 0) {
+	if (!nm_utils_fd_get_contents (closefd ? nm_steal_fd (&fd) : fd,
+	                               closefd,
+	                               10 * 1024 * 1024,
+	                               NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
+	                               &arena,
+	                               NULL,
+	                               NULL,
+	                               &local)) {
 		if (create)
 			return svFile_new (name);
 
@@ -839,7 +821,6 @@ svOpenFileInternal (const char *name, gboolean create, GError **error)
 		c_list_link_tail (&s->lst_head, &line_new_parse (p, q - p)->lst);
 	if (p[0])
 		c_list_link_tail (&s->lst_head, &line_new_parse (p, strlen (p))->lst);
-	g_free (arena);
 
 	/* closefd is set if we opened the file read-only, so go ahead and
 	 * close it, because we can't write to it anyway */
diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h
index 2f6912b3..c3bbabab 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.h
+++ b/src/settings/plugins/ifcfg-rh/shvar.h
@@ -1,32 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- * shvar.h
- *
- * Interface for non-destructively reading/writing files containing
- * only shell variable declarations and full-line comments.
- *
- * Includes explicit inheritance mechanism intended for use with
- * Red Hat Linux ifcfg-* files.  There is no protection against
- * inheritance loops; they will generally cause stack overflows.
- * Furthermore, they are only intended for one level of inheritance;
- * the value setting algorithm assumes this.
- *
- * Copyright 1999 Red Hat, Inc.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+ * Copyright (C) 1999 Red Hat, Inc.
  */
+
 #ifndef _SHVAR_H
 #define _SHVAR_H
 
diff --git a/src/settings/plugins/ifcfg-rh/tests/meson.build b/src/settings/plugins/ifcfg-rh/tests/meson.build
index f65494bb..21699045 100644
--- a/src/settings/plugins/ifcfg-rh/tests/meson.build
+++ b/src/settings/plugins/ifcfg-rh/tests/meson.build
@@ -1,11 +1,10 @@
 test_unit = 'test-ifcfg-rh'
 
-test_ifcfg_dir = meson.current_source_dir()
-
 exe = executable(
   test_unit,
   test_unit + '.c',
-  dependencies: test_nm_dep,
+  dependencies: libnetwork_manager_test_dep,
+  c_args: test_c_flags,
   link_with: libnms_ifcfg_rh_core,
 )
 
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk-adhoc b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk-adhoc
index aa00925e..c3cadbb8 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk-adhoc
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk-adhoc
@@ -12,5 +12,6 @@ USERCTL=yes
 PEERDNS=yes
 IPV6INIT=no
 CIPHER_GROUP=CCMP
+CIPHER_PAIRWISE=CCMP
 KEY_MGMT=WPA-PSK
 
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp
index 727d2ceb..5d36675a 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-dhcp
@@ -8,7 +8,12 @@ USERCTL=yes
 IPV6INIT=no
 NM_CONTROLLED=yes
 PEERDNS=no
-DHCP_HOSTNAME=foobar
+DHCP_FQDN=foo.bar
+DHCP_HOSTNAME_FLAGS=6
 DNS1=4.2.2.1
 DNS2=4.2.2.2
-
+IPV6_AUTOCONF=no
+IPV6INIT=yes
+DHCPV6C=yes
+DHCPV6_HOSTNAME_FLAGS=8
+DHCPV6_HOSTNAME=foo.bar
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes
index 8d6aaac2..5d02c62e 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes
@@ -6,10 +6,10 @@ ADDRESS1=44.55.66.77
 NETMASK1=255.255.255.255
 GATEWAY1=192.168.1.7
 METRIC1=3
-OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 initcwnd lock 13 initrwnd 14"
+OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 scope 10 initcwnd lock 13 initrwnd 14"
 
 ADDRESS2=44.55.66.78
 NETMASK2=255.255.255.255
 GATEWAY2=192.168.1.8
 METRIC2=3
-OPTIONS2="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 onlink window 30000 initcwnd lock 13 initrwnd 14"
+OPTIONS2="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 onlink window 30000 initcwnd lock 13 initrwnd 14 scope link"
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 45e90b91..675421d3 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2008 - 2011 Red Hat, Inc.
  */
 
@@ -901,6 +887,7 @@ test_read_wired_dhcp (void)
 	NMSettingConnection *s_con;
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
+	NMSettingIPConfig *s_ip6;
 	char *unmanaged = NULL;
 	char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0xee };
 	const char *mac;
@@ -930,11 +917,23 @@ test_read_wired_dhcp (void)
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	g_assert (s_ip4);
 	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
-	g_assert_cmpstr (nm_setting_ip_config_get_dhcp_hostname (s_ip4), ==, "foobar");
+	g_assert_cmpstr (nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4)), ==, "foo.bar");
 	g_assert (nm_setting_ip_config_get_ignore_auto_dns (s_ip4));
 	g_assert_cmpuint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 2);
 	g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 0), ==, "4.2.2.1");
 	g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 1), ==, "4.2.2.2");
+	g_assert_cmpuint (nm_setting_ip_config_get_dhcp_hostname_flags (s_ip4),
+	                  ==,
+	                  NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED | NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE);
+
+	/* ===== IPv6 SETTING ===== */
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	g_assert (s_ip6);
+	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_DHCP);
+	g_assert_cmpstr (nm_setting_ip_config_get_dhcp_hostname (s_ip6), ==, "foo.bar");
+	g_assert_cmpuint (nm_setting_ip_config_get_dhcp_hostname_flags (s_ip6),
+	                  ==,
+	                  NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS);
 
 	g_object_unref (connection);
 }
@@ -1348,6 +1347,7 @@ test_read_wired_static_routes (void)
 	nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE);
 	nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE);
 	nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1");
+	nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 10);
 
 	ip4_route = nm_setting_ip_config_get_route (s_ip4, 2);
 	g_assert (ip4_route);
@@ -1365,6 +1365,7 @@ test_read_wired_static_routes (void)
 	nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE);
 	nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1");
 	nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, TRUE);
+	nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 253);
 
 	g_object_unref (connection);
 }
@@ -1520,10 +1521,8 @@ test_read_wired_ipv6_manual (void)
 	NMIPAddress *ip6_addr;
 	NMIPRoute *ip6_route;
 
-	NMTST_EXPECT_NM_WARN ("*ignoring manual default route*");
 	connection = _connection_from_file (TEST_IFCFG_DIR"/ifcfg-test-wired-ipv6-manual",
 	                                    NULL, TYPE_ETHERNET, &unmanaged);
-	g_test_assert_expected_messages ();
 	g_assert (!unmanaged);
 
 	/* ===== CONNECTION SETTING ===== */
@@ -1581,7 +1580,7 @@ test_read_wired_ipv6_manual (void)
 	g_assert_cmpint (nm_ip_address_get_prefix (ip6_addr), ==, 96);
 
 	/* Routes */
-	g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 3);
+	g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 4);
 	/* Route #1 */
 	ip6_route = nm_setting_ip_config_get_route (s_ip6, 0);
 	g_assert (ip6_route);
@@ -1592,12 +1591,19 @@ test_read_wired_ipv6_manual (void)
 	/* Route #2 */
 	ip6_route = nm_setting_ip_config_get_route (s_ip6, 1);
 	g_assert (ip6_route);
+	g_assert_cmpstr (nm_ip_route_get_dest (ip6_route), ==, "::");
+	g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 0);
+	g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, "dead::beaf");
+	g_assert_cmpint (nm_ip_route_get_metric (ip6_route), ==, -1);
+	/* Route #3 */
+	ip6_route = nm_setting_ip_config_get_route (s_ip6, 2);
+	g_assert (ip6_route);
 	g_assert_cmpstr (nm_ip_route_get_dest (ip6_route), ==, "abbe::cafe");
 	g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64);
 	g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, NULL);
 	g_assert_cmpint (nm_ip_route_get_metric (ip6_route), ==, 777);
-	/* Route #3 */
-	ip6_route = nm_setting_ip_config_get_route (s_ip6, 2);
+	/* Route #4 */
+	ip6_route = nm_setting_ip_config_get_route (s_ip6, 3);
 	g_assert (ip6_route);
 	g_assert_cmpstr (nm_ip_route_get_dest (ip6_route), ==, "aaaa::cccc");
 	g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64);
@@ -3128,17 +3134,17 @@ test_read_wifi_wpa_psk_adhoc (void)
 
 	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	g_assert (s_wsec);
-	g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "wpa-none");
+	g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "wpa-psk");
 	g_assert_cmpstr (nm_setting_wireless_security_get_psk (s_wsec), ==, "I wonder what the king is doing tonight?");
 
-	/* Pairwise cipher is unused in adhoc mode */
-	g_assert_cmpint (nm_setting_wireless_security_get_num_pairwise (s_wsec), ==, 0);
+	g_assert_cmpint (nm_setting_wireless_security_get_num_pairwise (s_wsec), ==, 1);
+	g_assert_cmpstr (nm_setting_wireless_security_get_pairwise (s_wsec, 0), ==, "ccmp");
 
 	g_assert_cmpint (nm_setting_wireless_security_get_num_groups (s_wsec), ==, 1);
 	g_assert_cmpstr (nm_setting_wireless_security_get_group (s_wsec, 0), ==, "ccmp");
 
 	g_assert_cmpint (nm_setting_wireless_security_get_num_protos (s_wsec), ==, 1);
-	g_assert_cmpstr (nm_setting_wireless_security_get_proto (s_wsec, 0), ==, "wpa");
+	g_assert_cmpstr (nm_setting_wireless_security_get_proto (s_wsec, 0), ==, "rsn");
 
 	/* ===== IPv4 SETTING ===== */
 
@@ -4464,9 +4470,11 @@ test_write_wired_dhcp (void)
 	g_object_set (s_ip4,
 	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
 	              NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, "random-client-id-00:22:33",
-	              NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, "awesome-hostname",
+	              NM_SETTING_IP4_CONFIG_DHCP_FQDN, "awesome.hostname",
+	              NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS, (guint) NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED,
 	              NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, TRUE,
 	              NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, TRUE,
+	              NM_SETTING_IP_CONFIG_DHCP_IAID, "2864434397",
 	              NULL);
 
 	nmtst_assert_connection_verifies (connection);
@@ -4476,8 +4484,10 @@ test_write_wired_dhcp (void)
 	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
 
 	g_object_set (s_ip6,
-	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
+	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_DHCP,
 	              NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
+	              NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, "awesome.hostname",
+	              NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS, (guint) NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE,
 	              NULL);
 
 	_writer_new_connection (connection,
@@ -6455,12 +6465,13 @@ test_write_wifi_wpa_psk_adhoc (void)
 	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
 
 	g_object_set (s_wsec,
-	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none",
+	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
 	              NM_SETTING_WIRELESS_SECURITY_PSK, "7d308b11df1b4243b0f78e5f3fc68cdbb9a264ed0edf4c188edf329ff5b467f0",
 	              NULL);
 
-	nm_setting_wireless_security_add_proto (s_wsec, "wpa");
-	nm_setting_wireless_security_add_group (s_wsec, "tkip");
+	nm_setting_wireless_security_add_proto (s_wsec, "rsn");
+	nm_setting_wireless_security_add_pairwise (s_wsec, "ccmp");
+	nm_setting_wireless_security_add_group (s_wsec, "ccmp");
 
 	/* IP4 setting */
 	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
diff --git a/src/settings/plugins/ifupdown/meson.build b/src/settings/plugins/ifupdown/meson.build
index 365ae1a9..0cabe771 100644
--- a/src/settings/plugins/ifupdown/meson.build
+++ b/src/settings/plugins/ifupdown/meson.build
@@ -3,25 +3,18 @@ sources = files(
   'nms-ifupdown-parser.c',
 )
 
-deps = [
-  libudev_dep,
-  nm_dep,
-]
-
 libnms_ifupdown_core = static_library(
   'nms-ifupdown-core',
   sources: sources,
-  dependencies: deps,
-)
-
-sources = files(
-  'nms-ifupdown-plugin.c',
+  dependencies: daemon_nm_default_dep,
+  c_args: daemon_c_flags,
 )
 
 libnm_settings_plugin_ifupdown = shared_module(
   'nm-settings-plugin-ifupdown',
-  sources: sources,
-  dependencies: deps,
+  sources: 'nms-ifupdown-plugin.c',
+  dependencies: daemon_nm_default_dep,
+  c_args: daemon_c_flags,
   link_with: libnms_ifupdown_core,
   link_args: ldflags_linker_script_settings,
   link_depends: linker_script_settings,
@@ -31,18 +24,6 @@ libnm_settings_plugin_ifupdown = shared_module(
 
 core_plugins += libnm_settings_plugin_ifupdown
 
-# FIXME: check_so_symbols replacement
-'''
-run_target(
-  'check-local-symbols-settings-ifupdown',
-  command: [check_so_symbols, libnm_settings_plugin_ifupdown.full_path()],
-  depends: libnm_settings_plugin_ifupdown,
-)
-
-check-local-symbols-settings-ifupdown: src/settings/plugins/ifupdown/libnm-settings-plugin-ifupdown.la
-  $(call check_so_symbols,$(builddir)/src/settings/plugins/ifupdown/.libs/libnm-settings-plugin-ifupdown.so)
-'''
-
 if enable_tests
   subdir('tests')
 endif
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c
index 75f29878..a146ae60 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c
@@ -1,22 +1,7 @@
-/* NetworkManager -- Network link manager
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Tom Parker <palfrey@tevp.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2004 Tom Parker
+ * Copyright (C) 2004 Tom Parker
  */
 
 #include "nm-default.h"
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h
index 308228a4..af02c7f6 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h
@@ -1,22 +1,7 @@
-/* NetworkManager -- Network link manager
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Tom Parker <palfrey@tevp.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2004 Tom Parker
+ * Copyright (C) 2004 Tom Parker
  */
 
 #ifndef _INTERFACE_PARSER_H
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c
index 41b20850..1db9ef15 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c
@@ -1,22 +1,7 @@
-/* NetworkManager system settings service (ifupdown)
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Alexander Sack <asac@ubuntu.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2008 Canonical Ltd.
+ * Copyright (C) 2008 Canonical Ltd.
  */
 
 #include "nm-default.h"
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-parser.h b/src/settings/plugins/ifupdown/nms-ifupdown-parser.h
index 7569648f..b8761fc3 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-parser.h
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-parser.h
@@ -1,22 +1,7 @@
-/* NetworkManager system settings service (ifupdown)
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Alexander Sack <asac@ubuntu.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2008 Canonical Ltd.
+ * Copyright (C) 2008 Canonical Ltd.
  */
 
 #ifndef __NMS_IFUPDOWN_PARSER_H__
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
index e663ab8a..d19db0fd 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
@@ -1,23 +1,8 @@
-/* NetworkManager system settings service (ifupdown)
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Alexander Sack <asac@ubuntu.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2007,2008 Canonical Ltd.
- * (C) Copyright 2009 - 2011 Red Hat, Inc.
+ * Copyright (C) 2007, 2008 Canonical Ltd.
+ * Copyright (C) 2009 - 2011 Red Hat, Inc.
  */
 
 #include "nm-default.h"
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.h b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.h
index 10ea2be4..91e3e43a 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.h
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.h
@@ -1,22 +1,7 @@
-/* NetworkManager system settings service (ifupdown)
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Alexander Sack <asac@ubuntu.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2008 Canonical Ltd.
+ * Copyright (C) 2008 Canonical Ltd.
  */
 
 #ifndef __NMS_IFUPDOWN_PLUGIN_H__
diff --git a/src/settings/plugins/ifupdown/tests/meson.build b/src/settings/plugins/ifupdown/tests/meson.build
index 9b844c75..1ca094b5 100644
--- a/src/settings/plugins/ifupdown/tests/meson.build
+++ b/src/settings/plugins/ifupdown/tests/meson.build
@@ -3,7 +3,8 @@ test_unit = 'test-ifupdown'
 exe = executable(
   test_unit,
   test_unit + '.c',
-  dependencies: test_nm_dep,
+  dependencies: libnetwork_manager_test_dep,
+  c_args: test_c_flags,
   link_with: libnms_ifupdown_core,
 )
 
diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
index 4adcf085..6a7b5ecc 100644
--- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c
+++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
@@ -1,20 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
  * Copyright (C) 2010 Red Hat, Inc.
- *
  */
 
 #include "nm-default.h"
@@ -149,6 +135,9 @@ expected_free (Expected *e)
 	g_free (e);
 }
 
+NM_AUTO_DEFINE_FCN_VOID0 (Expected *, _nm_auto_free_expected, expected_free)
+#define nm_auto_free_expected nm_auto(_nm_auto_free_expected)
+
 static void
 compare_expected_to_ifparser (if_parser *parser, Expected *e)
 {
@@ -226,7 +215,7 @@ init_ifparser_with_file (const char *file)
 static void
 test1_ignore_line_before_first_block (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test1");
 
@@ -238,14 +227,12 @@ test1_ignore_line_before_first_block (void)
 	expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test2_wrapped_line (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test2");
 
@@ -254,14 +241,12 @@ test2_wrapped_line (void)
 	expected_add_block (e, b);
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test3_wrapped_multiline_multiarg (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test3");
 
@@ -274,14 +259,12 @@ test3_wrapped_multiline_multiarg (void)
 	expected_add_block (e, b);
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test4_allow_auto_is_auto (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test4");
 
@@ -290,14 +273,12 @@ test4_allow_auto_is_auto (void)
 	expected_add_block (e, b);
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test5_allow_auto_multiarg (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test5");
 
@@ -308,14 +289,12 @@ test5_allow_auto_multiarg (void)
 	expected_add_block (e, b);
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test6_mixed_whitespace (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test6");
 
@@ -325,8 +304,6 @@ test6_mixed_whitespace (void)
 	expected_add_block (e, b);
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
@@ -348,7 +325,7 @@ test8_long_line_wrapped (void)
 static void
 test9_wrapped_lines_in_block (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test9");
 
@@ -362,14 +339,12 @@ test9_wrapped_lines_in_block (void)
 	expected_block_add_key (b, expected_key_new ("gateway", "10.250.2.50"));
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test11_complex_wrap (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test11");
 
@@ -380,14 +355,12 @@ test11_complex_wrap (void)
 	expected_block_add_key (b, expected_key_new ("pre-up", "/sbin/ifconfig eth0 up"));
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test12_complex_wrap_split_word (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test12");
 
@@ -398,14 +371,12 @@ test12_complex_wrap_split_word (void)
 	expected_block_add_key (b, expected_key_new ("up", "ifup ppp0=dsl"));
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test13_more_mixed_whitespace (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test13");
 
@@ -415,14 +386,12 @@ test13_more_mixed_whitespace (void)
 	expected_add_block (e, b);
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test14_mixed_whitespace_block_start (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test14");
 
@@ -438,14 +407,12 @@ test14_mixed_whitespace_block_start (void)
 	expected_add_block (e, b);
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test15_trailing_space (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test15");
 
@@ -455,23 +422,20 @@ test15_trailing_space (void)
 	expected_add_block (e, b);
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test16_missing_newline (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test16");
 
 	e = expected_new ();
 	expected_add_block (e, expected_block_new ("mapping", "eth0"));
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
+
 static void
 test17_read_static_ipv4 (void)
 {
@@ -578,7 +542,7 @@ test19_read_static_ipv4_plen (void)
 static void
 test20_source_stanza (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test20-source-stanza");
 
@@ -597,14 +561,12 @@ test20_source_stanza (void)
 	expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
 
 	compare_expected_to_ifparser (parser, e);
-
-	expected_free (e);
 }
 
 static void
 test21_source_dir_stanza (void)
 {
-	Expected *e;
+	nm_auto_free_expected Expected *e = NULL;
 	ExpectedBlock *b;
 	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test21-source-dir-stanza");
 
@@ -617,10 +579,34 @@ test21_source_dir_stanza (void)
 	expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
 
 	compare_expected_to_ifparser (parser, e);
+}
+
+static void
+test22_duplicate_stanzas (void)
+{
+	nm_auto_free_expected Expected *e = NULL;
+	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test22-duplicate-stanzas");
+
+	e = expected_new ();
 
-	expected_free (e);
+	b = expected_block_new ("iface", "br10");
+	expected_add_block (e, b);
+	expected_block_add_key (b, expected_key_new ("inet", "manual"));
+	expected_block_add_key (b, expected_key_new ("bridge-ports", "enp6s0.15"));
+	expected_block_add_key (b, expected_key_new ("bridge-stp", "off"));
+	expected_block_add_key (b, expected_key_new ("bridge-maxwait", "0"));
+	expected_block_add_key (b, expected_key_new ("bridge-fd", "0"));
+	b = expected_block_new ("iface", "br10");
+	expected_add_block (e, b);
+	expected_block_add_key (b, expected_key_new ("inet", "auto"));
+	expected_block_add_key (b, expected_key_new ("bridge-ports", "enp6s0.15"));
+
+	compare_expected_to_ifparser (parser, e);
 }
 
+/*****************************************************************************/
+
 NMTST_DEFINE ();
 
 int
@@ -650,6 +636,7 @@ main (int argc, char **argv)
 	g_test_add_func ("/ifupdate/read_static_ipv4_plen",          test19_read_static_ipv4_plen);
 	g_test_add_func ("/ifupdate/source_stanza",                  test20_source_stanza);
 	g_test_add_func ("/ifupdate/source_dir_stanza",              test21_source_dir_stanza);
+	g_test_add_func ("/ifupdate/test22-duplicate-stanzas",       test22_duplicate_stanzas);
 
 	return g_test_run ();
 }
diff --git a/src/settings/plugins/ifupdown/tests/test22-duplicate-stanzas b/src/settings/plugins/ifupdown/tests/test22-duplicate-stanzas
new file mode 100644
index 00000000..c13c2e7e
--- /dev/null
+++ b/src/settings/plugins/ifupdown/tests/test22-duplicate-stanzas
@@ -0,0 +1,8 @@
+iface br10 inet manual
+    bridge_ports    enp6s0.15
+    bridge_stp      off
+    bridge_maxwait  0
+    bridge_fd       0
+
+iface br10 inet auto
+    bridge_ports enp6s0.15
diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c
index fbe70ef4..fdb88d2a 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 - 2018 Red Hat, Inc.
  */
@@ -369,7 +355,7 @@ _load_file (NMSKeyfilePlugin *self,
 	                              &local);
 	if (!connection) {
 		if (error)
-			g_propagate_error (error, local);
+			g_propagate_error (error, g_steal_pointer (&local));
 		else
 			_LOGW ("load: \"%s\": failed to load connection: %s", full_filename, local->message);
 		return NULL;
@@ -1090,7 +1076,7 @@ nms_keyfile_plugin_set_nmmeta_tombstone (NMSKeyfilePlugin *self,
 	gboolean hard_failure = FALSE;
 	NMSKeyfileStorage *storage;
 	gs_unref_object NMSKeyfileStorage *storage_result = NULL;
-	gboolean nmmeta_success = FALSE;
+	gboolean nmmeta_errno;
 	gs_free char *nmmeta_filename = NULL;
 	NMSKeyfileStorageType storage_type;
 	const char *loaded_path;
@@ -1116,6 +1102,7 @@ nms_keyfile_plugin_set_nmmeta_tombstone (NMSKeyfilePlugin *self,
 			       simulate ? "simulate " : "",
 			       loaded_path ? "write" : "delete",
 			       uuid);
+			nmmeta_errno = 0;
 			hard_failure = TRUE;
 			goto out;
 		}
@@ -1124,29 +1111,30 @@ nms_keyfile_plugin_set_nmmeta_tombstone (NMSKeyfilePlugin *self,
 	}
 
 	if (simulate) {
-		nmmeta_success = TRUE;
+		nmmeta_errno = 0;
 		nmmeta_filename = nms_keyfile_nmmeta_filename (dirname, uuid, FALSE);
 	} else {
-		nmmeta_success = nms_keyfile_nmmeta_write (dirname,
-		                                           uuid,
-		                                           loaded_path,
-		                                           FALSE,
-		                                           shadowed_storage,
-		                                           &nmmeta_filename);
+		nmmeta_errno = nms_keyfile_nmmeta_write (dirname,
+		                                         uuid,
+		                                         loaded_path,
+		                                         FALSE,
+		                                         shadowed_storage,
+		                                         &nmmeta_filename);
 	}
 
-	_LOGT ("commit: %s nmmeta file \"%s\"%s%s%s%s%s%s %s",
+	_LOGT ("commit: %s nmmeta file \"%s\"%s%s%s%s%s%s %s%s%s%s",
 	       loaded_path ? "writing" : "deleting",
 	       nmmeta_filename,
 	       NM_PRINT_FMT_QUOTED (loaded_path, " (pointing to \"", loaded_path, "\")", ""),
 	       NM_PRINT_FMT_QUOTED (shadowed_storage, " (shadows \"", shadowed_storage, "\")", ""),
 	       simulate
 	       ? "simulated"
-	       : (  nmmeta_success
-	          ? "succeeded"
-	          : "failed"));
+	       : (  nmmeta_errno < 0
+	          ? "failed"
+	          : "succeeded"),
+	       NM_PRINT_FMT_QUOTED (nmmeta_errno < 0, " (", nm_strerror_native (nm_errno_native (nmmeta_errno)), ")", ""));
 
-	if (!nmmeta_success)
+	if (nmmeta_errno < 0)
 		goto out;
 
 	storage = nm_sett_util_storages_lookup_by_filename (&priv->storages, nmmeta_filename);
@@ -1177,12 +1165,13 @@ nms_keyfile_plugin_set_nmmeta_tombstone (NMSKeyfilePlugin *self,
 	}
 
 out:
-	nm_assert (!nmmeta_success || !hard_failure);
-	nm_assert (nmmeta_success  || !storage_result);
+	nm_assert (nmmeta_errno <= 0);
+	nm_assert (nmmeta_errno < 0  || !hard_failure);
+	nm_assert (nmmeta_errno == 0 || !storage_result);
 
 	NM_SET_OUT (out_hard_failure, hard_failure);
 	NM_SET_OUT (out_storage, (NMSettingsStorage *) g_steal_pointer (&storage_result));
-	return nmmeta_success;
+	return nmmeta_errno >= 0;
 }
 
 /*****************************************************************************/
diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.h b/src/settings/plugins/keyfile/nms-keyfile-plugin.h
index 48440964..e885f16c 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-plugin.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.h
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 - 2011 Red Hat, Inc.
  */
diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.c b/src/settings/plugins/keyfile/nms-keyfile-reader.c
index 8d1f5599..af9e6726 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-reader.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-reader.c
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2015 Red Hat, Inc.
  */
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.h b/src/settings/plugins/keyfile/nms-keyfile-reader.h
index f20e6d93..307d6ffe 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-reader.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-reader.h
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Red Hat, Inc.
  */
diff --git a/src/settings/plugins/keyfile/nms-keyfile-storage.c b/src/settings/plugins/keyfile/nms-keyfile-storage.c
index d68d60c8..bcc06795 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-storage.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-storage.c
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2018 Red Hat, Inc.
  */
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-storage.h b/src/settings/plugins/keyfile/nms-keyfile-storage.h
index 2252b47b..00a034d4 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-storage.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-storage.h
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2018 Red Hat, Inc.
  */
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.c b/src/settings/plugins/keyfile/nms-keyfile-utils.c
index ea03e1b6..f03c601a 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-utils.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-utils.c
@@ -1,20 +1,6 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -206,7 +192,7 @@ nms_keyfile_nmmeta_read_from_file (const char *full_filename,
 	return TRUE;
 }
 
-gboolean
+int
 nms_keyfile_nmmeta_write (const char *dirname,
                           const char *uuid,
                           const char *loaded_path,
@@ -216,6 +202,7 @@ nms_keyfile_nmmeta_write (const char *dirname,
 {
 	gs_free char *full_filename_tmp = NULL;
 	gs_free char *full_filename = NULL;
+	int errsv;
 
 	nm_assert (dirname && dirname[0] == '/');
 	nm_assert (   nm_utils_is_uuid (uuid)
@@ -231,13 +218,15 @@ nms_keyfile_nmmeta_write (const char *dirname,
 	(void) unlink (full_filename_tmp);
 
 	if (!loaded_path) {
-		gboolean success = TRUE;
-
 		full_filename_tmp[strlen (full_filename_tmp) - 1] = '\0';
-		if (unlink (full_filename_tmp) != 0)
-			success = NM_IN_SET (errno, ENOENT);
+		errsv = 0;
+		if (unlink (full_filename_tmp) != 0) {
+			errsv = -NM_ERRNO_NATIVE (errno);
+			if (errsv == -ENOENT)
+				errsv = 0;
+		}
 		NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename_tmp));
-		return success;
+		return errsv;
 	}
 
 	if (loaded_path_allow_relative) {
@@ -266,29 +255,36 @@ nms_keyfile_nmmeta_write (const char *dirname,
 
 		contents = g_key_file_to_data (kf, &length, NULL);
 
-		if (!nm_utils_file_set_contents (full_filename, contents, length, 0600, NULL)) {
+		if (!nm_utils_file_set_contents (full_filename,
+		                                 contents,
+		                                 length,
+		                                 0600,
+		                                 &errsv,
+		                                 NULL)) {
 			NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename_tmp));
-			return FALSE;
+			return -NM_ERRNO_NATIVE (errsv);
 		}
 	} else {
 		/* we only have the "loaded_path" to store. That is commonly used for the tombstones to
 		 * link to /dev/null. A symlink is sufficient to store that ammount of information.
 		 * No need to bother with a keyfile. */
 		if (symlink (loaded_path, full_filename_tmp) != 0) {
+			errsv = -NM_ERRNO_NATIVE (errno);
 			full_filename_tmp[strlen (full_filename_tmp) - 1] = '\0';
 			NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename_tmp));
-			return FALSE;
+			return errsv;
 		}
 
 		if (rename (full_filename_tmp, full_filename) != 0) {
+			errsv = -NM_ERRNO_NATIVE (errno);
 			(void) unlink (full_filename_tmp);
 			NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename));
-			return FALSE;
+			return errsv;
 		}
 	}
 
 	NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename));
-	return TRUE;
+	return 0;
 }
 
 /*****************************************************************************/
diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.h b/src/settings/plugins/keyfile/nms-keyfile-utils.h
index 723c4436..f943d65c 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-utils.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-utils.h
@@ -1,20 +1,6 @@
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #ifndef __NMS_KEYFILE_UTILS_H__
@@ -66,12 +52,12 @@ gboolean nms_keyfile_nmmeta_read_from_file (const char *full_filename,
                                             char **out_loaded_path,
                                             char **out_shadowed_storage);
 
-gboolean nms_keyfile_nmmeta_write (const char *dirname,
-                                   const char *uuid,
-                                   const char *loaded_path,
-                                   gboolean loaded_path_allow_relative,
-                                   const char *shadowed_storage,
-                                   char **out_full_filename);
+int nms_keyfile_nmmeta_write (const char *dirname,
+                              const char *uuid,
+                              const char *loaded_path,
+                              gboolean loaded_path_allow_relative,
+                              const char *shadowed_storage,
+                              char **out_full_filename);
 
 /*****************************************************************************/
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c
index abd3f1f4..fa95198c 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-writer.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 - 2015 Red Hat, Inc.
  */
@@ -130,8 +116,12 @@ cert_writer (NMConnection *connection,
 		 * being sure that the entire profile can be written and all circumstances are good to
 		 * proceed. That means, while writing we must only collect the blogs in-memory, and write
 		 * them all in the end together (or not at all). */
-		success = nm_utils_file_set_contents (new_path, (const char *) blob_data,
-		                                      blob_len, 0600, &local);
+		success = nm_utils_file_set_contents (new_path,
+		                                      (const char *) blob_data,
+		                                      blob_len,
+		                                      0600,
+		                                      NULL,
+		                                      &local);
 		if (success) {
 			/* Write the path value to the keyfile.
 			 * We know, that basename(new_path) starts with a UUID, hence no conflict with "data:;base64,"  */
@@ -344,7 +334,12 @@ _internal_write_connection (NMConnection *connection,
 		}
 	}
 
-	nm_utils_file_set_contents (path, kf_content_buf, kf_content_len, 0600, &local_err);
+	nm_utils_file_set_contents (path,
+	                            kf_content_buf,
+	                            kf_content_len,
+	                            0600,
+	                            NULL,
+	                            &local_err);
 	if (local_err) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
 		             "error writing to file '%s': %s",
diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.h b/src/settings/plugins/keyfile/nms-keyfile-writer.h
index 99e86025..98ec8a6b 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-writer.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-writer.h
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 - 2011 Red Hat, Inc.
  */
diff --git a/src/settings/plugins/keyfile/tests/meson.build b/src/settings/plugins/keyfile/tests/meson.build
index f1e96bdf..7bf9fda0 100644
--- a/src/settings/plugins/keyfile/tests/meson.build
+++ b/src/settings/plugins/keyfile/tests/meson.build
@@ -3,7 +3,8 @@ test_unit = 'test-keyfile-settings'
 exe = executable(
   test_unit,
   test_unit + '.c',
-  dependencies: test_nm_dep,
+  dependencies: libnetwork_manager_test_dep,
+  c_args: test_c_flags,
 )
 
 test(
diff --git a/src/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/settings/plugins/keyfile/tests/test-keyfile-settings.c
index f96111a2..d2da09da 100644
--- a/src/settings/plugins/keyfile/tests/test-keyfile-settings.c
+++ b/src/settings/plugins/keyfile/tests/test-keyfile-settings.c
@@ -1,19 +1,5 @@
-/* NetworkManager system settings service - keyfile plugin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2008 - 2017 Red Hat, Inc.
  */
 
@@ -2543,7 +2529,7 @@ _assert_keyfile_nmmeta (const char *dirname,
 	nm_clear_g_free (&full_filename);
 
 
-	g_assert (nms_keyfile_nmmeta_write (dirname, uuid, loaded_path, allow_relative, NULL, &full_filename));
+	g_assert_cmpint (nms_keyfile_nmmeta_write (dirname, uuid, loaded_path, allow_relative, NULL, &full_filename), ==, 0);
 	g_assert_cmpstr (full_filename, ==, exp_full_filename);
 	nm_clear_g_free (&full_filename);