about summary refs log tree commit diff
path: root/src/settings/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/plugins')
-rw-r--r--src/settings/plugins/Makefile.in2
-rw-r--r--src/settings/plugins/ibft/Makefile.in2
-rw-r--r--src/settings/plugins/ibft/tests/Makefile.in2
-rw-r--r--src/settings/plugins/ifcfg-rh/Makefile.in2
-rw-r--r--src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c4
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.c78
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/Makefile.in2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am7
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in9
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 (renamed from src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master)0
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-25
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-invalid4
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 (renamed from src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port)0
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-24
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c59
-rw-r--r--src/settings/plugins/ifcfg-rh/utils.c19
-rw-r--r--src/settings/plugins/ifcfg-rh/utils.h2
-rw-r--r--src/settings/plugins/ifcfg-rh/writer.c137
-rw-r--r--src/settings/plugins/ifnet/Makefile.in2
-rw-r--r--src/settings/plugins/ifnet/tests/Makefile.in2
-rw-r--r--src/settings/plugins/ifupdown/Makefile.in2
-rw-r--r--src/settings/plugins/ifupdown/interface_parser.c50
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.am3
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.in5
-rw-r--r--src/settings/plugins/ifupdown/tests/test-ifupdown.c23
-rw-r--r--src/settings/plugins/ifupdown/tests/test21-source-dir-stanza1
-rw-r--r--src/settings/plugins/ifupdown/tests/test21-source-dir-stanza.d/test21-source-dir-stanza.eth02
-rw-r--r--src/settings/plugins/keyfile/Makefile.in2
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.in2
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.in2
30 files changed, 268 insertions, 166 deletions
diff --git a/src/settings/plugins/Makefile.in b/src/settings/plugins/Makefile.in
index ba388a5f..dfe5a45f 100644
--- a/src/settings/plugins/Makefile.in
+++ b/src/settings/plugins/Makefile.in
@@ -96,7 +96,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/ibft/Makefile.in b/src/settings/plugins/ibft/Makefile.in
index 9da764de..ea6a3a63 100644
--- a/src/settings/plugins/ibft/Makefile.in
+++ b/src/settings/plugins/ibft/Makefile.in
@@ -93,7 +93,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/ibft/tests/Makefile.in b/src/settings/plugins/ibft/tests/Makefile.in
index f0c681ab..4de64380 100644
--- a/src/settings/plugins/ibft/tests/Makefile.in
+++ b/src/settings/plugins/ibft/tests/Makefile.in
@@ -95,7 +95,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/ifcfg-rh/Makefile.in b/src/settings/plugins/ifcfg-rh/Makefile.in
index 3cd841c3..200289e5 100644
--- a/src/settings/plugins/ifcfg-rh/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/Makefile.in
@@ -94,7 +94,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
index 82f20598..184e95b2 100644
--- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
+++ b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
@@ -395,7 +395,9 @@ commit_changes (NMSettingsConnection *connection,
 	 */
 	filename = nm_settings_connection_get_filename (connection);
 	if (filename) {
-		reread = connection_from_file (filename, NULL, NULL, NULL);
+		gs_free char *unhandled = NULL;
+
+		reread = connection_from_file (filename, &unhandled, NULL, NULL);
 		if (reread) {
 			same = nm_connection_compare (NM_CONNECTION (connection),
 			                              reread,
diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c
index af5d2910..5a351cfa 100644
--- a/src/settings/plugins/ifcfg-rh/reader.c
+++ b/src/settings/plugins/ifcfg-rh/reader.c
@@ -1621,26 +1621,29 @@ check_if_bond_slave (shvarFile *ifcfg,
 	 */
 }
 
-static void
+static gboolean
 check_if_team_slave (shvarFile *ifcfg,
                      NMSettingConnection *s_con)
 {
-	char *value;
+	gs_free char *value = NULL;
 
-	value = svGetValue (ifcfg, "DEVICETYPE", FALSE);
-	if (!value)
-		return;
-	if (strcasecmp (value, TYPE_TEAM_PORT)) {
-		g_free (value);
-		return;
-	}
-	g_free (value);
 	value = svGetValue (ifcfg, "TEAM_MASTER", FALSE);
 	if (!value)
-		return;
+		return FALSE;
 	g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
 	g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL);
-	g_free (value);
+	return TRUE;
+}
+
+static void
+check_if_slave (shvarFile *ifcfg,
+                NMSettingConnection *s_con)
+{
+	g_return_if_fail (NM_IS_SETTING_CONNECTION (s_con));
+
+	if (check_if_team_slave (ifcfg, s_con))
+		return;
+	check_if_bond_slave (ifcfg, s_con);
 }
 
 typedef struct {
@@ -3157,14 +3160,6 @@ make_wpa_setting (shvarFile *ifcfg,
 		if (allow_rsn && svGetValueBoolean (ifcfg, "WPA_ALLOW_WPA2", TRUE))
 			nm_setting_wireless_security_add_proto (wsec, "rsn");
 
-		/* If neither WPA_ALLOW_WPA or WPA_ALLOW_WPA2 were present, default
-		 * to both WPA and RSN allowed.
-		 */
-		if (!allow_wpa && !allow_rsn && !ieee8021x) {
-			nm_setting_wireless_security_add_proto (wsec, "wpa");
-			nm_setting_wireless_security_add_proto (wsec, "rsn");
-		}
-
 		g_free (allow_wpa);
 		g_free (allow_rsn);
 	}
@@ -3211,6 +3206,12 @@ make_wpa_setting (shvarFile *ifcfg,
 	}
 
 	g_free (value);
+
+	value = svGetValue (ifcfg, "SECURITYMODE", FALSE);
+	if (NM_IN_STRSET (value, NULL, "open"))
+		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, value, NULL);
+
+	g_free (value);
 	return (NMSetting *) wsec;
 
 error:
@@ -3948,8 +3949,7 @@ wired_connection_from_ifcfg (const char *file,
 		g_object_unref (connection);
 		return NULL;
 	}
-	check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
-	check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
+	check_if_slave (ifcfg, (NMSettingConnection *) con_setting);
 	nm_connection_add_setting (connection, con_setting);
 
 	wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error);
@@ -4099,8 +4099,7 @@ infiniband_connection_from_ifcfg (const char *file,
 		g_object_unref (connection);
 		return NULL;
 	}
-	check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
-	check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
+	check_if_slave (ifcfg, (NMSettingConnection *) con_setting);
 	nm_connection_add_setting (connection, con_setting);
 
 	infiniband_setting = make_infiniband_setting (ifcfg, file, error);
@@ -4237,6 +4236,7 @@ bond_connection_from_ifcfg (const char *file,
 static char *
 read_team_config (shvarFile *ifcfg, const char *key, GError **error)
 {
+	gs_free_error GError *local_error = NULL;
 	char *value;
 	size_t l;
 
@@ -4257,6 +4257,12 @@ read_team_config (shvarFile *ifcfg, const char *key, GError **error)
 		return NULL;
 	}
 	svUnescape (value);
+
+	if (value && value[0] && !_nm_utils_check_valid_json (value, &local_error)) {
+		PARSE_WARNING ("ignoring invalid team configuration: %s", local_error->message);
+		g_clear_pointer (&value, g_free);
+	}
+
 	return value;
 }
 
@@ -4599,8 +4605,6 @@ is_bond_device (const char *name, shvarFile *parsed)
 
 	if (svGetValueBoolean (parsed, "BONDING_MASTER", FALSE))
 		return TRUE;
-	
-	/* XXX: Check for "bond[\d]+"? */
 
 	return FALSE;
 }
@@ -4816,8 +4820,7 @@ vlan_connection_from_ifcfg (const char *file,
 		g_object_unref (connection);
 		return NULL;
 	}
-	check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
-	check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
+	check_if_slave (ifcfg, (NMSettingConnection *) con_setting);
 	nm_connection_add_setting (connection, con_setting);
 
 	vlan_setting = make_vlan_setting (ifcfg, file, error);
@@ -4848,7 +4851,7 @@ create_unhandled_connection (const char *filename, shvarFile *ifcfg,
 	NMSetting *s_con;
 	char *value;
 
-	g_assert (out_spec != NULL);
+	nm_assert (out_spec && !*out_spec);
 
 	connection = nm_simple_connection_new ();
 
@@ -4963,8 +4966,7 @@ connection_from_file_full (const char *filename,
 	const char *ifcfg_name = NULL;
 
 	g_return_val_if_fail (filename != NULL, NULL);
-	if (out_unhandled)
-		g_return_val_if_fail (*out_unhandled == NULL, NULL);
+	g_return_val_if_fail (out_unhandled && !*out_unhandled, NULL);
 
 	/* Non-NULL only for unit tests; normally use /etc/sysconfig/network */
 	if (!network_file)
@@ -4982,8 +4984,6 @@ connection_from_file_full (const char *filename,
 		return NULL;
 
 	if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) {
-		g_assert (out_unhandled != NULL);
-
 		connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled);
 		if (!connection)
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
@@ -5011,6 +5011,16 @@ connection_from_file_full (const char *filename,
 			type = g_strdup (TYPE_ETHERNET);
 		g_free (devtype);
 	}
+	if (!type) {
+		gs_free char *t = NULL;
+
+		/* Team and TeamPort types are also accepted by the mere
+		 * presense of TEAM_CONFIG/TEAM_MASTER. They don't require
+		 * DEVICETYPE. */
+		t = svGetValue (parsed, "TEAM_CONFIG", FALSE);
+		if (t)
+			type = g_strdup (TYPE_TEAM);
+	}
 
 	if (!type)
 		type = svGetValue (parsed, "TYPE", FALSE);
@@ -5136,8 +5146,6 @@ connection_from_file_full (const char *filename,
 	else if (!strcasecmp (type, TYPE_BRIDGE))
 		connection = bridge_connection_from_ifcfg (filename, parsed, error);
 	else {
-		g_assert (out_unhandled != NULL);
-
 		connection = create_unhandled_connection (filename, parsed, "unrecognized", out_unhandled);
 		if (!connection)
 			PARSE_WARNING ("connection type was unrecognized but device was not uniquely identified; device may be managed");
diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
index ac21e19b..f2ce157b 100644
--- a/src/settings/plugins/ifcfg-rh/tests/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
@@ -97,7 +97,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am
index fc759e6d..de9c1ed7 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am
@@ -132,8 +132,11 @@ EXTRA_DIST = \
 	ifcfg-test-dcb-pgpct-not-100 \
 	ifcfg-test-fcoe-fabric \
 	ifcfg-test-fcoe-vn2vn \
-	ifcfg-test-team-master \
-	ifcfg-test-team-port \
+	ifcfg-test-team-master-1 \
+	ifcfg-test-team-master-2 \
+	ifcfg-test-team-master-invalid \
+	ifcfg-test-team-port-1 \
+	ifcfg-test-team-port-2 \
 	ifcfg-test-team-port-empty-config \
 	ifcfg-test-vlan-trailing-spaces \
 	ifcfg-test-dns-options \
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
index 30cc7c05..583f0809 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
@@ -92,7 +92,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
@@ -537,8 +537,11 @@ EXTRA_DIST = \
 	ifcfg-test-dcb-pgpct-not-100 \
 	ifcfg-test-fcoe-fabric \
 	ifcfg-test-fcoe-vn2vn \
-	ifcfg-test-team-master \
-	ifcfg-test-team-port \
+	ifcfg-test-team-master-1 \
+	ifcfg-test-team-master-2 \
+	ifcfg-test-team-master-invalid \
+	ifcfg-test-team-port-1 \
+	ifcfg-test-team-port-2 \
 	ifcfg-test-team-port-empty-config \
 	ifcfg-test-vlan-trailing-spaces \
 	ifcfg-test-dns-options \
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1
index 7edc736a..7edc736a 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2
new file mode 100644
index 00000000..d01e37c5
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2
@@ -0,0 +1,5 @@
+DEVICE=team0
+ONBOOT=no
+BOOTPROTO=dhcp
+TEAM_CONFIG="{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"
+
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-invalid b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-invalid
new file mode 100644
index 00000000..4534882e
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-invalid
@@ -0,0 +1,4 @@
+DEVICE=team0
+ONBOOT=no
+BOOTPROTO=dhcp
+TEAM_CONFIG="{ foobar }"
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1
index 966bec67..966bec67 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2
new file mode 100644
index 00000000..992510ee
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2
@@ -0,0 +1,4 @@
+TYPE=Ethernet
+TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }"
+DEVICE=p4p1
+TEAM_MASTER=team0
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 60938f6e..9ed48beb 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -67,11 +67,14 @@ _connection_from_file (const char *filename,
 {
 	NMConnection *connection;
 	GError *error = NULL;
+	char *unhandled_fallback = NULL;
 
 	g_assert (!out_unhandled || !*out_unhandled);
 
-	connection = connection_from_file_test (filename, network_file, test_type, out_unhandled, &error);
+	connection = connection_from_file_test (filename, network_file, test_type,
+	                                        out_unhandled ?: &unhandled_fallback, &error);
 	g_assert_no_error (error);
+	g_assert (!unhandled_fallback);
 
 	if (out_unhandled && *out_unhandled)
 		nmtst_assert_connection_verifies (connection);
@@ -89,13 +92,12 @@ _connection_from_file_fail (const char *filename,
 	NMConnection *connection;
 	GError *local = NULL;
 	char *unhandled = NULL;
-	char **p_unhandled = (nmtst_get_rand_int () % 2) ? &unhandled : NULL;
 
-	connection = connection_from_file_test (filename, network_file, test_type, p_unhandled, &local);
+	connection = connection_from_file_test (filename, network_file, test_type, &unhandled, &local);
 
 	g_assert (!connection);
 	g_assert (local);
-	g_assert (!p_unhandled || !*p_unhandled);
+	g_assert (!unhandled);
 	g_propagate_error (error, local);
 }
 
@@ -107,11 +109,14 @@ _writer_new_connection (NMConnection *connection,
 	gboolean success;
 	GError *error = NULL;
 	char *filename = NULL;
+	gs_unref_object NMConnection *con_verified = NULL;
 
 	g_assert (NM_IS_CONNECTION (connection));
 	g_assert (ifcfg_dir);
 
-	success = writer_new_connection (connection,
+	con_verified = nmtst_connection_duplicate_and_normalize (connection);
+
+	success = writer_new_connection (con_verified,
 	                                 ifcfg_dir,
 	                                 &filename,
 	                                 &error);
@@ -8425,15 +8430,15 @@ test_write_fcoe_mode (gconstpointer user_data)
 }
 
 static void
-test_read_team_master (void)
+test_read_team_master (gconstpointer user_data)
 {
+	const char *const PATH_NAME = user_data;
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingTeam *s_team;
 	const char *expected_config = "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }";
 
-	connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master",
-	                                    NULL, TYPE_ETHERNET, NULL);
+	connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL);
 
 	g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "team0");
 
@@ -8449,6 +8454,31 @@ test_read_team_master (void)
 }
 
 static void
+test_read_team_master_invalid (gconstpointer user_data)
+{
+	const char *const PATH_NAME = user_data;
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingTeam *s_team;
+
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*ignoring invalid team configuration*");
+	connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL);
+	g_test_assert_expected_messages ();
+
+	g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "team0");
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_TEAM_SETTING_NAME);
+
+	s_team = nm_connection_get_setting_team (connection);
+	g_assert (s_team);
+	g_assert (nm_setting_team_get_config (s_team) == NULL);
+
+	g_object_unref (connection);
+}
+
+static void
 test_write_team_master (void)
 {
 	NMConnection *connection, *reread;
@@ -8541,15 +8571,15 @@ test_write_team_master (void)
 }
 
 static void
-test_read_team_port (void)
+test_read_team_port (gconstpointer user_data)
 {
+	const char *const PATH_NAME = user_data;
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingTeamPort *s_team_port;
 	const char *expected_config = "{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }";
 
-	connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port",
-	                                    NULL, TYPE_ETHERNET, NULL);
+	connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL);
 
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
@@ -9043,9 +9073,12 @@ int main (int argc, char **argv)
 	g_test_add_func (TPATH "bridge/write-component", test_write_bridge_component);
 	g_test_add_func (TPATH "bridge/read-missing-stp", test_read_bridge_missing_stp);
 
-	g_test_add_func (TPATH "team/read-master", test_read_team_master);
+	g_test_add_data_func (TPATH "team/read-master-1", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master-1", test_read_team_master);
+	g_test_add_data_func (TPATH "team/read-master-2", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master-2", test_read_team_master);
+	g_test_add_data_func (TPATH "team/read-master-invalid", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master-invalid", test_read_team_master_invalid);
 	g_test_add_func (TPATH "team/write-master", test_write_team_master);
-	g_test_add_func (TPATH "team/read-port", test_read_team_port);
+	g_test_add_data_func (TPATH "team/read-port-1", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-1", test_read_team_port);
+	g_test_add_data_func (TPATH "team/read-port-2", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-2", test_read_team_port);
 	g_test_add_func (TPATH "team/write-port", test_write_team_port);
 	g_test_add_func (TPATH "team/read-port-empty-config", test_read_team_port_empty_config);
 
diff --git a/src/settings/plugins/ifcfg-rh/utils.c b/src/settings/plugins/ifcfg-rh/utils.c
index b602a7d7..b9d52b7f 100644
--- a/src/settings/plugins/ifcfg-rh/utils.c
+++ b/src/settings/plugins/ifcfg-rh/utils.c
@@ -382,25 +382,6 @@ utils_has_complex_routes (const char *filename)
 	return FALSE;
 }
 
-gboolean
-utils_ignore_ip_config (NMConnection *connection)
-{
-	NMSettingConnection *s_con;
-
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
-
-	/* bonding slaves have no IP configuration, and the system
-	 * scripts just ignore it if it's there.
-	 */
-	if (   nm_setting_connection_is_slave_type (s_con, NM_SETTING_BOND_SETTING_NAME)
-	    || nm_setting_connection_is_slave_type (s_con, NM_SETTING_BRIDGE_SETTING_NAME)
-	    || nm_setting_connection_is_slave_type (s_con, NM_SETTING_TEAM_SETTING_NAME))
-		return TRUE;
-
-	return FALSE;
-}
-
 /* Find out if the 'alias' file name might be an alias file for 'ifcfg' file name,
  * or any alias when 'ifcfg' is NULL. Does not check that it's actually a valid
  * alias name; that happens in reader.c
diff --git a/src/settings/plugins/ifcfg-rh/utils.h b/src/settings/plugins/ifcfg-rh/utils.h
index b8b172e7..c105487a 100644
--- a/src/settings/plugins/ifcfg-rh/utils.h
+++ b/src/settings/plugins/ifcfg-rh/utils.h
@@ -54,8 +54,6 @@ shvarFile *utils_get_route6_ifcfg (const char *parent, gboolean should_create);
 gboolean utils_has_route_file_new_syntax (const char *filename);
 gboolean utils_has_complex_routes (const char *filename);
 
-gboolean utils_ignore_ip_config (NMConnection *connection);
-
 gboolean utils_is_ifcfg_alias_file (const char *alias, const char *ifcfg);
 
 char *utils_detect_ifcfg_path (const char *path, gboolean only_ifcfg);
diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c
index 4817549e..dcc48f2a 100644
--- a/src/settings/plugins/ifcfg-rh/writer.c
+++ b/src/settings/plugins/ifcfg-rh/writer.c
@@ -2010,13 +2010,29 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	gint priority;
 	int timeout;
 	GString *searches;
-	gboolean success = FALSE;
-	gboolean fake_ip4 = FALSE;
 	const char *method = NULL;
 
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
-	if (s_ip4)
-		method = nm_setting_ip_config_get_method (s_ip4);
+	if (!s_ip4) {
+		/* slave-type: clear IPv4 settings.
+		 *
+		 * Some IPv4 setting related options are not cleared,
+		 * for no strong reason. */
+		svSetValue (ifcfg, "BOOTPROTO", NULL, FALSE);
+
+		svSetValue (ifcfg, "IPADDR", NULL, FALSE);
+		svSetValue (ifcfg, "PREFIX", NULL, FALSE);
+		svSetValue (ifcfg, "NETMASK", NULL, FALSE);
+		svSetValue (ifcfg, "GATEWAY", NULL, FALSE);
+
+		svSetValue (ifcfg, "IPADDR0", NULL, FALSE);
+		svSetValue (ifcfg, "PREFIX0", NULL, FALSE);
+		svSetValue (ifcfg, "NETMASK0", NULL, FALSE);
+		svSetValue (ifcfg, "GATEWAY0", NULL, FALSE);
+		return TRUE;
+	}
+
+	method = nm_setting_ip_config_get_method (s_ip4);
 
 	/* Missing IP4 setting is assumed to be DHCP */
 	if (!method)
@@ -2057,12 +2073,6 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 		return TRUE;
 	}
 
-	/* Temporarily create fake IP4 setting if missing; method set to DHCP above */
-	if (!s_ip4) {
-		s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
-		fake_ip4 = TRUE;
-	}
-
 	if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO))
 		svSetValue (ifcfg, "BOOTPROTO", "dhcp", FALSE);
 	else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
@@ -2237,7 +2247,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	if (!route_path) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
 		             "Could not get route file path for '%s'", ifcfg->fileName);
-		goto out;
+		return FALSE;
 	}
 
 	if (utils_has_route_file_new_syntax (route_path)) {
@@ -2248,7 +2258,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
 			             "Could not create route file '%s'", route_path);
 			g_free (route_path);
-			goto out;
+			return FALSE;
 		}
 		g_free (route_path);
 
@@ -2299,14 +2309,14 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 		}
 		if (!svWriteFile (routefile, 0644, error)) {
 			svCloseFile (routefile);
-			goto out;
+			return FALSE;
 		}
 		svCloseFile (routefile);
 	} else {
 		write_route_file_legacy (route_path, s_ip4, error);
 		g_free (route_path);
 		if (error && *error)
-			goto out;
+			return FALSE;
 	}
 
 	timeout = nm_setting_ip_config_get_dad_timeout (s_ip4);
@@ -2325,13 +2335,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	else
 		svSetValue (ifcfg, "IPV4_DNS_PRIORITY", NULL, FALSE);
 
-	success = TRUE;
-
-out:
-	if (fake_ip4)
-		g_object_unref (s_ip4);
-
-	return success;
+	return TRUE;
 }
 
 static void
@@ -2371,12 +2375,11 @@ write_ip4_aliases (NMConnection *connection, char *base_ifcfg_path)
 		g_dir_close (dir);
 	}
 
-	if (utils_ignore_ip_config (connection))
-		return;
-
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
-	if (!s_ip4)
+	if (!s_ip4) {
+		/* slave-type: no alias files */
 		return;
+	}
 
 	num = nm_setting_ip_config_get_num_addresses (s_ip4);
 	for (i = 0; i < num; i++) {
@@ -2495,16 +2498,19 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 
 	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	if (!s_ip6) {
-		/* Treat missing IPv6 setting as a setting with method "auto" */
-		svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
-		svSetValue (ifcfg, "IPV6_AUTOCONF", "yes", FALSE);
+		/* slave-type: clear IPv6 settings
+		 *
+		 * Some IPv6 setting related options are not cleared,
+		 * for no strong reason. */
+		svSetValue (ifcfg, "IPV6INIT", NULL, FALSE);
+		svSetValue (ifcfg, "IPV6_AUTOCONF", NULL, FALSE);
 		svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
-		svSetValue (ifcfg, "IPV6_DEFROUTE", "yes", FALSE);
-		svSetValue (ifcfg, "IPV6_PEERDNS", "yes", FALSE);
-		svSetValue (ifcfg, "IPV6_PEERROUTES", "yes", FALSE);
-		svSetValue (ifcfg, "IPV6_FAILURE_FATAL", "no", FALSE);
+		svSetValue (ifcfg, "IPV6_DEFROUTE", NULL, FALSE);
+		svSetValue (ifcfg, "IPV6_PEERDNS", NULL, FALSE);
+		svSetValue (ifcfg, "IPV6_PEERROUTES", NULL, FALSE);
+		svSetValue (ifcfg, "IPV6_FAILURE_FATAL", NULL, FALSE);
 		svSetValue (ifcfg, "IPV6_ROUTE_METRIC", NULL, FALSE);
-		svSetValue (ifcfg, "IPV6_ADDR_GEN_MODE", "stable-privacy", FALSE);
+		svSetValue (ifcfg, "IPV6_ADDR_GEN_MODE", NULL, FALSE);
 		return TRUE;
 	}
 
@@ -2695,34 +2701,37 @@ write_res_options (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	NMSettingIPConfig *s_ip4;
 	const char *method;
 	int i, num_options;
-	GPtrArray *array;
+	gs_unref_ptrarray GPtrArray *array = NULL;
 	GString *value;
 
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
-	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+
+	if (!s_ip4) {
+		/* slave-type: clear res-options */
+		svSetValue (ifcfg, "RES_OPTIONS", NULL, FALSE);
+		return TRUE;
+	}
+
 	array = g_ptr_array_new ();
 
-	if (s_ip4) {
-		method = nm_setting_ip_config_get_method (s_ip4);
-		if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
-			num_options = nm_setting_ip_config_get_num_dns_options (s_ip4);
-			for (i = 0; i < num_options; i++)
-				add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip4, i));
-		}
+	method = nm_setting_ip_config_get_method (s_ip4);
+	if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
+		num_options = nm_setting_ip_config_get_num_dns_options (s_ip4);
+		for (i = 0; i < num_options; i++)
+			add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip4, i));
 	}
 
-	if (s_ip6) {
-		method = nm_setting_ip_config_get_method (s_ip6);
-		if (g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
-			num_options = nm_setting_ip_config_get_num_dns_options (s_ip6);
-			for (i = 0; i < num_options; i++)
-				add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip6, i));
-		}
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	method = nm_setting_ip_config_get_method (s_ip6);
+	if (g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
+		num_options = nm_setting_ip_config_get_num_dns_options (s_ip6);
+		for (i = 0; i < num_options; i++)
+			add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip6, i));
 	}
 
-	if (array->len > 0
-	    || (s_ip4 && nm_setting_ip_config_has_dns_options (s_ip4))
-	    || (s_ip6 && nm_setting_ip_config_has_dns_options (s_ip6))) {
+	if (   array->len > 0
+	    || nm_setting_ip_config_has_dns_options (s_ip4)
+	    || nm_setting_ip_config_has_dns_options (s_ip6)) {
 		value = g_string_new (NULL);
 		for (i = 0; i < array->len; i++) {
 			if (i > 0)
@@ -2734,7 +2743,6 @@ write_res_options (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	} else
 		svSetValue (ifcfg, "RES_OPTIONS", NULL, FALSE);
 
-	g_ptr_array_unref (array);
 	return TRUE;
 }
 
@@ -2772,6 +2780,9 @@ write_connection (NMConnection *connection,
 	gboolean no_8021x = FALSE;
 	gboolean wired = FALSE;
 
+	nm_assert (NM_IS_CONNECTION (connection));
+	nm_assert (nm_connection_verify (connection, NULL));
+
 	if (!writer_can_write_connection (connection, error))
 		return FALSE;
 
@@ -2876,20 +2887,18 @@ write_connection (NMConnection *connection,
 	if (!write_dcb_setting (connection, ifcfg, error))
 		goto out;
 
-	if (!utils_ignore_ip_config (connection)) {
-		svSetValue (ifcfg, "DHCP_HOSTNAME", NULL, FALSE);
-		svSetValue (ifcfg, "DHCP_FQDN", NULL, FALSE);
+	svSetValue (ifcfg, "DHCP_HOSTNAME", NULL, FALSE);
+	svSetValue (ifcfg, "DHCP_FQDN", NULL, FALSE);
 
-		if (!write_ip4_setting (connection, ifcfg, error))
-			goto out;
-		write_ip4_aliases (connection, ifcfg_name);
+	if (!write_ip4_setting (connection, ifcfg, error))
+		goto out;
+	write_ip4_aliases (connection, ifcfg_name);
 
-		if (!write_ip6_setting (connection, ifcfg, error))
-			goto out;
+	if (!write_ip6_setting (connection, ifcfg, error))
+		goto out;
 
-		if (!write_res_options (connection, ifcfg, error))
-			goto out;
-	}
+	if (!write_res_options (connection, ifcfg, error))
+		goto out;
 
 	write_connection_setting (s_con, ifcfg);
 
diff --git a/src/settings/plugins/ifnet/Makefile.in b/src/settings/plugins/ifnet/Makefile.in
index 44295ada..a3b12364 100644
--- a/src/settings/plugins/ifnet/Makefile.in
+++ b/src/settings/plugins/ifnet/Makefile.in
@@ -93,7 +93,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/ifnet/tests/Makefile.in b/src/settings/plugins/ifnet/tests/Makefile.in
index 0aee0582..18f3c20c 100644
--- a/src/settings/plugins/ifnet/tests/Makefile.in
+++ b/src/settings/plugins/ifnet/tests/Makefile.in
@@ -95,7 +95,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/ifupdown/Makefile.in b/src/settings/plugins/ifupdown/Makefile.in
index 4e1c657b..385a55d9 100644
--- a/src/settings/plugins/ifupdown/Makefile.in
+++ b/src/settings/plugins/ifupdown/Makefile.in
@@ -93,7 +93,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/ifupdown/interface_parser.c b/src/settings/plugins/ifupdown/interface_parser.c
index 7ad902d4..764ba5c9 100644
--- a/src/settings/plugins/ifupdown/interface_parser.c
+++ b/src/settings/plugins/ifupdown/interface_parser.c
@@ -100,7 +100,7 @@ static char *join_values_with_spaces(char *dst, char **src)
 	return(dst);
 }
 
-static void _ifparser_source (const char *path, const char *en_dir, int quiet);
+static void _ifparser_source (const char *path, const char *en_dir, int quiet, int dir);
 
 static void
 _recursive_ifparser (const char *eni_file, int quiet)
@@ -189,9 +189,9 @@ _recursive_ifparser (const char *eni_file, int quiet)
 			continue;
 		}
 
-		/* There are five different stanzas:
-		 * iface, mapping, auto, allow-* and source.
-		 * Create a block for each of them except source.  */
+		/* There are six different stanzas:
+		 * iface, mapping, auto, allow-*, source, and source-directory.
+		 * Create a block for each of them except source and source-directory.  */
 
 		/* iface stanza takes at least 3 parameters */
 		if (strcmp(token[0], "iface") == 0) {
@@ -226,22 +226,28 @@ _recursive_ifparser (const char *eni_file, int quiet)
 				add_block(token[0], token[i]);
 			skip_to_block = 0;
 		}
-		/* source stanza takes one or more filepaths as parameters */
-		else if (strcmp(token[0], "source") == 0) {
+		/* source and source-directory stanzas take one or more paths as parameters */
+		else if (strcmp (token[0], "source") == 0 || strcmp (token[0], "source-directory") == 0) {
 			int i;
 			char *en_dir;
 
 			skip_to_block = 0;
 
 			if (toknum == 1) {
-				if (!quiet)
-					nm_log_warn (LOGD_SETTINGS, "Invalid source line without parameters\n");
+				if (!quiet) {
+					nm_log_warn (LOGD_SETTINGS, "Invalid %s line without parameters\n",
+					             token[0]);
+				}
 				continue;
 			}
 
 			en_dir = g_path_get_dirname (eni_file);
-			for (i = 1; i < toknum; ++i)
-				_ifparser_source (token[i], en_dir, quiet);
+			for (i = 1; i < toknum; ++i) {
+				if (strcmp (token[0], "source-directory") == 0)
+					_ifparser_source (token[i], en_dir, quiet, TRUE);
+				else
+					_ifparser_source (token[i], en_dir, quiet, FALSE);
+			}
 			g_free (en_dir);
 		}
 		else {
@@ -261,10 +267,13 @@ _recursive_ifparser (const char *eni_file, int quiet)
 }
 
 static void
-_ifparser_source (const char *path, const char *en_dir, int quiet)
+_ifparser_source (const char *path, const char *en_dir, int quiet, int dir)
 {
 	char *abs_path;
+	const char *item;
 	wordexp_t we;
+	GDir *source_dir;
+	GError *error = NULL;
 	uint i;
 
 	if (g_path_is_absolute (path))
@@ -280,8 +289,23 @@ _ifparser_source (const char *path, const char *en_dir, int quiet)
 		if (!quiet)
 			nm_log_warn (LOGD_SETTINGS, "word expansion for %s failed\n", abs_path);
 	} else {
-		for (i = 0; i < we.we_wordc; i++)
-			_recursive_ifparser (we.we_wordv[i], quiet);
+		for (i = 0; i < we.we_wordc; i++) {
+			if (dir) {
+				source_dir = g_dir_open (we.we_wordv[i], 0, &error);
+				if (!source_dir) {
+					if (!quiet) {
+						nm_log_warn (LOGD_SETTINGS, "Failed to open directory %s: %s",
+						             we.we_wordv[i], error->message);
+					}
+					g_clear_error (&error);
+				} else {
+					while ((item = g_dir_read_name (source_dir)))
+						_ifparser_source (item, we.we_wordv[i], quiet, FALSE);
+					g_dir_close (source_dir);
+				}
+			} else
+				_recursive_ifparser (we.we_wordv[i], quiet);
+		}
 		wordfree (&we);
 	}
 	g_free (abs_path);
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.am b/src/settings/plugins/ifupdown/tests/Makefile.am
index 1287a716..3d702375 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.am
+++ b/src/settings/plugins/ifupdown/tests/Makefile.am
@@ -35,4 +35,5 @@ EXTRA_DIST = \
 	test1 test2 test3 test4 test5 test6 test7 test8 test9 test11 test12 \
 	test13 test14 test15 test16 test17-wired-static-verify-ip4 \
 	test18-wired-static-verify-ip6 test19-wired-static-verify-ip4-plen \
-	test20-source-stanza test20-source-stanza.eth0 test20-source-stanza.eth1
+	test20-source-stanza test20-source-stanza.eth0 test20-source-stanza.eth1 \
+	test21-source-dir-stanza test21-source-dir-stanza.d
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.in b/src/settings/plugins/ifupdown/tests/Makefile.in
index b63f9a89..b3be79e1 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.in
+++ b/src/settings/plugins/ifupdown/tests/Makefile.in
@@ -95,7 +95,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
@@ -688,7 +688,8 @@ EXTRA_DIST = \
 	test1 test2 test3 test4 test5 test6 test7 test8 test9 test11 test12 \
 	test13 test14 test15 test16 test17-wired-static-verify-ip4 \
 	test18-wired-static-verify-ip6 test19-wired-static-verify-ip4-plen \
-	test20-source-stanza test20-source-stanza.eth0 test20-source-stanza.eth1
+	test20-source-stanza test20-source-stanza.eth0 test20-source-stanza.eth1 \
+	test21-source-dir-stanza test21-source-dir-stanza.d
 
 all: all-am
 
diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
index 7ce08aee..11b42c71 100644
--- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c
+++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
@@ -627,6 +627,27 @@ test20_source_stanza (const char *path)
 	expected_free (e);
 }
 
+static void
+test21_source_dir_stanza (const char *path)
+{
+	Expected *e;
+	ExpectedBlock *b;
+
+	e = expected_new ();
+
+	b = expected_block_new ("auto", "eth0");
+	expected_add_block (e, b);
+	b = expected_block_new ("iface", "eth0");
+	expected_add_block (e, b);
+	expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
+
+	init_ifparser_with_file (path, "test21-source-dir-stanza");
+	compare_expected_to_ifparser (e);
+
+	ifparser_destroy ();
+	expected_free (e);
+}
+
 NMTST_DEFINE ();
 
 int
@@ -675,6 +696,8 @@ main (int argc, char **argv)
 	                      (GTestDataFunc) test19_read_static_ipv4_plen);
 	g_test_add_data_func ("/ifupdate/source_stanza", TEST_ENI_DIR,
 	                      (GTestDataFunc) test20_source_stanza);
+	g_test_add_data_func ("/ifupdate/source_dir_stanza", TEST_ENI_DIR,
+	                      (GTestDataFunc) test21_source_dir_stanza);
 
 	return g_test_run ();
 }
diff --git a/src/settings/plugins/ifupdown/tests/test21-source-dir-stanza b/src/settings/plugins/ifupdown/tests/test21-source-dir-stanza
new file mode 100644
index 00000000..d0604ddc
--- /dev/null
+++ b/src/settings/plugins/ifupdown/tests/test21-source-dir-stanza
@@ -0,0 +1 @@
+source-directory test21-source-dir-stanza.d
diff --git a/src/settings/plugins/ifupdown/tests/test21-source-dir-stanza.d/test21-source-dir-stanza.eth0 b/src/settings/plugins/ifupdown/tests/test21-source-dir-stanza.d/test21-source-dir-stanza.eth0
new file mode 100644
index 00000000..81922cea
--- /dev/null
+++ b/src/settings/plugins/ifupdown/tests/test21-source-dir-stanza.d/test21-source-dir-stanza.eth0
@@ -0,0 +1,2 @@
+auto eth0
+iface eth0 inet dhcp
diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in
index e6f4b4cf..085dfdd5 100644
--- a/src/settings/plugins/keyfile/Makefile.in
+++ b/src/settings/plugins/keyfile/Makefile.in
@@ -93,7 +93,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in
index e2e56d4e..ffa882b2 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/Makefile.in
@@ -95,7 +95,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
index 88e03515..cac6dcd0 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
@@ -92,7 +92,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
 	$(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_options.m4 \
-	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/git-sha-record.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \