summary refs log tree commit diff
path: root/src/supplicant-manager
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-01-20 16:26:51 +0100
committerMichael Biebl <biebl@debian.org>2016-01-20 16:26:51 +0100
commit494f296a3baab08522617b24b1f126d8f9a17502 (patch)
treec8ef32fb0dd1c4ff35a0b38e787abb58692de0cd /src/supplicant-manager
parent54f6333410ffd570e62717d9e77c5c987175e397 (diff)
Imported Upstream version 1.1.90 upstream/1.1.90
Diffstat (limited to 'src/supplicant-manager')
-rw-r--r--src/supplicant-manager/nm-supplicant-config.c514
-rw-r--r--src/supplicant-manager/nm-supplicant-config.h19
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.c414
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.h30
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.c36
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.h2
-rw-r--r--src/supplicant-manager/nm-supplicant-settings-verify.c2
-rw-r--r--src/supplicant-manager/nm-supplicant-types.h20
-rw-r--r--src/supplicant-manager/tests/Makefile.am9
-rw-r--r--src/supplicant-manager/tests/Makefile.in27
-rw-r--r--src/supplicant-manager/tests/certs/Makefile.in18
-rw-r--r--src/supplicant-manager/tests/test-supplicant-config.c52
12 files changed, 710 insertions, 433 deletions
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index 692efef3..190ee0a7 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -23,12 +23,10 @@
 
 #include <string.h>
 #include <stdlib.h>
-#include <glib.h>
-#include <dbus/dbus-glib.h>
 
+#include "nm-default.h"
 #include "nm-supplicant-config.h"
 #include "nm-supplicant-settings-verify.h"
-#include "nm-logging.h"
 #include "nm-setting.h"
 #include "NetworkManagerUtils.h"
 #include "nm-utils.h"
@@ -41,7 +39,7 @@ G_DEFINE_TYPE (NMSupplicantConfig, nm_supplicant_config, G_TYPE_OBJECT)
 
 typedef struct {
 	char *value;
-	guint32 len;	
+	guint32 len;
 	OptType type;
 } ConfigOption;
 
@@ -50,6 +48,7 @@ typedef struct
 	GHashTable *config;
 	GHashTable *blobs;
 	guint32    ap_scan;
+	NMSettingMacRandomization mac_randomization;
 	gboolean   fast_required;
 	gboolean   dispose_has_run;
 } NMSupplicantConfigPrivate;
@@ -87,6 +86,7 @@ nm_supplicant_config_init (NMSupplicantConfig * self)
 	                                     (GDestroyNotify) blob_free);
 
 	priv->ap_scan = 1;
+	priv->mac_randomization = NM_SETTING_MAC_RANDOMIZATION_DEFAULT;
 	priv->dispose_has_run = FALSE;
 }
 
@@ -96,7 +96,8 @@ nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self,
                                            const char *value,
                                            gint32 len,
                                            OptType opt_type,
-                                           gboolean secret)
+                                           gboolean secret,
+                                           GError **error)
 {
 	NMSupplicantConfigPrivate *priv;
 	ConfigOption *old_opt;
@@ -106,6 +107,7 @@ nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self,
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
 	g_return_val_if_fail (key != NULL, FALSE);
 	g_return_val_if_fail (value != NULL, FALSE);
+	nm_assert (!error || !*error);
 
 	priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self);
 
@@ -120,23 +122,26 @@ nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self,
 			char buf[255];
 			memset (&buf[0], 0, sizeof (buf));
 			memcpy (&buf[0], value, len > 254 ? 254 : len);
-			nm_log_warn (LOGD_SUPPLICANT, "Key '%s' and/or value '%s' invalid.", key, secret ? "<omitted>" : buf);
+			g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+			             "key '%s' and/or value '%s' invalid", key, secret ? "<omitted>" : buf);
 			return FALSE;
 		}
 	}
 
 	old_opt = (ConfigOption *) g_hash_table_lookup (priv->config, key);
 	if (old_opt) {
-		nm_log_warn (LOGD_SUPPLICANT, "Key '%s' already in table.", key);
+		g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+		             "key '%s' already configured", key);
 		return FALSE;
 	}
 
 	opt = g_slice_new0 (ConfigOption);
-	opt->value = g_malloc0 ((sizeof (char) * len) + 1);
+	opt->value = g_malloc (len + 1);
 	memcpy (opt->value, value, len);
+	opt->value[len] = '\0';
 
 	opt->len = len;
-	opt->type = type;	
+	opt->type = type;
 
 	{
 		char buf[255];
@@ -155,16 +160,18 @@ nm_supplicant_config_add_option (NMSupplicantConfig *self,
                                  const char *key,
                                  const char *value,
                                  gint32 len,
-                                 gboolean secret)
+                                 gboolean secret,
+                                 GError **error)
 {
-	return nm_supplicant_config_add_option_with_type (self, key, value, len, TYPE_INVALID, secret);
+	return nm_supplicant_config_add_option_with_type (self, key, value, len, TYPE_INVALID, secret, error);
 }
 
 static gboolean
 nm_supplicant_config_add_blob (NMSupplicantConfig *self,
                                const char *key,
                                GBytes *value,
-                               const char *blobid)
+                               const char *blobid,
+                               GError **error)
 {
 	NMSupplicantConfigPrivate *priv;
 	ConfigOption *old_opt;
@@ -186,13 +193,15 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self,
 
 	type = nm_supplicant_settings_verify_setting (key, (const char *) data, data_len);
 	if (type == TYPE_INVALID) {
-		nm_log_warn (LOGD_SUPPLICANT, "Key '%s' and/or it's contained value is invalid.", key);
+		g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+		             "key '%s' and/or its contained value is invalid", key);
 		return FALSE;
 	}
 
 	old_opt = (ConfigOption *) g_hash_table_lookup (priv->config, key);
 	if (old_opt) {
-		nm_log_warn (LOGD_SUPPLICANT, "Key '%s' already in table.", key);
+		g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+		             "key '%s' already configured", key);
 		return FALSE;
 	}
 
@@ -202,7 +211,7 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self,
 	opt = g_slice_new0 (ConfigOption);
 	opt->value = g_strdup_printf ("blob://%s", blobid);
 	opt->len = strlen (opt->value);
-	opt->type = type;	
+	opt->type = type;
 
 	nm_log_info (LOGD_SUPPLICANT, "Config: added '%s' value '%s'", key, opt->value);
 
@@ -212,6 +221,28 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self,
 	return TRUE;
 }
 
+static gboolean
+nm_supplicant_config_add_blob_for_connection (NMSupplicantConfig *self,
+                                              GBytes *field,
+                                              const char *name,
+                                              const char *con_uid,
+                                              GError **error)
+{
+	if (field && g_bytes_get_size (field)) {
+		gs_free char *uid = NULL;
+		char *p;
+
+		uid = g_strdup_printf ("%s-%s", con_uid, name);
+		for (p = uid; *p; p++) {
+			if (*p == '/')
+				*p = '-';
+		}
+		if (!nm_supplicant_config_add_blob (self, name, field, uid, error))
+			return FALSE;
+	}
+	return TRUE;
+}
+
 static void
 nm_supplicant_config_finalize (GObject *object)
 {
@@ -242,14 +273,30 @@ nm_supplicant_config_get_ap_scan (NMSupplicantConfig * self)
 	return NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->ap_scan;
 }
 
-void
-nm_supplicant_config_set_ap_scan (NMSupplicantConfig * self,
-                                  guint32 ap_scan)
+const char *
+nm_supplicant_config_get_mac_randomization (NMSupplicantConfig *self)
 {
-	g_return_if_fail (NM_IS_SUPPLICANT_CONFIG (self));
-	g_return_if_fail (ap_scan <= 2);
+	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), 0);
+
+	/**
+	 * mac_addr - MAC address policy default
+	 *
+	 * 0 = use permanent MAC address
+	 * 1 = use random MAC address for each ESS connection
+	 * 2 = like 1, but maintain OUI (with local admin bit set)
+	 *
+	 * By default, permanent MAC address is used unless policy is changed by
+	 * the per-network mac_addr parameter.
+	 */
 
-	NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->ap_scan = ap_scan;
+	switch (NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->mac_randomization) {
+	case NM_SETTING_MAC_RANDOMIZATION_ALWAYS:
+		return "1";
+	case NM_SETTING_MAC_RANDOMIZATION_NEVER:
+	case NM_SETTING_MAC_RANDOMIZATION_DEFAULT:
+	default:
+		return "0";
+	}
 }
 
 gboolean
@@ -338,7 +385,10 @@ wifi_freqs_to_string (gboolean bg_band)
 gboolean
 nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
                                            NMSettingWireless * setting,
-                                           guint32 fixed_freq)
+                                           guint32 fixed_freq,
+                                           NMSupplicantFeature mac_randomization_support,
+                                           NMSettingMacRandomization mac_randomization_fallback,
+                                           GError **error)
 {
 	NMSupplicantConfigPrivate *priv;
 	gboolean is_adhoc, is_ap;
@@ -349,6 +399,7 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
 	g_return_val_if_fail (setting != NULL, FALSE);
+	g_return_val_if_fail (!error || !*error, FALSE);
 
 	priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self);
 
@@ -364,42 +415,33 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
 	if (!nm_supplicant_config_add_option (self, "ssid",
 	                                      (char *) g_bytes_get_data (ssid, NULL),
 	                                      g_bytes_get_size (ssid),
-	                                      FALSE)) {
-		nm_log_warn (LOGD_SUPPLICANT, "Error adding SSID to supplicant config.");
+	                                      FALSE,
+	                                      error))
 		return FALSE;
-	}
 
 	if (is_adhoc) {
-		if (!nm_supplicant_config_add_option (self, "mode", "1", -1, FALSE)) {
-			nm_log_warn (LOGD_SUPPLICANT, "Error adding mode=1 (adhoc) to supplicant config.");
+		if (!nm_supplicant_config_add_option (self, "mode", "1", -1, FALSE, error))
 			return FALSE;
-		}
 	}
 
 	if (is_ap) {
-		if (!nm_supplicant_config_add_option (self, "mode", "2", -1, FALSE)) {
-			nm_log_warn (LOGD_SUPPLICANT, "Error adding mode=2 (ap) to supplicant config.");
+		if (!nm_supplicant_config_add_option (self, "mode", "2", -1, FALSE, error))
 			return FALSE;
-		}
 	}
 
 	if ((is_adhoc || is_ap) && fixed_freq) {
-		char *str_freq;
+		gs_free char *str_freq = NULL;
 
 		str_freq = g_strdup_printf ("%u", fixed_freq);
-		if (!nm_supplicant_config_add_option (self, "frequency", str_freq, -1, FALSE)) {
-			g_free (str_freq);
-			nm_log_warn (LOGD_SUPPLICANT, "Error adding Ad-Hoc/AP frequency to supplicant config.");
+		if (!nm_supplicant_config_add_option (self, "frequency", str_freq, -1, FALSE, error))
 			return FALSE;
-		}
-		g_free (str_freq);
 	}
 
 	/* Except for Ad-Hoc and Hotspot, request that the driver probe for the
 	 * specific SSID we want to associate with.
 	 */
 	if (!(is_adhoc || is_ap)) {
-		if (!nm_supplicant_config_add_option (self, "scan_ssid", "1", -1, FALSE))
+		if (!nm_supplicant_config_add_option (self, "scan_ssid", "1", -1, FALSE, error))
 			return FALSE;
 	}
 
@@ -407,10 +449,9 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
 	if (bssid) {
 		if (!nm_supplicant_config_add_option (self, "bssid",
 		                                      bssid, strlen (bssid),
-		                                      FALSE)) {
-			nm_log_warn (LOGD_SUPPLICANT, "Error adding BSSID to supplicant config.");
+		                                      FALSE,
+		                                      error))
 			return FALSE;
-		}
 	}
 
 	band = nm_setting_wireless_get_band (setting);
@@ -418,16 +459,12 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
 	if (band) {
 		if (channel) {
 			guint32 freq;
-			char *str_freq;
+			gs_free char *str_freq = NULL;
 
 			freq = nm_utils_wifi_channel_to_freq (channel, band);
 			str_freq = g_strdup_printf ("%u", freq);
-			if (!nm_supplicant_config_add_option (self, "freq_list", str_freq, -1, FALSE)) {
-				g_free (str_freq);
-				nm_log_warn (LOGD_SUPPLICANT, "Error adding frequency list to supplicant config.");
+			if (!nm_supplicant_config_add_option (self, "freq_list", str_freq, -1, FALSE, error))
 				return FALSE;
-			}
-			g_free (str_freq);
 		} else {
 			const char *freqs = NULL;
 
@@ -436,13 +473,28 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
 			else if (!strcmp (band, "bg"))
 				freqs = wifi_freqs_to_string (TRUE);
 
-			if (freqs && !nm_supplicant_config_add_option (self, "freq_list", freqs, strlen (freqs), FALSE)) {
-				nm_log_warn (LOGD_SUPPLICANT, "Error adding frequency list/band to supplicant config.");
+			if (freqs && !nm_supplicant_config_add_option (self, "freq_list", freqs, strlen (freqs), FALSE, error))
 				return FALSE;
-			}
 		}
 	}
 
+	priv->mac_randomization = nm_setting_wireless_get_mac_address_randomization (setting);
+	if (priv->mac_randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT) {
+		priv->mac_randomization = mac_randomization_fallback;
+		if (priv->mac_randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT) {
+			/* Don't use randomization, unless explicitly enabled.
+			 * Randomization can work badly with captive portals. */
+			priv->mac_randomization = NM_SETTING_MAC_RANDOMIZATION_NEVER;
+		}
+	}
+
+	if (   priv->mac_randomization != NM_SETTING_MAC_RANDOMIZATION_NEVER
+	    && mac_randomization_support != NM_SUPPLICANT_FEATURE_YES) {
+		g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+		             "cannot enable mac-randomization due to missing supplicant support");
+		return FALSE;
+	}
+
 	return TRUE;
 }
 
@@ -451,73 +503,55 @@ add_string_val (NMSupplicantConfig *self,
                 const char *field,
                 const char *name,
                 gboolean ucase,
-                gboolean secret)
+                gboolean secret,
+                GError **error)
 {
-	gboolean success;
-	char *value;
 
-	if (!field)
-		return TRUE;
+	if (field) {
+		gs_free char *value = NULL;
 
-	value = ucase ? g_ascii_strup (field, -1) : g_strdup (field);
-	success = nm_supplicant_config_add_option (self, name, value, strlen (field), secret);
-	if (!success)
-		nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name);
-	g_free (value);
-	return success;
+		if (ucase) {
+			value = g_ascii_strup (field, -1);
+			field = value;
+		}
+		return nm_supplicant_config_add_option (self, name, field, strlen (field), secret, error);
+	}
+	return TRUE;
 }
 
-#define ADD_STRING_LIST_VAL(setting, setting_name, field, field_plural, name, separator, ucase, secret) \
-	if (nm_setting_##setting_name##_get_num_##field_plural (setting)) { \
-		guint32 k; \
-		GString *str = g_string_new (NULL); \
-		for (k = 0; k < nm_setting_##setting_name##_get_num_##field_plural (setting); k++) { \
-			const char *item = nm_setting_##setting_name##_get_##field (setting, k); \
-			if (!str->len) { \
-				g_string_append (str, item); \
-			} else { \
-				g_string_append_c (str, separator); \
-				g_string_append (str, item); \
+#define ADD_STRING_LIST_VAL(self, setting, setting_name, field, field_plural, name, separator, ucase, secret, error) \
+	({ \
+		typeof (*(setting)) *_setting = (setting); \
+		gboolean _success = TRUE; \
+		\
+		if (nm_setting_##setting_name##_get_num_##field_plural (_setting)) { \
+			const char _separator = (separator); \
+			GString *_str = g_string_new (NULL); \
+			guint _k, _n; \
+			\
+			_n = nm_setting_##setting_name##_get_num_##field_plural (_setting); \
+			for (_k = 0; _k < _n; _k++) { \
+				const char *item = nm_setting_##setting_name##_get_##field (_setting, _k); \
+				\
+				if (!_str->len) { \
+					g_string_append (_str, item); \
+				} else { \
+					g_string_append_c (_str, _separator); \
+					g_string_append (_str, item); \
+				} \
 			} \
+			if ((ucase)) \
+				g_string_ascii_up (_str); \
+			if (_str->len) { \
+				if (!nm_supplicant_config_add_option ((self), (name), _str->str, -1, (secret), (error))) \
+					_success = FALSE; \
+			} \
+			g_string_free (_str, TRUE); \
 		} \
-		if (ucase) \
-			g_string_ascii_up (str); \
-		if (str->len) \
-			success = nm_supplicant_config_add_option (self, name, str->str, -1, secret); \
-		else \
-			success = TRUE; \
-		g_string_free (str, TRUE); \
-		if (!success) { \
-			nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name); \
-			return FALSE; \
-		} \
-	}
+		_success; \
+	})
 
-static char *
-get_blob_id (const char *name, const char *seed_uid)
-{
-	char *uid = g_strdup_printf ("%s-%s", seed_uid, name);
-	char *p = uid;
-	while (*p) {
-		if (*p == '/') *p = '-';
-		p++;
-	}
-	return uid;
-}
-
-#define ADD_BLOB_VAL(field, name, con_uid) \
-	if (field && g_bytes_get_size (field)) { \
-		char *uid = get_blob_id (name, con_uid); \
-		success = nm_supplicant_config_add_blob (self, name, field, uid); \
-		g_free (uid); \
-		if (!success) { \
-			nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name); \
-			return FALSE; \
-		} \
-	}
-
-
-static gboolean
+static void
 wep128_passphrase_hash (const char *input,
                         size_t input_len,
                         guint8 *out_digest,
@@ -527,9 +561,9 @@ wep128_passphrase_hash (const char *input,
 	guint8 data[64];
 	int i;
 
-	g_return_val_if_fail (out_digest != NULL, FALSE);
-	g_return_val_if_fail (out_digest_len != NULL, FALSE);
-	g_return_val_if_fail (*out_digest_len >= 16, FALSE);
+	g_return_if_fail (out_digest != NULL);
+	g_return_if_fail (out_digest_len != NULL);
+	g_return_if_fail (*out_digest_len >= 16);
 
 	/* Get at least 64 bytes by repeating the passphrase into the buffer */
 	for (i = 0; i < sizeof (data); i++)
@@ -544,17 +578,15 @@ wep128_passphrase_hash (const char *input,
 	g_assert (*out_digest_len == 16);
 	/* WEP104 keys are 13 bytes in length (26 hex characters) */
 	*out_digest_len = 13;
-	return TRUE;
 }
 
 static gboolean
 add_wep_key (NMSupplicantConfig *self,
              const char *key,
              const char *name,
-             NMWepKeyType wep_type)
+             NMWepKeyType wep_type,
+             GError **error)
 {
-	GBytes *bytes;
-	gboolean success = FALSE;
 	size_t key_len = key ? strlen (key) : 0;
 
 	if (!key || !key_len)
@@ -570,39 +602,38 @@ add_wep_key (NMSupplicantConfig *self,
 	if (   (wep_type == NM_WEP_KEY_TYPE_UNKNOWN)
 	    || (wep_type == NM_WEP_KEY_TYPE_KEY)) {
 		if ((key_len == 10) || (key_len == 26)) {
+			gs_unref_bytes GBytes *bytes = NULL;
+
 			bytes = nm_utils_hexstr2bin (key);
-			if (bytes) {
-				success = nm_supplicant_config_add_option (self,
-				                                           name,
-				                                           g_bytes_get_data (bytes, NULL),
-				                                           g_bytes_get_size (bytes),
-				                                           TRUE);
-				g_bytes_unref (bytes);
-			}
-			if (!success) {
-				nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name);
+			if (!bytes) {
+				g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+				             "cannot add wep-key %s to suplicant config because key is not hex",
+				             name);
 				return FALSE;
 			}
+			if (!nm_supplicant_config_add_option (self,
+			                                      name,
+			                                      g_bytes_get_data (bytes, NULL),
+			                                      g_bytes_get_size (bytes),
+			                                      TRUE,
+			                                      error))
+				return FALSE;
 		} else if ((key_len == 5) || (key_len == 13)) {
-			if (!nm_supplicant_config_add_option (self, name, key, key_len, TRUE)) {
-				nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name);
+			if (!nm_supplicant_config_add_option (self, name, key, key_len, TRUE, error))
 				return FALSE;
-			}
 		} else {
-			nm_log_warn (LOGD_SUPPLICANT, "Invalid WEP key '%s'", name);
+			g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+			             "Cannot add wep-key %s to suplicant config because key-length %u is invalid",
+			             name, (guint) key_len);
 			return FALSE;
 		}
 	} else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
 		guint8 digest[16];
 		size_t digest_len = sizeof (digest);
 
-		success = wep128_passphrase_hash (key, key_len, digest, &digest_len);
-		if (success)
-			success = nm_supplicant_config_add_option (self, name, (const char *) digest, digest_len, TRUE);
-		if (!success) {
-			nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name);
+		wep128_passphrase_hash (key, key_len, digest, &digest_len);
+		if (!nm_supplicant_config_add_option (self, name, (const char *) digest, digest_len, TRUE, error))
 			return FALSE;
-		}
 	}
 
 	return TRUE;
@@ -613,22 +644,23 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                     NMSettingWirelessSecurity *setting,
                                                     NMSetting8021x *setting_8021x,
                                                     const char *con_uuid,
-                                                    guint32 mtu)
+                                                    guint32 mtu,
+                                                    GError **error)
 {
-	gboolean success = FALSE;
 	const char *key_mgmt, *auth_alg;
 	const char *psk;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
 	g_return_val_if_fail (setting != NULL, FALSE);
 	g_return_val_if_fail (con_uuid != NULL, FALSE);
+	g_return_val_if_fail (!error || !*error, FALSE);
 
 	key_mgmt = nm_setting_wireless_security_get_key_mgmt (setting);
-	if (!add_string_val (self, key_mgmt, "key_mgmt", TRUE, FALSE))
+	if (!add_string_val (self, key_mgmt, "key_mgmt", TRUE, FALSE, error))
 		return FALSE;
 
 	auth_alg = nm_setting_wireless_security_get_auth_alg (setting);
-	if (!add_string_val (self, auth_alg, "auth_alg", TRUE, FALSE))
+	if (!add_string_val (self, auth_alg, "auth_alg", TRUE, FALSE, error))
 		return FALSE;
 
 	psk = nm_setting_wireless_security_get_psk (setting);
@@ -636,35 +668,35 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 		size_t psk_len = strlen (psk);
 
 		if (psk_len == 64) {
-			GBytes *bytes;
+			gs_unref_bytes GBytes *bytes = NULL;
 
 			/* Hex PSK */
 			bytes = nm_utils_hexstr2bin (psk);
-			if (bytes) {
-				success = nm_supplicant_config_add_option (self,
-				                                           "psk",
-				                                           g_bytes_get_data (bytes, NULL),
-				                                           g_bytes_get_size (bytes),
-				                                           TRUE);
-				g_bytes_unref (bytes);
-			}
-			if (!success) {
-				nm_log_warn (LOGD_SUPPLICANT, "Error adding 'psk' to supplicant config.");
+			if (!bytes) {
+				g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+				             "Cannot add psk to supplicant config due to invalid hex");
 				return FALSE;
 			}
+
+			if (!nm_supplicant_config_add_option (self,
+			                                      "psk",
+			                                      g_bytes_get_data (bytes, NULL),
+			                                      g_bytes_get_size (bytes),
+			                                      TRUE,
+			                                      error))
+				return FALSE;
 		} else if (psk_len >= 8 && psk_len <= 63) {
 			/* Use TYPE_STRING here so that it gets pushed to the
 			 * supplicant as a string, and therefore gets quoted,
 			 * and therefore the supplicant will interpret it as a
 			 * passphrase and not a hex key.
 			 */
-			if (!nm_supplicant_config_add_option_with_type (self, "psk", psk, -1, TYPE_STRING, TRUE)) {
-				nm_log_warn (LOGD_SUPPLICANT, "Error adding 'psk' to supplicant config.");
+			if (!nm_supplicant_config_add_option_with_type (self, "psk", psk, -1, TYPE_STRING, TRUE, error))
 				return FALSE;
-			}
 		} else {
-			/* Invalid PSK */
-			nm_log_warn (LOGD_SUPPLICANT, "Invalid PSK length %u: not between 8 and 63 characters inclusive.", (guint32) psk_len);
+			g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+			             "Cannot add psk to supplicant config due to invalid PSK length %u (not between 8 and 63 characters)",
+			             (guint) psk_len);
 			return FALSE;
 		}
 	}
@@ -673,9 +705,12 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 	if (   !strcmp (key_mgmt, "wpa-none")
 	    || !strcmp (key_mgmt, "wpa-psk")
 	    || !strcmp (key_mgmt, "wpa-eap")) {
-		ADD_STRING_LIST_VAL (setting, wireless_security, proto, protos, "proto", ' ', TRUE, FALSE);
-		ADD_STRING_LIST_VAL (setting, wireless_security, pairwise, pairwise, "pairwise", ' ', TRUE, FALSE);
-		ADD_STRING_LIST_VAL (setting, wireless_security, group, groups, "group", ' ', TRUE, FALSE);
+		if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, proto, protos, "proto", ' ', TRUE, FALSE, error))
+			return FALSE;
+		if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, pairwise, pairwise, "pairwise", ' ', TRUE, FALSE, error))
+			return FALSE;
+		if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, group, groups, "group", ' ', TRUE, FALSE, error))
+			return FALSE;
 	}
 
 	/* WEP keys if required */
@@ -685,25 +720,22 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 		const char *wep1 = nm_setting_wireless_security_get_wep_key (setting, 1);
 		const char *wep2 = nm_setting_wireless_security_get_wep_key (setting, 2);
 		const char *wep3 = nm_setting_wireless_security_get_wep_key (setting, 3);
-		char *value;
 
-		if (!add_wep_key (self, wep0, "wep_key0", wep_type))
+		if (!add_wep_key (self, wep0, "wep_key0", wep_type, error))
 			return FALSE;
-		if (!add_wep_key (self, wep1, "wep_key1", wep_type))
+		if (!add_wep_key (self, wep1, "wep_key1", wep_type, error))
 			return FALSE;
-		if (!add_wep_key (self, wep2, "wep_key2", wep_type))
+		if (!add_wep_key (self, wep2, "wep_key2", wep_type, error))
 			return FALSE;
-		if (!add_wep_key (self, wep3, "wep_key3", wep_type))
+		if (!add_wep_key (self, wep3, "wep_key3", wep_type, error))
 			return FALSE;
 
 		if (wep0 || wep1 || wep2 || wep3) {
+			gs_free char *value = NULL;
+
 			value = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (setting));
-			success = nm_supplicant_config_add_option (self, "wep_tx_keyidx", value, -1, FALSE);
-			g_free (value);
-			if (!success) {
-				nm_log_warn (LOGD_SUPPLICANT, "Error adding wep_tx_keyidx to supplicant config.");
+			if (!nm_supplicant_config_add_option (self, "wep_tx_keyidx", value, -1, FALSE, error))
 				return FALSE;
-			}
 		}
 	}
 
@@ -713,24 +745,29 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 			const char *tmp;
 
 			tmp = nm_setting_wireless_security_get_leap_username (setting);
-			if (!add_string_val (self, tmp, "identity", FALSE, FALSE))
+			if (!add_string_val (self, tmp, "identity", FALSE, FALSE, error))
 				return FALSE;
 
 			tmp = nm_setting_wireless_security_get_leap_password (setting);
-			if (!add_string_val (self, tmp, "password", FALSE, TRUE))
+			if (!add_string_val (self, tmp, "password", FALSE, TRUE, error))
 				return FALSE;
 
-			if (!add_string_val (self, "leap", "eap", TRUE, FALSE))
+			if (!add_string_val (self, "leap", "eap", TRUE, FALSE, error))
 				return FALSE;
 		} else {
+			g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+			             "Invalid key-mgmt \"%s\" for leap", key_mgmt);
 			return FALSE;
 		}
 	} else {
 		/* 802.1x for Dynamic WEP and WPA-Enterprise */
 		if (!strcmp (key_mgmt, "ieee8021x") || !strcmp (key_mgmt, "wpa-eap")) {
-		    if (!setting_8021x)
-		    	return FALSE;
-			if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, con_uuid, mtu, FALSE))
+		    if (!setting_8021x) {
+				g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+				             "Cannot set key-mgmt %s with missing 8021x setting", key_mgmt);
+				return FALSE;
+			}
+			if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, con_uuid, mtu, FALSE, error))
 				return FALSE;
 		}
 
@@ -738,14 +775,14 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 			/* If using WPA Enterprise, enable optimized background scanning
 			 * to ensure roaming within an ESS works well.
 			 */
-			if (!nm_supplicant_config_add_option (self, "bgscan", "simple:30:-65:300", -1, FALSE))
-				nm_log_warn (LOGD_SUPPLICANT, "Error enabling background scanning for ESS roaming");
+			if (!nm_supplicant_config_add_option (self, "bgscan", "simple:30:-65:300", -1, FALSE, error))
+				return FALSE;
 
 			/* When using WPA-Enterprise, we want to use Proactive Key Caching (also
 			 * called Opportunistic Key Caching) to avoid full EAP exchanges when
 			 * roaming between access points in the same mobility group.
 			 */
-			if (!nm_supplicant_config_add_option (self, "proactive_key_caching", "1", -1, FALSE))
+			if (!nm_supplicant_config_add_option (self, "proactive_key_caching", "1", -1, FALSE, error))
 				return FALSE;
 		}
 	}
@@ -758,12 +795,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                         NMSetting8021x *setting,
                                         const char *con_uuid,
                                         guint32 mtu,
-                                        gboolean wired)
+                                        gboolean wired,
+                                        GError **error)
 {
 	NMSupplicantConfigPrivate *priv;
 	char *tmp;
 	const char *peapver, *value, *path;
-	gboolean success, added;
+	gboolean added;
 	GString *phase1, *phase2;
 	GBytes *bytes;
 	gboolean fast = FALSE;
@@ -771,7 +809,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	gboolean fast_provisoning_allowed = FALSE;
 	const char *ca_path_override = NULL, *ca_cert_override = NULL;
 	guint32 frag, hdrs;
-	char *frag_str = NULL;
+	gs_free char *frag_str = NULL;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
 	g_return_val_if_fail (setting != NULL, FALSE);
@@ -781,36 +819,35 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 
 	value = nm_setting_802_1x_get_password (setting);
 	if (value) {
-		if (!add_string_val (self, value, "password", FALSE, TRUE))
+		if (!add_string_val (self, value, "password", FALSE, TRUE, error))
 			return FALSE;
 	} else {
 		bytes = nm_setting_802_1x_get_password_raw (setting);
 		if (bytes) {
-			success = nm_supplicant_config_add_option (self,
-			                                           "password",
-			                                           (const char *) g_bytes_get_data (bytes, NULL),
-			                                           g_bytes_get_size (bytes),
-			                                           TRUE);
-			if (!success) {
-				nm_log_warn (LOGD_SUPPLICANT, "Error adding password-raw to supplicant config.");
+			if (!nm_supplicant_config_add_option (self,
+			                                      "password",
+			                                      (const char *) g_bytes_get_data (bytes, NULL),
+			                                      g_bytes_get_size (bytes),
+			                                      TRUE,
+			                                      error))
 				return FALSE;
-			}
 		}
 	}
 	value = nm_setting_802_1x_get_pin (setting);
-	if (!add_string_val (self, value, "pin", FALSE, TRUE))
+	if (!add_string_val (self, value, "pin", FALSE, TRUE, error))
 		return FALSE;
 
 	if (wired) {
-		if (!add_string_val (self, "IEEE8021X", "key_mgmt", FALSE, FALSE))
+		if (!add_string_val (self, "IEEE8021X", "key_mgmt", FALSE, FALSE, error))
 			return FALSE;
 		/* Wired 802.1x must always use eapol_flags=0 */
-		if (!add_string_val (self, "0", "eapol_flags", FALSE, FALSE))
+		if (!add_string_val (self, "0", "eapol_flags", FALSE, FALSE, error))
 			return FALSE;
-		nm_supplicant_config_set_ap_scan (self, 0);
+		priv->ap_scan = 0;
 	}
 
-	ADD_STRING_LIST_VAL (setting, 802_1x, eap_method, eap_methods, "eap", ' ', TRUE, FALSE);
+	if (!ADD_STRING_LIST_VAL (self, setting, 802_1x, eap_method, eap_methods, "eap", ' ', TRUE, FALSE, error))
+		return FALSE;
 
 	/* Check EAP method for special handling: PEAP + GTC, FAST */
 	num_eap = nm_setting_802_1x_get_num_eap_methods (setting);
@@ -831,11 +868,8 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		frag = CLAMP (mtu - hdrs, 100, frag);
 	frag_str = g_strdup_printf ("%u", frag);
 
-	if (!nm_supplicant_config_add_option (self, "fragment_size", frag_str, -1, FALSE)) {
-		g_free (frag_str);
+	if (!nm_supplicant_config_add_option (self, "fragment_size", frag_str, -1, FALSE, error))
 		return FALSE;
-	}
-	g_free (frag_str);
 
 	phase1 = g_string_new (NULL);
 	peapver = nm_setting_802_1x_get_phase1_peapver (setting);
@@ -857,13 +891,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		if (phase1->len)
 			g_string_append_c (phase1, ' ');
 		g_string_append_printf (phase1, "fast_provisioning=%s", value);
-		
+
 		if (strcmp (value, "0") != 0)
 			fast_provisoning_allowed = TRUE;
 	}
 
 	if (phase1->len) {
-		if (!add_string_val (self, phase1->str, "phase1", FALSE, FALSE)) {
+		if (!add_string_val (self, phase1->str, "phase1", FALSE, FALSE, error)) {
 			g_string_free (phase1, TRUE);
 			return FALSE;
 		}
@@ -886,7 +920,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	}
 
 	if (phase2->len) {
-		if (!add_string_val (self, phase2->str, "phase2", FALSE, FALSE)) {
+		if (!add_string_val (self, phase2->str, "phase2", FALSE, FALSE, error)) {
 			g_string_free (phase2, TRUE);
 			return FALSE;
 		}
@@ -896,24 +930,24 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	/* PAC file */
 	path = nm_setting_802_1x_get_pac_file (setting);
 	if (path) {
-		if (!add_string_val (self, path, "pac_file", FALSE, FALSE))
+		if (!add_string_val (self, path, "pac_file", FALSE, FALSE, error))
 			return FALSE;
 	} else {
 		/* PAC file is not specified.
 		 * If provisioning is allowed, use an blob format.
 		 */
 		if (fast_provisoning_allowed) {
-			char *blob_name = g_strdup_printf ("blob://pac-blob-%s", con_uuid);
-			if (!add_string_val (self, blob_name, "pac_file", FALSE, FALSE)) {
-				g_free (blob_name);
+			gs_free char *blob_name = NULL;
+
+			blob_name = g_strdup_printf ("blob://pac-blob-%s", con_uuid);
+			if (!add_string_val (self, blob_name, "pac_file", FALSE, FALSE, error))
 				return FALSE;
-			}
-			g_free (blob_name);
 		} else {
 			/* This is only error for EAP-FAST; don't disturb other methods. */
 			if (fast) {
-				nm_log_err (LOGD_SUPPLICANT, "EAP-FAST error: no PAC file provided and "
-				                              "automatic PAC provisioning is disabled.");
+				g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+				             "EAP-FAST error: no PAC file provided and "
+				             "automatic PAC provisioning is disabled");
 				return FALSE;
 			}
 		}
@@ -932,7 +966,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	path = nm_setting_802_1x_get_ca_path (setting);
 	path = ca_path_override ? ca_path_override : path;
 	if (path) {
-		if (!add_string_val (self, path, "ca_path", FALSE, FALSE))
+		if (!add_string_val (self, path, "ca_path", FALSE, FALSE, error))
 			return FALSE;
 	}
 
@@ -940,23 +974,24 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	path = nm_setting_802_1x_get_phase2_ca_path (setting);
 	path = ca_path_override ? ca_path_override : path;
 	if (path) {
-		if (!add_string_val (self, path, "ca_path2", FALSE, FALSE))
+		if (!add_string_val (self, path, "ca_path2", FALSE, FALSE, error))
 			return FALSE;
 	}
 
 	/* CA certificate */
 	if (ca_cert_override) {
-		if (!add_string_val (self, ca_cert_override, "ca_cert", FALSE, FALSE))
+		if (!add_string_val (self, ca_cert_override, "ca_cert", FALSE, FALSE, error))
 			return FALSE;
 	} else {
 		switch (nm_setting_802_1x_get_ca_cert_scheme (setting)) {
 		case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 			bytes = nm_setting_802_1x_get_ca_cert_blob (setting);
-			ADD_BLOB_VAL (bytes, "ca_cert", con_uuid);
+			if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "ca_cert", con_uuid, error))
+				return FALSE;
 			break;
 		case NM_SETTING_802_1X_CK_SCHEME_PATH:
 			path = nm_setting_802_1x_get_ca_cert_path (setting);
-			if (!add_string_val (self, path, "ca_cert", FALSE, FALSE))
+			if (!add_string_val (self, path, "ca_cert", FALSE, FALSE, error))
 				return FALSE;
 			break;
 		default:
@@ -966,17 +1001,18 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 
 	/* Phase 2 CA certificate */
 	if (ca_cert_override) {
-		if (!add_string_val (self, ca_cert_override, "ca_cert2", FALSE, FALSE))
+		if (!add_string_val (self, ca_cert_override, "ca_cert2", FALSE, FALSE, error))
 			return FALSE;
 	} else {
 		switch (nm_setting_802_1x_get_phase2_ca_cert_scheme (setting)) {
 		case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 			bytes = nm_setting_802_1x_get_phase2_ca_cert_blob (setting);
-			ADD_BLOB_VAL (bytes, "ca_cert2", con_uuid);
+			if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "ca_cert2", con_uuid, error))
+				return FALSE;
 			break;
 		case NM_SETTING_802_1X_CK_SCHEME_PATH:
 			path = nm_setting_802_1x_get_phase2_ca_cert_path (setting);
-			if (!add_string_val (self, path, "ca_cert2", FALSE, FALSE))
+			if (!add_string_val (self, path, "ca_cert2", FALSE, FALSE, error))
 				return FALSE;
 			break;
 		default:
@@ -986,27 +1022,30 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 
 	/* Subject match */
 	value = nm_setting_802_1x_get_subject_match (setting);
-	if (!add_string_val (self, value, "subject_match", FALSE, FALSE))
+	if (!add_string_val (self, value, "subject_match", FALSE, FALSE, error))
 		return FALSE;
 	value = nm_setting_802_1x_get_phase2_subject_match (setting);
-	if (!add_string_val (self, value, "subject_match2", FALSE, FALSE))
+	if (!add_string_val (self, value, "subject_match2", FALSE, FALSE, error))
 		return FALSE;
 
 	/* altSubjectName match */
-	ADD_STRING_LIST_VAL (setting, 802_1x, altsubject_match, altsubject_matches, "altsubject_match", ';', FALSE, FALSE);
-	ADD_STRING_LIST_VAL (setting, 802_1x, phase2_altsubject_match, phase2_altsubject_matches, "altsubject_match2", ';', FALSE, FALSE);
+	if (!ADD_STRING_LIST_VAL (self, setting, 802_1x, altsubject_match, altsubject_matches, "altsubject_match", ';', FALSE, FALSE, error))
+		return FALSE;
+	if (!ADD_STRING_LIST_VAL (self, setting, 802_1x, phase2_altsubject_match, phase2_altsubject_matches, "altsubject_match2", ';', FALSE, FALSE, error))
+		return FALSE;
 
 	/* Private key */
 	added = FALSE;
 	switch (nm_setting_802_1x_get_private_key_scheme (setting)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 		bytes = nm_setting_802_1x_get_private_key_blob (setting);
-		ADD_BLOB_VAL (bytes, "private_key", con_uuid);
+		if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "private_key", con_uuid, error))
+			return FALSE;
 		added = TRUE;
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
 		path = nm_setting_802_1x_get_private_key_path (setting);
-		if (!add_string_val (self, path, "private_key", FALSE, FALSE))
+		if (!add_string_val (self, path, "private_key", FALSE, FALSE, error))
 			return FALSE;
 		added = TRUE;
 		break;
@@ -1028,7 +1067,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 			 * isn't decrypted at all.
 			 */
 			value = nm_setting_802_1x_get_private_key_password (setting);
-			if (!add_string_val (self, value, "private_key_passwd", FALSE, TRUE))
+			if (!add_string_val (self, value, "private_key_passwd", FALSE, TRUE, error))
 				return FALSE;
 		}
 
@@ -1039,11 +1078,12 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 			switch (nm_setting_802_1x_get_client_cert_scheme (setting)) {
 			case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 				bytes = nm_setting_802_1x_get_client_cert_blob (setting);
-				ADD_BLOB_VAL (bytes, "client_cert", con_uuid);
+				if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "client_cert", con_uuid, error))
+					return FALSE;
 				break;
 			case NM_SETTING_802_1X_CK_SCHEME_PATH:
 				path = nm_setting_802_1x_get_client_cert_path (setting);
-				if (!add_string_val (self, path, "client_cert", FALSE, FALSE))
+				if (!add_string_val (self, path, "client_cert", FALSE, FALSE, error))
 					return FALSE;
 				break;
 			default:
@@ -1057,12 +1097,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	switch (nm_setting_802_1x_get_phase2_private_key_scheme (setting)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 		bytes = nm_setting_802_1x_get_phase2_private_key_blob (setting);
-		ADD_BLOB_VAL (bytes, "private_key2", con_uuid);
+		if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "private_key2", con_uuid, error))
+			return FALSE;
 		added = TRUE;
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
 		path = nm_setting_802_1x_get_phase2_private_key_path (setting);
-		if (!add_string_val (self, path, "private_key2", FALSE, FALSE))
+		if (!add_string_val (self, path, "private_key2", FALSE, FALSE, error))
 			return FALSE;
 		added = TRUE;
 		break;
@@ -1084,7 +1125,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 			 * isn't decrypted at all.
 			 */
 			value = nm_setting_802_1x_get_phase2_private_key_password (setting);
-			if (!add_string_val (self, value, "private_key2_passwd", FALSE, TRUE))
+			if (!add_string_val (self, value, "private_key2_passwd", FALSE, TRUE, error))
 				return FALSE;
 		}
 
@@ -1095,11 +1136,12 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 			switch (nm_setting_802_1x_get_phase2_client_cert_scheme (setting)) {
 			case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 				bytes = nm_setting_802_1x_get_phase2_client_cert_blob (setting);
-				ADD_BLOB_VAL (bytes, "client_cert2", con_uuid);
+				if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "client_cert2", con_uuid, error))
+					return FALSE;
 				break;
 			case NM_SETTING_802_1X_CK_SCHEME_PATH:
 				path = nm_setting_802_1x_get_phase2_client_cert_path (setting);
-				if (!add_string_val (self, path, "client_cert2", FALSE, FALSE))
+				if (!add_string_val (self, path, "client_cert2", FALSE, FALSE, error))
 					return FALSE;
 				break;
 			default:
@@ -1109,18 +1151,18 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	}
 
 	value = nm_setting_802_1x_get_identity (setting);
-	if (!add_string_val (self, value, "identity", FALSE, FALSE))
+	if (!add_string_val (self, value, "identity", FALSE, FALSE, error))
 		return FALSE;
 	value = nm_setting_802_1x_get_anonymous_identity (setting);
-	if (!add_string_val (self, value, "anonymous_identity", FALSE, FALSE))
+	if (!add_string_val (self, value, "anonymous_identity", FALSE, FALSE, error))
 		return FALSE;
 
 	return TRUE;
 }
 
 gboolean
-nm_supplicant_config_add_no_security (NMSupplicantConfig *self)
+nm_supplicant_config_add_no_security (NMSupplicantConfig *self, GError **error)
 {
-	return nm_supplicant_config_add_option (self, "key_mgmt", "NONE", -1, FALSE);
+	return nm_supplicant_config_add_option (self, "key_mgmt", "NONE", -1, FALSE, error);
 }
 
diff --git a/src/supplicant-manager/nm-supplicant-config.h b/src/supplicant-manager/nm-supplicant-config.h
index 9708a6d3..921bc16c 100644
--- a/src/supplicant-manager/nm-supplicant-config.h
+++ b/src/supplicant-manager/nm-supplicant-config.h
@@ -22,10 +22,10 @@
 #ifndef __NETWORKMANAGER_SUPPLICANT_CONFIG_H__
 #define __NETWORKMANAGER_SUPPLICANT_CONFIG_H__
 
-#include <glib-object.h>
 #include <nm-setting-wireless.h>
 #include <nm-setting-wireless-security.h>
 #include <nm-setting-8021x.h>
+#include "nm-default.h"
 #include "nm-supplicant-types.h"
 
 G_BEGIN_DECLS
@@ -54,8 +54,7 @@ NMSupplicantConfig *nm_supplicant_config_new (void);
 
 guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self);
 
-void nm_supplicant_config_set_ap_scan (NMSupplicantConfig *self,
-                                       guint32 ap_scan);
+const char *nm_supplicant_config_get_mac_randomization (NMSupplicantConfig *self);
 
 gboolean nm_supplicant_config_fast_required (NMSupplicantConfig *self);
 
@@ -65,21 +64,27 @@ GHashTable *nm_supplicant_config_get_blobs (NMSupplicantConfig *self);
 
 gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self,
                                                     NMSettingWireless *setting,
-                                                    guint32 fixed_freq);
+                                                    guint32 fixed_freq,
+                                                    NMSupplicantFeature mac_randomization_support,
+                                                    NMSettingMacRandomization mac_randomization_fallback,
+                                                    GError **error);
 
 gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                              NMSettingWirelessSecurity *setting,
                                                              NMSetting8021x *setting_8021x,
                                                              const char *con_uuid,
-                                                             guint32 mtu);
+                                                             guint32 mtu,
+                                                             GError **error);
 
-gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self);
+gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self,
+                                               GError **error);
 
 gboolean nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                                  NMSetting8021x *setting,
                                                  const char *con_uuid,
                                                  guint32 mtu,
-                                                 gboolean wired);
+                                                 gboolean wired,
+                                                 GError **error);
 
 G_END_DECLS
 
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c
index 30be23ae..9251af1f 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/nm-supplicant-interface.c
@@ -23,15 +23,13 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <glib.h>
 
+#include "nm-default.h"
 #include "NetworkManagerUtils.h"
 #include "nm-supplicant-interface.h"
-#include "nm-logging.h"
 #include "nm-supplicant-config.h"
-#include "nm-glib-compat.h"
-#include "gsystem-local-alloc.h"
 #include "nm-core-internal.h"
+#include "nm-dbus-compat.h"
 
 #define WPAS_DBUS_IFACE_INTERFACE   WPAS_DBUS_INTERFACE ".Interface"
 #define WPAS_DBUS_IFACE_BSS         WPAS_DBUS_INTERFACE ".BSS"
@@ -64,6 +62,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
 enum {
 	PROP_0 = 0,
 	PROP_SCANNING,
+	PROP_CURRENT_BSS,
 	LAST_PROP
 };
 
@@ -72,7 +71,8 @@ typedef struct {
 	char *         dev;
 	gboolean       is_wireless;
 	gboolean       has_credreq;  /* Whether querying 802.1x credentials is supported */
-	ApSupport      ap_support;   /* Lightweight AP mode support */
+	NMSupplicantFeature ap_support;   /* Lightweight AP mode support */
+	NMSupplicantFeature mac_randomization_support;
 	gboolean       fast_supported;
 	guint32        max_scan_ssids;
 	guint32        ready_count;
@@ -91,6 +91,7 @@ typedef struct {
 	char *         net_path;
 	guint32        blobs_left;
 	GHashTable *   bss_proxies;
+	char *         current_bss;
 
 	gint32         last_scan; /* timestamp as returned by nm_utils_get_monotonic_timestamp_s() */
 
@@ -333,6 +334,17 @@ nm_supplicant_interface_get_scanning (NMSupplicantInterface *self)
 	return FALSE;
 }
 
+const char *
+nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self)
+{
+	NMSupplicantInterfacePrivate *priv;
+
+	g_return_val_if_fail (self != NULL, FALSE);
+
+	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	return priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY ? priv->current_bss : NULL;
+}
+
 gint32
 nm_supplicant_interface_get_last_scan_time (NMSupplicantInterface *self)
 {
@@ -413,21 +425,10 @@ nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self,
 	                                5000,
 	                                NULL,
 	                                error);
-	/* reply will be unrefed when function exits */
-	return !!reply;
-}
-
-static gboolean
-_dbus_error_has_name (GError *error, const char *dbus_error_name)
-{
-	gs_free char *error_name = NULL;
-	gboolean is_error = FALSE;
+	if (error && *error)
+		g_dbus_error_strip_remote_error (*error);
 
-	if (error && g_dbus_error_is_remote_error (error)) {
-		error_name = g_dbus_error_get_remote_error (error);
-		is_error = !g_strcmp0 (error_name, dbus_error_name);
-	}
-	return is_error;
+	return !!reply;
 }
 
 static void
@@ -452,7 +453,7 @@ iface_check_netreply_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
 	self = NM_SUPPLICANT_INTERFACE (user_data);
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-	if (variant || _dbus_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs"))
+	if (variant || _nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs"))
 		priv->has_credreq = TRUE;
 
 	nm_log_dbg (LOGD_SUPPLICANT, "Supplicant %s network credentials requests",
@@ -461,7 +462,7 @@ iface_check_netreply_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
 	iface_check_ready (self);
 }
 
-ApSupport
+NMSupplicantFeature
 nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self)
 {
 	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->ap_support;
@@ -469,7 +470,7 @@ nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self)
 
 void
 nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self,
-                                        ApSupport ap_support)
+                                        NMSupplicantFeature ap_support)
 {
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
@@ -480,8 +481,31 @@ nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self,
 		priv->ap_support = ap_support;
 }
 
+NMSupplicantFeature
+nm_supplicant_interface_get_mac_randomization_support (NMSupplicantInterface *self)
+{
+	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->mac_randomization_support;
+}
+
+static void
+set_preassoc_scan_mac_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+{
+	gs_unref_variant GVariant *variant = NULL;
+	gs_free_error GError *error = NULL;
+
+	variant = _nm_dbus_proxy_call_finish (proxy, result,
+	                                      G_VARIANT_TYPE ("()"),
+	                                      &error);
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+	if (error)
+		nm_log_warn (LOGD_SUPPLICANT, "Failed to enable scan MAC address randomization");
+
+	iface_check_ready (NM_SUPPLICANT_INTERFACE (user_data));
+}
+
 static void
-iface_check_ap_mode_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 {
 	NMSupplicantInterface *self;
 	NMSupplicantInterfacePrivate *priv;
@@ -489,77 +513,115 @@ iface_check_ap_mode_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d
 	gs_free_error GError *error = NULL;
 	const char *data;
 
-	/* The ProbeRequest method only exists if AP mode has been enabled */
-	variant = g_dbus_proxy_call_finish (proxy, result, &error);
+	variant = _nm_dbus_proxy_call_finish (proxy, result,
+	                                      G_VARIANT_TYPE ("(s)"),
+	                                      &error);
 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
 
 	self = NM_SUPPLICANT_INTERFACE (user_data);
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-	if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE ("(s)"))) {
+	if (variant) {
 		g_variant_get (variant, "(&s)", &data);
+
+		/* The ProbeRequest method only exists if AP mode has been enabled */
 		if (strstr (data, "ProbeRequest"))
-			priv->ap_support = AP_SUPPORT_YES;
+			priv->ap_support = NM_SUPPLICANT_FEATURE_YES;
+
+		if (strstr (data, "PreassocMacAddr")) {
+			priv->mac_randomization_support = NM_SUPPLICANT_FEATURE_YES;
+
+			/* Turn on MAC randomization during scans by default */
+			priv->ready_count++;
+			g_dbus_proxy_call (priv->iface_proxy,
+			                   DBUS_INTERFACE_PROPERTIES ".Set",
+			                   g_variant_new ("(ssv)",
+			                                  WPAS_DBUS_IFACE_INTERFACE,
+			                                  "PreassocMacAddr",
+			                                  g_variant_new_string ("1")),
+			                   G_DBUS_CALL_FLAGS_NONE,
+			                   -1,
+			                   priv->init_cancellable,
+			                   (GAsyncReadyCallback) set_preassoc_scan_mac_cb,
+			                   self);
+		}
 	}
 
 	iface_check_ready (self);
 }
 
-#define MATCH_SIGNAL(s, n, v, t) (!strcmp (s, n) && g_variant_is_of_type (v, t))
-
 static void
-signal_cb (GDBusProxy  *proxy,
-           const gchar *sender,
-           const gchar *signal,
-           GVariant    *args,
-           gpointer     user_data)
+wpas_iface_scan_done (GDBusProxy *proxy,
+                      gboolean success,
+                      gpointer user_data)
 {
 	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	const char *path, *field, *message;
-	gboolean success;
+	GVariant *props;
+	GHashTableIter iter;
+	char *bss_path;
+	GDBusProxy *bss_proxy;
 
-	if (MATCH_SIGNAL (signal, "ScanDone", args, G_VARIANT_TYPE ("(b)"))) {
-		GVariant *props;
-		GHashTableIter iter;
-		char *bss_path;
-		GDBusProxy *bss_proxy;
+	/* Cache last scan completed time */
+	priv->last_scan = nm_utils_get_monotonic_timestamp_s ();
+
+	g_signal_emit (self, signals[SCAN_DONE], 0, success);
+
+	/* Emit NEW_BSS so that wifi device has the APs (in case it removed them) */
+	g_hash_table_iter_init (&iter, priv->bss_proxies);
+	while (g_hash_table_iter_next (&iter, (gpointer) &bss_path, (gpointer) &bss_proxy)) {
+		if (g_object_get_data (G_OBJECT (bss_proxy), BSS_PROXY_INITED)) {
+			props = _get_bss_proxy_properties (self, bss_proxy);
+			if (props) {
+				g_signal_emit (self, signals[NEW_BSS], 0,
+				               bss_path,
+				               g_variant_ref_sink (props));
+				g_variant_unref (props);
+			}
+		}
+	}
+}
+
+static void
+wpas_iface_bss_added (GDBusProxy *proxy,
+                      const char *path,
+                      GVariant *props,
+                      gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-		/* Cache last scan completed time */
+	if (priv->scanning)
 		priv->last_scan = nm_utils_get_monotonic_timestamp_s ();
 
-		g_variant_get (args, "(b)", &success);
-		g_signal_emit (self, signals[SCAN_DONE], 0, success);
-
-		/* Emit NEW_BSS so that wifi device has the APs (in case it removed them) */
-		g_hash_table_iter_init (&iter, priv->bss_proxies);
-		while (g_hash_table_iter_next (&iter, (gpointer) &bss_path, (gpointer) &bss_proxy)) {
-			if (g_object_get_data (G_OBJECT (bss_proxy), BSS_PROXY_INITED)) {
-				props = _get_bss_proxy_properties (self, bss_proxy);
-				if (props) {
-					g_signal_emit (self, signals[NEW_BSS], 0,
-					               bss_path,
-					               g_variant_ref_sink (props));
-					g_variant_unref (props);
-				}
-			}
-		}
-	} else if (MATCH_SIGNAL (signal, "BSSAdded", args, G_VARIANT_TYPE ("(oa{sv})"))) {
-		if (priv->scanning)
-			priv->last_scan = nm_utils_get_monotonic_timestamp_s ();
+	handle_new_bss (self, path);
+}
 
-		g_variant_get (args, "(&oa{sv})", &path, NULL);
-		handle_new_bss (self, path);
-	} else if (MATCH_SIGNAL (signal, "BSSRemoved", args, G_VARIANT_TYPE ("(o)"))) {
-		g_variant_get (args, "(&o)", &path);
-		g_signal_emit (self, signals[BSS_REMOVED], 0, path);
-		g_hash_table_remove (priv->bss_proxies, path);
-	} else if (MATCH_SIGNAL (signal, "NetworkRequest", args, G_VARIANT_TYPE ("(oss)"))) {
-		g_variant_get (args, "(&o&s&s)", &path, &field, &message);
-		if (priv->has_credreq && priv->net_path && !g_strcmp0 (path, priv->net_path))
-			g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message);
-	}
+static void
+wpas_iface_bss_removed (GDBusProxy *proxy,
+                        const char *path,
+                        gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	g_signal_emit (self, signals[BSS_REMOVED], 0, path);
+	g_hash_table_remove (priv->bss_proxies, path);
+}
+
+static void
+wpas_iface_network_request (GDBusProxy *proxy,
+                            const char *path,
+                            const char *field,
+                            const char *message,
+                            gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	if (priv->has_credreq && priv->net_path && !g_strcmp0 (path, priv->net_path))
+		g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message);
 }
 
 static void
@@ -575,6 +637,8 @@ props_changed_cb (GDBusProxy *proxy,
 	gint32 i32;
 	GVariant *v;
 
+	g_object_freeze_notify (G_OBJECT (self));
+
 	if (g_variant_lookup (changed_properties, "Scanning", "b", &b))
 		set_scanning (self, b);
 
@@ -595,6 +659,16 @@ props_changed_cb (GDBusProxy *proxy,
 		g_free (array);
 	}
 
+	if (g_variant_lookup (changed_properties, "CurrentBSS", "&o", &s)) {
+		if (strcmp (s, "/") == 0)
+			s = NULL;
+		if (g_strcmp0 (s, priv->current_bss) != 0) {
+			g_free (priv->current_bss);
+			priv->current_bss = g_strdup (s);
+			g_object_notify (G_OBJECT (self), NM_SUPPLICANT_INTERFACE_CURRENT_BSS);
+		}
+	}
+
 	v = g_variant_lookup_value (changed_properties, "Capabilities", G_VARIANT_TYPE_VARDICT);
 	if (v) {
 		parse_capabilities (self, v);
@@ -614,6 +688,8 @@ props_changed_cb (GDBusProxy *proxy,
 				         priv->disconnect_reason);
 		}
 	}
+
+	g_object_thaw_notify (G_OBJECT (self));
 }
 
 static void
@@ -634,7 +710,38 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
 	self = NM_SUPPLICANT_INTERFACE (user_data);
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-	g_signal_connect (priv->iface_proxy, "g-signal", G_CALLBACK (signal_cb), self);
+	_nm_dbus_signal_connect (priv->iface_proxy, "ScanDone", G_VARIANT_TYPE ("(b)"),
+	                         G_CALLBACK (wpas_iface_scan_done), self);
+	_nm_dbus_signal_connect (priv->iface_proxy, "BSSAdded", G_VARIANT_TYPE ("(oa{sv})"),
+	                         G_CALLBACK (wpas_iface_bss_added), self);
+	_nm_dbus_signal_connect (priv->iface_proxy, "BSSRemoved", G_VARIANT_TYPE ("(o)"),
+	                         G_CALLBACK (wpas_iface_bss_removed), self);
+	_nm_dbus_signal_connect (priv->iface_proxy, "NetworkRequest", G_VARIANT_TYPE ("(oss)"),
+	                         G_CALLBACK (wpas_iface_network_request), self);
+
+	/* Scan result aging parameters */
+	g_dbus_proxy_call (priv->iface_proxy,
+	                   "org.freedesktop.DBus.Properties.Set",
+	                   g_variant_new ("(ssv)",
+	                                  WPAS_DBUS_IFACE_INTERFACE,
+	                                  "BSSExpireAge",
+	                                  g_variant_new_uint32 (250)),
+	                   G_DBUS_CALL_FLAGS_NONE,
+	                   -1,
+	                   priv->init_cancellable,
+	                   NULL,
+	                   NULL);
+	g_dbus_proxy_call (priv->iface_proxy,
+	                   "org.freedesktop.DBus.Properties.Set",
+	                   g_variant_new ("(ssv)",
+	                                  WPAS_DBUS_IFACE_INTERFACE,
+	                                  "BSSExpireCount",
+	                                  g_variant_new_uint32 (2)),
+	                   G_DBUS_CALL_FLAGS_NONE,
+	                   -1,
+	                   priv->init_cancellable,
+	                   NULL,
+	                   NULL);
 
 	/* Check whether NetworkReply and AP mode are supported */
 	priv->ready_count = 1;
@@ -650,7 +757,8 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
 	                   (GAsyncReadyCallback) iface_check_netreply_cb,
 	                   self);
 
-	if (priv->ap_support == AP_SUPPORT_UNKNOWN) {
+	if (priv->ap_support == NM_SUPPLICANT_FEATURE_UNKNOWN ||
+	    priv->mac_randomization_support == NM_SUPPLICANT_FEATURE_UNKNOWN) {
 		/* If the global supplicant capabilities property is not present, we can
 		 * fall back to checking whether the ProbeRequest method is supported.  If
 		 * neither of these works we have no way of determining if AP mode is
@@ -658,12 +766,12 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
 		 */
 		priv->ready_count++;
 		g_dbus_proxy_call (priv->iface_proxy,
-		                   "org.freedesktop.DBus.Introspectable.Introspect",
+		                   DBUS_INTERFACE_INTROSPECTABLE ".Introspect",
 		                   NULL,
 		                   G_DBUS_CALL_FLAGS_NONE,
 		                   -1,
 		                   priv->init_cancellable,
-		                   (GAsyncReadyCallback) iface_check_ap_mode_cb,
+		                   (GAsyncReadyCallback) iface_introspect_cb,
 		                   self);
 	}
 }
@@ -698,20 +806,22 @@ interface_get_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	NMSupplicantInterfacePrivate *priv;
 	gs_unref_variant GVariant *variant = NULL;
 	gs_free_error GError *error = NULL;
-	char *path;
+	const char *path;
 
-	variant = g_dbus_proxy_call_finish (proxy, result, &error);
+	variant = _nm_dbus_proxy_call_finish (proxy, result,
+	                                      G_VARIANT_TYPE ("(o)"),
+	                                      &error);
 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
 
 	self = NM_SUPPLICANT_INTERFACE (user_data);
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-	if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE ("(o)"))) {
-		g_variant_get (variant, "(o)", &path);
+	if (variant) {
+		g_variant_get (variant, "(&o)", &path);
 		interface_add_done (self, path);
-		g_free (path);
 	} else {
+		g_dbus_error_strip_remote_error (error);
 		nm_log_err (LOGD_SUPPLICANT, "(%s): error getting interface: %s", priv->dev, error->message);
 		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
 	}
@@ -724,20 +834,21 @@ interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	NMSupplicantInterfacePrivate *priv;
 	gs_free_error GError *error = NULL;
 	gs_unref_variant GVariant *variant = NULL;
-	char *path;
+	const char *path;
 
-	variant = g_dbus_proxy_call_finish (proxy, result, &error);
+	variant = _nm_dbus_proxy_call_finish (proxy, result,
+	                                      G_VARIANT_TYPE ("(o)"),
+	                                      &error);
 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
 
 	self = NM_SUPPLICANT_INTERFACE (user_data);
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-	if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE ("(o)"))) {
-		g_variant_get (variant, "(o)", &path);
+	if (variant) {
+		g_variant_get (variant, "(&o)", &path);
 		interface_add_done (self, path);
-		g_free (path);
-	} else if (_dbus_error_has_name (error, WPAS_ERROR_EXISTS_ERROR)) {
+	} else if (_nm_dbus_error_has_name (error, WPAS_ERROR_EXISTS_ERROR)) {
 		/* Interface already added, just get its object path */
 		g_dbus_proxy_call (priv->wpas_proxy,
 		                   "GetInterface",
@@ -759,10 +870,12 @@ interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 		 * activation.  Wait for it to start by moving back to the INIT
 		 * state.
 		 */
+		g_dbus_error_strip_remote_error (error);
 		nm_log_dbg (LOGD_SUPPLICANT, "(%s): failed to activate supplicant: %s",
 		            priv->dev, error->message);
 		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_INIT);
 	} else {
+		g_dbus_error_strip_remote_error (error);
 		nm_log_err (LOGD_SUPPLICANT, "(%s): error adding interface: %s", priv->dev, error->message);
 		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
 	}
@@ -877,8 +990,12 @@ log_result_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	gs_free_error GError *error = NULL;
 
 	reply = g_dbus_proxy_call_finish (proxy, result, &error);
-	if (!reply && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-		nm_log_warn (LOGD_SUPPLICANT, "Failed to %s: %s.", error->message, (char *) user_data);
+	if (   !reply
+	    && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
+	    && !strstr (error->message, "fi.w1.wpa_supplicant1.NotConnected")) {
+		g_dbus_error_strip_remote_error (error);
+		nm_log_warn (LOGD_SUPPLICANT, "Failed to %s: %s.", (char *) user_data, error->message);
+	}
 }
 
 void
@@ -936,6 +1053,7 @@ select_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 
 	reply = g_dbus_proxy_call_finish (proxy, result, &err);
 	if (!reply && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		g_dbus_error_strip_remote_error (err);
 		nm_log_warn (LOGD_SUPPLICANT, "Couldn't select network config: %s.", err->message);
 		emit_error_helper (NM_SUPPLICANT_INTERFACE (user_data), err);
 	}
@@ -978,6 +1096,7 @@ add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	if (reply)
 		call_select_network (self);
 	else {
+		g_dbus_error_strip_remote_error (err);
 		nm_log_warn (LOGD_SUPPLICANT, "Couldn't set network certificates: %s.", err->message);
 		emit_error_helper (self, err);
 	}
@@ -995,30 +1114,26 @@ add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	const char *blob_name;
 	GByteArray *blob_data;
 
-	reply = g_dbus_proxy_call_finish (proxy, result, &error);
+	reply = _nm_dbus_proxy_call_finish (proxy, result,
+	                                    G_VARIANT_TYPE ("(o)"),
+	                                    &error);
 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
 
 	self = NM_SUPPLICANT_INTERFACE (user_data);
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-	if (reply && !g_variant_is_of_type (reply, G_VARIANT_TYPE ("(o)"))) {
-		error = g_error_new (NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
-		                     "Unexpected AddNetwork reply type %s",
-		                     g_variant_get_type_string (reply));
-	}
-
 	g_free (priv->net_path);
 	priv->net_path = NULL;
 
 	if (error) {
+		g_dbus_error_strip_remote_error (error);
 		nm_log_warn (LOGD_SUPPLICANT, "Adding network to supplicant failed: %s.", error->message);
 		emit_error_helper (self, error);
 		return;
 	}
 
 	g_variant_get (reply, "(o)", &priv->net_path);
-	g_assert (priv->net_path);
 
 	/* Send blobs first; otherwise jump to selecting the network */
 	blobs = nm_supplicant_config_get_blobs (priv->cfg);
@@ -1043,6 +1158,51 @@ add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 }
 
 static void
+add_network (NMSupplicantInterface *self)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	g_dbus_proxy_call (priv->iface_proxy,
+	                   "AddNetwork",
+	                   g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->cfg)),
+	                   G_DBUS_CALL_FLAGS_NONE,
+	                   -1,
+	                   priv->assoc_cancellable,
+	                   (GAsyncReadyCallback) add_network_cb,
+	                   self);
+}
+
+static void
+set_mac_randomization_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+{
+	NMSupplicantInterface *self;
+	NMSupplicantInterfacePrivate *priv;
+	gs_unref_variant GVariant *reply = NULL;
+	gs_free_error GError *error = NULL;
+
+	reply = g_dbus_proxy_call_finish (proxy, result, &error);
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+
+	self = NM_SUPPLICANT_INTERFACE (user_data);
+	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	if (!reply) {
+		g_dbus_error_strip_remote_error (error);
+		nm_log_warn (LOGD_SUPPLICANT, "Couldn't send MAC randomization mode to "
+		             "the supplicant interface: %s.",
+		             error->message);
+		emit_error_helper (self, error);
+		return;
+	}
+
+	nm_log_info (LOGD_SUPPLICANT, "Config: set MAC randomization to %s",
+	             nm_supplicant_config_get_mac_randomization (priv->cfg));
+
+	add_network (self);
+}
+
+static void
 set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 {
 	NMSupplicantInterface *self;
@@ -1058,6 +1218,7 @@ set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
 	if (!reply) {
+		g_dbus_error_strip_remote_error (error);
 		nm_log_warn (LOGD_SUPPLICANT, "Couldn't send AP scan mode to the supplicant interface: %s.",
 		             error->message);
 		emit_error_helper (self, error);
@@ -1067,19 +1228,30 @@ set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	nm_log_info (LOGD_SUPPLICANT, "Config: set interface ap_scan to %d",
 	             nm_supplicant_config_get_ap_scan (priv->cfg));
 
-	g_dbus_proxy_call (priv->iface_proxy,
-	                   "AddNetwork",
-	                   g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->cfg)),
-	                   G_DBUS_CALL_FLAGS_NONE,
-	                   -1,
-	                   priv->assoc_cancellable,
-	                   (GAsyncReadyCallback) add_network_cb,
-	                   self);
+	if (priv->mac_randomization_support == NM_SUPPLICANT_FEATURE_YES) {
+		const char *mac_randomization = nm_supplicant_config_get_mac_randomization (priv->cfg);
+
+		/* Enable/disable association MAC address randomization */
+		g_dbus_proxy_call (priv->iface_proxy,
+		                   DBUS_INTERFACE_PROPERTIES ".Set",
+		                   g_variant_new ("(ssv)",
+		                                  WPAS_DBUS_IFACE_INTERFACE,
+		                                  "MacAddr",
+		                                  g_variant_new_string (mac_randomization)),
+		                   G_DBUS_CALL_FLAGS_NONE,
+		                   -1,
+		                   priv->assoc_cancellable,
+		                   (GAsyncReadyCallback) set_mac_randomization_cb,
+		                   self);
+	} else {
+		add_network (self);
+	}
 }
 
 gboolean
 nm_supplicant_interface_set_config (NMSupplicantInterface *self,
-                                    NMSupplicantConfig *cfg)
+                                    NMSupplicantConfig *cfg,
+                                    GError **error)
 {
 	NMSupplicantInterfacePrivate *priv;
 
@@ -1093,7 +1265,8 @@ nm_supplicant_interface_set_config (NMSupplicantInterface *self,
 	 * it an EAP-FAST configuration.
 	 */
 	if (nm_supplicant_config_fast_required (cfg) && !priv->fast_supported) {
-		nm_log_warn (LOGD_SUPPLICANT, "EAP-FAST is not supported by the supplicant");
+		g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
+		             "EAP-FAST is not supported by the supplicant");
 		return FALSE;
 	}
 
@@ -1101,7 +1274,7 @@ nm_supplicant_interface_set_config (NMSupplicantInterface *self,
 	if (cfg) {
 		priv->cfg = g_object_ref (cfg);
 		g_dbus_proxy_call (priv->iface_proxy,
-		                   "org.freedesktop.DBus.Properties.Set",
+		                   DBUS_INTERFACE_PROPERTIES ".Set",
 		                   g_variant_new ("(ssv)",
 		                                  WPAS_DBUS_IFACE_INTERFACE,
 		                                  "ApScan",
@@ -1258,7 +1431,7 @@ NMSupplicantInterface *
 nm_supplicant_interface_new (const char *ifname,
                              gboolean is_wireless,
                              gboolean fast_supported,
-                             ApSupport ap_support,
+                             NMSupplicantFeature ap_support,
                              gboolean start_now)
 {
 	NMSupplicantInterface *self;
@@ -1295,11 +1468,7 @@ set_property (GObject *object,
               const GValue *value,
               GParamSpec *pspec)
 {
-	switch (prop_id) {
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 }
 
 static void
@@ -1308,9 +1477,14 @@ get_property (GObject *object,
               GValue *value,
               GParamSpec *pspec)
 {
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);
+
 	switch (prop_id) {
 	case PROP_SCANNING:
-		g_value_set_boolean (value, NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object)->scanning);
+		g_value_set_boolean (value, priv->scanning);
+		break;
+	case PROP_CURRENT_BSS:
+		g_value_set_string (value, priv->current_bss);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1341,6 +1515,7 @@ dispose (GObject *object)
 	g_clear_pointer (&priv->net_path, g_free);
 	g_clear_pointer (&priv->dev, g_free);
 	g_clear_pointer (&priv->object_path, g_free);
+	g_clear_pointer (&priv->current_bss, g_free);
 
 	g_clear_object (&priv->cfg);
 
@@ -1367,6 +1542,13 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 		                       G_PARAM_READABLE |
 		                       G_PARAM_STATIC_STRINGS));
 
+	g_object_class_install_property
+		(object_class, PROP_CURRENT_BSS,
+		 g_param_spec_string (NM_SUPPLICANT_INTERFACE_CURRENT_BSS, "", "",
+		                      NULL,
+		                      G_PARAM_READABLE |
+		                      G_PARAM_STATIC_STRINGS));
+
 	/* Signals */
 	signals[STATE] =
 		g_signal_new (NM_SUPPLICANT_INTERFACE_STATE,
@@ -1398,7 +1580,7 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 		              G_SIGNAL_RUN_LAST,
 		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, bss_updated),
 		              NULL, NULL, NULL,
-		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VARIANT);
 
 	signals[BSS_REMOVED] =
 		g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_REMOVED,
diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h
index 1b1139d4..2f866076 100644
--- a/src/supplicant-manager/nm-supplicant-interface.h
+++ b/src/supplicant-manager/nm-supplicant-interface.h
@@ -22,7 +22,7 @@
 #ifndef __NETWORKMANAGER_SUPPLICANT_INTERFACE_H__
 #define __NETWORKMANAGER_SUPPLICANT_INTERFACE_H__
 
-#include <glib-object.h>
+#include "nm-default.h"
 #include "nm-supplicant-types.h"
 
 /*
@@ -54,6 +54,10 @@ enum {
 #define NM_IS_SUPPLICANT_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_SUPPLICANT_INTERFACE))
 #define NM_SUPPLICANT_INTERFACE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass))
 
+/* Properties */
+#define NM_SUPPLICANT_INTERFACE_CURRENT_BSS      "current-bss"
+
+/* Signals */
 #define NM_SUPPLICANT_INTERFACE_STATE            "state"
 #define NM_SUPPLICANT_INTERFACE_REMOVED          "removed"
 #define NM_SUPPLICANT_INTERFACE_NEW_BSS          "new-bss"
@@ -63,12 +67,6 @@ enum {
 #define NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR "connection-error"
 #define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request"
 
-typedef enum {
-	AP_SUPPORT_UNKNOWN = 0,  /* Can't detect whether supported or not */
-	AP_SUPPORT_NO = 1,       /* AP mode definitely not supported */
-	AP_SUPPORT_YES = 2,      /* AP mode definitely supported */
-} ApSupport;
-
 struct _NMSupplicantInterface {
 	GObject parent;
 };
@@ -90,12 +88,12 @@ typedef struct {
 	/* interface saw a new BSS */
 	void (*new_bss)          (NMSupplicantInterface *iface,
 	                          const char *object_path,
-	                          GHashTable *props);
+	                          GVariant *props);
 
 	/* a BSS property changed */
 	void (*bss_updated)      (NMSupplicantInterface *iface,
 	                          const char *object_path,
-	                          GHashTable *props);
+	                          GVariant *props);
 
 	/* supplicant removed a BSS from its scan list */
 	void (*bss_removed)      (NMSupplicantInterface *iface,
@@ -116,20 +114,20 @@ typedef struct {
 	                             const char *message);
 } NMSupplicantInterfaceClass;
 
-
 GType nm_supplicant_interface_get_type (void);
 
 NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname,
                                                      gboolean is_wireless,
                                                      gboolean fast_supported,
-                                                     ApSupport ap_support,
+                                                     NMSupplicantFeature ap_support,
                                                      gboolean start_now);
 
 void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self,
                                                        gboolean available);
 
 gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface,
-                                             NMSupplicantConfig * cfg);
+                                             NMSupplicantConfig * cfg,
+                                             GError **error);
 
 void nm_supplicant_interface_disconnect (NMSupplicantInterface * iface);
 
@@ -145,6 +143,8 @@ const char *nm_supplicant_interface_state_to_string (guint32 state);
 
 gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self);
 
+const char *nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self);
+
 gint32 nm_supplicant_interface_get_last_scan_time (NMSupplicantInterface *self);
 
 const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self);
@@ -158,9 +158,11 @@ gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self,
                                                     const char *value,
                                                     GError **error);
 
-ApSupport nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self);
+NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self);
 
 void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self,
-                                             ApSupport apmode);
+                                             NMSupplicantFeature apmode);
+
+NMSupplicantFeature nm_supplicant_interface_get_mac_randomization_support (NMSupplicantInterface *self);
 
 #endif	/* NM_SUPPLICANT_INTERFACE_H */
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c
index 083f2ebc..29c0cd42 100644
--- a/src/supplicant-manager/nm-supplicant-manager.c
+++ b/src/supplicant-manager/nm-supplicant-manager.c
@@ -22,14 +22,11 @@
 #include "config.h"
 
 #include <string.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-
-#include "nm-glib-compat.h"
 
+#include "nm-default.h"
 #include "nm-supplicant-manager.h"
 #include "nm-supplicant-interface.h"
-#include "nm-logging.h"
+#include "nm-supplicant-types.h"
 #include "nm-core-internal.h"
 
 #define NM_SUPPLICANT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
@@ -43,15 +40,19 @@ typedef struct {
 	GCancellable *   cancellable;
 	gboolean         running;
 
-	GHashTable *    ifaces;
-	gboolean        fast_supported;
-	ApSupport       ap_support;
-	guint           die_count_reset_id;
-	guint           die_count;
+	GHashTable *      ifaces;
+	gboolean          fast_supported;
+	NMSupplicantFeature ap_support;
+	guint             die_count_reset_id;
+	guint             die_count;
 } NMSupplicantManagerPrivate;
 
 /********************************************************************/
 
+G_DEFINE_QUARK (nm-supplicant-error-quark, nm_supplicant_error);
+
+/********************************************************************/
+
 static inline gboolean
 die_count_exceeded (guint32 count)
 {
@@ -150,15 +151,15 @@ update_capabilities (NMSupplicantManager *self)
 	 *
 	 * dbus: Add global capabilities property
 	 */
-	priv->ap_support = AP_SUPPORT_UNKNOWN;
+	priv->ap_support = NM_SUPPLICANT_FEATURE_UNKNOWN;
 
 	value = g_dbus_proxy_get_cached_property (priv->proxy, "Capabilities");
 	if (value) {
 		if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY)) {
 			array = g_variant_get_strv (value, NULL);
-			priv->ap_support = AP_SUPPORT_NO;
+			priv->ap_support = NM_SUPPLICANT_FEATURE_NO;
 			if (_nm_utils_string_in_list ("ap", array))
-				priv->ap_support = AP_SUPPORT_YES;
+				priv->ap_support = NM_SUPPLICANT_FEATURE_YES;
 			g_free (array);
 		}
 		g_variant_unref (value);
@@ -170,8 +171,8 @@ update_capabilities (NMSupplicantManager *self)
 		nm_supplicant_interface_set_ap_support (iface, priv->ap_support);
 
 	nm_log_dbg (LOGD_SUPPLICANT, "AP mode is %ssupported",
-	            (priv->ap_support == AP_SUPPORT_YES) ? "" :
-	                (priv->ap_support == AP_SUPPORT_NO) ? "not " : "possibly ");
+	            (priv->ap_support == NM_SUPPLICANT_FEATURE_YES) ? "" :
+	                (priv->ap_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly ");
 
 	/* EAP-FAST */
 	priv->fast_supported = FALSE;
@@ -344,10 +345,7 @@ dispose (GObject *object)
 {
 	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object);
 
-	if (priv->die_count_reset_id) {
-		g_source_remove (priv->die_count_reset_id);
-		priv->die_count_reset_id = 0;
-	}
+	nm_clear_g_source (&priv->die_count_reset_id);
 
 	if (priv->cancellable) {
 		g_cancellable_cancel (priv->cancellable);
diff --git a/src/supplicant-manager/nm-supplicant-manager.h b/src/supplicant-manager/nm-supplicant-manager.h
index 3b8fddf4..d7456467 100644
--- a/src/supplicant-manager/nm-supplicant-manager.h
+++ b/src/supplicant-manager/nm-supplicant-manager.h
@@ -22,7 +22,7 @@
 #ifndef __NETWORKMANAGER_SUPPLICANT_MANAGER_H__
 #define __NETWORKMANAGER_SUPPLICANT_MANAGER_H__
 
-#include <glib-object.h>
+#include "nm-default.h"
 #include "nm-supplicant-types.h"
 #include "nm-device.h"
 
diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.c b/src/supplicant-manager/nm-supplicant-settings-verify.c
index 1328fd51..f2d56540 100644
--- a/src/supplicant-manager/nm-supplicant-settings-verify.c
+++ b/src/supplicant-manager/nm-supplicant-settings-verify.c
@@ -20,12 +20,12 @@
 
 #include "config.h"
 
-#include <glib.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
+#include "nm-default.h"
 #include "nm-supplicant-settings-verify.h"
 
 struct Opt {
diff --git a/src/supplicant-manager/nm-supplicant-types.h b/src/supplicant-manager/nm-supplicant-types.h
index 1c16e494..e9be5be4 100644
--- a/src/supplicant-manager/nm-supplicant-types.h
+++ b/src/supplicant-manager/nm-supplicant-types.h
@@ -29,4 +29,24 @@ typedef struct _NMSupplicantManager NMSupplicantManager;
 typedef struct _NMSupplicantInterface NMSupplicantInterface;
 typedef struct _NMSupplicantConfig NMSupplicantConfig;
 
+typedef enum {
+	NM_SUPPLICANT_FEATURE_UNKNOWN = 0,  /* Can't detect whether supported or not */
+	NM_SUPPLICANT_FEATURE_NO = 1,       /* Feature definitely not supported */
+	NM_SUPPLICANT_FEATURE_YES = 2,      /* Feature definitely supported */
+} NMSupplicantFeature;
+
+/**
+ * NMSupplicantError:
+ * @NM_SUPPLICANT_ERROR_UNKNOWN: unknown or unclassified error
+ * @NM_SUPPLICANT_ERROR_CONFIG: a failure constructing the
+ *   wpa-supplicant configuration.
+ */
+typedef enum {
+	NM_SUPPLICANT_ERROR_UNKNOWN = 0,                    /*< nick=Unknown >*/
+	NM_SUPPLICANT_ERROR_CONFIG = 1,                     /*< nick=Config >*/
+} NMSupplicantError;
+
+#define NM_SUPPLICANT_ERROR (nm_supplicant_error_quark ())
+GQuark nm_supplicant_error_quark (void);
+
 #endif  /* NM_SUPPLICANT_TYPES_H */
diff --git a/src/supplicant-manager/tests/Makefile.am b/src/supplicant-manager/tests/Makefile.am
index 517f57b7..9ac0387c 100644
--- a/src/supplicant-manager/tests/Makefile.am
+++ b/src/supplicant-manager/tests/Makefile.am
@@ -1,18 +1,17 @@
 SUBDIRS=certs
 
 AM_CPPFLAGS = \
-	-I$(top_srcdir)/include \
-	-I$(top_builddir)/include \
+	-I$(top_srcdir)/shared \
+	-I$(top_builddir)/shared \
 	-I$(top_srcdir)/libnm-core \
 	-I$(top_builddir)/libnm-core \
 	-I$(top_srcdir)/src \
 	-I$(top_srcdir)/src/supplicant-manager \
 	-DG_LOG_DOMAIN=\""NetworkManager"\" \
-	-DNETWORKMANAGER_COMPILATION \
+	-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \
 	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
 	-DTEST_CERT_DIR=\"$(srcdir)/certs/\" \
-	$(GLIB_CFLAGS) \
-	$(DBUS_CFLAGS)
+	$(GLIB_CFLAGS)
 
 noinst_PROGRAMS = test-supplicant-config
 
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index e36c4c00..cbc8a5a1 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/tests/Makefile.in
@@ -444,7 +444,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
-CKDB_PATH = @CKDB_PATH@
 CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
 CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
 CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
@@ -456,8 +455,6 @@ CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DBUS_CFLAGS = @DBUS_CFLAGS@
-DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
-DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
 DBUS_LIBS = @DBUS_LIBS@
 DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
@@ -467,6 +464,7 @@ DHCPCD_PATH = @DHCPCD_PATH@
 DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
 DLLTOOL = @DLLTOOL@
 DNSMASQ_PATH = @DNSMASQ_PATH@
+DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
 ECHO_C = @ECHO_C@
@@ -521,16 +519,13 @@ INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
 INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
 INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
 IPTABLES_PATH = @IPTABLES_PATH@
-IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
-IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
 KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
 LCOV = @LCOV@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@
+LIBAUDIT_LIBS = @LIBAUDIT_LIBS@
 LIBDL = @LIBDL@
-LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
-LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
-LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
@@ -567,6 +562,8 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
+NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
 NM_MICRO_VERSION = @NM_MICRO_VERSION@
 NM_MINOR_VERSION = @NM_MINOR_VERSION@
@@ -595,7 +592,6 @@ POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
 PPPD_PATH = @PPPD_PATH@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
-PPPOE_PATH = @PPPOE_PATH@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
@@ -610,6 +606,8 @@ SYSTEMD_200_CFLAGS = @SYSTEMD_200_CFLAGS@
 SYSTEMD_200_LIBS = @SYSTEMD_200_LIBS@
 SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
 SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
+SYSTEMD_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@
+SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@
 SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
 SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
@@ -670,6 +668,7 @@ mkdir_p = @mkdir_p@
 nmbinary = @nmbinary@
 nmconfdir = @nmconfdir@
 nmdatadir = @nmdatadir@
+nmlibdir = @nmlibdir@
 nmrundir = @nmrundir@
 nmstatedir = @nmstatedir@
 oldincludedir = @oldincludedir@
@@ -677,6 +676,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -694,18 +694,17 @@ with_resolvconf = @with_resolvconf@
 with_valgrind = @with_valgrind@
 SUBDIRS = certs
 AM_CPPFLAGS = \
-	-I$(top_srcdir)/include \
-	-I$(top_builddir)/include \
+	-I$(top_srcdir)/shared \
+	-I$(top_builddir)/shared \
 	-I$(top_srcdir)/libnm-core \
 	-I$(top_builddir)/libnm-core \
 	-I$(top_srcdir)/src \
 	-I$(top_srcdir)/src/supplicant-manager \
 	-DG_LOG_DOMAIN=\""NetworkManager"\" \
-	-DNETWORKMANAGER_COMPILATION \
+	-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \
 	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
 	-DTEST_CERT_DIR=\"$(srcdir)/certs/\" \
-	$(GLIB_CFLAGS) \
-	$(DBUS_CFLAGS)
+	$(GLIB_CFLAGS)
 
 test_supplicant_config_SOURCES = \
 	test-supplicant-config.c
diff --git a/src/supplicant-manager/tests/certs/Makefile.in b/src/supplicant-manager/tests/certs/Makefile.in
index fcfdd689..7f29bb3c 100644
--- a/src/supplicant-manager/tests/certs/Makefile.in
+++ b/src/supplicant-manager/tests/certs/Makefile.in
@@ -146,7 +146,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
-CKDB_PATH = @CKDB_PATH@
 CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
 CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
 CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
@@ -158,8 +157,6 @@ CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DBUS_CFLAGS = @DBUS_CFLAGS@
-DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
-DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
 DBUS_LIBS = @DBUS_LIBS@
 DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
@@ -169,6 +166,7 @@ DHCPCD_PATH = @DHCPCD_PATH@
 DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
 DLLTOOL = @DLLTOOL@
 DNSMASQ_PATH = @DNSMASQ_PATH@
+DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
 ECHO_C = @ECHO_C@
@@ -223,16 +221,13 @@ INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
 INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
 INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
 IPTABLES_PATH = @IPTABLES_PATH@
-IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
-IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
 KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
 LCOV = @LCOV@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@
+LIBAUDIT_LIBS = @LIBAUDIT_LIBS@
 LIBDL = @LIBDL@
-LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
-LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
-LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
@@ -269,6 +264,8 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
+NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
 NM_MICRO_VERSION = @NM_MICRO_VERSION@
 NM_MINOR_VERSION = @NM_MINOR_VERSION@
@@ -297,7 +294,6 @@ POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
 PPPD_PATH = @PPPD_PATH@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
-PPPOE_PATH = @PPPOE_PATH@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
@@ -312,6 +308,8 @@ SYSTEMD_200_CFLAGS = @SYSTEMD_200_CFLAGS@
 SYSTEMD_200_LIBS = @SYSTEMD_200_LIBS@
 SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
 SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
+SYSTEMD_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@
+SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@
 SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
 SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
@@ -372,6 +370,7 @@ mkdir_p = @mkdir_p@
 nmbinary = @nmbinary@
 nmconfdir = @nmconfdir@
 nmdatadir = @nmdatadir@
+nmlibdir = @nmlibdir@
 nmrundir = @nmrundir@
 nmstatedir = @nmstatedir@
 oldincludedir = @oldincludedir@
@@ -379,6 +378,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/src/supplicant-manager/tests/test-supplicant-config.c b/src/supplicant-manager/tests/test-supplicant-config.c
index 15be2ba8..bd532b24 100644
--- a/src/supplicant-manager/tests/test-supplicant-config.c
+++ b/src/supplicant-manager/tests/test-supplicant-config.c
@@ -30,12 +30,11 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include <dbus/dbus-glib.h>
-
 #include "nm-core-internal.h"
 
 #include "nm-supplicant-config.h"
 #include "nm-supplicant-settings-verify.h"
+#include "nm-default.h"
 
 #include "nm-test-utils.h"
 
@@ -159,12 +158,19 @@ test_wifi_open (void)
 	                       "*added 'bssid' value '11:22:33:44:55:66'*");
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
 	                       "*added 'freq_list' value *");
-	g_assert (nm_supplicant_config_add_setting_wireless (config, s_wifi, 0));
+	g_assert (nm_supplicant_config_add_setting_wireless (config,
+	                                                     s_wifi,
+	                                                     0,
+	                                                     NM_SUPPLICANT_FEATURE_UNKNOWN,
+	                                                     NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
+	                                                     &error));
+	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
 	                       "*added 'key_mgmt' value 'NONE'");
-	g_assert (nm_supplicant_config_add_no_security (config));
+	g_assert (nm_supplicant_config_add_no_security (config, &error));
+	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
 
 	config_dict = nm_supplicant_config_to_variant (config);
@@ -257,7 +263,13 @@ test_wifi_wep_key (const char *detail,
 	                       "*added 'bssid' value '11:22:33:44:55:66'*");
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
 	                       "*added 'freq_list' value *");
-	g_assert (nm_supplicant_config_add_setting_wireless (config, s_wifi, 0));
+	g_assert (nm_supplicant_config_add_setting_wireless (config,
+	                                                     s_wifi,
+	                                                     0,
+	                                                     NM_SUPPLICANT_FEATURE_UNKNOWN,
+	                                                     NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
+	                                                     &error));
+	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
@@ -270,7 +282,9 @@ test_wifi_wep_key (const char *detail,
 	                                                              s_wsec,
 	                                                              NULL,
 	                                                              "376aced7-b28c-46be-9a62-fcdf072571da",
-	                                                              1500));
+	                                                              1500,
+	                                                              &error));
+	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
 
 	config_dict = nm_supplicant_config_to_variant (config);
@@ -394,7 +408,13 @@ test_wifi_wpa_psk (const char *detail,
 	                       "*added 'bssid' value '11:22:33:44:55:66'*");
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
 	                       "*added 'freq_list' value *");
-	g_assert (nm_supplicant_config_add_setting_wireless (config, s_wifi, 0));
+	g_assert (nm_supplicant_config_add_setting_wireless (config,
+	                                                     s_wifi,
+	                                                     0,
+	                                                     NM_SUPPLICANT_FEATURE_UNKNOWN,
+	                                                     NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
+	                                                     &error));
+	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
@@ -411,7 +431,9 @@ test_wifi_wpa_psk (const char *detail,
 	                                                              s_wsec,
 	                                                              NULL,
 	                                                              "376aced7-b28c-46be-9a62-fcdf072571da",
-	                                                              1500));
+	                                                              1500,
+	                                                              &error));
+	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
 
 	config_dict = nm_supplicant_config_to_variant (config);
@@ -533,7 +555,13 @@ test_wifi_eap (void)
 	                       "*added 'bssid' value '11:22:33:44:55:66'*");
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
 	                       "*added 'freq_list' value *");
-	g_assert (nm_supplicant_config_add_setting_wireless (config, s_wifi, 0));
+	g_assert (nm_supplicant_config_add_setting_wireless (config,
+	                                                     s_wifi,
+	                                                     0,
+	                                                     NM_SUPPLICANT_FEATURE_UNKNOWN,
+	                                                     NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
+	                                                     &error));
+	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
 
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
@@ -560,7 +588,9 @@ test_wifi_eap (void)
 	                                                              s_wsec,
 	                                                              s_8021x,
 	                                                              "d5b488af-9cab-41ed-bad4-97709c58430f",
-	                                                              mtu));
+	                                                              mtu,
+	                                                              &error));
+	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
 
 	config_dict = nm_supplicant_config_to_variant (config);
@@ -581,7 +611,7 @@ NMTST_DEFINE ();
 
 int main (int argc, char **argv)
 {
-	nmtst_init (&argc, &argv, TRUE);
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
 
 	g_test_add_func ("/supplicant-config/wifi-open", test_wifi_open);
 	g_test_add_func ("/supplicant-config/wifi-wep", test_wifi_wep);