about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile.in10
-rw-r--r--src/NetworkManager.ver10
-rw-r--r--src/NetworkManagerUtils.c36
-rw-r--r--src/devices/Makefile.in2
-rw-r--r--src/devices/adsl/Makefile.in2
-rw-r--r--src/devices/bluetooth/Makefile.in2
-rw-r--r--src/devices/nm-device-ethernet.c13
-rw-r--r--src/devices/nm-device-veth.c13
-rw-r--r--src/devices/nm-device.c183
-rw-r--r--src/devices/nm-device.h4
-rw-r--r--src/devices/team/Makefile.in2
-rw-r--r--src/devices/tests/Makefile.in2
-rw-r--r--src/devices/wifi/Makefile.in2
-rw-r--r--src/devices/wifi/nm-device-wifi.c13
-rw-r--r--src/devices/wifi/nm-wifi-ap.c13
-rw-r--r--src/devices/wifi/tests/Makefile.in2
-rw-r--r--src/devices/wwan/Makefile.in2
-rw-r--r--src/dhcp-manager/Makefile.am5
-rw-r--r--src/dhcp-manager/Makefile.in8
-rw-r--r--src/dhcp-manager/nm-dhcp-helper-api.h36
-rw-r--r--src/dhcp-manager/nm-dhcp-helper.c149
-rw-r--r--src/dhcp-manager/nm-dhcp-listener.c192
-rw-r--r--src/dhcp-manager/nm-dhcp-listener.h4
-rw-r--r--src/dhcp-manager/tests/Makefile.in2
-rw-r--r--src/dns-manager/nm-dns-manager.c13
-rw-r--r--src/dnsmasq-manager/tests/Makefile.in2
-rw-r--r--src/nm-auth-subject.c13
-rw-r--r--src/nm-bus-manager.c6
-rw-r--r--src/nm-checkpoint.c15
-rw-r--r--src/nm-enum-types.c1
-rw-r--r--src/nm-exported-object.c188
-rw-r--r--src/nm-iface-helper.c14
-rw-r--r--src/nm-ip4-config.c13
-rw-r--r--src/nm-ip6-config.c13
-rw-r--r--src/nm-logging.c2
-rw-r--r--src/nm-manager.c22
-rw-r--r--src/platform/Makefile.in2
-rw-r--r--src/platform/nm-linux-platform.c66
-rw-r--r--src/platform/tests/Makefile.in2
-rw-r--r--src/platform/tests/test-link.c8
-rw-r--r--src/ppp-manager/Makefile.in2
-rw-r--r--src/rdisc/Makefile.in2
-rw-r--r--src/rdisc/nm-lndp-rdisc.c13
-rw-r--r--src/rdisc/nm-rdisc.c13
-rw-r--r--src/rdisc/tests/Makefile.in2
-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
-rw-r--r--src/supplicant-manager/tests/Makefile.in2
-rw-r--r--src/supplicant-manager/tests/certs/Makefile.in2
-rw-r--r--src/tests/Makefile.in2
-rw-r--r--src/tests/config/Makefile.in2
-rw-r--r--src/vpn-manager/nm-vpn-connection.c13
81 files changed, 995 insertions, 580 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c460caff..8d29b191 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -335,6 +335,7 @@ libNetworkManager_la_SOURCES = \
 	dhcp-manager/nm-dhcp-client.c \
 	dhcp-manager/nm-dhcp-client.h \
 	dhcp-manager/nm-dhcp-client-logging.h \
+	dhcp-manager/nm-dhcp-helper-api.h \
 	dhcp-manager/nm-dhcp-utils.c \
 	dhcp-manager/nm-dhcp-utils.h \
 	dhcp-manager/nm-dhcp-listener.c \
diff --git a/src/Makefile.in b/src/Makefile.in
index 7f4cf252..d7a37db5 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -118,7 +118,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 \
@@ -162,8 +162,8 @@ am__libNetworkManager_la_SOURCES_DIST =  \
 	devices/nm-device-private.h dhcp-manager/nm-dhcp-client.c \
 	dhcp-manager/nm-dhcp-client.h \
 	dhcp-manager/nm-dhcp-client-logging.h \
-	dhcp-manager/nm-dhcp-utils.c dhcp-manager/nm-dhcp-utils.h \
-	dhcp-manager/nm-dhcp-listener.c \
+	dhcp-manager/nm-dhcp-helper-api.h dhcp-manager/nm-dhcp-utils.c \
+	dhcp-manager/nm-dhcp-utils.h dhcp-manager/nm-dhcp-listener.c \
 	dhcp-manager/nm-dhcp-listener.h dhcp-manager/nm-dhcp-manager.c \
 	dhcp-manager/nm-dhcp-manager.h dns-manager/nm-dns-dnsmasq.c \
 	dns-manager/nm-dns-dnsmasq.h dns-manager/nm-dns-unbound.c \
@@ -1085,8 +1085,8 @@ libNetworkManager_la_SOURCES = dhcp-manager/nm-dhcp-dhclient-utils.c \
 	devices/nm-device-private.h dhcp-manager/nm-dhcp-client.c \
 	dhcp-manager/nm-dhcp-client.h \
 	dhcp-manager/nm-dhcp-client-logging.h \
-	dhcp-manager/nm-dhcp-utils.c dhcp-manager/nm-dhcp-utils.h \
-	dhcp-manager/nm-dhcp-listener.c \
+	dhcp-manager/nm-dhcp-helper-api.h dhcp-manager/nm-dhcp-utils.c \
+	dhcp-manager/nm-dhcp-utils.h dhcp-manager/nm-dhcp-listener.c \
 	dhcp-manager/nm-dhcp-listener.h dhcp-manager/nm-dhcp-manager.c \
 	dhcp-manager/nm-dhcp-manager.h dns-manager/nm-dns-dnsmasq.c \
 	dns-manager/nm-dns-dnsmasq.h dns-manager/nm-dns-unbound.c \
diff --git a/src/NetworkManager.ver b/src/NetworkManager.ver
index c91affcb..d5358e5c 100644
--- a/src/NetworkManager.ver
+++ b/src/NetworkManager.ver
@@ -5,6 +5,16 @@ global:
 	_nm*;
 	NM*;
 	_NM*;
+
+	/* The _IO_stdin_used symbol is used by the GNU libc to determine
+	   which version of the I/O function should be used.  Not
+	   exporting it means that the "old" version is used, causing
+	   crashes or other issues on some architectures.  It should be
+	   exported as an anonymous tag, but ld does not support mixing
+	   anonymous version tags with other version tags.  Fortunately
+	   the GNU libc is able to cope with the symbol having the wrong
+	   version tag. */
+	_IO_stdin_used;
 local:
 	*;
 };
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 7eb6cf16..7cfe03f1 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -528,6 +528,39 @@ check_connection_mac_address (NMConnection *orig,
 }
 
 static gboolean
+check_connection_infiniband_mac_address (NMConnection *orig,
+                                         NMConnection *candidate,
+                                         GHashTable *settings)
+{
+	GHashTable *props;
+	const char *orig_mac = NULL, *cand_mac = NULL;
+	NMSettingInfiniband *s_infiniband_orig, *s_infiniband_cand;
+
+	props = check_property_in_hash (settings,
+	                                NM_SETTING_INFINIBAND_SETTING_NAME,
+	                                NM_SETTING_INFINIBAND_MAC_ADDRESS);
+	if (!props)
+		return TRUE;
+
+	/* If one of the MAC addresses is NULL, we accept that connection */
+	s_infiniband_orig = nm_connection_get_setting_infiniband (orig);
+	if (s_infiniband_orig)
+		orig_mac = nm_setting_infiniband_get_mac_address (s_infiniband_orig);
+
+	s_infiniband_cand = nm_connection_get_setting_infiniband (candidate);
+	if (s_infiniband_cand)
+		cand_mac = nm_setting_infiniband_get_mac_address (s_infiniband_cand);
+
+	if (!orig_mac || !cand_mac) {
+		remove_from_hash (settings, props,
+		                  NM_SETTING_INFINIBAND_SETTING_NAME,
+		                  NM_SETTING_INFINIBAND_MAC_ADDRESS);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean
 check_connection_cloned_mac_address (NMConnection *orig,
                                      NMConnection *candidate,
                                      GHashTable *settings)
@@ -640,6 +673,9 @@ check_possible_match (NMConnection *orig,
 	if (!check_connection_mac_address (orig, candidate, settings))
 		return NULL;
 
+	if (!check_connection_infiniband_mac_address (orig, candidate, settings))
+		return NULL;
+
 	if (!check_connection_cloned_mac_address (orig, candidate, settings))
 		return NULL;
 
diff --git a/src/devices/Makefile.in b/src/devices/Makefile.in
index 4791015d..b247b35b 100644
--- a/src/devices/Makefile.in
+++ b/src/devices/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 \
diff --git a/src/devices/adsl/Makefile.in b/src/devices/adsl/Makefile.in
index f3fbad4c..37015ab1 100644
--- a/src/devices/adsl/Makefile.in
+++ b/src/devices/adsl/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/devices/bluetooth/Makefile.in b/src/devices/bluetooth/Makefile.in
index c010f4c7..ce12d2d4 100644
--- a/src/devices/bluetooth/Makefile.in
+++ b/src/devices/bluetooth/Makefile.in
@@ -99,7 +99,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/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 90d472da..b213a0cc 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -127,18 +127,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceEthernet,
 
 G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE)
 
-#define NM_DEVICE_ETHERNET_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMDeviceEthernet *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_DEVICE_ETHERNET (_self)); \
-		_self->_priv; \
-	})
+#define NM_DEVICE_ETHERNET_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMDeviceEthernet, NM_IS_DEVICE_ETHERNET)
 
 /*****************************************************************************/
 
diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c
index cca86fbe..56923315 100644
--- a/src/devices/nm-device-veth.c
+++ b/src/devices/nm-device-veth.c
@@ -62,18 +62,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceVeth,
 
 G_DEFINE_TYPE (NMDeviceVeth, nm_device_veth, NM_TYPE_DEVICE_ETHERNET)
 
-#define NM_DEVICE_VETH_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMDeviceVeth *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_DEVICE_VETH (_self)); \
-		&_self->_priv; \
-	})
+#define NM_DEVICE_VETH_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDeviceVeth, NM_IS_DEVICE_VETH)
 
 /*****************************************************************************/
 
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 199acc66..27d940c9 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -75,18 +75,7 @@ _LOG_DECLARE_SELF (NMDevice);
 
 G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT)
 
-#define NM_DEVICE_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMDevice *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_DEVICE (_self)); \
-		_self->priv; \
-	})
+#define NM_DEVICE_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMDevice, NM_IS_DEVICE)
 
 enum {
 	STATE_CHANGED,
@@ -1526,7 +1515,7 @@ is_unmanaged_external_down (NMDevice *self, gboolean consider_can)
 	/* Manage externally-created software interfaces only when they are IFF_UP */
 	if (   priv->ifindex <= 0
 	    || !priv->up
-	    || !nm_platform_link_can_assume (NM_PLATFORM_GET, priv->ifindex))
+	    || !(priv->slaves || nm_platform_link_can_assume (NM_PLATFORM_GET, priv->ifindex)))
 		return NM_UNMAN_FLAG_OP_SET_UNMANAGED;
 
 	return NM_UNMAN_FLAG_OP_SET_MANAGED;
@@ -2029,7 +2018,7 @@ link_type_compatible (NMDevice *self,
 		return FALSE;
 	}
 
-	device_type = self->priv->link_type;
+	device_type = self->_priv->link_type;
 	if (device_type > NM_LINK_TYPE_UNKNOWN && device_type != link_type) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
 		             "Needed link type 0x%x does not match the platform link type 0x%X",
@@ -2526,6 +2515,7 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 	                               NM_UNMANAGED_PARENT |
 	                               NM_UNMANAGED_LOOPBACK |
 	                               NM_UNMANAGED_USER_UDEV |
+	                               NM_UNMANAGED_USER_EXPLICIT |
 	                               NM_UNMANAGED_EXTERNAL_DOWN |
 	                               NM_UNMANAGED_IS_SLAVE,
 	                               NM_UNMAN_FLAG_OP_FORGET);
@@ -2627,6 +2617,7 @@ slave_state_changed (NMDevice *slave,
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	gboolean release = FALSE;
+	gboolean configure = TRUE;
 
 	_LOGD (LOGD_DEVICE, "slave %s state change %d (%s) -> %d (%s)",
 	       nm_device_get_iface (slave),
@@ -2649,8 +2640,12 @@ slave_state_changed (NMDevice *slave,
 		release = TRUE;
 	}
 
+	/* Don't touch the device if its state changed externally. */
+	if (reason == NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED)
+		configure = FALSE;
+
 	if (release) {
-		nm_device_master_release_one_slave (self, slave, TRUE, reason);
+		nm_device_master_release_one_slave (self, slave, configure, reason);
 		/* Bridge/bond/team interfaces are left up until manually deactivated */
 		if (priv->slaves == NULL && priv->state == NM_DEVICE_STATE_ACTIVATED)
 			_LOGD (LOGD_DEVICE, "last slave removed; remaining activated");
@@ -3215,8 +3210,8 @@ device_has_config (NMDevice *self)
 	if (nm_device_is_software (self) && nm_device_is_real (self))
 		return TRUE;
 
-	/* Slaves are also configured by definition */
-	if (nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) > 0)
+	/* Master-slave relationship is also a configuration */
+	if (priv->slaves || nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) > 0)
 		return TRUE;
 
 	return FALSE;
@@ -5970,7 +5965,7 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason)
 	}
 
 	if (!dhcp6_start_with_link_ready (self, connection)) {
-		*reason = NM_DEVICE_STATE_REASON_DHCP_START_FAILED;
+		NM_SET_OUT (reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED);
 		return FALSE;
 	}
 
@@ -7005,7 +7000,7 @@ nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self)
 	s_con = nm_connection_get_setting_connection (connection);
 
 	if (!priv->fw_ready) {
-		if (nm_device_uses_assumed_connection (self))
+		if (nm_device_uses_generated_assumed_connection (self))
 			priv->fw_ready = TRUE;
 		else {
 			if (!priv->fw_call) {
@@ -7786,6 +7781,7 @@ nm_device_reactivate_ip4_config (NMDevice *self,
                                  NMSettingIPConfig *s_ip4_new)
 {
 	NMDevicePrivate *priv;
+	const char *method_old, *method_new;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 	priv = NM_DEVICE_GET_PRIVATE (self);
@@ -7798,8 +7794,14 @@ nm_device_reactivate_ip4_config (NMDevice *self,
 		                             s_ip4_new,
 		                             nm_device_get_ip4_route_metric (self));
 
-		if (strcmp (nm_setting_ip_config_get_method (s_ip4_new),
-		            nm_setting_ip_config_get_method (s_ip4_old))) {
+		method_old = s_ip4_old ?
+			nm_setting_ip_config_get_method (s_ip4_old) :
+			NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
+		method_new = s_ip4_new ?
+			nm_setting_ip_config_get_method (s_ip4_new) :
+			NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
+
+		if (!nm_streq0 (method_old, method_new)) {
 			_cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE);
 			priv->ip4_state = IP_WAIT;
 			if (!nm_device_activate_stage3_ip4_start (self))
@@ -7817,6 +7819,7 @@ nm_device_reactivate_ip6_config (NMDevice *self,
                                  NMSettingIPConfig *s_ip6_new)
 {
 	NMDevicePrivate *priv;
+	const char *method_old, *method_new;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 	priv = NM_DEVICE_GET_PRIVATE (self);
@@ -7829,8 +7832,14 @@ nm_device_reactivate_ip6_config (NMDevice *self,
 		                             s_ip6_new,
 		                             nm_device_get_ip6_route_metric (self));
 
-		if (strcmp (nm_setting_ip_config_get_method (s_ip6_new),
-		            nm_setting_ip_config_get_method (s_ip6_old))) {
+		method_old = s_ip6_old ?
+			nm_setting_ip_config_get_method (s_ip6_old) :
+			NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
+		method_new = s_ip6_new ?
+			nm_setting_ip_config_get_method (s_ip6_new) :
+			NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
+
+		if (!nm_streq0 (method_old, method_new)) {
 			_cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE);
 			priv->ip6_state = IP_WAIT;
 			if (!nm_device_activate_stage3_ip6_start (self))
@@ -10058,7 +10067,7 @@ nm_device_set_unmanaged_by_user_udev (NMDevice *self)
 	int ifindex;
 	gboolean platform_unmanaged = FALSE;
 
-	ifindex = self->priv->ifindex;
+	ifindex = self->_priv->ifindex;
 
 	if (   ifindex <= 0
 	    || !nm_platform_link_get_unmanaged (NM_PLATFORM_GET, ifindex, &platform_unmanaged))
@@ -10145,7 +10154,7 @@ nm_device_reapply_settings_immediately (NMDevice *self)
 	if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)),
 	               nm_setting_connection_get_zone (s_con_applied)) != 0) {
 
-		version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->priv->act_request);
+		version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request);
 		_LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s (version-id %llu)", NM_PRINT_FMT_QUOTE_STRING (zone), (long long unsigned) version_id);
 
 		g_object_set (G_OBJECT (s_con_applied),
@@ -10157,7 +10166,7 @@ nm_device_reapply_settings_immediately (NMDevice *self)
 
 	if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) {
 
-		version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->priv->act_request);
+		version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request);
 		_LOGD (LOGD_DEVICE, "reapply setting: metered = %d (version-id %llu)", (int) metered, (long long unsigned) version_id);
 
 		g_object_set (G_OBJECT (s_con_applied),
@@ -10181,8 +10190,8 @@ nm_device_update_firewall_zone (NMDevice *self)
 		return;
 
 	s_con = nm_connection_get_setting_connection (applied_connection);
-	if (    nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED
-	    && !nm_device_uses_assumed_connection (self)) {
+	if (   nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED
+	    && !nm_device_uses_generated_assumed_connection (self)) {
 		nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (),
 		                                        nm_device_get_ip_iface (self),
 		                                        nm_setting_connection_get_zone (s_con),
@@ -10336,22 +10345,22 @@ nm_device_check_connection_available (NMDevice *self,
 static gboolean
 available_connections_del_all (NMDevice *self)
 {
-	if (g_hash_table_size (self->priv->available_connections) == 0)
+	if (g_hash_table_size (self->_priv->available_connections) == 0)
 		return FALSE;
-	g_hash_table_remove_all (self->priv->available_connections);
+	g_hash_table_remove_all (self->_priv->available_connections);
 	return TRUE;
 }
 
 static gboolean
 available_connections_add (NMDevice *self, NMConnection *connection)
 {
-	return nm_g_hash_table_add (self->priv->available_connections, g_object_ref (connection));
+	return nm_g_hash_table_add (self->_priv->available_connections, g_object_ref (connection));
 }
 
 static gboolean
 available_connections_del (NMDevice *self, NMConnection *connection)
 {
-	return g_hash_table_remove (self->priv->available_connections, connection);
+	return g_hash_table_remove (self->_priv->available_connections, connection);
 }
 
 static gboolean
@@ -10673,7 +10682,7 @@ _cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type)
 	connection = nm_device_get_applied_connection (self);
 	if (   cleanup_type == CLEANUP_TYPE_DECONFIGURE
 	    && connection
-	    && !nm_device_uses_assumed_connection (self)) {
+	    && !nm_device_uses_generated_assumed_connection (self)) {
 		nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (),
 		                                      nm_device_get_ip_iface (self),
 		                                      NULL,
@@ -11374,7 +11383,7 @@ _set_state_full (NMDevice *self,
 
 		if (   applied_connection
 		    && priv->ifindex != priv->ip_ifindex
-		    && !nm_device_uses_assumed_connection (self)) {
+		    && !nm_device_uses_generated_assumed_connection (self)) {
 			NMSettingConnection *s_con;
 			const char *zone;
 
@@ -11560,16 +11569,17 @@ nm_device_get_hw_address (NMDevice *self)
 	return priv->hw_addr;
 }
 
-void
+gboolean
 nm_device_update_hw_address (NMDevice *self)
 {
 	NMDevicePrivate *priv;
 	const guint8 *hwaddr;
 	gsize hwaddrlen = 0;
+	gboolean changed = FALSE;
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	if (priv->ifindex <= 0)
-		return;
+		return FALSE;
 
 	hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &hwaddrlen);
 
@@ -11596,6 +11606,7 @@ nm_device_update_hw_address (NMDevice *self)
 				 * update our inital hw-address as well. */
 				nm_device_update_initial_hw_address (self);
 			}
+			changed = TRUE;
 		}
 	} else {
 		/* Invalid or no hardware address */
@@ -11608,6 +11619,7 @@ nm_device_update_hw_address (NMDevice *self)
 			       "hw-addr: failed reading current MAC address");
 		}
 	}
+	return changed;
 }
 
 void
@@ -11767,6 +11779,15 @@ nm_device_hw_addr_is_explict (NMDevice *self)
 }
 
 static gboolean
+_hw_addr_matches (NMDevice *self, const char *addr)
+{
+	const char *cur_addr;
+
+	cur_addr = nm_device_get_hw_address (self);
+	return cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1);
+}
+
+static gboolean
 _hw_addr_set (NMDevice *self,
               const char *addr,
               const char *operation,
@@ -11775,7 +11796,6 @@ _hw_addr_set (NMDevice *self,
 	NMDevicePrivate *priv;
 	gboolean success = FALSE;
 	NMPlatformError plerr;
-	const char *cur_addr;
 	guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX];
 	guint hw_addr_len;
 	gboolean was_up;
@@ -11786,11 +11806,9 @@ _hw_addr_set (NMDevice *self,
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
-	cur_addr = nm_device_get_hw_address (self);
-
 	/* Do nothing if current MAC is same */
-	if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
-		_LOGT (LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", cur_addr);
+	if (_hw_addr_matches (self, addr)) {
+		_LOGT (LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", addr);
 		return TRUE;
 	}
 
@@ -11814,15 +11832,59 @@ _hw_addr_set (NMDevice *self,
 	if (success) {
 		/* MAC address succesfully changed; update the current MAC to match */
 		nm_device_update_hw_address (self);
-		cur_addr = nm_device_get_hw_address (self);
-		if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
+		if (_hw_addr_matches (self, addr)) {
 			_LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
 			       operation, addr, detail);
 		} else {
-			_LOGW (LOGD_DEVICE,
-			       "set-hw-addr: new MAC address %s not successfully set to %s (%s)",
+			gint64 poll_end, now;
+
+			_LOGD (LOGD_DEVICE,
+			       "set-hw-addr: new MAC address %s not successfully %s (%s) (refresh link)",
 			       addr, operation, detail);
-			success = FALSE;
+
+			/* The platform call indicated success, however the address is not
+			 * as expected. That is either due to a driver issue (brcmfmac, bgo#770456,
+			 * rh#1374023) or a race where externally the MAC address was reset.
+			 * The race is rather unlikely.
+			 *
+			 * The alternative would be to postpone the activation in case the
+			 * MAC address is not yet ready and poll without blocking. However,
+			 * that is rather complicated and it is not expected that this case
+			 * happens for regular drivers.
+			 * Note that brcmfmac can block NetworkManager for 500 msec while
+			 * taking down the device. Let's add annother 100 msec to that.
+			 *
+			 * wait/poll up to 100 msec until it changes. */
+
+			poll_end = nm_utils_get_monotonic_timestamp_us () + (100 * 1000);
+			for (;;) {
+				if (!nm_platform_link_refresh (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self)))
+					goto handle_fail;
+				if (!nm_device_update_hw_address (self))
+					goto handle_wait;
+				if (!_hw_addr_matches (self, addr))
+					goto handle_fail;
+
+				break;
+handle_wait:
+				now = nm_utils_get_monotonic_timestamp_us ();
+				if (now < poll_end) {
+					g_usleep (NM_MIN (poll_end - now, 500));
+					continue;
+				}
+handle_fail:
+				success = FALSE;
+				break;
+			}
+
+			if (success) {
+				_LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
+				       operation, addr, detail);
+			} else {
+				_LOGW (LOGD_DEVICE,
+				       "set-hw-addr: new MAC address %s not successfully %s (%s)",
+				       addr, operation, detail);
+			}
 		}
 	} else {
 		_NMLOG (plerr == NM_PLATFORM_ERROR_NOT_FOUND ? LOGL_DEBUG : LOGL_WARN,
@@ -12075,7 +12137,7 @@ nm_device_init (NMDevice *self)
 
 	priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_DEVICE, NMDevicePrivate);
 
-	self->priv = priv;
+	self->_priv = priv;
 
 	priv->type = NM_DEVICE_TYPE_UNKNOWN;
 	priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED;
@@ -12328,21 +12390,22 @@ set_property (GObject *object, guint prop_id,
 	case PROP_IP4_ADDRESS:
 		priv->ip4_address = g_value_get_uint (value);
 		break;
-	case PROP_MANAGED: {
-		gboolean managed;
-		NMDeviceStateReason reason;
+	case PROP_MANAGED:
+		if (nm_device_is_real (self)) {
+			gboolean managed;
+			NMDeviceStateReason reason;
 
-		managed = g_value_get_boolean (value);
-		if (managed)
-			reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED;
-		else
-			reason = NM_DEVICE_STATE_REASON_REMOVED;
-		nm_device_set_unmanaged_by_flags (self,
-		                                  NM_UNMANAGED_USER_EXPLICIT,
-		                                  !managed,
-		                                  reason);
+			managed = g_value_get_boolean (value);
+			if (managed)
+				reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED;
+			else
+				reason = NM_DEVICE_STATE_REASON_REMOVED;
+			nm_device_set_unmanaged_by_flags (self,
+			                                  NM_UNMANAGED_USER_EXPLICIT,
+			                                  !managed,
+			                                  reason);
+		}
 		break;
-	}
 	case PROP_AUTOCONNECT:
 		nm_device_set_autoconnect (self, g_value_get_boolean (value));
 		break;
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 34d31cad..a757a37e 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -125,7 +125,7 @@ struct _NMDevice {
 	NMExportedObject parent;
 
 	/* private */
-	struct _NMDevicePrivate *priv;
+	struct _NMDevicePrivate *_priv;
 };
 
 /* The flags have an relaxing meaning, that means, specifying more flags, can make
@@ -588,7 +588,7 @@ void nm_device_reactivate_ip6_config (NMDevice *device,
                                       NMSettingIPConfig *s_ip6_old,
                                       NMSettingIPConfig *s_ip6_new);
 
-void nm_device_update_hw_address (NMDevice *self);
+gboolean nm_device_update_hw_address (NMDevice *self);
 void nm_device_update_initial_hw_address (NMDevice *self);
 void nm_device_update_permanent_hw_address (NMDevice *self);
 void nm_device_update_dynamic_ip_setup (NMDevice *self);
diff --git a/src/devices/team/Makefile.in b/src/devices/team/Makefile.in
index 922ec593..f227a77a 100644
--- a/src/devices/team/Makefile.in
+++ b/src/devices/team/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/devices/tests/Makefile.in b/src/devices/tests/Makefile.in
index 7c25dc11..866fe0e1 100644
--- a/src/devices/tests/Makefile.in
+++ b/src/devices/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/devices/wifi/Makefile.in b/src/devices/wifi/Makefile.in
index 134c4012..42246d5c 100644
--- a/src/devices/wifi/Makefile.in
+++ b/src/devices/wifi/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/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 49c380af..f97e6689 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -138,18 +138,7 @@ struct _NMDeviceWifiClass
 
 G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE)
 
-#define NM_DEVICE_WIFI_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMDeviceWifi *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_DEVICE_WIFI (_self)); \
-		&_self->_priv; \
-	})
+#define NM_DEVICE_WIFI_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDeviceWifi, NM_IS_DEVICE_WIFI)
 
 /*****************************************************************************/
 
diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c
index e1beb85b..2232f826 100644
--- a/src/devices/wifi/nm-wifi-ap.c
+++ b/src/devices/wifi/nm-wifi-ap.c
@@ -68,18 +68,7 @@ struct _NMAccessPointClass{
 	NMExportedObjectClass parent;
 };
 
-#define NM_AP_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMAccessPoint *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_AP (_self)); \
-		&_self->_priv; \
-	})
+#define NM_AP_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMAccessPoint, NM_IS_AP)
 
 G_DEFINE_TYPE (NMAccessPoint, nm_ap, NM_TYPE_EXPORTED_OBJECT)
 
diff --git a/src/devices/wifi/tests/Makefile.in b/src/devices/wifi/tests/Makefile.in
index 64113a21..676ae990 100644
--- a/src/devices/wifi/tests/Makefile.in
+++ b/src/devices/wifi/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/devices/wwan/Makefile.in b/src/devices/wwan/Makefile.in
index 6d395567..22ba0f30 100644
--- a/src/devices/wwan/Makefile.in
+++ b/src/devices/wwan/Makefile.in
@@ -98,7 +98,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/dhcp-manager/Makefile.am b/src/dhcp-manager/Makefile.am
index b4590b4b..42954127 100644
--- a/src/dhcp-manager/Makefile.am
+++ b/src/dhcp-manager/Makefile.am
@@ -1,6 +1,9 @@
 libexec_PROGRAMS = nm-dhcp-helper
 
-nm_dhcp_helper_SOURCES = nm-dhcp-helper.c
+nm_dhcp_helper_SOURCES = \
+	nm-dhcp-helper.c \
+	nm-dhcp-helper-api.h \
+	$(NULL)
 
 nm_dhcp_helper_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
diff --git a/src/dhcp-manager/Makefile.in b/src/dhcp-manager/Makefile.in
index dcb45183..5309cde6 100644
--- a/src/dhcp-manager/Makefile.in
+++ b/src/dhcp-manager/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 \
@@ -456,7 +456,11 @@ with_dhcpcd = @with_dhcpcd@
 with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
 with_valgrind = @with_valgrind@
-nm_dhcp_helper_SOURCES = nm-dhcp-helper.c
+nm_dhcp_helper_SOURCES = \
+	nm-dhcp-helper.c \
+	nm-dhcp-helper-api.h \
+	$(NULL)
+
 nm_dhcp_helper_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
 	-I$(top_srcdir)/shared \
diff --git a/src/dhcp-manager/nm-dhcp-helper-api.h b/src/dhcp-manager/nm-dhcp-helper-api.h
new file mode 100644
index 00000000..a3eb171d
--- /dev/null
+++ b/src/dhcp-manager/nm-dhcp-helper-api.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * 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.
+ *
+ * (C) Copyright 2016 Red Hat, Inc.
+ */
+
+#ifndef __NM_DHCP_HELPER_API_H__
+#define __NM_DHCP_HELPER_API_H__
+
+/******************************************************************************/
+
+#define NM_DHCP_CLIENT_DBUS_IFACE "org.freedesktop.nm_dhcp_client"
+
+#define NM_DHCP_HELPER_SERVER_BUS_NAME          "org.freedesktop.nm_dhcp_server"
+#define NM_DHCP_HELPER_SERVER_OBJECT_PATH       "/org/freedesktop/nm_dhcp_server"
+#define NM_DHCP_HELPER_SERVER_INTERFACE_NAME    "org.freedesktop.nm_dhcp_server"
+#define NM_DHCP_HELPER_SERVER_METHOD_NOTIFY     "Notify"
+
+/******************************************************************************/
+
+#endif /* __NM_DHCP_HELPER_API_H__ */
diff --git a/src/dhcp-manager/nm-dhcp-helper.c b/src/dhcp-manager/nm-dhcp-helper.c
index 7667084d..9c6f69b8 100644
--- a/src/dhcp-manager/nm-dhcp-helper.c
+++ b/src/dhcp-manager/nm-dhcp-helper.c
@@ -25,7 +25,42 @@
 #include <string.h>
 #include <signal.h>
 
-#define NM_DHCP_CLIENT_DBUS_IFACE   "org.freedesktop.nm_dhcp_client"
+#include "nm-utils/nm-vpn-plugin-macros.h"
+
+#include "nm-dhcp-helper-api.h"
+
+/*****************************************************************************/
+
+#ifdef NM_MORE_LOGGING
+#define _NMLOG_ENABLED(level) TRUE
+#else
+#define _NMLOG_ENABLED(level) ((level) <= LOG_ERR)
+#endif
+
+#define _NMLOG(always_enabled, level, ...) \
+	G_STMT_START { \
+		if ((always_enabled) || _NMLOG_ENABLED (level)) { \
+			GTimeVal _tv; \
+			\
+			g_get_current_time (&_tv); \
+			g_print ("nm-dhcp-helper[%ld] %-7s [%ld.%04ld] " _NM_UTILS_MACRO_FIRST (__VA_ARGS__) "\n", \
+			         (long) getpid (), \
+			         nm_utils_syslog_to_str (level), \
+			         _tv.tv_sec, _tv.tv_usec / 100 \
+			         _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+		} \
+	} G_STMT_END
+
+#define _LOGD(...) _NMLOG(TRUE,  LOG_INFO,    __VA_ARGS__)
+#define _LOGI(...) _NMLOG(TRUE,  LOG_NOTICE,  __VA_ARGS__)
+#define _LOGW(...) _NMLOG(TRUE,  LOG_WARNING, __VA_ARGS__)
+#define _LOGE(...) _NMLOG(TRUE,  LOG_ERR,     __VA_ARGS__)
+
+#define _LOGd(...) _NMLOG(FALSE, LOG_INFO,    __VA_ARGS__)
+#define _LOGi(...) _NMLOG(FALSE, LOG_NOTICE,  __VA_ARGS__)
+#define _LOGw(...) _NMLOG(FALSE, LOG_WARNING, __VA_ARGS__)
+
+/*****************************************************************************/
 
 static const char * ignore[] = {"PATH", "SHLVL", "_", "PWD", "dhc_dbus", NULL};
 
@@ -70,30 +105,34 @@ build_signal_parameters (void)
 		g_free (name);
 	}
 
-	return g_variant_new ("(a{sv})", &builder);
+	return g_variant_ref_sink (g_variant_new ("(a{sv})", &builder));
 }
 
 static void
-fatal_error (void)
+kill_pid (void)
 {
-	const char *pid_str = getenv ("pid");
-	int pid = 0;
+	const char *pid_str;
+	pid_t pid = 0;
 
+	pid_str = getenv ("pid");
 	if (pid_str)
 		pid = strtol (pid_str, NULL, 10);
 	if (pid) {
-		g_printerr ("Fatal error occured, killing dhclient instance with pid %d.\n", pid);
+		_LOGI ("a fatal error occured, kill dhclient instance with pid %d\n", pid);
 		kill (pid, SIGTERM);
 	}
-
-	exit (1);
 }
 
 int
 main (int argc, char *argv[])
 {
-	GDBusConnection *connection;
-	GError *error = NULL;
+	gs_unref_object GDBusConnection *connection = NULL;
+	gs_free_error GError *error = NULL;
+	gs_unref_variant GVariant *parameters = NULL;
+	gs_unref_variant GVariant *result = NULL;
+	gboolean success = FALSE;
+	guint try_count = 0;
+	gint64 time_end;
 
 	nm_g_type_init ();
 
@@ -102,33 +141,81 @@ main (int argc, char *argv[])
 	                                                     NULL, NULL, &error);
 	if (!connection) {
 		g_dbus_error_strip_remote_error (error);
-		g_printerr ("Error: could not connect to NetworkManager D-Bus socket: %s\n",
-		            error->message);
-		g_error_free (error);
-		fatal_error ();
+		_LOGE ("could not connect to NetworkManager D-Bus socket: %s",
+		       error->message);
+		goto out;
 	}
 
-	if (!g_dbus_connection_emit_signal (connection,
-	                                    NULL,
-	                                    "/",
-	                                    NM_DHCP_CLIENT_DBUS_IFACE,
-	                                    "Event",
-	                                    build_signal_parameters (),
-	                                    &error)) {
-		g_dbus_error_strip_remote_error (error);
-		g_printerr ("Error: Could not send DHCP Event signal: %s\n", error->message);
-		g_error_free (error);
-		fatal_error ();
-	}
+	parameters = build_signal_parameters ();
+
+	time_end = g_get_monotonic_time () + (200 * 1000L); /* retry for at most 200 milliseconds */
+
+do_notify:
+	try_count++;
+	result = g_dbus_connection_call_sync (connection,
+	                                      NULL,
+	                                      NM_DHCP_HELPER_SERVER_OBJECT_PATH,
+	                                      NM_DHCP_HELPER_SERVER_INTERFACE_NAME,
+	                                      NM_DHCP_HELPER_SERVER_METHOD_NOTIFY,
+	                                      parameters,
+	                                      NULL,
+	                                      G_DBUS_CALL_FLAGS_NONE,
+	                                      1000,
+	                                      NULL,
+	                                      &error);
+
+	if (!result) {
+		gs_free char *s_err = NULL;
+
+		s_err = g_dbus_error_get_remote_error (error);
+		if (NM_IN_STRSET (s_err, "org.freedesktop.DBus.Error.UnknownMethod")) {
+			gint64 remaining_time = time_end - g_get_monotonic_time ();
+
+			/* I am not sure that a race can actually happen, as we register the object
+			 * on the server side during GDBusServer:new-connection signal.
+			 *
+			 * However, there was also a race for subscribing to an event, so let's just
+			 * do some retry. */
+			if (remaining_time > 0) {
+				_LOGi ("failure to call notify: %s (retry %u)", error->message, try_count);
+				g_usleep (NM_MIN (NM_CLAMP ((gint64) (100L * (1L << try_count)), 5000, 25000), remaining_time));
+				g_clear_error (&error);
+				goto do_notify;
+			}
+		}
+		_LOGW ("failure to call notify: %s (try signal via Event)", error->message);
+		g_clear_error (&error);
+
+		/* for backward compatibilty, try to emit the signal. There is no stable
+		 * API between the dhcp-helper and NetworkManager. However, while upgrading
+		 * the NetworkManager package, a newer helper might want to notify an
+		 * older server, which still uses the "Event". */
+		if (!g_dbus_connection_emit_signal (connection,
+		                                    NULL,
+		                                    "/",
+		                                    NM_DHCP_CLIENT_DBUS_IFACE,
+		                                    "Event",
+		                                    parameters,
+		                                    &error)) {
+			g_dbus_error_strip_remote_error (error);
+			_LOGE ("could not send DHCP Event signal: %s", error->message);
+			goto out;
+		}
+		/* We were able to send the asynchronous Event. Consider that a success. */
+		success = TRUE;
+	} else
+		success = TRUE;
 
 	if (!g_dbus_connection_flush_sync (connection, NULL, &error)) {
 		g_dbus_error_strip_remote_error (error);
-		g_printerr ("Error: Could not flush D-Bus connection: %s\n", error->message);
-		g_error_free (error);
-		fatal_error ();
+		_LOGE ("could not flush D-Bus connection: %s", error->message);
+		success = FALSE;
+		goto out;
 	}
 
-	g_object_unref (connection);
-	return 0;
+out:
+	if (!success)
+		kill_pid ();
+	return success ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
diff --git a/src/dhcp-manager/nm-dhcp-listener.c b/src/dhcp-manager/nm-dhcp-listener.c
index eadff3ec..0df41973 100644
--- a/src/dhcp-manager/nm-dhcp-listener.c
+++ b/src/dhcp-manager/nm-dhcp-listener.c
@@ -13,12 +13,14 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright 2014 Red Hat, Inc.
+ * Copyright 2014 - 2016 Red Hat, Inc.
  *
  */
 
 #include "nm-default.h"
 
+#include "nm-dhcp-listener.h"
+
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <signal.h>
@@ -27,25 +29,31 @@
 #include <errno.h>
 #include <unistd.h>
 
-#include "nm-dhcp-listener.h"
+#include "nm-dhcp-helper-api.h"
 #include "nm-core-internal.h"
 #include "nm-bus-manager.h"
 #include "NetworkManagerUtils.h"
 
-#define NM_DHCP_CLIENT_DBUS_IFACE "org.freedesktop.nm_dhcp_client"
 #define PRIV_SOCK_PATH            NMRUNDIR "/private-dhcp"
 #define PRIV_SOCK_TAG             "dhcp"
 
+/*****************************************************************************/
+
 typedef struct {
 	NMBusManager *      dbus_mgr;
 	gulong              new_conn_id;
 	gulong              dis_conn_id;
-	GHashTable *        signal_handlers;
+	GHashTable *        connections;
 } NMDhcpListenerPrivate;
 
-#define NM_DHCP_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_LISTENER, NMDhcpListenerPrivate))
+struct _NMDhcpListener {
+	GObject parent;
+	NMDhcpListenerPrivate _priv;
+};
 
-G_DEFINE_TYPE (NMDhcpListener, nm_dhcp_listener, G_TYPE_OBJECT)
+struct _NMDhcpListenerClass {
+	GObjectClass parent_class;
+};
 
 enum {
 	EVENT,
@@ -53,7 +61,30 @@ enum {
 };
 static guint signals[LAST_SIGNAL] = { 0 };
 
-/***************************************************/
+G_DEFINE_TYPE (NMDhcpListener, nm_dhcp_listener, G_TYPE_OBJECT)
+
+#define NM_DHCP_LISTENER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDhcpListener, NM_IS_DHCP_LISTENER)
+
+NM_DEFINE_SINGLETON_GETTER (NMDhcpListener, nm_dhcp_listener_get, NM_TYPE_DHCP_LISTENER);
+
+/*****************************************************************************/
+
+#define _NMLOG_PREFIX_NAME    "dhcp-listener"
+#define _NMLOG_DOMAIN         LOGD_DHCP
+#define _NMLOG(level, ...) \
+    G_STMT_START { \
+        const NMDhcpListener *_self = (self); \
+        char _prefix[64]; \
+        \
+        nm_log ((level), (_NMLOG_DOMAIN), \
+                "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+                (_self != singleton_instance \
+                    ? nm_sprintf_buf (_prefix, "%s[%p]", _NMLOG_PREFIX_NAME, _self) \
+                    : _NMLOG_PREFIX_NAME )\
+                _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+    } G_STMT_END
+
+/*****************************************************************************/
 
 static char *
 get_option (GVariant *options, const char *key)
@@ -88,13 +119,14 @@ get_option (GVariant *options, const char *key)
 }
 
 static void
-handle_event (GDBusConnection  *connection,
-              const char       *sender_name,
-              const char       *object_path,
-              const char       *interface_name,
-              const char       *signal_name,
-              GVariant         *parameters,
-              gpointer          user_data)
+_method_call (GDBusConnection *connection,
+              const char *sender,
+              const char *object_path,
+              const char *interface_name,
+              const char *method_name,
+              GVariant *parameters,
+              GDBusMethodInvocation *invocation,
+              gpointer user_data)
 {
 	NMDhcpListener *self = NM_DHCP_LISTENER (user_data);
 	char *iface = NULL;
@@ -104,27 +136,31 @@ handle_event (GDBusConnection  *connection,
 	gboolean handled = FALSE;
 	GVariant *options;
 
+	if (!nm_streq0 (interface_name, NM_DHCP_HELPER_SERVER_INTERFACE_NAME))
+		g_return_if_reached ();
+	if (!nm_streq0 (method_name, NM_DHCP_HELPER_SERVER_METHOD_NOTIFY))
+		g_return_if_reached ();
 	if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})")))
-		return;
+		g_return_if_reached ();
 
 	g_variant_get (parameters, "(@a{sv})", &options);
 
 	iface = get_option (options, "interface");
 	if (iface == NULL) {
-		nm_log_warn (LOGD_DHCP, "dhcp-event: didn't have associated interface.");
+		_LOGW ("dhcp-event: didn't have associated interface.");
 		goto out;
 	}
 
 	pid_str = get_option (options, "pid");
 	pid = _nm_utils_ascii_str_to_int64 (pid_str, 10, 0, G_MAXINT32, -1);
 	if (pid == -1) {
-		nm_log_warn (LOGD_DHCP, "dhcp-event: couldn't convert PID '%s' to an integer", pid_str ? pid_str : "(null)");
+		_LOGW ("dhcp-event: couldn't convert PID '%s' to an integer", pid_str ? pid_str : "(null)");
 		goto out;
 	}
 
 	reason = get_option (options, "reason");
 	if (reason == NULL) {
-		nm_log_warn (LOGD_DHCP, "dhcp-event: (pid %d) DHCP event didn't have a reason", pid);
+		_LOGW ("dhcp-event: (pid %d) DHCP event didn't have a reason", pid);
 		goto out;
 	}
 
@@ -132,9 +168,9 @@ handle_event (GDBusConnection  *connection,
 	if (!handled) {
 		if (g_ascii_strcasecmp (reason, "RELEASE") == 0) {
 			/* Ignore event when the dhcp client gets killed and we receive its last message */
-			nm_log_dbg (LOGD_DHCP, "dhcp-event: (pid %d) unhandled RELEASE DHCP event for interface %s", pid, iface);
+			_LOGD ("dhcp-event: (pid %d) unhandled RELEASE DHCP event for interface %s", pid, iface);
 		} else
-			nm_log_warn (LOGD_DHCP, "dhcp-event: (pid %d) unhandled DHCP event for interface %s", pid, iface);
+			_LOGW ("dhcp-event: (pid %d) unhandled DHCP event for interface %s", pid, iface);
 	}
 
 out:
@@ -142,6 +178,57 @@ out:
 	g_free (pid_str);
 	g_free (reason);
 	g_variant_unref (options);
+	g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static guint
+_dbus_connection_register_object (NMDhcpListener *self,
+                                  GDBusConnection *connection,
+                                  GError **error)
+{
+	static GDBusArgInfo arg_info_notify_in = {
+		.ref_count = -1,
+		.name = "data",
+		.signature = "a{sv}",
+		.annotations = NULL,
+	};
+	static GDBusArgInfo *arg_infos_notify[] = {
+		&arg_info_notify_in,
+		NULL,
+	};
+	static GDBusMethodInfo method_info_notify = {
+		.ref_count = -1,
+		.name = NM_DHCP_HELPER_SERVER_METHOD_NOTIFY,
+		.in_args = arg_infos_notify,
+		.out_args = NULL,
+		.annotations = NULL,
+	};
+	static GDBusMethodInfo *method_infos[] = {
+		&method_info_notify,
+		NULL,
+	};
+	static GDBusInterfaceInfo interface_info = {
+		.ref_count = -1,
+		.name = NM_DHCP_HELPER_SERVER_INTERFACE_NAME,
+		.methods = method_infos,
+		.signals = NULL,
+		.properties = NULL,
+		.annotations = NULL,
+	};
+
+	static GDBusInterfaceVTable interface_vtable = {
+		.method_call = _method_call,
+		.get_property = NULL,
+		.set_property = NULL,
+	};
+
+	return g_dbus_connection_register_object (connection,
+	                                          NM_DHCP_HELPER_SERVER_OBJECT_PATH,
+	                                          &interface_info,
+	                                          &interface_vtable,
+	                                          self,
+	                                          NULL,
+	                                          error);
 }
 
 static void
@@ -151,17 +238,20 @@ new_connection_cb (NMBusManager *mgr,
                    NMDhcpListener *self)
 {
 	NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self);
-	guint id;
+	guint registration_id;
+	GError *error = NULL;
+
+	/* it is important to register the object during the new-connection signal,
+	 * as this avoids races with the connecting object. */
+	registration_id = _dbus_connection_register_object (self, connection, &error);
+	if (!registration_id) {
+		_LOGE ("failure to register %s for connection %p: %s",
+		       NM_DHCP_HELPER_SERVER_OBJECT_PATH, connection, error->message);
+		g_error_free (error);
+		return;
+	}
 
-	id = g_dbus_connection_signal_subscribe (connection,
-	                                         NULL,
-	                                         NM_DHCP_CLIENT_DBUS_IFACE,
-	                                         "Event",
-	                                         NULL,
-	                                         NULL,
-	                                         G_DBUS_SIGNAL_FLAGS_NONE,
-	                                         handle_event, self, NULL);
-	g_hash_table_insert (priv->signal_handlers, connection, GUINT_TO_POINTER (id));
+	g_hash_table_insert (priv->connections, connection, GUINT_TO_POINTER (registration_id));
 }
 
 static void
@@ -172,24 +262,22 @@ dis_connection_cb (NMBusManager *mgr,
 	NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self);
 	guint id;
 
-	id = GPOINTER_TO_UINT (g_hash_table_lookup (priv->signal_handlers, connection));
+	id = GPOINTER_TO_UINT (g_hash_table_lookup (priv->connections, connection));
 	if (id) {
-		g_dbus_connection_signal_unsubscribe (connection, id);
-		g_hash_table_remove (priv->signal_handlers, connection);
+		g_dbus_connection_unregister_object (connection, id);
+		g_hash_table_remove (priv->connections, connection);
 	}
 }
 
 /***************************************************/
 
-NM_DEFINE_SINGLETON_GETTER (NMDhcpListener, nm_dhcp_listener_get, NM_TYPE_DHCP_LISTENER);
-
 static void
 nm_dhcp_listener_init (NMDhcpListener *self)
 {
 	NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self);
 
-	/* Maps GDBusConnection :: GDBusProxy */
-	priv->signal_handlers = g_hash_table_new (NULL, NULL);
+	/* Maps GDBusConnection :: signal-id */
+	priv->connections = g_hash_table_new (NULL, NULL);
 
 	priv->dbus_mgr = nm_bus_manager_get ();
 
@@ -208,13 +296,13 @@ nm_dhcp_listener_init (NMDhcpListener *self)
 static void
 dispose (GObject *object)
 {
-	NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (object);
+	NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE ((NMDhcpListener *) object);
 
 	nm_clear_g_signal_handler (priv->dbus_mgr, &priv->new_conn_id);
 	nm_clear_g_signal_handler (priv->dbus_mgr, &priv->dis_conn_id);
 	priv->dbus_mgr = NULL;
 
-	g_clear_pointer (&priv->signal_handlers, g_hash_table_destroy);
+	g_clear_pointer (&priv->connections, g_hash_table_destroy);
 
 	G_OBJECT_CLASS (nm_dhcp_listener_parent_class)->dispose (object);
 }
@@ -224,22 +312,18 @@ nm_dhcp_listener_class_init (NMDhcpListenerClass *listener_class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (listener_class);
 
-	g_type_class_add_private (listener_class, sizeof (NMDhcpListenerPrivate));
-
-	/* virtual methods */
 	object_class->dispose = dispose;
 
-	/* signals */
 	signals[EVENT] =
-		g_signal_new (NM_DHCP_LISTENER_EVENT,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_LAST, 0,
-		              g_signal_accumulator_true_handled,
-		              NULL, NULL,
-		              G_TYPE_BOOLEAN,     /* listeners return TRUE if handled */
-		              4,
-		              G_TYPE_STRING,      /* iface */
-		              G_TYPE_INT,         /* pid */
-		              G_TYPE_VARIANT,     /* options */
-		              G_TYPE_STRING);     /* reason */
+	    g_signal_new (NM_DHCP_LISTENER_EVENT,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_LAST, 0,
+	                  g_signal_accumulator_true_handled,
+	                  NULL, NULL,
+	                  G_TYPE_BOOLEAN,     /* listeners return TRUE if handled */
+	                  4,
+	                  G_TYPE_STRING,      /* iface */
+	                  G_TYPE_INT,         /* pid */
+	                  G_TYPE_VARIANT,     /* options */
+	                  G_TYPE_STRING);     /* reason */
 }
diff --git a/src/dhcp-manager/nm-dhcp-listener.h b/src/dhcp-manager/nm-dhcp-listener.h
index ff31fe34..3018b97a 100644
--- a/src/dhcp-manager/nm-dhcp-listener.h
+++ b/src/dhcp-manager/nm-dhcp-listener.h
@@ -26,8 +26,8 @@
 
 #define NM_DHCP_LISTENER_EVENT "event"
 
-typedef GObject NMDhcpListener;
-typedef GObjectClass NMDhcpListenerClass;
+typedef struct _NMDhcpListener NMDhcpListener;
+typedef struct _NMDhcpListenerClass NMDhcpListenerClass;
 
 GType nm_dhcp_listener_get_type (void);
 
diff --git a/src/dhcp-manager/tests/Makefile.in b/src/dhcp-manager/tests/Makefile.in
index 1ce288ba..3f5f1466 100644
--- a/src/dhcp-manager/tests/Makefile.in
+++ b/src/dhcp-manager/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/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index 3efd5ac1..ce8f4d93 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -151,18 +151,7 @@ G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, G_TYPE_OBJECT)
 
 NM_DEFINE_SINGLETON_INSTANCE (NMDnsManager);
 
-#define NM_DNS_MANAGER_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMDnsManager *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_DNS_MANAGER (_self)); \
-		&_self->_priv; \
-	})
+#define NM_DNS_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDnsManager, NM_IS_DNS_MANAGER)
 
 /*****************************************************************************/
 
diff --git a/src/dnsmasq-manager/tests/Makefile.in b/src/dnsmasq-manager/tests/Makefile.in
index 70f1ba1d..8ba82f87 100644
--- a/src/dnsmasq-manager/tests/Makefile.in
+++ b/src/dnsmasq-manager/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/nm-auth-subject.c b/src/nm-auth-subject.c
index eb496b28..54d35959 100644
--- a/src/nm-auth-subject.c
+++ b/src/nm-auth-subject.c
@@ -68,18 +68,7 @@ struct _NMAuthSubjectClass {
 
 G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT)
 
-#define NM_AUTH_SUBJECT_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMAuthSubject *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_AUTH_SUBJECT (_self)); \
-		&_self->_priv; \
-	})
+#define NM_AUTH_SUBJECT_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMAuthSubject, NM_IS_AUTH_SUBJECT)
 
 /**************************************************************/
 
diff --git a/src/nm-bus-manager.c b/src/nm-bus-manager.c
index 449de4e6..270792ef 100644
--- a/src/nm-bus-manager.c
+++ b/src/nm-bus-manager.c
@@ -221,7 +221,11 @@ private_server_new_connection (GDBusServer *server,
 
 	_LOGD ("(%s) accepted connection %p on private socket", s->tag, conn);
 
-	/* Emit this for the manager */
+	/* Emit this for the manager.
+	 *
+	 * It is essential to do this from the "new-connection" signal handler, as
+	 * at that point no messages from the connection are yet processed
+	 * (which avoids races with registering objects). */
 	g_signal_emit (s->manager,
 	               signals[PRIVATE_CONNECTION_NEW],
 	               s->detail,
diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c
index cb1adc39..605e0700 100644
--- a/src/nm-checkpoint.c
+++ b/src/nm-checkpoint.c
@@ -70,7 +70,7 @@ typedef struct {
 
 struct _NMCheckpoint {
 	NMExportedObject parent;
-	NMCheckpointPrivate priv;
+	NMCheckpointPrivate _priv;
 };
 
 typedef struct {
@@ -79,18 +79,7 @@ typedef struct {
 
 G_DEFINE_TYPE (NMCheckpoint, nm_checkpoint, NM_TYPE_EXPORTED_OBJECT)
 
-#define NM_CHECKPOINT_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMCheckpoint *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_CHECKPOINT (_self)); \
-		&_self->priv; \
-	})
+#define NM_CHECKPOINT_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMCheckpoint, NM_IS_CHECKPOINT)
 
 NM_GOBJECT_PROPERTIES_DEFINE_BASE (
 	PROP_DEVICES,
diff --git a/src/nm-enum-types.c b/src/nm-enum-types.c
index 670502cf..50a0cfd5 100644
--- a/src/nm-enum-types.c
+++ b/src/nm-enum-types.c
@@ -18,6 +18,7 @@
 #include "nm-device-factory.h" 
 #include "nm-device-generic.h" 
 #include "nm-dhcp-client.h" 
+#include "nm-dhcp-helper-api.h" 
 #include "nm-dhcp-utils.h" 
 #include "nm-dhcp-listener.h" 
 #include "nm-dhcp-manager.h" 
diff --git a/src/nm-exported-object.c b/src/nm-exported-object.c
index c4dbab87..32b5ec05 100644
--- a/src/nm-exported-object.c
+++ b/src/nm-exported-object.c
@@ -27,6 +27,10 @@
 
 #include "nm-bus-manager.h"
 
+#include "nm-device.h"
+#include "nm-active-connection.h"
+#include "nmdbus-device-statistics.h"
+
 #if NM_MORE_ASSERTS >= 2
 #define _ASSERT_NO_EARLY_EXPORT
 #endif
@@ -38,14 +42,13 @@ G_DEFINE_ABSTRACT_TYPE (NMExportedObject, nm_exported_object, G_TYPE_DBUS_OBJECT
 typedef struct {
 	GDBusInterfaceSkeleton *interface;
 	guint property_changed_signal_id;
+	GHashTable *pending_notifies;
 } InterfaceData;
 
 typedef struct {
 	NMBusManager *bus_mgr;
 	char *path;
 
-	GHashTable *pending_notifies;
-
 	InterfaceData *interfaces;
 	guint num_interfaces;
 
@@ -73,11 +76,20 @@ G_DEFINE_QUARK (NMExportedObjectClassInfo, nm_exported_object_class_info)
 #define _NMLOG_DOMAIN                     LOGD_CORE
 
 #define _NMLOG(level, ...) \
-    nm_log (level, _NMLOG_DOMAIN, \
+    nm_log ((level), _NMLOG_DOMAIN, \
             "%s[%p]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
             _NMLOG_PREFIX_NAME, (self) \
             _NM_UTILS_MACRO_REST (__VA_ARGS__))
 
+#define _NMLOG2_PREFIX_NAME               "properties-changed"
+#define _NMLOG2_DOMAIN                    LOGD_DBUS_PROPS
+
+#define _NMLOG2(level, ...) \
+    nm_log ((level), _NMLOG2_DOMAIN, \
+            "%s[%p]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+            _NMLOG2_PREFIX_NAME, (self) \
+            _NM_UTILS_MACRO_REST (__VA_ARGS__))
+
 /*****************************************************************************/
 
 /* "AddConnectionUnsaved" -> "handle-add-connection-unsaved" */
@@ -492,9 +504,17 @@ nm_exported_object_create_skeletons (NMExportedObject *self,
 		g_dbus_object_skeleton_add_interface ((GDBusObjectSkeleton *) self, ifdata->interface);
 
 		ifdata->property_changed_signal_id = g_signal_lookup ("properties-changed", G_OBJECT_TYPE (ifdata->interface));
+
+		ifdata->pending_notifies = g_hash_table_new_full (g_direct_hash,
+		                                                  g_direct_equal,
+		                                                  NULL,
+		                                                  (GDestroyNotify) g_variant_unref);
 	}
 	nm_assert (i == 0);
 
+	/* The list of interfaces priv->interfaces is to be sorted from parent-class to derived-class.
+	 * On the other hand, if one class defines multiple interfaces, the interfaces are sorted in
+	 * the order of calls to nm_exported_object_class_add_interface(). */
 	if (priv->num_interfaces > 0) {
 		memcpy (&interfaces[num_interfaces], priv->interfaces, sizeof (InterfaceData) * priv->num_interfaces);
 		g_slice_free1 (sizeof (InterfaceData) * priv->num_interfaces, priv->interfaces);
@@ -542,6 +562,7 @@ nm_exported_object_destroy_skeletons (NMExportedObject *self)
 
 		g_dbus_object_skeleton_remove_interface ((GDBusObjectSkeleton *) self, ifdata->interface);
 		nm_exported_object_skeleton_release (ifdata->interface);
+		g_hash_table_destroy (ifdata->pending_notifies);
 	}
 
 	g_slice_free1 (sizeof (InterfaceData) * n, priv->interfaces);
@@ -701,11 +722,7 @@ nm_exported_object_unexport (NMExportedObject *self)
 
 	g_clear_pointer (&priv->path, g_free);
 
-	if (nm_clear_g_source (&priv->notify_idle_id)) {
-		/* We had a notification queued. Since we removed all interfaces,
-		 * the notification is obsolete and must be cleaned up. */
-		g_hash_table_remove_all (priv->pending_notifies);
-	}
+	nm_clear_g_source (&priv->notify_idle_id);
 }
 
 /*****************************************************************************/
@@ -784,70 +801,82 @@ static gboolean
 idle_emit_properties_changed (gpointer self)
 {
 	NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
-	gs_unref_variant GVariant *variant = NULL;
-	InterfaceData *ifdata = NULL;
-	GHashTableIter hash_iter;
-	GVariantBuilder notifies;
-	guint i, n;
-	PendingNotifiesItem *values;
+	guint k;
 
 	priv->notify_idle_id = 0;
 
+	for (k = 0; k < priv->num_interfaces; k++) {
+		InterfaceData *ifdata = &priv->interfaces[k];
+		gs_unref_variant GVariant *variant = NULL;
+		PendingNotifiesItem *values;
+		GVariantBuilder notifies;
+		GHashTableIter hash_iter;
+		guint i, n;
 
-	n = g_hash_table_size (priv->pending_notifies);
-	g_return_val_if_fail (n > 0, FALSE);
+		n = g_hash_table_size (ifdata->pending_notifies);
+		if (n == 0)
+			continue;
 
-	values = g_alloca (sizeof (values[0]) * n);
+		nm_assert (ifdata->property_changed_signal_id);
 
-	i = 0;
-	g_hash_table_iter_init (&hash_iter, priv->pending_notifies);
-	while (g_hash_table_iter_next (&hash_iter, (gpointer) &values[i].property_name, (gpointer) &values[i].variant))
-		i++;
-	nm_assert (i == n);
+		/* We use here alloca in a loop, something that is usually avoided.
+		 * But the number of interfaces "priv->num_interfaces" is small (determined by
+		 * the depth of the type inheritance) and the number of possible pending_notifies
+		 * "n" is small (determined by the number of GObject properties). */
+		values = g_alloca (sizeof (values[0]) * n);
 
-	g_qsort_with_data (values, n, sizeof (values[0]), _sort_pending_notifies, NULL);
+		i = 0;
+		g_hash_table_iter_init (&hash_iter, ifdata->pending_notifies);
+		while (g_hash_table_iter_next (&hash_iter, (gpointer) &values[i].property_name, (gpointer) &values[i].variant))
+			i++;
+		nm_assert (i == n);
 
-	g_variant_builder_init (&notifies, G_VARIANT_TYPE_VARDICT);
-	for (i = 0; i < n; i++)
-		g_variant_builder_add (&notifies, "{sv}", values[i].property_name, values[i].variant);
-	variant = g_variant_ref_sink (g_variant_builder_end (&notifies));
+		g_qsort_with_data (values, n, sizeof (values[0]), _sort_pending_notifies, NULL);
 
-	g_hash_table_remove_all (priv->pending_notifies);
+		g_variant_builder_init (&notifies, G_VARIANT_TYPE_VARDICT);
+		for (i = 0; i < n; i++)
+			g_variant_builder_add (&notifies, "{sv}", values[i].property_name, values[i].variant);
+		variant = g_variant_ref_sink (g_variant_builder_end (&notifies));
 
-	for (i = 0; i < priv->num_interfaces; i++) {
-		if (priv->interfaces[i].property_changed_signal_id != 0) {
-			ifdata = &priv->interfaces[i];
-			break;
+
+		if (_LOG2D_ENABLED ()) {
+			gs_free char *notification = g_variant_print (variant, TRUE);
+
+			_LOG2D ("type %s, iface %s: %s",
+			        G_OBJECT_TYPE_NAME (self), G_OBJECT_TYPE_NAME (ifdata->interface),
+			        notification);
 		}
-	}
-	g_return_val_if_fail (ifdata, FALSE);
 
-	if (nm_logging_enabled (LOGL_DEBUG, LOGD_DBUS_PROPS)) {
-		gs_free char *notification = g_variant_print (variant, TRUE);
+		g_signal_emit (ifdata->interface, ifdata->property_changed_signal_id, 0, variant);
 
-		nm_log_dbg (LOGD_DBUS_PROPS, "PropertiesChanged %s %p: %s",
-		            G_OBJECT_TYPE_NAME (self), self, notification);
+		g_hash_table_remove_all (ifdata->pending_notifies);
 	}
 
-	g_signal_emit (ifdata->interface, ifdata->property_changed_signal_id, 0, variant);
-	return FALSE;
+	return G_SOURCE_REMOVE;
 }
 
 static void
 nm_exported_object_notify (GObject *object, GParamSpec *pspec)
 {
-	NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (object);
+	NMExportedObject *self = (NMExportedObject *) object;
+	NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
 	NMExportedObjectClassInfo *classinfo;
 	GType type;
 	const char *dbus_property_name = NULL;
 	GValue value = G_VALUE_INIT;
+	GVariant *value_variant;
+	InterfaceData *ifdata = NULL;
 	const GVariantType *vtype;
 	guint i, j;
 
+	/* Hook to emit deprecated "PropertiesChanged" signal on NetworkManager interfaces.
+	 * This is to preserve deprecated D-Bus API, nowadays we use instead
+	 * the "PropertiesChanged" signal of "org.freedesktop.DBus.Properties". */
+
 	if (priv->num_interfaces == 0)
 		return;
 
-	for (type = G_OBJECT_TYPE (object); type; type = g_type_parent (type)) {
+	for (type = G_OBJECT_TYPE (self); type; type = g_type_parent (type)) {
 		classinfo = g_type_get_qdata (type, nm_exported_object_class_info_quark ());
 		if (!classinfo)
 			continue;
@@ -857,16 +886,16 @@ nm_exported_object_notify (GObject *object, GParamSpec *pspec)
 			break;
 	}
 	if (!dbus_property_name) {
-		nm_log_trace (LOGD_DBUS_PROPS, "ignoring notification for prop %s on type %s",
-		              pspec->name, G_OBJECT_TYPE_NAME (object));
+		_LOG2T ("ignoring notification for prop %s on type %s",
+		        pspec->name, G_OBJECT_TYPE_NAME (self));
 		return;
 	}
 
 	for (i = 0; i < priv->num_interfaces; i++) {
-		GDBusInterfaceSkeleton *skel = priv->interfaces[i].interface;
 		GDBusInterfaceInfo *iinfo;
 
-		iinfo = g_dbus_interface_skeleton_get_info (skel);
+		ifdata = &priv->interfaces[i];
+		iinfo = g_dbus_interface_skeleton_get_info (ifdata->interface);
 		for (j = 0; iinfo->properties[j]; j++) {
 			if (nm_streq (iinfo->properties[j]->name, dbus_property_name)) {
 				vtype = G_VARIANT_TYPE (iinfo->properties[j]->signature);
@@ -878,17 +907,61 @@ nm_exported_object_notify (GObject *object, GParamSpec *pspec)
 
 vtype_found:
 	g_value_init (&value, pspec->value_type);
-	g_object_get_property (G_OBJECT (object), pspec->name, &value);
-
-	/* @dbus_property_name is inside classinfo and never freed, thus we don't clone it.
-	 * Also, we do a pointer, not string comparison. */
-	g_hash_table_insert (priv->pending_notifies,
-	                     (gpointer) dbus_property_name,
-	                     g_dbus_gvalue_to_gvariant (&value, vtype));
+	g_object_get_property ((GObject *) self, pspec->name, &value);
+	value_variant = g_dbus_gvalue_to_gvariant (&value, vtype);
 	g_value_unset (&value);
 
+	if (   (   NM_IS_DEVICE (self)
+	        && !NMDBUS_IS_DEVICE_STATISTICS_SKELETON (ifdata->interface))
+	    || NM_IS_ACTIVE_CONNECTION (self)) {
+		/* This PropertiesChanged signal is nodaways deprecated in favor
+		 * of "org.freedesktop.DBus.Properties"'s PropertiesChanged signal.
+		 * This function solely exists to raise the NM version of PropertiesChanged.
+		 *
+		 * With types exported on D-Bus that are implemented as derived
+		 * types in glib (NMDevice and NMActiveConnection), multiple types
+		 * in the inheritance tree define a "PropertiesChanged" signal.
+		 *
+		 * In 1.0.0 and earlier, the signal was emitted once for every interface
+		 * that had a "PropertiesChanged" signal. For example:
+		 *   - NMDeviceEthernet.HwAddress was emitted on "fdo.NM.Device.Ethernet"
+		 *     and "fdo.NM.Device.Veth" (if the device was of type NMDeviceVeth).
+		 *   - NMVpnConnection.VpnState was emitted on "fdo.NM.Connecion.Active"
+		 *     and "fdo.NM.VPN.Connection".
+		 *
+		 * NMDevice is special in that it didn't have a "PropertiesChanged" signal.
+		 * Thus, a change to "NMDevice.StateReason" would be emitted on "fdo.NM.Device.Ethernet"
+		 * and also on "fdo.NM.Device.Veth" (in case of a device of type NMDeviceVeth).
+		 *
+		 * The releases of 1.2.0 and 1.4.0 failed to realize above and broke this behavior.
+		 * This special handling here is to bring back the 1.0.0 behavior.
+		 *
+		 * The Device.Statistics signal is special, because it was only added with 1.4.0
+		 * and didn't have above behavior. So let's save the overhead of emitting multiple
+		 * deprecated signals for wrong interfaces. */
+		for (i = 0, j = 0; i < priv->num_interfaces; i++) {
+			ifdata = &priv->interfaces[i];
+			if (   ifdata->property_changed_signal_id
+			    && !NMDBUS_IS_DEVICE_STATISTICS_SKELETON (ifdata->interface)) {
+				j++;
+				g_hash_table_insert (ifdata->pending_notifies,
+				                     (gpointer) dbus_property_name,
+				                     g_variant_ref (value_variant));
+			}
+		}
+		nm_assert (j > 0);
+		g_variant_unref (value_variant);
+	} else if (ifdata->property_changed_signal_id) {
+		/* @dbus_property_name is inside classinfo and never freed, thus we don't clone it.
+		 * Also, we do a pointer, not string comparison. */
+		g_hash_table_insert (ifdata->pending_notifies,
+		                     (gpointer) dbus_property_name,
+		                     value_variant);
+	} else
+		nm_assert_not_reached ();
+
 	if (!priv->notify_idle_id)
-		priv->notify_idle_id = g_idle_add (idle_emit_properties_changed, object);
+		priv->notify_idle_id = g_idle_add (idle_emit_properties_changed, self);
 }
 
 /*****************************************************************************/
@@ -896,12 +969,6 @@ vtype_found:
 static void
 nm_exported_object_init (NMExportedObject *self)
 {
-	NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self);
-
-	priv->pending_notifies = g_hash_table_new_full (g_direct_hash,
-	                                                g_direct_equal,
-	                                                NULL,
-	                                                (GDestroyNotify) g_variant_unref);
 }
 
 static void
@@ -937,7 +1004,6 @@ nm_exported_object_dispose (GObject *object)
 	} else
 		g_clear_pointer (&priv->path, g_free);
 
-	g_clear_pointer (&priv->pending_notifies, g_hash_table_destroy);
 	nm_clear_g_source (&priv->notify_idle_id);
 
 	G_OBJECT_CLASS (nm_exported_object_parent_class)->dispose (object);
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 49672cf5..de035f1a 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -534,6 +534,8 @@ gboolean nm_config_get_configure_and_quit (gpointer unused);
 gconstpointer nm_bus_manager_get (void);
 void nm_bus_manager_register_object (gpointer unused, gpointer object);
 void nm_bus_manager_unregister_object (gpointer unused, gpointer object);
+GType nm_device_get_type (void);
+GType nm_active_connection_get_type (void);
 
 gconstpointer
 nm_config_get (void)
@@ -569,3 +571,15 @@ nm_bus_manager_unregister_object (gpointer unused, gpointer object)
 {
 }
 
+GType
+nm_device_get_type (void)
+{
+	g_return_val_if_reached (0);
+}
+
+GType
+nm_active_connection_get_type (void)
+{
+	g_return_val_if_reached (0);
+}
+
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 22d1d077..a4d43612 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -68,18 +68,7 @@ struct _NMIP4ConfigClass {
 
 G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, NM_TYPE_EXPORTED_OBJECT)
 
-#define NM_IP4_CONFIG_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMIP4Config *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_IP4_CONFIG (_self)); \
-		&_self->_priv; \
-	})
+#define NM_IP4_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIP4Config, NM_IS_IP4_CONFIG)
 
 /* internal guint32 are assigned to gobject properties of type uint. Ensure, that uint is large enough */
 G_STATIC_ASSERT (sizeof (uint) >= sizeof (guint32));
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index ac9e6cd1..8002d61a 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -61,18 +61,7 @@ struct _NMIP6ConfigClass {
 
 G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, NM_TYPE_EXPORTED_OBJECT)
 
-#define NM_IP6_CONFIG_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMIP6Config *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_IP6_CONFIG (_self)); \
-		&_self->_priv; \
-	})
+#define NM_IP6_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIP6Config, NM_IS_IP6_CONFIG)
 
 NM_GOBJECT_PROPERTIES_DEFINE (NMIP6Config,
 	PROP_IFINDEX,
diff --git a/src/nm-logging.c b/src/nm-logging.c
index 3db8d20c..6ecc1606 100644
--- a/src/nm-logging.c
+++ b/src/nm-logging.c
@@ -512,7 +512,7 @@ _nm_log_impl (const char *file,
 	va_end (args);
 
 	g_get_current_time (&tv);
-	nm_sprintf_buf (s_buf_timestamp, " [%ld.%04ld]", tv.tv_sec, (tv.tv_usec + 50) / 100);
+	nm_sprintf_buf (s_buf_timestamp, " [%ld.%04ld]", tv.tv_sec, tv.tv_usec / 100);
 
 	switch (global.log_backend) {
 #if SYSTEMD_JOURNAL
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 5794bb9a..836ab768 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -158,21 +158,10 @@ typedef struct {
 	NMExportedObjectClass parent;
 } NMManagerClass;
 
-#define NM_MANAGER_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMManager *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_MANAGER (_self)); \
-		&_self->_priv; \
-	})
-
 G_DEFINE_TYPE (NMManager, nm_manager, NM_TYPE_EXPORTED_OBJECT)
 
+#define NM_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMManager, NM_IS_MANAGER)
+
 enum {
 	DEVICE_ADDED,
 	INTERNAL_DEVICE_ADDED,
@@ -1879,8 +1868,10 @@ device_realized (NMDevice *device,
                  GParamSpec *pspec,
                  NMManager *self)
 {
+	gboolean real = nm_device_is_real (device);
+
 	/* Emit D-Bus signals */
-	g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
+	g_signal_emit (self, signals[real ? DEVICE_ADDED : DEVICE_REMOVED], 0, device);
 	_notify (self, PROP_DEVICES);
 }
 
@@ -6056,7 +6047,8 @@ nm_manager_class_init (NMManagerClass *manager_class)
 	                  NULL, NULL, NULL,
 	                  G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
-	/* D-Bus exported; emitted only for realized devices */
+	/* D-Bus exported; emitted only for realized devices when a device
+	 * becomes unrealized or removed */
 	signals[DEVICE_REMOVED] =
 	    g_signal_new (NM_MANAGER_DEVICE_REMOVED,
 	                  G_OBJECT_CLASS_TYPE (object_class),
diff --git a/src/platform/Makefile.in b/src/platform/Makefile.in
index bf094348..be78d19f 100644
--- a/src/platform/Makefile.in
+++ b/src/platform/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 \
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 98c4e461..070a83ea 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -4060,21 +4060,17 @@ out:
 	return !!nmp_cache_lookup_obj (priv->cache, obj_id);
 }
 
-static NMPlatformError
-do_change_link (NMPlatform *platform,
-                int ifindex,
-                struct nl_msg *nlmsg)
+static WaitForNlResponseResult
+do_change_link_request (NMPlatform *platform,
+                        int ifindex,
+                        struct nl_msg *nlmsg)
 {
 	nm_auto_pop_netns NMPNetns *netns = NULL;
 	WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
 	int nle;
-	char s_buf[256];
-	NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS;
-	NMLogLevel log_level = LOGL_DEBUG;
-	const char *log_result = "failure", *log_detail = "";
 
 	if (!nm_platform_netns_push (platform, &netns))
-		return NM_PLATFORM_ERROR_UNSPECIFIED;
+		return WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
 
 retry:
 	nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
@@ -4082,7 +4078,7 @@ retry:
 		_LOGE ("do-change-link[%d]: failure sending netlink request \"%s\" (%d)",
 		       ifindex,
 		       nl_geterror (nle), -nle);
-		return NM_PLATFORM_ERROR_UNSPECIFIED;
+		return WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
 	}
 
 	/* always refetch the link after changing it. There seems to be issues
@@ -4098,6 +4094,18 @@ retry:
 		nlmsg_hdr (nlmsg)->nlmsg_type = RTM_SETLINK;
 		goto retry;
 	}
+	return seq_result;
+}
+
+static NMPlatformError
+do_change_link_result (NMPlatform *platform,
+                       int ifindex,
+                       WaitForNlResponseResult seq_result)
+{
+	char s_buf[256];
+	NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS;
+	NMLogLevel log_level = LOGL_DEBUG;
+	const char *log_result = "failure", *log_detail = "";
 
 	if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) {
 		log_result = "success";
@@ -4123,6 +4131,17 @@ retry:
 	return result;
 }
 
+static NMPlatformError
+do_change_link (NMPlatform *platform,
+                int ifindex,
+                struct nl_msg *nlmsg)
+{
+	WaitForNlResponseResult seq_result;
+
+	seq_result = do_change_link_request (platform, ifindex, nlmsg);
+	return do_change_link_result (platform, ifindex, seq_result);
+}
+
 static gboolean
 link_add (NMPlatform *platform,
           const char *name,
@@ -4430,6 +4449,8 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size
 {
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 	gs_free char *mac = NULL;
+	WaitForNlResponseResult seq_result;
+	char s_buf[256];
 
 	if (!address || !length)
 		g_return_val_if_reached (NM_PLATFORM_ERROR_BUG);
@@ -4449,7 +4470,30 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size
 
 	NLA_PUT (nlmsg, IFLA_ADDRESS, length, address);
 
-	return do_change_link (platform, ifindex, nlmsg);
+	seq_result = do_change_link_request (platform, ifindex, nlmsg);
+
+	if (NM_IN_SET (-((int) seq_result), ENFILE)) {
+		const NMPObject *obj_cache;
+
+		/* workaround ENFILE which may be wrongly returned (bgo #770456).
+		 * If the MAC address is as expected, assume success? */
+
+		obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex);
+		if (   obj_cache
+		    && obj_cache->link.addr.len == length
+		    && memcmp (obj_cache->link.addr.data, address, length) == 0) {
+			_NMLOG (LOGL_DEBUG,
+			        "do-change-link[%d]: %s changing link: %s%s",
+			        ifindex,
+			        "success",
+			        wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)),
+			        " (assume success changing address)");
+			return NM_PLATFORM_ERROR_SUCCESS;
+		}
+	}
+
+	return do_change_link_result (platform, ifindex, seq_result);
+
 nla_put_failure:
 	g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED);
 }
diff --git a/src/platform/tests/Makefile.in b/src/platform/tests/Makefile.in
index 4922a3dc..3f452b0f 100644
--- a/src/platform/tests/Makefile.in
+++ b/src/platform/tests/Makefile.in
@@ -105,7 +105,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/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 99873620..e242a71f 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -297,9 +297,9 @@ test_slave (int master, int type, SignalData *master_changed)
 	switch (type) {
 	case NM_LINK_TYPE_BRIDGE:
 		if (nmtstp_is_sysfs_writable ()) {
-			g_assert (nm_platform_sysctl_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "789"));
+			g_assert (nm_platform_sysctl_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "614"));
 			value = nm_platform_sysctl_slave_get_option (NM_PLATFORM_GET, ifindex, "priority");
-			g_assert_cmpstr (value, ==, "789");
+			g_assert_cmpstr (value, ==, "614");
 			g_free (value);
 		}
 		break;
@@ -398,9 +398,9 @@ test_software (NMLinkType link_type, const char *link_typename)
 	switch (link_type) {
 	case NM_LINK_TYPE_BRIDGE:
 		if (nmtstp_is_sysfs_writable ()) {
-			g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "789"));
+			g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "628"));
 			value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay");
-			g_assert_cmpstr (value, ==, "789");
+			g_assert_cmpstr (value, ==, "628");
 			g_free (value);
 		}
 		break;
diff --git a/src/ppp-manager/Makefile.in b/src/ppp-manager/Makefile.in
index b8215aab..656bdd6c 100644
--- a/src/ppp-manager/Makefile.in
+++ b/src/ppp-manager/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/rdisc/Makefile.in b/src/rdisc/Makefile.in
index 68fed001..719ce8a2 100644
--- a/src/rdisc/Makefile.in
+++ b/src/rdisc/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 \
diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c
index 12c2e30d..db2965b1 100644
--- a/src/rdisc/nm-lndp-rdisc.c
+++ b/src/rdisc/nm-lndp-rdisc.c
@@ -60,18 +60,7 @@ struct _NMLndpRDiscClass {
 
 G_DEFINE_TYPE (NMLndpRDisc, nm_lndp_rdisc, NM_TYPE_RDISC)
 
-#define NM_LNDP_RDISC_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMLndpRDisc *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_LNDP_RDISC (_self)); \
-		&_self->_priv; \
-	})
+#define NM_LNDP_RDISC_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMLndpRDisc, NM_IS_LNDP_RDISC)
 
 /*****************************************************************************/
 
diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c
index cf993bc3..3bc69750 100644
--- a/src/rdisc/nm-rdisc.c
+++ b/src/rdisc/nm-rdisc.c
@@ -87,18 +87,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (NMRDisc, nm_rdisc, G_TYPE_OBJECT)
 
-#define NM_RDISC_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMRDisc *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_RDISC (_self)); \
-		_self->_priv; \
-	})
+#define NM_RDISC_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMRDisc, NM_IS_RDISC)
 
 /*****************************************************************************/
 
diff --git a/src/rdisc/tests/Makefile.in b/src/rdisc/tests/Makefile.in
index f160600e..3cbc48a0 100644
--- a/src/rdisc/tests/Makefile.in
+++ b/src/rdisc/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/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 \
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index bb5efff7..eb6b03ea 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/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/supplicant-manager/tests/certs/Makefile.in b/src/supplicant-manager/tests/certs/Makefile.in
index a1be6bcb..3d348a38 100644
--- a/src/supplicant-manager/tests/certs/Makefile.in
+++ b/src/supplicant-manager/tests/certs/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 \
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index a4ca2212..a115170e 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -105,7 +105,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/tests/config/Makefile.in b/src/tests/config/Makefile.in
index 89c18941..738788cf 100644
--- a/src/tests/config/Makefile.in
+++ b/src/tests/config/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/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 92c5bd8f..69b45dcc 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -168,18 +168,7 @@ struct _NMVpnConnectionClass {
 
 G_DEFINE_TYPE (NMVpnConnection, nm_vpn_connection, NM_TYPE_ACTIVE_CONNECTION)
 
-#define NM_VPN_CONNECTION_GET_PRIVATE(self) \
-	({ \
-		/* preserve the const-ness of self. Unfortunately, that
-		 * way, @self cannot be a void pointer */ \
-		typeof (self) _self = (self); \
-		\
-		/* Get compiler error if variable is of wrong type */ \
-		_nm_unused const NMVpnConnection *_self2 = (_self); \
-		\
-		nm_assert (NM_IS_VPN_CONNECTION (_self)); \
-		&_self->_priv; \
-	})
+#define NM_VPN_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMVpnConnection, NM_IS_VPN_CONNECTION)
 
 /*****************************************************************************/