summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/nm-device-6lowpan.c10
-rw-r--r--src/devices/nm-device-wpan.c8
-rw-r--r--src/devices/nm-device.c71
-rw-r--r--src/devices/nm-device.h4
-rw-r--r--src/devices/wifi/nm-device-iwd.c148
-rw-r--r--src/devices/wifi/nm-device-wifi.c1
-rw-r--r--src/dhcp/nm-dhcp-client.c14
-rw-r--r--src/dhcp/nm-dhcp-client.h14
-rw-r--r--src/dhcp/nm-dhcp-dhclient.c181
-rw-r--r--src/dhcp/nm-dhcp-dhcpcanon.c90
-rw-r--r--src/dhcp/nm-dhcp-dhcpcd.c66
-rw-r--r--src/dhcp/nm-dhcp-manager.c59
-rw-r--r--src/dhcp/nm-dhcp-manager.h6
-rw-r--r--src/dhcp/nm-dhcp-systemd.c79
-rw-r--r--src/dns/nm-dns-dnsmasq.c10
-rw-r--r--src/dns/nm-dns-unbound.c2
-rw-r--r--src/meson.build80
-rw-r--r--src/nm-iface-helper.c9
-rw-r--r--src/platform/nm-netlink.c230
-rw-r--r--src/platform/nm-netlink.h48
-rw-r--r--src/ppp/nm-ppp-manager.c22
-rw-r--r--src/ppp/nm-pppd-plugin.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/meson.build6
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-network.c2
-rw-r--r--src/vpn/nm-vpn-connection.c13
27 files changed, 694 insertions, 485 deletions
diff --git a/src/devices/nm-device-6lowpan.c b/src/devices/nm-device-6lowpan.c
index 600d1b80..b6b9157c 100644
--- a/src/devices/nm-device-6lowpan.c
+++ b/src/devices/nm-device-6lowpan.c
@@ -114,7 +114,7 @@ create_and_realize (NMDevice *device,
 	NMSetting6Lowpan *s_6lowpan;
 	int parent_ifindex;
 
-	s_6lowpan = nm_connection_get_setting_6lowpan (connection);
+	s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN));
 	g_return_val_if_fail (s_6lowpan, FALSE);
 
 	parent_ifindex = parent ? nm_device_get_ifindex (parent) : 0;
@@ -192,7 +192,7 @@ complete_connection (NMDevice *device,
 	                           NULL,
 	                           TRUE);
 
-	s_6lowpan = nm_connection_get_setting_6lowpan (connection);
+	s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN));
 	if (!s_6lowpan) {
 		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION,
 		                     "A '6lowpan' setting is required.");
@@ -215,7 +215,7 @@ complete_connection (NMDevice *device,
 static void
 update_connection (NMDevice *device, NMConnection *connection)
 {
-	NMSetting6Lowpan *s_6lowpan = nm_connection_get_setting_6lowpan (connection);
+	NMSetting6Lowpan *s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN));
 
 	if (!s_6lowpan) {
 		s_6lowpan = (NMSetting6Lowpan *) nm_setting_6lowpan_new ();
@@ -310,7 +310,7 @@ get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
 
 	g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_6LOWPAN_SETTING_NAME), NULL);
 
-	s_6lowpan = nm_connection_get_setting_6lowpan (connection);
+	s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN));
 	g_assert (s_6lowpan);
 
 	return nm_setting_6lowpan_get_parent (s_6lowpan);
@@ -326,7 +326,7 @@ get_connection_iface (NMDeviceFactory *factory,
 
 	g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_6LOWPAN_SETTING_NAME), NULL);
 
-	s_6lowpan = nm_connection_get_setting_6lowpan (connection);
+	s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN));
 	g_assert (s_6lowpan);
 
 	if (!parent_iface)
diff --git a/src/devices/nm-device-wpan.c b/src/devices/nm-device-wpan.c
index dd2ebac1..f910b0b8 100644
--- a/src/devices/nm-device-wpan.c
+++ b/src/devices/nm-device-wpan.c
@@ -69,7 +69,7 @@ complete_connection (NMDevice *device,
 	                           NULL,
 	                           TRUE);
 
-	s_wpan = nm_connection_get_setting_wpan (connection);
+	s_wpan = NM_SETTING_WPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_WPAN));
 	if (!s_wpan) {
 		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION,
 		                     "A 'wpan' setting is required.");
@@ -82,7 +82,7 @@ complete_connection (NMDevice *device,
 static void
 update_connection (NMDevice *device, NMConnection *connection)
 {
-	NMSettingWpan *s_wpan = nm_connection_get_setting_wpan (connection);
+	NMSettingWpan *s_wpan = NM_SETTING_WPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_WPAN));
 
 	if (!s_wpan) {
 		s_wpan = (NMSettingWpan *) nm_setting_wpan_new ();
@@ -99,7 +99,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection, GError
 	if (!NM_DEVICE_CLASS (nm_device_wpan_parent_class)->check_connection_compatible (device, connection, error))
 		return FALSE;
 
-	s_wpan = nm_connection_get_setting_wpan (connection);
+	s_wpan = NM_SETTING_WPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_WPAN));
 
 	mac = nm_setting_wpan_get_mac_address (s_wpan);
 	if (mac) {
@@ -143,7 +143,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
 	connection = nm_device_get_applied_connection (device);
 	g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE);
 
-	s_wpan = nm_connection_get_setting_wpan (connection);
+	s_wpan = NM_SETTING_WPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_WPAN));
 	g_return_val_if_fail (s_wpan, NM_ACT_STAGE_RETURN_FAILURE);
 
 	hwaddr = nm_platform_link_get_address (platform, ifindex, &hwaddr_len);
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 515e6334..8ca899a2 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -80,7 +80,10 @@
 #include "nm-audit-manager.h"
 #include "nm-connectivity.h"
 #include "nm-dbus-interface.h"
+
+#include "nm-device-generic.h"
 #include "nm-device-vlan.h"
+#include "nm-device-wireguard.h"
 
 #include "nm-device-logging.h"
 _LOG_DECLARE_SELF (NMDevice);
@@ -823,6 +826,13 @@ _ethtool_state_set (NMDevice *self)
 
 /*****************************************************************************/
 
+static gboolean
+is_loopback (NMDevice *self)
+{
+	return    NM_IS_DEVICE_GENERIC (self)
+	       && NM_DEVICE_GET_PRIVATE (self)->ifindex == 1;
+}
+
 NMSettings *
 nm_device_get_settings (NMDevice *self)
 {
@@ -2460,7 +2470,7 @@ concheck_is_possible (NMDevice *self)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
 	if (   !nm_device_is_real (self)
-	    || NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_LOOPBACK))
+	    || is_loopback (self))
 		return FALSE;
 
 	/* we enable periodic checks for every device state (except UNKNOWN). Especially with
@@ -4289,10 +4299,13 @@ realize_start_setup (NMDevice *self,
 	                               NM_UNMANAGED_EXTERNAL_DOWN,
 	                               is_unmanaged_external_down (self, TRUE));
 
-	/* Unmanaged the loopback device with an explicit NM_UNMANAGED_LOOPBACK flag.
+	/* Unmanaged the loopback device with an explicit NM_UNMANAGED_BY_TYPE flag.
 	 * Later we might want to manage 'lo' too. Currently that doesn't work because
 	 * NetworkManager might down the interface or remove the 127.0.0.1 address. */
-	nm_device_set_unmanaged_flags (self, NM_UNMANAGED_LOOPBACK, priv->ifindex == 1);
+	nm_device_set_unmanaged_flags (self,
+	                               NM_UNMANAGED_BY_TYPE,
+	                                  is_loopback (self)
+	                               || NM_IS_DEVICE_WIREGUARD (self));
 
 	nm_device_set_unmanaged_by_user_udev (self);
 	nm_device_set_unmanaged_by_user_conf (self);
@@ -4488,7 +4501,7 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 
 	nm_device_set_unmanaged_flags (self,
 	                               NM_UNMANAGED_PARENT |
-	                               NM_UNMANAGED_LOOPBACK |
+	                               NM_UNMANAGED_BY_TYPE |
 	                               NM_UNMANAGED_USER_UDEV |
 	                               NM_UNMANAGED_USER_EXPLICIT |
 	                               NM_UNMANAGED_EXTERNAL_DOWN |
@@ -5596,6 +5609,14 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError **
 		                                        klass->connection_type_check_compatible,
 		                                        error))
 			return FALSE;
+	} else if (klass->check_connection_compatible == check_connection_compatible) {
+		/* the device class does not implement check_connection_compatible nor set
+		 * connection_type_check_compatible. That means, it is by default not compatible
+		 * with any connection type. */
+		nm_utils_error_set_literal (error,
+		                            NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
+		                            "device does not support any connections");
+		return FALSE;
 	}
 
 	conn_iface = nm_manager_get_connection_iface (nm_manager_get (),
@@ -7540,6 +7561,7 @@ dhcp4_start (NMDevice *self)
 	gs_unref_bytes GBytes *hwaddr = NULL;
 	gs_unref_bytes GBytes *client_id = NULL;
 	NMConnection *connection;
+	GError *error = NULL;
 
 	connection = nm_device_get_applied_connection (self);
 	g_return_val_if_fail (connection, FALSE);
@@ -7570,10 +7592,14 @@ dhcp4_start (NMDevice *self)
 	                                                client_id,
 	                                                get_dhcp_timeout (self, AF_INET),
 	                                                priv->dhcp_anycast_address,
-	                                                NULL);
+	                                                NULL,
+	                                                &error);
 
-	if (!priv->dhcp4.client)
+	if (!priv->dhcp4.client) {
+		_LOGW (LOGD_DHCP4, "failure to start DHCP: %s", error->message);
+		g_clear_error (&error);
 		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
 
 	priv->dhcp4.state_sigid = g_signal_connect (priv->dhcp4.client,
 	                                            NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
@@ -8375,6 +8401,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
 	gs_unref_bytes GBytes *hwaddr = NULL;
 	gs_unref_bytes GBytes *duid = NULL;
 	gboolean enforce_duid = FALSE;
+	GError *error = NULL;
 
 	const NMPlatformIP6Address *ll_addr = NULL;
 
@@ -8414,23 +8441,29 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
 	                                                priv->dhcp_anycast_address,
 	                                                (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE,
 	                                                nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)),
-	                                                priv->dhcp6.needed_prefixes);
-
-	if (priv->dhcp6.client) {
-		priv->dhcp6.state_sigid = g_signal_connect (priv->dhcp6.client,
-		                                            NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
-		                                            G_CALLBACK (dhcp6_state_changed),
-		                                            self);
-		priv->dhcp6.prefix_sigid = g_signal_connect (priv->dhcp6.client,
-		                                             NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED,
-		                                             G_CALLBACK (dhcp6_prefix_delegated),
-		                                             self);
+	                                                priv->dhcp6.needed_prefixes,
+	                                                &error);
+	if (!priv->dhcp6.client) {
+		_LOGW (LOGD_DHCP6, "failure to start DHCPv6: %s", error->message);
+		g_clear_error (&error);
+		if (nm_device_sys_iface_state_is_external_or_assume (self))
+			priv->dhcp6.was_active = TRUE;
+		return FALSE;
 	}
 
+	priv->dhcp6.state_sigid = g_signal_connect (priv->dhcp6.client,
+	                                            NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
+	                                            G_CALLBACK (dhcp6_state_changed),
+	                                            self);
+	priv->dhcp6.prefix_sigid = g_signal_connect (priv->dhcp6.client,
+	                                             NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED,
+	                                             G_CALLBACK (dhcp6_prefix_delegated),
+	                                             self);
+
 	if (nm_device_sys_iface_state_is_external_or_assume (self))
 		priv->dhcp6.was_active = TRUE;
 
-	return !!priv->dhcp6.client;
+	return TRUE;
 }
 
 static gboolean
@@ -12859,7 +12892,7 @@ NM_UTILS_FLAGS2STR_DEFINE (nm_unmanaged_flags2str, NMUnmanagedFlags,
 	NM_UTILS_FLAGS2STR (NM_UNMANAGED_SLEEPING, "sleeping"),
 	NM_UTILS_FLAGS2STR (NM_UNMANAGED_QUITTING, "quitting"),
 	NM_UTILS_FLAGS2STR (NM_UNMANAGED_PARENT, "parent"),
-	NM_UTILS_FLAGS2STR (NM_UNMANAGED_LOOPBACK, "loopback"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_BY_TYPE, "by-type"),
 	NM_UTILS_FLAGS2STR (NM_UNMANAGED_PLATFORM_INIT, "platform-init"),
 	NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_EXPLICIT, "user-explicit"),
 	NM_UTILS_FLAGS2STR (NM_UNMANAGED_BY_DEFAULT, "by-default"),
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 7d74e5b9..6342a657 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -583,7 +583,7 @@ void nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device);
  * @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping.
  * @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down.
  * @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged
- * @NM_UNMANAGED_LOOPBACK: %TRUE for unmanaging loopback device
+ * @NM_UNMANAGED_BY_TYPE: %TRUE for unmanaging device by type, like loopback.
  * @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not
  *   yet initialized. Unrealized device are also unmanaged for this reason.
  * @NM_UNMANAGED_USER_EXPLICIT: %TRUE when unmanaged by explicit user decision
@@ -614,7 +614,7 @@ typedef enum { /*< skip >*/
 	NM_UNMANAGED_SLEEPING      = (1LL <<  0),
 	NM_UNMANAGED_QUITTING      = (1LL <<  1),
 	NM_UNMANAGED_PARENT        = (1LL <<  2),
-	NM_UNMANAGED_LOOPBACK      = (1LL <<  3),
+	NM_UNMANAGED_BY_TYPE       = (1LL <<  3),
 	NM_UNMANAGED_PLATFORM_INIT = (1LL <<  4),
 	NM_UNMANAGED_USER_EXPLICIT = (1LL <<  5),
 	NM_UNMANAGED_USER_SETTINGS = (1LL <<  6),
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index 56b1f853..32d49916 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -229,6 +229,85 @@ vardict_from_network_type (const char *type)
 }
 
 static void
+insert_ap_from_network (GHashTable *aps, GDBusProxy *proxy, const char *path, int16_t signal, uint32_t ap_id)
+{
+	gs_unref_object GDBusProxy *network_proxy = NULL;
+	gs_unref_variant GVariant *name_value = NULL, *type_value = NULL;
+	const char *name, *type;
+	GVariantBuilder builder;
+	gs_unref_variant GVariant *props = NULL;
+	GVariant *rsn;
+	uint8_t bssid[6];
+	NMWifiAP *ap;
+	GError *error;
+
+	network_proxy = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy),
+	                                       G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+	                                       NULL,
+	                                       NM_IWD_SERVICE,
+	                                       path,
+	                                       NM_IWD_NETWORK_INTERFACE,
+	                                       NULL, &error);
+	if (!network_proxy) {
+		g_clear_error (&error);
+		return;
+	}
+
+	name_value = g_dbus_proxy_get_cached_property (network_proxy, "Name");
+	type_value = g_dbus_proxy_get_cached_property (network_proxy, "Type");
+	if (   !name_value
+	    || !g_variant_is_of_type (name_value, G_VARIANT_TYPE_STRING)
+	    || !type_value
+	    || !g_variant_is_of_type (type_value, G_VARIANT_TYPE_STRING))
+		return;
+
+	name = g_variant_get_string (name_value, NULL);
+	type = g_variant_get_string (type_value, NULL);
+
+	/* What we get from IWD are networks, or ESSs, that may contain
+	 * multiple APs, or BSSs, each.  We don't get information about any
+	 * specific BSSs within an ESS but we can safely present each ESS
+	 * as an individual BSS to NM, which will be seen as ESSs comprising
+	 * a single BSS each.  NM won't be able to handle roaming but IWD
+	 * already does that.  We fake the BSSIDs as they don't play any
+	 * role either.
+	 */
+	bssid[0] = 0x00;
+	bssid[1] = 0x01;
+	bssid[2] = 0x02;
+	bssid[3] = ap_id >> 16;
+	bssid[4] = ap_id >> 8;
+	bssid[5] = ap_id;
+
+	/* WEP not supported */
+	if (nm_streq (type, "wep"))
+		return;
+
+	g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+	g_variant_builder_add (&builder, "{sv}", "BSSID",
+	                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid, 6, 1));
+	g_variant_builder_add (&builder, "{sv}", "Mode",
+	                       g_variant_new_string ("infrastructure"));
+
+	rsn = vardict_from_network_type (type);
+	if (rsn)
+		g_variant_builder_add (&builder, "{sv}", "RSN", rsn);
+
+	props = g_variant_new ("a{sv}", &builder);
+
+	ap = nm_wifi_ap_new_from_properties (path, props);
+
+	nm_wifi_ap_set_ssid_arr (ap,
+	                         (const guint8 *) name,
+	                         NM_MIN (32, strlen (name)));
+
+	nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100));
+	nm_wifi_ap_set_freq (ap, 2417);
+	nm_wifi_ap_set_max_bitrate (ap, 65000);
+	g_hash_table_insert (aps, (gpointer) nm_wifi_ap_get_supplicant_path (ap), ap);
+}
+
+static void
 get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data)
 {
 	NMDeviceIwd *self = user_data;
@@ -242,9 +321,16 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data)
 	gboolean changed = FALSE;
 	GHashTableIter ap_iter;
 	gs_unref_hashtable GHashTable *new_aps = NULL;
+	/* Depending on whether we're using the Station interface or the Device
+	 * interface for compatibility with IWD <= 0.7, the return signature of
+	 * GetOrderedNetworks will be different.
+	 */
+	gboolean compat = priv->dbus_station_proxy == priv->dbus_device_proxy;
+	const char *return_sig = compat ? "(a(osns))" : "(a(on))";
+	static uint32_t ap_id = 0;
 
 	variant = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res,
-	                                      G_VARIANT_TYPE ("(a(osns))"),
+	                                      G_VARIANT_TYPE (return_sig),
 	                                      &error);
 	if (!variant) {
 		_LOGE (LOGD_WIFI, "Station.GetOrderedNetworks failed: %s",
@@ -254,60 +340,14 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data)
 
 	new_aps = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref);
 
-	g_variant_get (variant, "(a(osns))", &networks);
-
-	while (g_variant_iter_next (networks, "(&o&sn&s)", &path, &name, &signal, &type)) {
-		GVariantBuilder builder;
-		gs_unref_variant GVariant *props = NULL;
-		GVariant *rsn;
-		static uint32_t ap_id = 0;
-		uint8_t bssid[6];
+	g_variant_get (variant, return_sig, &networks);
 
-		/*
-		 * What we get from IWD are networks, or ESSs, that may
-		 * contain multiple APs, or BSSs, each.  We don't get
-		 * information about any specific BSSs within an ESS but
-		 * we can safely present each ESS as an individual BSS to
-		 * NM, which will be seen as ESSs comprising a single BSS
-		 * each.  NM won't be able to handle roaming but IWD already
-		 * does that.  We fake the BSSIDs as they don't play any
-		 * role either.
-		 */
-		bssid[0] = 0x00;
-		bssid[1] = 0x01;
-		bssid[2] = 0x02;
-		bssid[3] = ap_id >> 16;
-		bssid[4] = ap_id >> 8;
-		bssid[5] = ap_id++;
-
-		/* WEP not supported */
-		if (!strcmp (type, "wep"))
-			continue;
-
-		g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
-		g_variant_builder_add (&builder, "{sv}", "BSSID",
-		                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid, 6, 1));
-		g_variant_builder_add (&builder, "{sv}", "Mode",
-		                       g_variant_new_string ("infrastructure"));
-
-		rsn = vardict_from_network_type (type);
-		if (rsn)
-			g_variant_builder_add (&builder, "{sv}", "RSN", rsn);
-
-		props = g_variant_new ("a{sv}", &builder);
-
-		ap = nm_wifi_ap_new_from_properties (path, props);
-
-		nm_wifi_ap_set_ssid_arr (ap,
-		                         (const guint8 *) name,
-		                         NM_MIN (32, strlen (name)));
-
-		nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100));
-		nm_wifi_ap_set_freq (ap, 2417);
-		nm_wifi_ap_set_max_bitrate (ap, 65000);
-		g_hash_table_insert (new_aps,
-		                     (gpointer) nm_wifi_ap_get_supplicant_path (ap),
-		                     ap);
+	if (compat) {
+		while (g_variant_iter_next (networks, "(&o&sn&s)", &path, &name, &signal, &type))
+			insert_ap_from_network (new_aps, priv->dbus_station_proxy, path, signal, ap_id++);
+	} else {
+		while (g_variant_iter_next (networks, "(&on)", &path, &signal))
+			insert_ap_from_network (new_aps, priv->dbus_station_proxy, path, signal, ap_id++);
 	}
 
 	g_variant_iter_free (networks);
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 64ab82cb..ec1150bb 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -2593,6 +2593,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
 	set_current_ap (self, ap, FALSE);
 	nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req),
 	                                          nm_dbus_object_get_path (NM_DBUS_OBJECT (ap)));
+	g_object_unref (ap);
 	return NM_ACT_STAGE_RETURN_SUCCESS;
 
 done:
diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c
index 9fc7d2c1..16db8306 100644
--- a/src/dhcp/nm-dhcp-client.c
+++ b/src/dhcp/nm-dhcp-client.c
@@ -510,7 +510,8 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self,
                           GBytes *client_id,
                           const char *dhcp_anycast_addr,
                           const char *hostname,
-                          const char *last_ip4_address)
+                          const char *last_ip4_address,
+                          GError **error)
 {
 	NMDhcpClientPrivate *priv;
 
@@ -531,7 +532,10 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self,
 	g_clear_pointer (&priv->hostname, g_free);
 	priv->hostname = g_strdup (hostname);
 
-	return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address);
+	return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self,
+	                                                   dhcp_anycast_addr,
+	                                                   last_ip4_address,
+	                                                   error);
 }
 
 static GBytes *
@@ -548,7 +552,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
                           const struct in6_addr *ll_addr,
                           const char *hostname,
                           NMSettingIP6ConfigPrivacy privacy,
-                          guint needed_prefixes)
+                          guint needed_prefixes,
+                          GError **error)
 {
 	NMDhcpClientPrivate *priv;
 	gs_free char *str = NULL;
@@ -584,7 +589,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
 	                                                   ll_addr,
 	                                                   privacy,
 	                                                   priv->duid,
-	                                                   needed_prefixes);
+	                                                   needed_prefixes,
+	                                                   error);
 }
 
 void
diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h
index b50ea515..86d60e38 100644
--- a/src/dhcp/nm-dhcp-client.h
+++ b/src/dhcp/nm-dhcp-client.h
@@ -76,18 +76,18 @@ typedef enum {
 typedef struct {
 	GObjectClass parent;
 
-	/* Methods */
-
 	gboolean (*ip4_start)     (NMDhcpClient *self,
 	                           const char *anycast_addr,
-	                           const char *last_ip4_address);
+	                           const char *last_ip4_address,
+	                           GError **error);
 
 	gboolean (*ip6_start)     (NMDhcpClient *self,
 	                           const char *anycast_addr,
 	                           const struct in6_addr *ll_addr,
 	                           NMSettingIP6ConfigPrivacy privacy,
 	                           GBytes *duid,
-	                           guint needed_prefixes);
+	                           guint needed_prefixes,
+	                           GError **error);
 
 	void (*stop)              (NMDhcpClient *self,
 	                           gboolean release,
@@ -151,7 +151,8 @@ gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self,
                                    GBytes *client_id,
                                    const char *dhcp_anycast_addr,
                                    const char *hostname,
-                                   const char *last_ip4_address);
+                                   const char *last_ip4_address,
+                                   GError **error);
 
 gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self,
                                    GBytes *client_id,
@@ -160,7 +161,8 @@ gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self,
                                    const struct in6_addr *ll_addr,
                                    const char *hostname,
                                    NMSettingIP6ConfigPrivacy privacy,
-                                   guint needed_prefixes);
+                                   guint needed_prefixes,
+                                   GError **error);
 
 void nm_dhcp_client_stop (NMDhcpClient *self, gboolean release);
 
diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c
index 8408e3f9..46d2339b 100644
--- a/src/dhcp/nm-dhcp-dhclient.c
+++ b/src/dhcp/nm-dhcp-dhclient.c
@@ -174,13 +174,14 @@ merge_dhclient_config (NMDhcpDhclient *self,
                        GBytes **out_new_client_id,
                        GError **error)
 {
-	char *orig = NULL, *new;
-	gboolean success = FALSE;
+	gs_free char *orig = NULL;
+	gs_free char *new = NULL;
 
-	g_return_val_if_fail (iface != NULL, FALSE);
-	g_return_val_if_fail (conf_file != NULL, FALSE);
+	g_return_val_if_fail (iface, FALSE);
+	g_return_val_if_fail (conf_file, FALSE);
 
-	if (orig_path && g_file_test (orig_path, G_FILE_TEST_EXISTS)) {
+	if (   orig_path
+	    && g_file_test (orig_path, G_FILE_TEST_EXISTS)) {
 		GError *read_error = NULL;
 
 		if (!g_file_get_contents (orig_path, &orig, NULL, &read_error)) {
@@ -190,14 +191,22 @@ merge_dhclient_config (NMDhcpDhclient *self,
 		}
 	}
 
-	new = nm_dhcp_dhclient_create_config (iface, addr_family, client_id, anycast_addr, hostname, timeout,
-	                                      use_fqdn, orig_path, orig, out_new_client_id);
+	new = nm_dhcp_dhclient_create_config (iface,
+	                                      addr_family,
+	                                      client_id,
+	                                      anycast_addr,
+	                                      hostname,
+	                                      timeout,
+	                                      use_fqdn,
+	                                      orig_path,
+	                                      orig,
+	                                      out_new_client_id);
 	g_assert (new);
-	success = g_file_set_contents (conf_file, new, -1, error);
-	g_free (new);
-	g_free (orig);
 
-	return success;
+	return g_file_set_contents (conf_file,
+	                            new,
+	                            -1,
+	                            error);
 }
 
 static char *
@@ -282,13 +291,14 @@ create_dhclient_config (NMDhcpDhclient *self,
                         gboolean use_fqdn,
                         GBytes **out_new_client_id)
 {
-	char *orig = NULL, *new = NULL;
+	gs_free char *orig = NULL;
+	char *new = NULL;
 	GError *error = NULL;
-	gboolean success = FALSE;
 
 	g_return_val_if_fail (iface != NULL, NULL);
 
 	new = g_strdup_printf (NMSTATEDIR "/dhclient%s-%s.conf", _addr_family_to_path_part (addr_family), iface);
+
 	_LOGD ("creating composite dhclient config %s", new);
 
 	orig = find_existing_config (self, addr_family, iface, uuid);
@@ -297,15 +307,12 @@ create_dhclient_config (NMDhcpDhclient *self,
 	else
 		_LOGD ("no existing dhclient configuration to merge");
 
-	error = NULL;
-	success = merge_dhclient_config (self, addr_family, iface, new, client_id, dhcp_anycast_addr,
-	                                 hostname, timeout, use_fqdn, orig, out_new_client_id, &error);
-	if (!success) {
+	if (!merge_dhclient_config (self, addr_family, iface, new, client_id, dhcp_anycast_addr,
+	                            hostname, timeout, use_fqdn, orig, out_new_client_id, &error)) {
 		_LOGW ("error creating dhclient configuration: %s", error->message);
-		g_error_free (error);
+		g_clear_error (&error);
 	}
 
-	g_free (orig);
 	return new;
 }
 
@@ -315,13 +322,14 @@ dhclient_start (NMDhcpClient *client,
                 GBytes *duid,
                 gboolean release,
                 pid_t *out_pid,
-                int prefixes)
+                int prefixes,
+                GError **error)
 {
 	NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client);
 	NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self);
 	gs_unref_ptrarray GPtrArray *argv = NULL;
 	pid_t pid;
-	GError *error = NULL;
+	gs_free_error GError *local = NULL;
 	const char *iface;
 	const char *uuid;
 	const char *system_bus_address;
@@ -339,7 +347,7 @@ dhclient_start (NMDhcpClient *client,
 
 	dhclient_path = nm_dhcp_dhclient_get_path ();
 	if (!dhclient_path) {
-		_LOGW ("dhclient could not be found");
+		nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhclient binary not found");
 		return FALSE;
 	}
 
@@ -371,16 +379,20 @@ dhclient_start (NMDhcpClient *client,
 		gs_unref_object GFile *dst = g_file_new_for_path (preferred_leasefile_path);
 
 		/* Try to copy the existing leasefile to the preferred location */
-		if (g_file_copy (src, dst, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error)) {
-			/* Success; use the preferred leasefile path */
-			g_free (priv->lease_file);
-			priv->lease_file = g_strdup (g_file_get_path (dst));
-		} else {
+		if (!g_file_copy (src, dst, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &local)) {
+			gs_free char *s_path = NULL;
+			gs_free char *d_path = NULL;
+
 			/* Failure; just use the existing leasefile */
 			_LOGW ("failed to copy leasefile %s to %s: %s",
-			       g_file_get_path (src), g_file_get_path (dst),
-			       error->message);
-			g_clear_error (&error);
+			       (s_path = g_file_get_path (src)),
+			       (d_path = g_file_get_path (dst)),
+			       local->message);
+			g_clear_error (&local);
+		} else {
+			/* Success; use the preferred leasefile path */
+			g_free (priv->lease_file);
+			priv->lease_file = g_file_get_path (dst);
 		}
 	}
 
@@ -389,9 +401,12 @@ dhclient_start (NMDhcpClient *client,
 		gs_free char *escaped = NULL;
 
 		escaped = nm_dhcp_dhclient_escape_duid (duid);
-		if (!nm_dhcp_dhclient_save_duid (priv->lease_file, escaped, &error)) {
-			_LOGW ("failed to save DUID to %s: %s", priv->lease_file, error->message);
-			g_clear_error (&error);
+		if (!nm_dhcp_dhclient_save_duid (priv->lease_file, escaped, &local)) {
+			nm_utils_error_set (error,
+			                    NM_UTILS_ERROR_UNKNOWN,
+			                    "failed to save DUID to '%s': %s",
+			                    priv->lease_file,
+			                    local->message);
 			return FALSE;
 		}
 	}
@@ -451,9 +466,11 @@ dhclient_start (NMDhcpClient *client,
 
 	if (!g_spawn_async (NULL, (char **) argv->pdata, NULL,
 	                    G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
-	                    nm_utils_setpgid, NULL, &pid, &error)) {
-		_LOGW ("dhclient failed to start: '%s'", error->message);
-		g_error_free (error);
+	                    nm_utils_setpgid, NULL, &pid, &local)) {
+		nm_utils_error_set (error,
+		                    NM_UTILS_ERROR_UNKNOWN,
+		                    "dhclient failed to start: %s",
+		                    local->message);
 		return FALSE;
 	}
 
@@ -469,36 +486,46 @@ dhclient_start (NMDhcpClient *client,
 }
 
 static gboolean
-ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address)
+ip4_start (NMDhcpClient *client,
+           const char *dhcp_anycast_addr,
+           const char *last_ip4_address,
+           GError **error)
 {
 	NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client);
 	NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self);
 	GBytes *client_id;
 	gs_unref_bytes GBytes *new_client_id = NULL;
-	const char *iface, *uuid, *hostname;
-	guint32 timeout;
-	gboolean success = FALSE;
-	gboolean use_fqdn;
 
-	iface = nm_dhcp_client_get_iface (client);
-	uuid = nm_dhcp_client_get_uuid (client);
 	client_id = nm_dhcp_client_get_client_id (client);
-	hostname = nm_dhcp_client_get_hostname (client);
-	timeout = nm_dhcp_client_get_timeout (client);
-	use_fqdn = nm_dhcp_client_get_use_fqdn (client);
 
-	priv->conf_file = create_dhclient_config (self, AF_INET, iface, uuid, client_id, dhcp_anycast_addr,
-	                                          hostname, timeout, use_fqdn, &new_client_id);
-	if (priv->conf_file) {
-		if (new_client_id) {
-			nm_assert (!client_id);
-			nm_dhcp_client_set_client_id (client, new_client_id);
-		}
-		success = dhclient_start (client, NULL, NULL, FALSE, NULL, 0);
-	} else
-		_LOGW ("error creating dhclient configuration file");
+	priv->conf_file = create_dhclient_config (self,
+	                                          AF_INET,
+	                                          nm_dhcp_client_get_iface (client),
+	                                          nm_dhcp_client_get_uuid (client),
+	                                          client_id,
+	                                          dhcp_anycast_addr,
+	                                          nm_dhcp_client_get_hostname (client),
+	                                          nm_dhcp_client_get_timeout (client),
+	                                          nm_dhcp_client_get_use_fqdn (client),
+	                                          &new_client_id);
+	if (!priv->conf_file) {
+		nm_utils_error_set_literal (error,
+		                            NM_UTILS_ERROR_UNKNOWN,
+		                            "error creating dhclient configuration file");
+		return FALSE;
+	}
 
-	return success;
+	if (new_client_id) {
+		nm_assert (!client_id);
+		nm_dhcp_client_set_client_id (client, new_client_id);
+	}
+	return dhclient_start (client,
+	                       NULL,
+	                       NULL,
+	                       FALSE,
+	                       NULL,
+	                       0,
+	                       error);
 }
 
 static gboolean
@@ -507,22 +534,26 @@ ip6_start (NMDhcpClient *client,
            const struct in6_addr *ll_addr,
            NMSettingIP6ConfigPrivacy privacy,
            GBytes *duid,
-           guint needed_prefixes)
+           guint needed_prefixes,
+           GError **error)
 {
 	NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client);
 	NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self);
-	const char *iface, *uuid, *hostname;
-	guint32 timeout;
-
-	iface = nm_dhcp_client_get_iface (client);
-	uuid = nm_dhcp_client_get_uuid (client);
-	hostname = nm_dhcp_client_get_hostname (client);
-	timeout = nm_dhcp_client_get_timeout (client);
 
-	priv->conf_file = create_dhclient_config (self, AF_INET6, iface, uuid, NULL, dhcp_anycast_addr,
-	                                          hostname, timeout, TRUE, NULL);
+	priv->conf_file = create_dhclient_config (self,
+	                                          AF_INET6,
+	                                          nm_dhcp_client_get_iface (client),
+	                                          nm_dhcp_client_get_uuid (client),
+	                                          NULL,
+	                                          dhcp_anycast_addr,
+	                                          nm_dhcp_client_get_hostname (client),
+	                                          nm_dhcp_client_get_timeout (client),
+	                                          TRUE,
+	                                          NULL);
 	if (!priv->conf_file) {
-		_LOGW ("error creating dhclient configuration file");
+		nm_utils_error_set_literal (error,
+		                            NM_UTILS_ERROR_UNKNOWN,
+		                            "error creating dhclient configuration file");
 		return FALSE;
 	}
 
@@ -530,7 +561,11 @@ ip6_start (NMDhcpClient *client,
 	                       nm_dhcp_client_get_info_only (NM_DHCP_CLIENT (self))
 	                         ? "-S"
 	                         : "-N",
-	                       duid, FALSE, NULL, needed_prefixes);
+	                       duid,
+	                       FALSE,
+	                       NULL,
+	                       needed_prefixes,
+	                       error);
 }
 
 static void
@@ -556,7 +591,13 @@ stop (NMDhcpClient *client, gboolean release, GBytes *duid)
 	if (release) {
 		pid_t rpid = -1;
 
-		if (dhclient_start (client, NULL, duid, TRUE, &rpid, 0)) {
+		if (dhclient_start (client,
+		                    NULL,
+		                    duid,
+		                    TRUE,
+		                    &rpid,
+		                    0,
+		                    NULL)) {
 			/* Wait a few seconds for the release to happen */
 			nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client));
 		}
diff --git a/src/dhcp/nm-dhcp-dhcpcanon.c b/src/dhcp/nm-dhcp-dhcpcanon.c
index 92aa7f8c..de403020 100644
--- a/src/dhcp/nm-dhcp-dhcpcanon.c
+++ b/src/dhcp/nm-dhcp-dhcpcanon.c
@@ -82,28 +82,36 @@ dhcpcanon_start (NMDhcpClient *client,
                 GBytes *duid,
                 gboolean release,
                 pid_t *out_pid,
-                int prefixes)
+                guint needed_prefixes,
+                GError **error)
 {
 	NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client);
 	NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (self);
-	GPtrArray *argv = NULL;
+	gs_unref_ptrarray GPtrArray *argv = NULL;
 	pid_t pid;
-	GError *error = NULL;
-	const char *iface, *system_bus_address, *dhcpcanon_path = NULL;
-	char *binary_name, *cmd_str, *pid_file = NULL, *system_bus_address_env = NULL;
+	gs_free_error GError *local = NULL;
+	const char *iface;
+	const char *system_bus_address;
+	const char *dhcpcanon_path;
+	gs_free char *binary_name = NULL;
+	gs_free char *pid_file = NULL;
+	gs_free char *system_bus_address_env = NULL;
 	int addr_family;
 
-	g_return_val_if_fail (priv->pid_file == NULL, FALSE);
+	g_return_val_if_fail (!priv->pid_file, FALSE);
 
 	iface = nm_dhcp_client_get_iface (client);
+
 	addr_family = nm_dhcp_client_get_addr_family (client);
+
 	dhcpcanon_path = nm_dhcp_dhcpcanon_get_path ();
-	_LOGD ("dhcpcanon_path: %s", dhcpcanon_path);
 	if (!dhcpcanon_path) {
-		_LOGW ("dhcpcanon could not be found");
+		nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhcpcanon binary not found");
 		return FALSE;
 	}
 
+	_LOGD ("dhcpcanon_path: %s", dhcpcanon_path);
+
 	pid_file = g_strdup_printf (RUNSTATEDIR "/dhcpcanon%c-%s.pid",
 	                            nm_utils_addr_family_to_char (addr_family),
 	                            iface);
@@ -112,7 +120,6 @@ dhcpcanon_start (NMDhcpClient *client,
 	/* Kill any existing dhcpcanon from the pidfile */
 	binary_name = g_path_get_basename (dhcpcanon_path);
 	nm_dhcp_client_stop_existing (pid_file, binary_name);
-	g_free (binary_name);
 
 	argv = g_ptr_array_new ();
 	g_ptr_array_add (argv, (gpointer) dhcpcanon_path);
@@ -120,10 +127,8 @@ dhcpcanon_start (NMDhcpClient *client,
 	g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */
 	g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path);
 
-	if (pid_file) {
-		g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */
-		g_ptr_array_add (argv, (gpointer) pid_file);
-	}
+	g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */
+	g_ptr_array_add (argv, (gpointer) pid_file);
 
 	if (priv->conf_file) {
 		g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */
@@ -144,33 +149,43 @@ dhcpcanon_start (NMDhcpClient *client,
 	g_ptr_array_add (argv, (gpointer) iface);
 	g_ptr_array_add (argv, NULL);
 
-	cmd_str = g_strjoinv (" ", (char **) argv->pdata);
-	g_free (cmd_str);
-
-	if (g_spawn_async (NULL, (char **) argv->pdata, NULL,
-	                   G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
-	                   nm_utils_setpgid, NULL, &pid, &error)) {
-		 g_assert (pid > 0);
-		_LOGI ("dhcpcanon started with pid %d", pid);
-		nm_dhcp_client_watch_child (client, pid);
-		priv->pid_file = pid_file;
-	} else {
-		_LOGW ("dhcpcanon failed to start: '%s'", error->message);
-		g_error_free (error);
-		g_free (pid_file);
+	if (!g_spawn_async (NULL,
+	                   (char **) argv->pdata,
+	                   NULL,
+	                     G_SPAWN_DO_NOT_REAP_CHILD
+	                   | G_SPAWN_STDOUT_TO_DEV_NULL
+	                   | G_SPAWN_STDERR_TO_DEV_NULL,
+	                   nm_utils_setpgid,
+	                   NULL,
+	                   &pid,
+	                   &local)) {
+		nm_utils_error_set (error,
+		                    NM_UTILS_ERROR_UNKNOWN,
+		                    "dhcpcanon failed to start: %s",
+		                    local->message);
+		return FALSE;
 	}
 
-	g_ptr_array_free (argv, TRUE);
-	g_free (system_bus_address_env);
-	return pid > 0 ? TRUE : FALSE;
+	nm_assert (pid > 0);
+	_LOGI ("dhcpcanon started with pid %d", pid);
+	nm_dhcp_client_watch_child (client, pid);
+	priv->pid_file = g_steal_pointer (&pid_file);
+	return TRUE;
 }
 
 static gboolean
-ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address)
+ip4_start (NMDhcpClient *client,
+           const char *dhcp_anycast_addr,
+           const char *last_ip4_address,
+           GError **error)
 {
-	gboolean success = FALSE;
-	success = dhcpcanon_start (client, NULL, NULL, FALSE, NULL, 0);
-	return success;
+	return dhcpcanon_start (client,
+	                        NULL,
+	                        NULL,
+	                        FALSE,
+	                        NULL,
+	                        0,
+	                        error);
 }
 
 static gboolean
@@ -179,11 +194,10 @@ ip6_start (NMDhcpClient *client,
            const struct in6_addr *ll_addr,
            NMSettingIP6ConfigPrivacy privacy,
            GBytes *duid,
-           guint needed_prefixes)
+           guint needed_prefixes,
+           GError **error)
 {
-	NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client);
-
-	_LOGW ("the dhcpcd backend does not support IPv6");
+	nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhcpcanon plugin does not support IPv6");
 	return FALSE;
 }
 static void
diff --git a/src/dhcp/nm-dhcp-dhcpcd.c b/src/dhcp/nm-dhcp-dhcpcd.c
index 10094e5c..98ab5342 100644
--- a/src/dhcp/nm-dhcp-dhcpcd.c
+++ b/src/dhcp/nm-dhcp-dhcpcd.c
@@ -81,15 +81,21 @@ nm_dhcp_dhcpcd_get_path (void)
 }
 
 static gboolean
-ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address)
+ip4_start (NMDhcpClient *client,
+           const char *dhcp_anycast_addr,
+           const char *last_ip4_address,
+           GError **error)
 {
 	NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client);
 	NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (self);
-	GPtrArray *argv = NULL;
+	gs_unref_ptrarray GPtrArray *argv = NULL;
 	pid_t pid = -1;
-	GError *error = NULL;
-	char *pid_contents = NULL, *binary_name, *cmd_str;
-	const char *iface, *dhcpcd_path, *hostname;
+	GError *local = NULL;
+	gs_free char *cmd_str = NULL;
+	gs_free char *binary_name = NULL;
+	const char *iface;
+	const char *dhcpcd_path;
+	const char *hostname;
 
 	g_return_val_if_fail (priv->pid_file == NULL, FALSE);
 
@@ -102,14 +108,13 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
 
 	dhcpcd_path = nm_dhcp_dhcpcd_get_path ();
 	if (!dhcpcd_path) {
-		_LOGW ("dhcpcd could not be found");
+		nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhcpcd binary not found");
 		return FALSE;
 	}
 
 	/* Kill any existing dhcpcd from the pidfile */
 	binary_name = g_path_get_basename (dhcpcd_path);
 	nm_dhcp_client_stop_existing (priv->pid_file, binary_name);
-	g_free (binary_name);
 
 	argv = g_ptr_array_new ();
 	g_ptr_array_add (argv, (gpointer) dhcpcd_path);
@@ -128,13 +133,11 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
 	g_ptr_array_add (argv, (gpointer) "-c");    /* Set script file */
 	g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path);
 
-#ifdef DHCPCD_SUPPORTS_IPV6
 	/* IPv4-only for now.  NetworkManager knows better than dhcpcd when to
 	 * run IPv6, and dhcpcd's automatic Router Solicitations cause problems
 	 * with devices that don't expect them.
 	 */
 	g_ptr_array_add (argv, (gpointer) "-4");
-#endif
 
 	hostname = nm_dhcp_client_get_hostname (client);
 
@@ -153,24 +156,30 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
 	g_ptr_array_add (argv, (gpointer) iface);
 	g_ptr_array_add (argv, NULL);
 
-	cmd_str = g_strjoinv (" ", (char **) argv->pdata);
-	_LOGD ("running: %s", cmd_str);
-	g_free (cmd_str);
-
-	if (g_spawn_async (NULL, (char **) argv->pdata, NULL,
-	                   G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
-	                   nm_utils_setpgid, NULL, &pid, &error)) {
-		g_assert (pid > 0);
-		_LOGI ("dhcpcd started with pid %d", pid);
-		nm_dhcp_client_watch_child (client, pid);
-	} else {
-		_LOGW ("dhcpcd failed to start, error: '%s'", error->message);
-		g_error_free (error);
+	_LOGD ("running: %s",
+	       (cmd_str = g_strjoinv (" ", (char **) argv->pdata)));
+
+	if (!g_spawn_async (NULL,
+	                    (char **) argv->pdata, NULL,
+	                      G_SPAWN_DO_NOT_REAP_CHILD
+	                    | G_SPAWN_STDOUT_TO_DEV_NULL
+	                    | G_SPAWN_STDERR_TO_DEV_NULL,
+	                    nm_utils_setpgid,
+	                    NULL,
+	                    &pid,
+	                    &local)) {
+		nm_utils_error_set (error,
+		                    NM_UTILS_ERROR_UNKNOWN,
+		                    "dhcpcd failed to start: %s",
+		                    local->message);
+		g_error_free (local);
+		return FALSE;
 	}
 
-	g_free (pid_contents);
-	g_ptr_array_free (argv, TRUE);
-	return pid > 0 ? TRUE : FALSE;
+	nm_assert (pid > 0);
+	_LOGI ("dhcpcd started with pid %d", pid);
+	nm_dhcp_client_watch_child (client, pid);
+	return TRUE;
 }
 
 static gboolean
@@ -179,11 +188,10 @@ ip6_start (NMDhcpClient *client,
            const struct in6_addr *ll_addr,
            NMSettingIP6ConfigPrivacy privacy,
            GBytes *duid,
-           guint needed_prefixes)
+           guint needed_prefixes,
+           GError **error)
 {
-	NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client);
-
-	_LOGW ("the dhcpcd backend does not support IPv6");
+	nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhcpcd plugin does not support IPv6");
 	return FALSE;
 }
 
diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c
index 67254323..6c71af9d 100644
--- a/src/dhcp/nm-dhcp-manager.c
+++ b/src/dhcp/nm-dhcp-manager.c
@@ -172,22 +172,39 @@ client_start (NMDhcpManager *self,
               gboolean info_only,
               NMSettingIP6ConfigPrivacy privacy,
               const char *last_ip4_address,
-              guint needed_prefixes)
+              guint needed_prefixes,
+              GError **error)
 {
 	NMDhcpManagerPrivate *priv;
 	NMDhcpClient *client;
 	gboolean success = FALSE;
+	gsize hwaddr_len;
 
-	g_return_val_if_fail (self, NULL);
 	g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
 	g_return_val_if_fail (ifindex > 0, NULL);
 	g_return_val_if_fail (uuid != NULL, NULL);
 	g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL);
+	g_return_val_if_fail (!error || !*error, NULL);
+
+	if (!hwaddr) {
+		nm_utils_error_set (error,
+		                    NM_UTILS_ERROR_UNKNOWN,
+		                    "missing MAC address");
+		return NULL;
+	}
+
+	hwaddr_len = g_bytes_get_size (hwaddr);
+	if (   hwaddr_len == 0
+	    || hwaddr_len > NM_UTILS_HWADDR_LEN_MAX) {
+		nm_utils_error_set (error,
+		                    NM_UTILS_ERROR_UNKNOWN,
+		                    "invalid MAC address");
+		g_return_val_if_reached (NULL) ;
+	}
 
 	priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
 
-	if (!priv->client_factory)
-		return NULL;
+	nm_assert (priv->client_factory);
 
 	/* Kill any old client instance */
 	client = get_client_for_ifindex (self, addr_family, ifindex);
@@ -216,10 +233,24 @@ client_start (NMDhcpManager *self,
 	c_list_link_tail (&priv->dhcp_client_lst_head, &client->dhcp_client_lst);
 	g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self);
 
-	if (addr_family == AF_INET)
-		success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address);
-	else
-		success = nm_dhcp_client_start_ip6 (client, dhcp_client_id, enforce_duid, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes);
+	if (addr_family == AF_INET) {
+		success = nm_dhcp_client_start_ip4 (client,
+		                                    dhcp_client_id,
+		                                    dhcp_anycast_addr,
+		                                    hostname,
+		                                    last_ip4_address,
+		                                    error);
+	} else {
+		success = nm_dhcp_client_start_ip6 (client,
+		                                    dhcp_client_id,
+		                                    enforce_duid,
+		                                    dhcp_anycast_addr,
+		                                    ipv6_ll_addr,
+		                                    hostname,
+		                                    privacy,
+		                                    needed_prefixes,
+		                                    error);
+	}
 
 	if (!success) {
 		remove_client_unref (self, client);
@@ -245,7 +276,8 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
                            GBytes *dhcp_client_id,
                            guint32 timeout,
                            const char *dhcp_anycast_addr,
-                           const char *last_ip_address)
+                           const char *last_ip_address,
+                           GError **error)
 {
 	NMDhcpManagerPrivate *priv;
 	const char *hostname = NULL;
@@ -282,7 +314,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
 	return client_start (self, AF_INET, multi_idx, iface, ifindex, hwaddr, uuid,
 	                     route_table, route_metric, NULL,
 	                     dhcp_client_id, 0, timeout, dhcp_anycast_addr, hostname,
-	                     use_fqdn, FALSE, 0, last_ip_address, 0);
+	                     use_fqdn, FALSE, 0, last_ip_address, 0, error);
 }
 
 /* Caller owns a reference to the NMDhcpClient on return */
@@ -304,7 +336,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
                            const char *dhcp_anycast_addr,
                            gboolean info_only,
                            NMSettingIP6ConfigPrivacy privacy,
-                           guint needed_prefixes)
+                           guint needed_prefixes,
+                           GError **error)
 {
 	NMDhcpManagerPrivate *priv;
 	const char *hostname = NULL;
@@ -319,7 +352,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
 	return client_start (self, AF_INET6, multi_idx, iface, ifindex, hwaddr, uuid,
 	                     route_table, route_metric, ll_addr, duid, enforce_duid,
 	                     timeout, dhcp_anycast_addr, hostname, TRUE, info_only,
-	                     privacy, NULL, needed_prefixes);
+	                     privacy, NULL, needed_prefixes, error);
 }
 
 void
@@ -409,7 +442,7 @@ nm_dhcp_manager_init (NMDhcpManager *self)
 		}
 	}
 
-	nm_assert (client_factory);
+	g_return_if_fail (client_factory);
 
 	nm_log_info (LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name);
 
diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h
index 7eb32c37..1d9e5c21 100644
--- a/src/dhcp/nm-dhcp-manager.h
+++ b/src/dhcp/nm-dhcp-manager.h
@@ -59,7 +59,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip4     (NMDhcpManager *manager,
                                               GBytes *dhcp_client_id,
                                               guint32 timeout,
                                               const char *dhcp_anycast_addr,
-                                              const char *last_ip_address);
+                                              const char *last_ip_address,
+                                              GError **error);
 
 NMDhcpClient * nm_dhcp_manager_start_ip6     (NMDhcpManager *manager,
                                               struct _NMDedupMultiIndex *multi_idx,
@@ -78,7 +79,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6     (NMDhcpManager *manager,
                                               const char *dhcp_anycast_addr,
                                               gboolean info_only,
                                               NMSettingIP6ConfigPrivacy privacy,
-                                              guint needed_prefixes);
+                                              guint needed_prefixes,
+                                              GError **error);
 
 /* For testing only */
 extern const char* nm_dhcp_helper_path;
diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c
index 2d0202bb..b51c6e7b 100644
--- a/src/dhcp/nm-dhcp-systemd.c
+++ b/src/dhcp/nm-dhcp-systemd.c
@@ -567,7 +567,10 @@ get_arp_type (GBytes *hwaddr)
 }
 
 static gboolean
-ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address)
+ip4_start (NMDhcpClient *client,
+           const char *dhcp_anycast_addr,
+           const char *last_ip4_address,
+           GError **error)
 {
 	NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client);
 	NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
@@ -590,7 +593,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
 
 	r = sd_dhcp_client_new (&priv->client4, FALSE);
 	if (r < 0) {
-		_LOGW ("failed to create client (%d)", r);
+		nm_utils_error_set_errno (error, r, "failed to create dhcp-client: %s");
 		return FALSE;
 	}
 
@@ -598,8 +601,8 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
 
 	r = sd_dhcp_client_attach_event (priv->client4, NULL, 0);
 	if (r < 0) {
-		_LOGW ("failed to attach event (%d)", r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to attach event: %s");
+		goto errout;
 	}
 
 	hwaddr = nm_dhcp_client_get_hw_addr (client);
@@ -613,21 +616,21 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
 		                            len,
 		                            get_arp_type (hwaddr));
 		if (r < 0) {
-			_LOGW ("failed to set MAC address (%d)", r);
-			goto error;
+			nm_utils_error_set_errno (error, r, "failed to set MAC address: %s");
+			goto errout;
 		}
 	}
 
 	r = sd_dhcp_client_set_ifindex (priv->client4, nm_dhcp_client_get_ifindex (client));
 	if (r < 0) {
-		_LOGW ("failed to set ififindex (%d)", r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to set ifindex: %s");
+		goto errout;
 	}
 
 	r = sd_dhcp_client_set_callback (priv->client4, dhcp_event_cb, client);
 	if (r < 0) {
-		_LOGW ("failed to set callback (%d)", r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to set callback: %s");
+		goto errout;
 	}
 
 	dhcp_lease_load (&lease, priv->lease_file);
@@ -640,8 +643,8 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
 	if (last_addr.s_addr) {
 		r = sd_dhcp_client_set_request_address (priv->client4, &last_addr);
 		if (r < 0) {
-			_LOGW ("failed to set last IPv4 address (%d)", r);
-			goto error;
+			nm_utils_error_set_errno (error, r, "failed to set last IPv4 address: %s");
+			goto errout;
 		}
 	}
 
@@ -681,25 +684,25 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
 		 */
 		r = sd_dhcp_client_set_hostname (priv->client4, hostname);
 		if (r < 0) {
-			_LOGW ("failed to set DHCP hostname to '%s' (%d)", hostname, r);
-			goto error;
+			nm_utils_error_set_errno (error, r, "failed to set DHCP hostname: %s");
+			goto errout;
 		}
 	}
 
 	r = sd_dhcp_client_start (priv->client4);
 	if (r < 0) {
-		_LOGW ("failed to start client (%d)", r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to start DHCP client: %s");
+		goto errout;
 	}
 
 	nm_dhcp_client_start_timeout (client);
 
 	success = TRUE;
 
-error:
+errout:
 	sd_dhcp_lease_unref (lease);
 	if (!success)
-		priv->client4 = sd_dhcp_client_unref (priv->client4);
+		sd_dhcp_client_unref (g_steal_pointer (&priv->client4));
 	return success;
 }
 
@@ -864,7 +867,8 @@ ip6_start (NMDhcpClient *client,
            const struct in6_addr *ll_addr,
            NMSettingIP6ConfigPrivacy privacy,
            GBytes *duid,
-           guint needed_prefixes)
+           guint needed_prefixes,
+           GError **error)
 {
 	NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client);
 	NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
@@ -888,7 +892,7 @@ ip6_start (NMDhcpClient *client,
 
 	r = sd_dhcp6_client_new (&priv->client6);
 	if (r < 0) {
-		_LOGW ("failed to create client (%d)", r);
+		nm_utils_error_set_errno (error, r, "failed to create dhcp-client: %s");
 		return FALSE;
 	}
 
@@ -907,14 +911,14 @@ ip6_start (NMDhcpClient *client,
 	                              &duid_arr[2],
 	                              duid_len - 2);
 	if (r < 0) {
-		_LOGW ("failed to set DUID (%d)", r);
+		nm_utils_error_set_errno (error, r, "failed to set DUID: %s");
 		return FALSE;
 	}
 
 	r = sd_dhcp6_client_attach_event (priv->client6, NULL, 0);
 	if (r < 0) {
-		_LOGW ("failed to attach event (%d)", r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to attach event: %s");
+		goto errout;
 	}
 
 	hwaddr = nm_dhcp_client_get_hw_addr (client);
@@ -928,21 +932,21 @@ ip6_start (NMDhcpClient *client,
 		                             len,
 		                             get_arp_type (hwaddr));
 		if (r < 0) {
-			_LOGW ("failed to set MAC address (%d)", r);
-			goto error;
+			nm_utils_error_set_errno (error, r, "failed to set MAC address: %s");
+			goto errout;
 		}
 	}
 
 	r = sd_dhcp6_client_set_ifindex (priv->client6, nm_dhcp_client_get_ifindex (client));
 	if (r < 0) {
-		_LOGW ("failed to set ifindex (%d)", r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to set ifindex: %s");
+		goto errout;
 	}
 
 	r = sd_dhcp6_client_set_callback (priv->client6, dhcp6_event_cb, client);
 	if (r < 0) {
-		_LOGW ("failed to set callback (%d)", r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to set callback: %s");
+		goto errout;
 	}
 
 	/* Add requested options */
@@ -953,30 +957,29 @@ ip6_start (NMDhcpClient *client,
 
 	r = sd_dhcp6_client_set_local_address (priv->client6, ll_addr);
 	if (r < 0) {
-		_LOGW ("failed to set local address (%d)", r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to set local address: %s");
+		goto errout;
 	}
 
 	hostname = nm_dhcp_client_get_hostname (client);
 	r = sd_dhcp6_client_set_fqdn (priv->client6, hostname);
 	if (r < 0) {
-		_LOGW ("failed to set DHCP hostname to '%s' (%d)", hostname, r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to set DHCP hostname: %s");
+		goto errout;
 	}
 
 	r = sd_dhcp6_client_start (priv->client6);
 	if (r < 0) {
-		_LOGW ("failed to start client (%d)", r);
-		goto error;
+		nm_utils_error_set_errno (error, r, "failed to start client: %s");
+		goto errout;
 	}
 
 	nm_dhcp_client_start_timeout (client);
 
 	return TRUE;
 
-error:
-	sd_dhcp6_client_unref (priv->client6);
-	priv->client6 = NULL;
+errout:
+	sd_dhcp6_client_unref (g_steal_pointer (&priv->client6));
 	return FALSE;
 }
 
diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c
index 90a08d59..cb7a626c 100644
--- a/src/dns/nm-dns-dnsmasq.c
+++ b/src/dns/nm-dns-dnsmasq.c
@@ -183,10 +183,12 @@ add_ip_config (NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfig
 			                        domain[0] ? domain : NULL);
 		}
 
-		for (j = 0; ip_data->domains.reverse[j]; j++) {
-			add_dnsmasq_nameserver (self, servers,
-			                        ip_addr_to_string_buf,
-			                        ip_data->domains.reverse[j]);
+		if (ip_data->domains.reverse) {
+			for (j = 0; ip_data->domains.reverse[j]; j++) {
+				add_dnsmasq_nameserver (self, servers,
+				                        ip_addr_to_string_buf,
+				                        ip_data->domains.reverse[j]);
+			}
 		}
 	}
 }
diff --git a/src/dns/nm-dns-unbound.c b/src/dns/nm-dns-unbound.c
index e06128aa..b900f29e 100644
--- a/src/dns/nm-dns-unbound.c
+++ b/src/dns/nm-dns-unbound.c
@@ -43,7 +43,7 @@ update (NMDnsPlugin *plugin,
         const CList *ip_config_lst_head,
         const char *hostname)
 {
-	char *argv[] = { DNSSEC_TRIGGER_SCRIPT, "--async", "--update", NULL };
+	char *argv[] = { DNSSEC_TRIGGER_PATH, "--async", "--update", NULL };
 	int status;
 
 	/* TODO: We currently call a script installed with the dnssec-trigger
diff --git a/src/meson.build b/src/meson.build
index 83fc3eac..f46366a9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -143,7 +143,7 @@ sources = files(
   'nm-sleep-monitor.c'
 )
 
-deps = [
+nm_deps = [
   dl_dep,
   libndp_dep,
   libudev_dep,
@@ -153,70 +153,29 @@ deps = [
 ]
 
 if enable_concheck
-  deps += libcurl_dep
+  nm_deps += libcurl_dep
 endif
 
 if enable_libaudit
-  deps += libaudit_dep
+  nm_deps += libaudit_dep
 endif
 
 if enable_libpsl
-  deps += libpsl_dep
+  nm_deps += libpsl_dep
 endif
 
 if enable_selinux
-  deps += selinux_dep
+  nm_deps += selinux_dep
 endif
 
 libnetwork_manager = static_library(
   nm_name,
   sources: sources,
-  dependencies: deps,
+  dependencies: nm_deps,
   c_args: cflags,
   link_with: [libnetwork_manager_base, libsystemd_nm]
 )
 
-ldflags = ['-rdynamic']
-
-# FIXME: this doesn't work and it depends on libtool
-'''
-src/NetworkManager.ver: src/libNetworkManager.la $(core_plugins)
-  $(AM_V_GEN) NM="$(NM)" "$(srcdir)/tools/create-exports-NetworkManager.sh" --called-from-make "$(srcdir)"
-
-src_NetworkManager_LDFLAGS = \
-  -rdynamic \
-  -Wl,--version-script="src/NetworkManager.ver"
-
-nm = find_program('gcc-nm', 'nm')
-create_exports_networkmanager = join_paths(meson.source_root(), 'tools', 'create-exports-NetworkManager.sh')
-
-symbol_map_name = 'NetworkManager.ver'
-
-linker_script = custom_target(
-  symbol_map_name,
-  input: meson.source_root(),
-  output: symbol_map_name,
-  capture: true,
-  #command: ['NM=' + nm.path(), create_exports_networkmanager, '--called-from-make', '@INPUT@']
-  command: [create_exports_networkmanager, '--called-from-make', '@INPUT@']
-)
-
-ldflags += '-Wl,--version-script,@0@'.format(linker_script)
-'''
-
-network_manager = executable(
-  nm_name,
-  'main.c',
-  dependencies: deps,
-  c_args: cflags,
-  link_with: libnetwork_manager,
-  link_args: ldflags,
-  #FIXME
-  #link_depends: linker_script,
-  install: true,
-  install_dir: nm_sbindir
-)
-
 deps = [
   dl_dep,
   libndp_dep,
@@ -287,3 +246,30 @@ endif
 
 subdir('devices')
 subdir('settings/plugins')
+
+# NetworkManager binary
+
+create_exports_networkmanager = join_paths(meson.source_root(), 'tools', 'create-exports-NetworkManager.sh')
+symbol_map_name = 'NetworkManager.ver'
+
+ver_script = custom_target(
+  symbol_map_name,
+  input: meson.source_root(),
+  output: symbol_map_name,
+  depends: [ libnetwork_manager, core_plugins ],
+  command: [create_exports_networkmanager, '--called-from-build', '@INPUT@']
+)
+
+ldflags = ['-rdynamic', '-Wl,--version-script,@0@'.format(ver_script.full_path())]
+
+network_manager = executable(
+  nm_name,
+  'main.c',
+  dependencies: nm_deps,
+  c_args: nm_cflags,
+  link_with: libnetwork_manager,
+  link_args: ldflags,
+  link_depends: ver_script,
+  install: true,
+  install_dir: nm_sbindir
+)
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 308c9e1f..805c6e4f 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -380,7 +380,7 @@ int
 main (int argc, char *argv[])
 {
 	char *bad_domains = NULL;
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 	gboolean wrote_pidfile = FALSE;
 	gs_free char *pidfile = NULL;
 	gs_unref_object NMDhcpClient *dhcp4_client = NULL;
@@ -516,8 +516,11 @@ main (int argc, char *argv[])
 		                                          client_id,
 		                                          NM_DHCP_TIMEOUT_DEFAULT,
 		                                          NULL,
-		                                          global_opt.dhcp4_address);
-		g_assert (dhcp4_client);
+		                                          global_opt.dhcp4_address,
+		                                          &error);
+		if (!dhcp4_client)
+			g_error ("failure to start DHCP: %s", error->message);
+
 		g_signal_connect (dhcp4_client,
 		                  NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
 		                  G_CALLBACK (dhcp4_state_changed),
diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c
index fa8a812c..3e2ad911 100644
--- a/src/platform/nm-netlink.c
+++ b/src/platform/nm-netlink.c
@@ -83,18 +83,18 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int,
 )
 
 const char *
-nl_geterror (int err)
+nl_geterror (int nlerr)
 {
 	const char *s;
 
-	err = nl_errno (err);
+	nlerr = nl_errno (nlerr);
 
-	if (err >= _NLE_BASE) {
-		s = _geterror (err);
+	if (nlerr >= _NLE_BASE) {
+		s = _geterror (nlerr);
 		if (s)
 			return s;
 	}
-	return g_strerror (err);
+	return g_strerror (nlerr);
 }
 
 /*****************************************************************************/
@@ -251,7 +251,7 @@ nlmsg_reserve (struct nl_msg *n, size_t len, int pad)
 	n->nm_nlh->nlmsg_len += tlen;
 
 	if (tlen > len)
-		memset(buf + len, 0, tlen - len);
+		memset (buf + len, 0, tlen - len);
 
 	return buf;
 }
@@ -267,17 +267,17 @@ nla_reserve (struct nl_msg *msg, int attrtype, int attrlen)
 	if (attrlen < 0)
 		return NULL;
 
-	tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
+	tlen = NLMSG_ALIGN (msg->nm_nlh->nlmsg_len) + nla_total_size (attrlen);
 
 	if (tlen > msg->nm_size)
 		return NULL;
 
-	nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
+	nla = (struct nlattr *) nlmsg_tail (msg->nm_nlh);
 	nla->nla_type = attrtype;
-	nla->nla_len = nla_attr_size(attrlen);
+	nla->nla_len = nla_attr_size (attrlen);
 
 	if (attrlen)
-		memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
+		memset ((unsigned char *) nla + nla->nla_len, 0, nla_padlen (attrlen));
 	msg->nm_nlh->nlmsg_len = tlen;
 
 	return nla;
@@ -337,7 +337,7 @@ nlmsg_alloc_convert (struct nlmsghdr *hdr)
 	struct nl_msg *nm;
 
 	nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len));
-	memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
+	memcpy (nm->nm_nlh, hdr, hdr->nlmsg_len);
 	return nm;
 }
 
@@ -374,7 +374,7 @@ nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad)
 	if (tmp == NULL)
 		return -ENOMEM;
 
-	memcpy(tmp, data, len);
+	memcpy (tmp, data, len);
 	return 0;
 }
 
@@ -384,11 +384,11 @@ int
 nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
              int maxtype, const struct nla_policy *policy)
 {
-	if (!nlmsg_valid_hdr(nlh, hdrlen))
+	if (!nlmsg_valid_hdr (nlh, hdrlen))
 		return -NLE_MSG_TOOSHORT;
 
-	return nla_parse (tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
-	                  nlmsg_attrlen(nlh, hdrlen), policy);
+	return nla_parse (tb, maxtype, nlmsg_attrdata (nlh, hdrlen),
+	                  nlmsg_attrlen (nlh, hdrlen), policy);
 }
 
 struct nlmsghdr *
@@ -406,8 +406,8 @@ nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq,
 	nlh->nlmsg_pid = pid;
 	nlh->nlmsg_seq = seq;
 
-	if (payload > 0 &&
-	    nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
+	if (   payload > 0
+	    && nlmsg_reserve (n, payload, NLMSG_ALIGNTO) == NULL)
 		return NULL;
 
 	return nlh;
@@ -418,8 +418,8 @@ nla_get_u64 (const struct nlattr *nla)
 {
 	uint64_t tmp = 0;
 
-	if (nla && nla_len(nla) >= sizeof (tmp))
-		memcpy(&tmp, nla_data(nla), sizeof (tmp));
+	if (nla && nla_len (nla) >= sizeof (tmp))
+		memcpy (&tmp, nla_data (nla), sizeof (tmp));
 
 	return tmp;
 }
@@ -427,8 +427,8 @@ nla_get_u64 (const struct nlattr *nla)
 size_t
 nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize)
 {
-	size_t srclen = nla_len(nla);
-	const char *src = nla_data(nla);
+	size_t srclen = nla_len (nla);
+	const char *src = nla_data (nla);
 
 	if (srclen > 0 && src[srclen - 1] == '\0')
 		srclen--;
@@ -436,8 +436,8 @@ nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize)
 	if (dstsize > 0) {
 		size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
 
-		memset(dst, 0, dstsize);
-		memcpy(dst, src, len);
+		memset (dst, 0, dstsize);
+		memcpy (dst, src, len);
 	}
 
 	return srclen;
@@ -452,7 +452,7 @@ nla_memcpy (void *dest, const struct nlattr *src, int count)
 		return 0;
 
 	minlen = NM_MIN (count, (int) nla_len (src));
-	memcpy(dest, nla_data(src), minlen);
+	memcpy (dest, nla_data (src), minlen);
 
 	return minlen;
 }
@@ -462,7 +462,7 @@ nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data)
 {
 	struct nlattr *nla;
 
-	nla = nla_reserve(msg, attrtype, datalen);
+	nla = nla_reserve (msg, attrtype, datalen);
 	if (!nla) {
 		if (datalen < 0)
 			g_return_val_if_reached (-NLE_BUG);
@@ -471,7 +471,7 @@ nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data)
 	}
 
 	if (datalen > 0)
-		memcpy (nla_data(nla), data, datalen);
+		memcpy (nla_data (nla), data, datalen);
 
 	return 0;
 }
@@ -495,21 +495,21 @@ nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr)
 {
 	ssize_t len;
 
-	len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) attr;
+	len = (char *) nlmsg_tail (msg->nm_nlh) - (char *) attr;
 	if (len < 0)
 		g_return_if_reached ();
 	else if (len > 0) {
 		msg->nm_nlh->nlmsg_len -= len;
-		memset(nlmsg_tail(msg->nm_nlh), 0, len);
+		memset (nlmsg_tail (msg->nm_nlh), 0, len);
 	}
 }
 
 struct nlattr *
 nla_nest_start (struct nl_msg *msg, int attrtype)
 {
-	struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
+	struct nlattr *start = (struct nlattr *) nlmsg_tail (msg->nm_nlh);
 
-	if (nla_put(msg, attrtype, 0, NULL) < 0)
+	if (nla_put (msg, attrtype, 0, NULL) < 0)
 		return NULL;
 
 	return start;
@@ -520,7 +520,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty)
 {
 	size_t pad, len;
 
-	len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start;
+	len = (char *) nlmsg_tail (msg->nm_nlh) - (char *) start;
 
 	if (   len > USHRT_MAX
 	    || (!keep_empty && len == NLA_HDRLEN)) {
@@ -528,7 +528,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty)
 		 * Max nlattr size exceeded or empty nested attribute, trim the
 		 * attribute header again
 		 */
-		nla_nest_cancel(msg, start);
+		nla_nest_cancel (msg, start);
 
 		/* Return error only if nlattr size was exceeded */
 		return (len == NLA_HDRLEN) ? 0 : -NLE_ATTRSIZE;
@@ -536,7 +536,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty)
 
 	start->nla_len = len;
 
-	pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len;
+	pad = NLMSG_ALIGN (msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len;
 	if (pad > 0) {
 		/*
 		 * Data inside attribute does not end at a alignment boundry.
@@ -544,7 +544,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty)
 		 * the message. nlmsg_reserve() may never fail in this situation,
 		 * the allocate message buffer must be a multiple of NLMSG_ALIGNTO.
 		 */
-		if (!nlmsg_reserve(msg, pad, 0))
+		if (!nlmsg_reserve (msg, pad, 0))
 			g_return_val_if_reached (-NLE_BUG);
 	}
 
@@ -572,7 +572,7 @@ validate_nla (const struct nlattr *nla, int maxtype,
 {
 	const struct nla_policy *pt;
 	unsigned int minlen = 0;
-	int type = nla_type(nla);
+	int type = nla_type (nla);
 
 	if (type < 0 || type > maxtype)
 		return 0;
@@ -587,15 +587,15 @@ validate_nla (const struct nlattr *nla, int maxtype,
 	else if (pt->type != NLA_UNSPEC)
 		minlen = nla_attr_minlen[pt->type];
 
-	if (nla_len(nla) < minlen)
+	if (nla_len (nla) < minlen)
 		return -NLE_UNSPEC;
 
-	if (pt->maxlen && nla_len(nla) > pt->maxlen)
+	if (pt->maxlen && nla_len (nla) > pt->maxlen)
 		return -NLE_UNSPEC;
 
 	if (pt->type == NLA_STRING) {
-		const char *data = nla_data(nla);
-		if (data[nla_len(nla) - 1] != '\0')
+		const char *data = nla_data (nla);
+		if (data[nla_len (nla) - 1] != '\0')
 			return -NLE_UNSPEC;
 	}
 
@@ -607,28 +607,28 @@ nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
            const struct nla_policy *policy)
 {
 	struct nlattr *nla;
-	int rem, err;
+	int rem, nlerr;
 
-	memset(tb, 0, sizeof (struct nlattr *) * (maxtype + 1));
+	memset (tb, 0, sizeof (struct nlattr *) * (maxtype + 1));
 
-	nla_for_each_attr(nla, head, len, rem) {
-		int type = nla_type(nla);
+	nla_for_each_attr (nla, head, len, rem) {
+		int type = nla_type (nla);
 
 		if (type > maxtype)
 			continue;
 
 		if (policy) {
-			err = validate_nla(nla, maxtype, policy);
-			if (err < 0)
+			nlerr = validate_nla (nla, maxtype, policy);
+			if (nlerr < 0)
 				goto errout;
 		}
 
 		tb[type] = nla;
 	}
 
-	err = 0;
+	nlerr = 0;
 errout:
-	return err;
+	return nlerr;
 }
 
 /*****************************************************************************/
@@ -839,7 +839,7 @@ nl_socket_alloc (void)
 	sk->s_fd = -1;
 	sk->s_local.nl_family = AF_NETLINK;
 	sk->s_peer.nl_family = AF_NETLINK;
-	sk->s_seq_expect = sk->s_seq_next = time(NULL);
+	sk->s_seq_expect = sk->s_seq_next = time (NULL);
 
 	return sk;
 }
@@ -914,7 +914,7 @@ nl_socket_set_nonblocking (const struct nl_sock *sk)
 	if (sk->s_fd == -1)
 		return -NLE_BAD_SOCK;
 
-	if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
+	if (fcntl (sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
 		return -nl_syserr2nlerr (errno);
 
 	return 0;
@@ -958,25 +958,27 @@ nl_socket_add_memberships (struct nl_sock *sk, int group, ...)
 	if (sk->s_fd == -1)
 		return -NLE_BAD_SOCK;
 
-	va_start(ap, group);
+	va_start (ap, group);
 
 	while (group != 0) {
 		if (group < 0) {
-			va_end(ap);
+			va_end (ap);
 			g_return_val_if_reached (-NLE_BUG);
 		}
 
 		err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
 		                  &group, sizeof (group));
 		if (err < 0) {
-			va_end(ap);
-			return -nl_syserr2nlerr (errno);
+			int errsv = errno;
+
+			va_end (ap);
+			return -nl_syserr2nlerr (errsv);
 		}
 
-		group = va_arg(ap, int);
+		group = va_arg (ap, int);
 	}
 
-	va_end(ap);
+	va_end (ap);
 
 	return 0;
 }
@@ -1006,7 +1008,7 @@ void nl_socket_disable_msg_peek (struct nl_sock *sk)
 int
 nl_connect (struct nl_sock *sk, int protocol)
 {
-	int err;
+	int err, nlerr;
 	socklen_t addrlen;
 	struct sockaddr_nl local = { 0 };
 
@@ -1015,12 +1017,12 @@ nl_connect (struct nl_sock *sk, int protocol)
 
 	sk->s_fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
 	if (sk->s_fd < 0) {
-		err = -nl_syserr2nlerr (errno);
+		nlerr = -nl_syserr2nlerr (errno);
 		goto errout;
 	}
 
-	err = nl_socket_set_buffer_size(sk, 0, 0);
-	if (err < 0)
+	nlerr = nl_socket_set_buffer_size (sk, 0, 0);
+	if (nlerr < 0)
 		goto errout;
 
 	nm_assert (sk->s_local.nl_pid == 0);
@@ -1028,7 +1030,7 @@ nl_connect (struct nl_sock *sk, int protocol)
 	err = bind (sk->s_fd, (struct sockaddr*) &sk->s_local,
 	            sizeof (sk->s_local));
 	if (err != 0) {
-		err = -nl_syserr2nlerr (errno);
+		nlerr = -nl_syserr2nlerr (errno);
 		goto errout;
 	}
 
@@ -1036,17 +1038,17 @@ nl_connect (struct nl_sock *sk, int protocol)
 	err = getsockname (sk->s_fd, (struct sockaddr *) &local,
 	                   &addrlen);
 	if (err < 0) {
-		err = -nl_syserr2nlerr (errno);
+		nlerr = -nl_syserr2nlerr (errno);
 		goto errout;
 	}
 
 	if (addrlen != sizeof (local)) {
-		err = -NLE_UNSPEC;
+		nlerr = -NLE_UNSPEC;
 		goto errout;
 	}
 
 	if (local.nl_family != AF_NETLINK) {
-		err = -NLE_UNSPEC;
+		nlerr = -NLE_UNSPEC;
 		goto errout;
 	}
 
@@ -1057,10 +1059,10 @@ nl_connect (struct nl_sock *sk, int protocol)
 
 errout:
 	if (sk->s_fd != -1) {
-		close(sk->s_fd);
+		close (sk->s_fd);
 		sk->s_fd = -1;
 	}
-	return err;
+	return nlerr;
 }
 
 /*****************************************************************************/
@@ -1076,7 +1078,7 @@ _cb_init (struct nl_cb *dst, const struct nl_cb *src)
 		memset (dst, 0, sizeof (*dst));
 }
 
-static int ack_wait_handler(struct nl_msg *msg, void *arg)
+static int ack_wait_handler (struct nl_msg *msg, void *arg)
 {
 	return NL_STOP;
 }
@@ -1097,19 +1099,21 @@ do { \
 	const struct nl_cb *_cb = (cb); \
 	\
 	if (_cb->type##_cb) { \
-		err = _cb->type##_cb ((msg), _cb->type##_arg); \
-		switch (err) { \
+		/* the returned value here must be either a negative
+		 * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ \
+		nlerr = _cb->type##_cb ((msg), _cb->type##_arg); \
+		switch (nlerr) { \
 		case NL_OK: \
-			err = 0; \
+			nlerr = 0; \
 			break; \
 		case NL_SKIP: \
 			goto skip; \
 		case NL_STOP: \
 			goto stop; \
 		default: \
-			if (err >= 0) { \
+			if (nlerr >= 0) { \
 				nm_assert_not_reached (); \
-				err = -NLE_BUG; \
+				nlerr = -NLE_BUG; \
 			} \
 			goto out; \
 		} \
@@ -1119,7 +1123,7 @@ do { \
 int
 nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb)
 {
-	int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0;
+	int n, nlerr = 0, multipart = 0, interrupted = 0, nrecv = 0;
 	gs_free unsigned char *buf = NULL;
 	struct nlmsghdr *hdr;
 	struct sockaddr_nl nla = { 0 };
@@ -1144,9 +1148,9 @@ continue_reading:
 		nrecv++;
 
 		/* Only do sequence checking if auto-ack mode is enabled */
-		if (!(sk->s_flags & NL_NO_AUTO_ACK)) {
+		if (! (sk->s_flags & NL_NO_AUTO_ACK)) {
 			if (hdr->nlmsg_seq != sk->s_seq_expect) {
-				err = -NLE_SEQ_MISMATCH;
+				nlerr = -NLE_SEQ_MISMATCH;
 				goto out;
 			}
 		}
@@ -1178,7 +1182,7 @@ continue_reading:
 		 * this action by skipping this packet. */
 		if (hdr->nlmsg_type == NLMSG_DONE) {
 			multipart = 0;
-			NL_CB_CALL(cb, finish, msg);
+			NL_CB_CALL (cb, finish, msg);
 		}
 
 		/* Message to be ignored, the default action is to
@@ -1192,51 +1196,53 @@ continue_reading:
 		 * quit parsing. The user may overrule this action by retuning
 		 * NL_SKIP or NL_PROCEED (dangerous) */
 		else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
-			err = -NLE_MSG_OVERFLOW;
+			nlerr = -NLE_MSG_OVERFLOW;
 			goto out;
 		}
 
 		/* Message carries a nlmsgerr */
 		else if (hdr->nlmsg_type == NLMSG_ERROR) {
-			struct nlmsgerr *e = nlmsg_data(hdr);
+			struct nlmsgerr *e = nlmsg_data (hdr);
 
-			if (hdr->nlmsg_len < nlmsg_size(sizeof (*e))) {
+			if (hdr->nlmsg_len < nlmsg_size (sizeof (*e))) {
 				/* Truncated error message, the default action
 				 * is to stop parsing. The user may overrule
 				 * this action by returning NL_SKIP or
 				 * NL_PROCEED (dangerous) */
-				err = -NLE_MSG_TRUNC;
+				nlerr = -NLE_MSG_TRUNC;
 				goto out;
 			}
 			if (e->error) {
 				/* Error message reported back from kernel. */
 				if (cb->err_cb) {
-					err = cb->err_cb (&nla, e,
-					                  cb->err_arg);
-					if (err < 0)
+					/* the returned value here must be either a negative
+					 * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */
+					nlerr = cb->err_cb (&nla, e,
+					                    cb->err_arg);
+					if (nlerr < 0)
 						goto out;
-					else if (err == NL_SKIP)
+					else if (nlerr == NL_SKIP)
 						goto skip;
-					else if (err == NL_STOP) {
-						err = -nl_syserr2nlerr (e->error);
+					else if (nlerr == NL_STOP) {
+						nlerr = -nl_syserr2nlerr (e->error);
 						goto out;
 					}
-					nm_assert (err == NL_OK);
+					nm_assert (nlerr == NL_OK);
 				} else {
-					err = -nl_syserr2nlerr (e->error);
+					nlerr = -nl_syserr2nlerr (e->error);
 					goto out;
 				}
 			} else
-				NL_CB_CALL(cb, ack, msg);
+				NL_CB_CALL (cb, ack, msg);
 		} else {
 			/* Valid message (not checking for MULTIPART bit to
 			 * get along with broken kernels. NL_SKIP has no
 			 * effect on this.  */
-			NL_CB_CALL(cb, valid, msg);
+			NL_CB_CALL (cb, valid, msg);
 		}
 skip:
-		err = 0;
-		hdr = nlmsg_next(hdr, &n);
+		nlerr = 0;
+		hdr = nlmsg_next (hdr, &n);
 	}
 
 	if (multipart) {
@@ -1248,14 +1254,14 @@ skip:
 	}
 
 stop:
-	err = 0;
+	nlerr = 0;
 
 out:
 	if (interrupted)
-		err = -NLE_DUMP_INTR;
+		nlerr = -NLE_DUMP_INTR;
 
-	nm_assert (err <= 0);
-	return err ?: nrecv;
+	nm_assert (nlerr <= 0);
+	return nlerr ?: nrecv;
 }
 
 int
@@ -1268,7 +1274,7 @@ nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
 
 	nlmsg_set_src (msg, &sk->s_local);
 
-	ret = sendmsg(sk->s_fd, hdr, 0);
+	ret = sendmsg (sk->s_fd, hdr, 0);
 	if (ret < 0)
 		return -nl_syserr2nlerr (errno);
 
@@ -1286,28 +1292,28 @@ nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsign
 		.msg_iov = iov,
 		.msg_iovlen = iovlen,
 	};
-	char buf[CMSG_SPACE(sizeof (struct ucred))];
+	char buf[CMSG_SPACE (sizeof (struct ucred))];
 
 	/* Overwrite destination if specified in the message itself, defaults
 	 * to the peer address of the socket.
 	 */
-	dst = nlmsg_get_dst(msg);
+	dst = nlmsg_get_dst (msg);
 	if (dst->nl_family == AF_NETLINK)
 		hdr.msg_name = dst;
 
 	/* Add credentials if present. */
-	creds = nlmsg_get_creds(msg);
+	creds = nlmsg_get_creds (msg);
 	if (creds != NULL) {
 		struct cmsghdr *cmsg;
 
 		hdr.msg_control = buf;
 		hdr.msg_controllen = sizeof (buf);
 
-		cmsg = CMSG_FIRSTHDR(&hdr);
+		cmsg = CMSG_FIRSTHDR (&hdr);
 		cmsg->cmsg_level = SOL_SOCKET;
 		cmsg->cmsg_type = SCM_CREDENTIALS;
-		cmsg->cmsg_len = CMSG_LEN(sizeof (struct ucred));
-		memcpy(CMSG_DATA(cmsg), creds, sizeof (struct ucred));
+		cmsg->cmsg_len = CMSG_LEN (sizeof (struct ucred));
+		memcpy (CMSG_DATA (cmsg), creds, sizeof (struct ucred));
 	}
 
 	return nl_sendmsg (sk, msg, &hdr);
@@ -1318,9 +1324,9 @@ nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg)
 {
 	struct nlmsghdr *nlh;
 
-	nlh = nlmsg_hdr(msg);
+	nlh = nlmsg_hdr (msg);
 	if (nlh->nlmsg_pid == NL_AUTO_PORT)
-		nlh->nlmsg_pid = nl_socket_get_local_port(sk);
+		nlh->nlmsg_pid = nl_socket_get_local_port (sk);
 
 	if (nlh->nlmsg_seq == NL_AUTO_SEQ)
 		nlh->nlmsg_seq = sk->s_seq_next++;
@@ -1338,14 +1344,14 @@ int
 nl_send (struct nl_sock *sk, struct nl_msg *msg)
 {
 	struct iovec iov = {
-		.iov_base = (void *) nlmsg_hdr(msg),
-		.iov_len = nlmsg_hdr(msg)->nlmsg_len,
+		.iov_base = (void *) nlmsg_hdr (msg),
+		.iov_len = nlmsg_hdr (msg)->nlmsg_len,
 	};
 
-	return nl_send_iovec(sk, msg, &iov, 1);
+	return nl_send_iovec (sk, msg, &iov, 1);
 }
 
-int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
+int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg)
 {
 	nl_complete_msg (sk, msg);
 
@@ -1379,7 +1385,7 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla,
 		flags |= MSG_PEEK | MSG_TRUNC;
 
 	if (page_size == 0)
-		page_size = getpagesize() * 4;
+		page_size = getpagesize () * 4;
 
 	iov.iov_len = sk->s_bufsize ?: page_size;
 	iov.iov_base = g_malloc (iov.iov_len);
@@ -1391,7 +1397,7 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla,
 	}
 
 retry:
-	n = recvmsg(sk->s_fd, &msg, flags);
+	n = recvmsg (sk->s_fd, &msg, flags);
 	if (!n) {
 		retval = 0;
 		goto abort;
@@ -1447,12 +1453,12 @@ retry:
 	if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
 		struct cmsghdr *cmsg;
 
-		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) {
 			if (cmsg->cmsg_level != SOL_SOCKET)
 				continue;
 			if (cmsg->cmsg_type != SCM_CREDENTIALS)
 				continue;
-			tmpcreds = nm_memdup (CMSG_DATA(cmsg), sizeof (*tmpcreds));
+			tmpcreds = nm_memdup (CMSG_DATA (cmsg), sizeof (*tmpcreds));
 			break;
 		}
 	}
diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h
index 187685d8..1fccddb9 100644
--- a/src/platform/nm-netlink.h
+++ b/src/platform/nm-netlink.h
@@ -52,32 +52,48 @@
 #endif
 
 static inline int
-nl_errno (int err)
+nl_errno (int nlerr)
 {
-	/* the error codes from our netlink implementation are plain errno
-	 * extended with our own error in a particular range starting from
-	 * _NLE_BASE.
+	/* Normalizes an netlink error to be positive. Various API returns negative
+	 * error codes, and this function converts the negative value to its
+	 * positive.
 	 *
-	 * However, often we encode errors as negative values. This function
-	 * normalizes the error and returns its positive value. */
-	return err >= 0
-	       ? err
-	       : ((err == G_MININT) ? NLE_BUG : -err);
+	 * It's very similar to nm_errno(), but not exactly. The difference is that
+	 * nm_errno() is for plain errno, while nl_errno() is for netlink error numbers.
+	 * Yes, netlink error number are ~almost~ the same as errno, except that a particular
+	 * range (_NLE_BASE, _NLE_BASE_END) is reserved. The difference between the two
+	 * functions is only how G_MININT is mapped.
+	 *
+	 * See also nl_syserr2nlerr() below. */
+	return nlerr >= 0
+	       ? nlerr
+	       : ((nlerr == G_MININT) ? NLE_BUG : -nlerr);
 }
 
 static inline int
-nl_syserr2nlerr (int err)
+nl_syserr2nlerr (int errsv)
 {
-	if (err == G_MININT)
+	/* this maps a native errno to a (always non-negative) netlink error number.
+	 *
+	 * Note that netlink error numbers are embedded into the range of regular
+	 * errno. The only difference is, that netlink error numbers reserve a
+	 * range (_NLE_BASE, _NLE_BASE_END) for their own purpose.
+	 *
+	 * That means, converting an errno to netlink error number means in
+	 * most cases just returning itself (negative values are normalized
+	 * to be positive). Only values G_MININT and [_NLE_BASE, _NLE_BASE_END]
+	 * are coerced to the special value NLE_NATIVE_ERRNO, as they cannot
+	 * otherwise be represented in netlink error number domain. */
+	if (errsv == G_MININT)
 		return NLE_NATIVE_ERRNO;
-	if (err < 0)
-		err = -err;
-	return (err >= _NLE_BASE && err < _NLE_BASE_END)
+	if (errsv < 0)
+		errsv = -errsv;
+	return (errsv >= _NLE_BASE && errsv < _NLE_BASE_END)
 	       ? NLE_NATIVE_ERRNO
-	       : err;
+	       : errsv;
 }
 
-const char *nl_geterror (int err);
+const char *nl_geterror (int nlerr);
 
 /*****************************************************************************/
 
diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c
index fdec4763..b231ff20 100644
--- a/src/ppp/nm-ppp-manager.c
+++ b/src/ppp/nm-ppp-manager.c
@@ -438,11 +438,12 @@ impl_ppp_manager_set_ifindex (NMDBusObject *obj,
 
 	g_variant_get (parameters, "(i)", &ifindex);
 
-	_LOGD ("set-ifindex %d", (int) ifindex);
-
 	if (priv->ifindex >= 0) {
-		_LOGW ("can't change the ifindex from %d to %d", priv->ifindex, (int) ifindex);
-		return;
+		if (priv->ifindex == ifindex)
+			_LOGD ("set-ifindex: ignore repeated calls setting ifindex to %d", (int) ifindex);
+		else
+			_LOGW ("set-ifindex: can't change the ifindex from %d to %d", priv->ifindex, (int) ifindex);
+		goto out;
 	}
 
 	if (ifindex > 0) {
@@ -454,15 +455,22 @@ impl_ppp_manager_set_ifindex (NMDBusObject *obj,
 	}
 
 	if (!plink) {
-		_LOGW ("unknown interface with ifindex %d", ifindex);
+		_LOGW ("set-ifindex: unknown interface with ifindex %d", ifindex);
 		ifindex = 0;
+	} else {
+		obj_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink));
+		_LOGD ("set-ifindex: %d, name \"%s\"", (int) ifindex, plink->name);
 	}
 
 	priv->ifindex = ifindex;
 
-	obj_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink));
+	g_signal_emit (self,
+	               signals[IFINDEX_SET],
+	               0,
+	               ifindex,
+	               plink ? plink->name : NULL);
 
-	g_signal_emit (self, signals[IFINDEX_SET], 0, ifindex, plink->name);
+out:
 	g_dbus_method_invocation_return_value (invocation, NULL);
 }
 
diff --git a/src/ppp/nm-pppd-plugin.c b/src/ppp/nm-pppd-plugin.c
index 989f7433..09196340 100644
--- a/src/ppp/nm-pppd-plugin.c
+++ b/src/ppp/nm-pppd-plugin.c
@@ -147,7 +147,7 @@ nm_phasechange (void *data, int arg)
 		if (   if_indextoname (index, new_name)
 		    && !nm_streq0 (ifname, new_name)) {
 			g_message ("nm-ppp-plugin: interface name changed from '%s' to '%s'", ifname, new_name);
-			strncpy (ifname, new_name, IF_NAMESIZE);
+			g_strlcpy (ifname, new_name, IF_NAMESIZE);
 		}
 	}
 }
diff --git a/src/settings/plugins/ifcfg-rh/meson.build b/src/settings/plugins/ifcfg-rh/meson.build
index 5d9689a5..e4bce09b 100644
--- a/src/settings/plugins/ifcfg-rh/meson.build
+++ b/src/settings/plugins/ifcfg-rh/meson.build
@@ -18,7 +18,7 @@ libnmdbus_ifcfg_rh = static_library(
   dependencies: glib_dep,
 )
 
-sources = files(
+core_sources = files(
   'nm-inotify-helper.c',
   'nms-ifcfg-rh-reader.c',
   'nms-ifcfg-rh-utils.c',
@@ -32,11 +32,11 @@ deps = [
 
 libnms_ifcfg_rh_core = static_library(
   'nms-ifcfg-rh-core',
-  sources: sources,
+  sources: core_sources,
   dependencies: deps,
 )
 
-sources = [dbus_sources] + files('nms-ifcfg-rh-connection.c')
+sources = [dbus_sources] + core_sources + files('nms-ifcfg-rh-connection.c', 'nms-ifcfg-rh-plugin.c')
 
 libnm_settings_plugin_ifcfg_rh = shared_module(
   'nm-settings-plugin-ifcfg-rh',
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index e1a2289e..b70690cc 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -2223,7 +2223,7 @@ write_sriov_setting (NMConnection *connection, shvarFile *ifcfg)
 
 	svUnsetAll (ifcfg, SV_KEY_TYPE_SRIOV_VF);
 
-	s_sriov = nm_connection_get_setting_sriov (connection);
+	s_sriov = NM_SETTING_SRIOV (nm_connection_get_setting (connection, NM_TYPE_SETTING_SRIOV));
 	if (s_sriov)
 		num = nm_setting_sriov_get_total_vfs (s_sriov);
 	if (num == 0) {
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 70693861..0c0dd64e 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -9721,7 +9721,7 @@ test_sriov_read (void)
 
 	g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "eth0");
 
-	s_sriov = nm_connection_get_setting_sriov (connection);
+	s_sriov = NM_SETTING_SRIOV (nm_connection_get_setting (connection, NM_TYPE_SETTING_SRIOV));
 	g_assert (s_sriov);
 
 	g_assert_cmpint (nm_setting_sriov_get_total_vfs (s_sriov), ==, 16);
diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c
index 90fe29d0..80e9577c 100644
--- a/src/systemd/src/libsystemd-network/dhcp-network.c
+++ b/src/systemd/src/libsystemd-network/dhcp-network.c
@@ -128,8 +128,6 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
         const uint8_t *bcast_addr = NULL;
         uint8_t dhcp_hlen = 0;
 
-        assert_return(mac_addr_len > 0, -EINVAL);
-
         if (arp_type == ARPHRD_ETHER) {
                 assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
                 memcpy(&eth_mac, mac_addr, ETH_ALEN);
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index d1aaa7c9..bd847d75 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -2684,12 +2684,16 @@ plugin_interactive_secrets_required (NMVpnConnection *self,
 	gs_free const char **hints = NULL;
 	gs_free char *message_hint = NULL;
 
+	if (!NM_IN_SET (priv->vpn_state, STATE_CONNECT,
+	                                 STATE_NEED_AUTH)) {
+		_LOGD ("VPN plugin: requested secrets; state %s (%d); ignore request in current state",
+		       vpn_state_to_string (priv->vpn_state), priv->vpn_state);
+		return;
+	}
+
 	_LOGI ("VPN plugin: requested secrets; state %s (%d)",
 	       vpn_state_to_string (priv->vpn_state), priv->vpn_state);
 
-	g_return_if_fail (priv->vpn_state == STATE_CONNECT ||
-	                  priv->vpn_state == STATE_NEED_AUTH);
-
 	priv->secrets_idx = SECRETS_REQ_INTERACTIVE;
 	_set_vpn_state (self, STATE_NEED_AUTH, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE);
 
@@ -2756,6 +2760,9 @@ dispose (GObject *object)
 	NMVpnConnection *self = NM_VPN_CONNECTION (object);
 	NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
 
+	if (priv->proxy)
+		g_signal_handlers_disconnect_by_data (priv->proxy, self);
+
 	nm_clear_g_source (&priv->start_timeout);
 
 	g_clear_pointer (&priv->connect_hash, g_variant_unref);