summary refs log tree commit diff
path: root/src/supplicant
diff options
context:
space:
mode:
Diffstat (limited to 'src/supplicant')
-rw-r--r--src/supplicant/nm-supplicant-config.c96
-rw-r--r--src/supplicant/nm-supplicant-config.h7
-rw-r--r--src/supplicant/nm-supplicant-interface.c388
-rw-r--r--src/supplicant/nm-supplicant-interface.h18
-rw-r--r--src/supplicant/nm-supplicant-manager.c18
-rw-r--r--src/supplicant/nm-supplicant-settings-verify.c5
-rw-r--r--src/supplicant/tests/test-supplicant-config.c585
7 files changed, 748 insertions, 369 deletions
diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c
index f9a84620..16e7851a 100644
--- a/src/supplicant/nm-supplicant-config.c
+++ b/src/supplicant/nm-supplicant-config.c
@@ -31,6 +31,7 @@
 #include "nm-auth-subject.h"
 #include "NetworkManagerUtils.h"
 #include "nm-utils.h"
+#include "nm-setting-ip4-config.h"
 
 typedef struct {
 	char *value;
@@ -87,11 +88,11 @@ nm_supplicant_config_init (NMSupplicantConfig * self)
 {
 	NMSupplicantConfigPrivate *priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self);
 
-	priv->config = g_hash_table_new_full (g_str_hash, g_str_equal,
+	priv->config = g_hash_table_new_full (nm_str_hash, g_str_equal,
 	                                      (GDestroyNotify) g_free,
 	                                      (GDestroyNotify) config_option_free);
 
-	priv->blobs = g_hash_table_new_full (g_str_hash, g_str_equal,
+	priv->blobs = g_hash_table_new_full (nm_str_hash, g_str_equal,
 	                                     (GDestroyNotify) g_free,
 	                                     (GDestroyNotify) blob_free);
 
@@ -537,6 +538,56 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
 	return TRUE;
 }
 
+gboolean
+nm_supplicant_config_add_bgscan (NMSupplicantConfig *self,
+                                 NMConnection *connection,
+                                 GError **error)
+{
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	const char *bgscan;
+
+	s_wifi = nm_connection_get_setting_wireless (connection);
+	g_assert (s_wifi);
+
+	/* Don't scan when a shared connection (either AP or Ad-Hoc) is active;
+	 * it will disrupt connected clients.
+	 */
+	if (NM_IN_STRSET (nm_setting_wireless_get_mode (s_wifi),
+	                  NM_SETTING_WIRELESS_MODE_AP,
+	                  NM_SETTING_WIRELESS_MODE_ADHOC))
+		return TRUE;
+
+	/* Don't scan when the connection is locked to a specifc AP, since
+	 * intra-ESS roaming (which requires periodic scanning) isn't being
+	 * used due to the specific AP lock. (bgo #513820)
+	 */
+	if (nm_setting_wireless_get_bssid (s_wifi))
+		return TRUE;
+
+	/* Default to a very long bgscan interval when signal is OK on the assumption
+	 * that either (a) there aren't multiple APs and we don't need roaming, or
+	 * (b) since EAP/802.1x isn't used and thus there are fewer steps to fail
+	 * during a roam, we can wait longer before scanning for roam candidates.
+	 */
+	bgscan = "simple:30:-80:86400";
+
+	/* If using WPA Enterprise or Dynamic WEP use a shorter bgscan interval on
+	 * the assumption that this is a multi-AP ESS in which we want more reliable
+	 * roaming between APs.  Thus trigger scans when the signal is still somewhat
+	 * OK so we have an up-to-date roam candidate list when the signal gets bad.
+	 */
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	if (s_wsec) {
+		if (NM_IN_STRSET (nm_setting_wireless_security_get_key_mgmt (s_wsec),
+		                  "ieee8021x",
+		                  "wpa-eap"))
+			bgscan = "simple:30:-65:300";
+	}
+
+	return nm_supplicant_config_add_option (self, "bgscan", bgscan, -1, FALSE, error);
+}
+
 static gboolean
 add_string_val (NMSupplicantConfig *self,
                 const char *field,
@@ -684,9 +735,10 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                     NMSetting8021x *setting_8021x,
                                                     const char *con_uuid,
                                                     guint32 mtu,
+                                                    NMSettingWirelessSecurityPmf pmf,
                                                     GError **error)
 {
-	const char *key_mgmt, *auth_alg;
+	const char *key_mgmt, *key_mgmt_conf, *auth_alg;
 	const char *psk;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
@@ -694,8 +746,19 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 	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, NULL, error))
+	key_mgmt = key_mgmt_conf = nm_setting_wireless_security_get_key_mgmt (setting);
+	if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL) {
+		if (nm_streq (key_mgmt_conf, "wpa-psk"))
+			key_mgmt_conf = "wpa-psk wpa-psk-sha256";
+		else if (nm_streq (key_mgmt_conf, "wpa-eap"))
+			key_mgmt_conf = "wpa-eap wpa-eap-sha256";
+	} else if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED) {
+		if (nm_streq (key_mgmt_conf, "wpa-psk"))
+			key_mgmt_conf = "wpa-psk-sha256";
+		else if (nm_streq (key_mgmt_conf, "wpa-eap"))
+			key_mgmt_conf = "wpa-eap-sha256";
+	}
+	if (!add_string_val (self, key_mgmt_conf, "key_mgmt", TRUE, NULL, error))
 		return FALSE;
 
 	auth_alg = nm_setting_wireless_security_get_auth_alg (setting);
@@ -750,6 +813,19 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 			return FALSE;
 		if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, group, groups, "group", ' ', TRUE, NULL, error))
 			return FALSE;
+
+		if (   !nm_streq (key_mgmt, "wpa-none")
+		    && NM_IN_SET (pmf,
+		                  NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL,
+		                  NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED)) {
+			if (!nm_supplicant_config_add_option (self,
+			                                      "ieee80211w",
+			                                      pmf == NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL ? "1" : "2",
+			                                      -1,
+			                                      NULL,
+			                                      error))
+				return FALSE;
+		}
 	}
 
 	/* WEP keys if required */
@@ -811,12 +887,6 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 		}
 
 		if (!strcmp (key_mgmt, "wpa-eap")) {
-			/* 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, NULL, 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.
@@ -866,11 +936,11 @@ add_pkcs11_uri_with_pin (NMSupplicantConfig *self,
 	}
 
 	tmp = g_strdup_printf ("%s%s%s", split[0],
-	                       (pin_qattr ? "&" : ""),
+	                       (pin_qattr ? "?" : ""),
 	                       (pin_qattr ? pin_qattr : ""));
 
 	tmp_log = g_strdup_printf ("%s%s%s", split[0],
-	                           (pin_qattr ? "&" : ""),
+	                           (pin_qattr ? "?" : ""),
 	                           (pin_qattr ? "pin-value=<hidden>" : ""));
 
 	return add_string_val (self, tmp, name, FALSE, tmp_log, error);
diff --git a/src/supplicant/nm-supplicant-config.h b/src/supplicant/nm-supplicant-config.h
index 6acfb7ee..d90d82b8 100644
--- a/src/supplicant/nm-supplicant-config.h
+++ b/src/supplicant/nm-supplicant-config.h
@@ -55,11 +55,16 @@ gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self,
                                                     guint32 fixed_freq,
                                                     GError **error);
 
+gboolean nm_supplicant_config_add_bgscan           (NMSupplicantConfig *self,
+                                                    NMConnection *connection,
+                                                    GError **error);
+
 gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                              NMSettingWirelessSecurity *setting,
                                                              NMSetting8021x *setting_8021x,
                                                              const char *con_uuid,
                                                              guint32 mtu,
+                                                             NMSettingWirelessSecurityPmf pmf,
                                                              GError **error);
 
 gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self,
@@ -76,4 +81,6 @@ gboolean nm_supplicant_config_add_setting_macsec (NMSupplicantConfig *self,
                                                   NMSettingMacsec *setting,
                                                   GError **error);
 
+gboolean nm_supplicant_config_enable_pmf_akm (NMSupplicantConfig *self,
+                                              GError **error);
 #endif /* __NETWORKMANAGER_SUPPLICANT_CONFIG_H__ */
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c
index ab8a0670..44f887cb 100644
--- a/src/supplicant/nm-supplicant-interface.c
+++ b/src/supplicant/nm-supplicant-interface.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2006 - 2012 Red Hat, Inc.
+ * Copyright (C) 2006 - 2017 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -31,11 +31,12 @@
 #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"
-#define WPAS_DBUS_IFACE_NETWORK	    WPAS_DBUS_INTERFACE ".Network"
-#define WPAS_ERROR_INVALID_IFACE    WPAS_DBUS_INTERFACE ".InvalidInterface"
-#define WPAS_ERROR_EXISTS_ERROR     WPAS_DBUS_INTERFACE ".InterfaceExists"
+#define WPAS_DBUS_IFACE_INTERFACE       WPAS_DBUS_INTERFACE ".Interface"
+#define WPAS_DBUS_IFACE_INTERFACE_WPS   WPAS_DBUS_INTERFACE ".Interface.WPS"
+#define WPAS_DBUS_IFACE_BSS             WPAS_DBUS_INTERFACE ".BSS"
+#define WPAS_DBUS_IFACE_NETWORK         WPAS_DBUS_INTERFACE ".Network"
+#define WPAS_ERROR_INVALID_IFACE        WPAS_DBUS_INTERFACE ".InvalidInterface"
+#define WPAS_ERROR_EXISTS_ERROR         WPAS_DBUS_INTERFACE ".InterfaceExists"
 
 /*****************************************************************************/
 
@@ -48,6 +49,16 @@ struct _AddNetworkData;
 
 typedef struct {
 	NMSupplicantInterface *self;
+	char *type;
+	char *bssid;
+	char *pin;
+	GDBusProxy *proxy;
+	GCancellable *cancellable;
+	bool is_cancelling;
+} WpsData;
+
+typedef struct {
+	NMSupplicantInterface *self;
 	NMSupplicantConfig *cfg;
 	GCancellable *cancellable;
 	NMSupplicantInterfaceAssocCb callback;
@@ -69,6 +80,7 @@ enum {
 	BSS_REMOVED,         /* supplicant removed BSS from its scan list */
 	SCAN_DONE,           /* wifi scan is complete */
 	CREDENTIALS_REQUEST, /* 802.1x identity or password requested */
+	WPS_CREDENTIALS,     /* WPS credentials received */
 	LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -80,6 +92,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface,
 	PROP_DRIVER,
 	PROP_FAST_SUPPORT,
 	PROP_AP_SUPPORT,
+	PROP_PMF_SUPPORT,
 );
 
 typedef struct {
@@ -88,6 +101,7 @@ typedef struct {
 	gboolean       has_credreq;  /* Whether querying 802.1x credentials is supported */
 	NMSupplicantFeature fast_support;
 	NMSupplicantFeature ap_support;   /* Lightweight AP mode support */
+	NMSupplicantFeature pmf_support;
 	guint32        max_scan_ssids;
 	guint32        ready_count;
 
@@ -105,6 +119,8 @@ typedef struct {
 	GDBusProxy *   iface_proxy;
 	GCancellable * other_cancellable;
 
+	WpsData *wps_data;
+
 	AssocData *    assoc_data;
 
 	char *         net_path;
@@ -543,6 +559,12 @@ nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self)
 	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->ap_support;
 }
 
+NMSupplicantFeature
+nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self)
+{
+	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->pmf_support;
+}
+
 void
 nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self,
                                         NMSupplicantFeature ap_support)
@@ -565,6 +587,315 @@ nm_supplicant_interface_set_fast_support (NMSupplicantInterface *self,
 	priv->fast_support = fast_support;
 }
 
+void
+nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self,
+                                         NMSupplicantFeature pmf_support)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	priv->pmf_support = pmf_support;
+}
+
+/*****************************************************************************/
+
+static void
+_wps_data_free (WpsData *data)
+{
+	g_free (data->type);
+	g_free (data->pin);
+	g_free (data->bssid);
+	g_clear_object (&data->cancellable);
+	if (data->proxy && data->self)
+		g_signal_handlers_disconnect_by_data (data->proxy, data->self);
+	g_clear_object (&data->proxy);
+	g_slice_free (WpsData, data);
+}
+
+static void
+_wps_credentials_changed_cb (GDBusProxy *proxy,
+                             GVariant *props,
+                             gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+
+	_LOGT ("wps: new credentials");
+	g_signal_emit (self, signals[WPS_CREDENTIALS], 0, props);
+}
+
+static void
+_wps_handle_start_cb (GObject *source_object,
+                      GAsyncResult *res,
+                      gpointer user_data)
+{
+	NMSupplicantInterface *self;
+	WpsData *data;
+	gs_unref_variant GVariant *result = NULL;
+	gs_free_error GError *error = NULL;
+
+	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
+	if (   !result
+	    && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+
+	data = user_data;
+	self = data->self;
+
+	if (result)
+		_LOGT ("wps: started with success");
+	else
+		_LOGW ("wps: start failed with %s", error->message);
+
+	g_clear_object (&data->cancellable);
+	nm_clear_g_free (&data->type);
+	nm_clear_g_free (&data->pin);
+	nm_clear_g_free (&data->bssid);
+}
+
+static void
+_wps_handle_set_pc_cb (GObject *source_object,
+                       GAsyncResult *res,
+                       gpointer user_data)
+{
+	WpsData *data;
+	NMSupplicantInterface *self;
+	gs_unref_variant GVariant *result = NULL;
+	gs_free_error GError *error = NULL;
+	GVariantBuilder start_args;
+	guint8 bssid_buf[ETH_ALEN];
+
+	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
+	if (   !result
+	    && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+
+	data = user_data;
+	self = data->self;
+
+	if (result)
+		_LOGT ("wps: ProcessCredentials successfully set, starting...");
+	else
+		_LOGW ("wps: ProcessCredentials failed to set (%s), starting...", error->message);
+
+	_nm_dbus_signal_connect (data->proxy, "Credentials", G_VARIANT_TYPE ("(a{sv})"),
+	                         G_CALLBACK (_wps_credentials_changed_cb), self);
+
+	g_variant_builder_init (&start_args, G_VARIANT_TYPE_VARDICT);
+	g_variant_builder_add (&start_args, "{sv}", "Role", g_variant_new_string ("enrollee"));
+	g_variant_builder_add (&start_args, "{sv}", "Type", g_variant_new_string (data->type));
+	if (data->pin)
+		g_variant_builder_add (&start_args, "{sv}", "Pin", g_variant_new_string (data->pin));
+
+	if (data->bssid) {
+		/* The BSSID is in fact not mandatory. If it is not set the supplicant would
+		 * enroll with any BSS in range. */
+		if (!nm_utils_hwaddr_aton (data->bssid, bssid_buf, sizeof (bssid_buf)))
+			nm_assert_not_reached ();
+		g_variant_builder_add (&start_args, "{sv}", "Bssid",
+		                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid_buf,
+		                                                  ETH_ALEN, sizeof (guint8)));
+	}
+
+	g_dbus_proxy_call (data->proxy,
+	                   "Start",
+	                   g_variant_new ("(a{sv})", &start_args),
+	                   G_DBUS_CALL_FLAGS_NONE,
+	                   -1,
+	                   data->cancellable,
+	                   _wps_handle_start_cb,
+	                   data);
+}
+
+static void
+_wps_call_set_pc (WpsData *data)
+{
+	g_dbus_proxy_call (data->proxy,
+	                   "org.freedesktop.DBus.Properties.Set",
+	                   g_variant_new ("(ssv)",
+	                                  WPAS_DBUS_IFACE_INTERFACE_WPS,
+	                                  "ProcessCredentials",
+	                                  g_variant_new_boolean (TRUE)),
+	                   G_DBUS_CALL_FLAGS_NONE,
+	                   -1,
+	                   data->cancellable,
+	                   _wps_handle_set_pc_cb,
+	                   data);
+}
+
+static void
+_wps_handle_proxy_cb (GObject *source_object,
+                      GAsyncResult *res,
+                      gpointer user_data)
+{
+	NMSupplicantInterface *self;
+	NMSupplicantInterfacePrivate *priv;
+	WpsData *data;
+	gs_free_error GError *error = NULL;
+	GDBusProxy *proxy;
+
+	proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+	if (   !proxy
+	    && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+
+	data = user_data;
+	self = data->self;
+	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	if (!proxy) {
+		_LOGW ("wps: failure to create D-Bus proxy: %s", error->message);
+		_wps_data_free (data);
+		priv->wps_data = NULL;
+		return;
+	}
+
+	data->proxy = proxy;
+	_LOGT ("wps: D-Bus proxy created. set ProcessCredentials...");
+	_wps_call_set_pc (data);
+}
+
+static void
+_wps_handle_cancel_cb (GObject *source_object,
+                       GAsyncResult *res,
+                       gpointer user_data)
+{
+	NMSupplicantInterface *self;
+	NMSupplicantInterfacePrivate *priv;
+	WpsData *data;
+	gs_unref_variant GVariant *result = NULL;
+	gs_free_error GError *error = NULL;
+
+	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
+	if (   !result
+	    && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+
+	data = user_data;
+	self = data->self;
+
+	if (!self) {
+		_wps_data_free (data);
+		if (result)
+			_LOGT ("wps: cancel completed successfully, after supplicant interface is gone");
+		else
+			_LOGW ("wps: cancel failed (%s), after supplicant interface is gone", error->message);
+		return;
+	}
+
+	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	data->is_cancelling = FALSE;
+
+	if (!data->type) {
+		priv->wps_data = NULL;
+		_wps_data_free (data);
+		if (result)
+			_LOGT ("wps: cancel completed successfully");
+		else
+			_LOGW ("wps: cancel failed (%s)", error->message);
+		return;
+	}
+
+	if (result)
+		_LOGT ("wps: cancel completed successfully, setting ProcessCredentials now...");
+	else
+		_LOGW ("wps: cancel failed (%s), setting ProcessCredentials now...", error->message);
+	_wps_call_set_pc (data);
+}
+
+static void
+_wps_start (NMSupplicantInterface *self,
+            const char *type,
+            const char *bssid,
+            const char *pin)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	WpsData *data = priv->wps_data;
+
+	if (type)
+		_LOGI ("wps: type %s start...", type);
+
+	if (!data) {
+		if (!type)
+			return;
+
+		data = g_slice_new0 (WpsData);
+		data->self = self;
+		data->type = g_strdup (type);
+		data->bssid = g_strdup (bssid);
+		data->pin = g_strdup (pin);
+		data->cancellable = g_cancellable_new ();
+
+		priv->wps_data = data;
+
+		_LOGT ("wps: create D-Bus proxy...");
+
+		g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+		                          G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+		                          NULL,
+		                          WPAS_DBUS_SERVICE,
+		                          priv->object_path,
+		                          WPAS_DBUS_IFACE_INTERFACE_WPS,
+		                          data->cancellable,
+		                          _wps_handle_proxy_cb,
+		                          data);
+		return;
+	}
+
+	g_free (data->type);
+	g_free (data->bssid);
+	g_free (data->pin);
+	data->type = g_strdup (type);
+	data->bssid = g_strdup (bssid);
+	data->pin = g_strdup (pin);
+
+	if (!data->proxy) {
+		if (!type) {
+			nm_clear_g_cancellable (&data->cancellable);
+			priv->wps_data = NULL;
+			_wps_data_free (data);
+
+			_LOGT ("wps: abort creation of D-Bus proxy");
+		} else
+			_LOGT ("wps: new enrollment. Wait for D-Bus proxy...");
+		return;
+	}
+
+	if (data->is_cancelling)
+		return;
+
+	_LOGT ("wps: cancel previous enrollment...");
+
+	data->is_cancelling = TRUE;
+	nm_clear_g_cancellable (&data->cancellable);
+	data->cancellable = g_cancellable_new ();
+	g_signal_handlers_disconnect_by_data (data->proxy, self);
+	g_dbus_proxy_call (data->proxy,
+	                   "Cancel",
+	                   NULL,
+	                   G_DBUS_CALL_FLAGS_NONE,
+	                   -1,
+	                   data->cancellable,
+	                   _wps_handle_cancel_cb,
+	                   data);
+}
+
+void
+nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self,
+                                    const char *type,
+                                    const char *bssid,
+                                    const char *pin)
+{
+	_wps_start (self, type, bssid, pin);
+}
+
+void
+nm_supplicant_interface_cancel_wps (NMSupplicantInterface *self)
+{
+	_wps_start (self, NULL, NULL, NULL);
+}
+
+/*****************************************************************************/
+
 static void
 iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 {
@@ -786,7 +1117,7 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
 
 	/* Scan result aging parameters */
 	g_dbus_proxy_call (priv->iface_proxy,
-	                   "org.freedesktop.DBus.Properties.Set",
+	                   DBUS_INTERFACE_PROPERTIES ".Set",
 	                   g_variant_new ("(ssv)",
 	                                  WPAS_DBUS_IFACE_INTERFACE,
 	                                  "BSSExpireAge",
@@ -797,7 +1128,7 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
 	                   NULL,
 	                   NULL);
 	g_dbus_proxy_call (priv->iface_proxy,
-	                   "org.freedesktop.DBus.Properties.Set",
+	                   DBUS_INTERFACE_PROPERTIES ".Set",
 	                   g_variant_new ("(ssv)",
 	                                  WPAS_DBUS_IFACE_INTERFACE,
 	                                  "BSSExpireCount",
@@ -1158,6 +1489,9 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self)
 		g_free (priv->net_path);
 		priv->net_path = NULL;
 	}
+
+	/* Cancel any WPS enrollment, if any */
+	nm_supplicant_interface_cancel_wps (self);
 }
 
 static void
@@ -1455,6 +1789,7 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface *self, const GPtrArr
 	/* Scan parameters */
 	g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
 	g_variant_builder_add (&builder, "{sv}", "Type", g_variant_new_string ("active"));
+	g_variant_builder_add (&builder, "{sv}", "AllowRoam", g_variant_new_boolean (FALSE));
 	if (ssids) {
 		GVariantBuilder ssids_builder;
 
@@ -1561,6 +1896,10 @@ set_property (GObject *object,
 		/* construct-only */
 		priv->ap_support = g_value_get_int (value);
 		break;
+	case PROP_PMF_SUPPORT:
+		/* construct-only */
+		priv->pmf_support = g_value_get_int (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -1573,14 +1912,15 @@ nm_supplicant_interface_init (NMSupplicantInterface * self)
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
 	priv->state = NM_SUPPLICANT_INTERFACE_STATE_INIT;
-	priv->bss_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, bss_data_destroy);
+	priv->bss_proxies = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, bss_data_destroy);
 }
 
 NMSupplicantInterface *
 nm_supplicant_interface_new (const char *ifname,
                              NMSupplicantDriver driver,
                              NMSupplicantFeature fast_support,
-                             NMSupplicantFeature ap_support)
+                             NMSupplicantFeature ap_support,
+                             NMSupplicantFeature pmf_support)
 {
 	g_return_val_if_fail (ifname != NULL, NULL);
 
@@ -1589,6 +1929,7 @@ nm_supplicant_interface_new (const char *ifname,
 	                     NM_SUPPLICANT_INTERFACE_DRIVER, (guint) driver,
 	                     NM_SUPPLICANT_INTERFACE_FAST_SUPPORT, (int) fast_support,
 	                     NM_SUPPLICANT_INTERFACE_AP_SUPPORT, (int) ap_support,
+	                     NM_SUPPLICANT_INTERFACE_PMF_SUPPORT, (int) pmf_support,
 	                     NULL);
 }
 
@@ -1598,6 +1939,16 @@ dispose (GObject *object)
 	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (object);
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
+	nm_supplicant_interface_cancel_wps (self);
+	if (priv->wps_data) {
+		/* we shut down, but an asynchronous Cancel request is pending.
+		 * We don't want to cancel it, so mark wps-data that @self is gone.
+		 * This way, _wps_handle_cancel_cb() knows it must no longer touch
+		 * @self */
+		priv->wps_data->self = NULL;
+		priv->wps_data = NULL;
+	}
+
 	if (priv->assoc_data) {
 		gs_free_error GError *error = NULL;
 
@@ -1670,6 +2021,14 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 	                      G_PARAM_WRITABLE |
 	                      G_PARAM_CONSTRUCT_ONLY |
 	                      G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_PMF_SUPPORT] =
+	    g_param_spec_int (NM_SUPPLICANT_INTERFACE_PMF_SUPPORT, "", "",
+	                      NM_SUPPLICANT_FEATURE_UNKNOWN,
+	                      NM_SUPPLICANT_FEATURE_YES,
+	                      NM_SUPPLICANT_FEATURE_UNKNOWN,
+	                      G_PARAM_WRITABLE |
+	                      G_PARAM_CONSTRUCT_ONLY |
+	                      G_PARAM_STATIC_STRINGS);
 
 	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
@@ -1720,5 +2079,12 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 	                  0,
 	                  NULL, NULL, NULL,
 	                  G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
-}
 
+	signals[WPS_CREDENTIALS] =
+	    g_signal_new (NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_LAST,
+	                  0,
+	                  NULL, NULL, NULL,
+	                  G_TYPE_NONE, 1, G_TYPE_VARIANT);
+}
diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h
index d60d4a54..567cf96f 100644
--- a/src/supplicant/nm-supplicant-interface.h
+++ b/src/supplicant/nm-supplicant-interface.h
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2006 - 2010 Red Hat, Inc.
+ * Copyright (C) 2006 - 2017 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -60,6 +60,7 @@ typedef enum {
 #define NM_SUPPLICANT_INTERFACE_DRIVER           "driver"
 #define NM_SUPPLICANT_INTERFACE_FAST_SUPPORT     "fast-support"
 #define NM_SUPPLICANT_INTERFACE_AP_SUPPORT       "ap-support"
+#define NM_SUPPLICANT_INTERFACE_PMF_SUPPORT      "pmf-support"
 
 /* Signals */
 #define NM_SUPPLICANT_INTERFACE_STATE            "state"
@@ -68,6 +69,7 @@ typedef enum {
 #define NM_SUPPLICANT_INTERFACE_BSS_REMOVED      "bss-removed"
 #define NM_SUPPLICANT_INTERFACE_SCAN_DONE        "scan-done"
 #define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request"
+#define NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS  "wps-credentials"
 
 typedef struct _NMSupplicantInterfaceClass NMSupplicantInterfaceClass;
 
@@ -76,7 +78,8 @@ GType nm_supplicant_interface_get_type (void);
 NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname,
                                                      NMSupplicantDriver driver,
                                                      NMSupplicantFeature fast_support,
-                                                     NMSupplicantFeature ap_support);
+                                                     NMSupplicantFeature ap_support,
+                                                     NMSupplicantFeature pmf_support);
 
 void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self,
                                                        gboolean available);
@@ -119,6 +122,7 @@ gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self,
                                                     GError **error);
 
 NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self);
+NMSupplicantFeature nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self);
 
 void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self,
                                              NMSupplicantFeature apmode);
@@ -126,4 +130,14 @@ void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self,
 void nm_supplicant_interface_set_fast_support (NMSupplicantInterface *self,
                                                NMSupplicantFeature fast_support);
 
+void nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self,
+                                              NMSupplicantFeature pmf_support);
+
+void nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self,
+                                         const char *const type,
+                                         const char *bssid,
+                                         const char *pin);
+
+void nm_supplicant_interface_cancel_wps (NMSupplicantInterface *self);
+
 #endif /* __NM_SUPPLICANT_INTERFACE_H__ */
diff --git a/src/supplicant/nm-supplicant-manager.c b/src/supplicant/nm-supplicant-manager.c
index 49650ab7..0f2eb63a 100644
--- a/src/supplicant/nm-supplicant-manager.c
+++ b/src/supplicant/nm-supplicant-manager.c
@@ -39,6 +39,7 @@ typedef struct {
 	GSList          *ifaces;
 	NMSupplicantFeature fast_support;
 	NMSupplicantFeature ap_support;
+	NMSupplicantFeature pmf_support;
 	guint             die_count_reset_id;
 	guint             die_count;
 } NMSupplicantManagerPrivate;
@@ -159,7 +160,8 @@ nm_supplicant_manager_create_interface (NMSupplicantManager *self,
 	iface = nm_supplicant_interface_new (ifname,
 	                                     driver,
 	                                     priv->fast_support,
-	                                     priv->ap_support);
+	                                     priv->ap_support,
+	                                     priv->pmf_support);
 
 	priv->ifaces = g_slist_prepend (priv->ifaces, iface);
 	g_object_add_toggle_ref ((GObject *) iface, _sup_iface_last_ref, self);
@@ -193,28 +195,37 @@ update_capabilities (NMSupplicantManager *self)
 	 * dbus: Add global capabilities property
 	 */
 	priv->ap_support = NM_SUPPLICANT_FEATURE_UNKNOWN;
+	priv->pmf_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 = NM_SUPPLICANT_FEATURE_NO;
+			priv->pmf_support = NM_SUPPLICANT_FEATURE_NO;
 			if (array) {
 				if (g_strv_contains (array, "ap"))
 					priv->ap_support = NM_SUPPLICANT_FEATURE_YES;
+				if (g_strv_contains (array, "pmf"))
+					priv->pmf_support = NM_SUPPLICANT_FEATURE_YES;
 				g_free (array);
 			}
 		}
 		g_variant_unref (value);
 	}
 
-	/* Tell all interfaces about results of the AP check */
-	for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next)
+	/* Tell all interfaces about results of the AP/PMF check */
+	for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) {
 		nm_supplicant_interface_set_ap_support (ifaces->data, priv->ap_support);
+		nm_supplicant_interface_set_pmf_support (ifaces->data, priv->pmf_support);
+	}
 
 	_LOGD ("AP mode is %ssupported",
 	       (priv->ap_support == NM_SUPPLICANT_FEATURE_YES) ? "" :
 	           (priv->ap_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly ");
+	_LOGD ("PMF is %ssupported",
+	       (priv->pmf_support == NM_SUPPLICANT_FEATURE_YES) ? "" :
+	           (priv->pmf_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly ");
 
 	/* EAP-FAST */
 	priv->fast_support = NM_SUPPLICANT_FEATURE_NO;
@@ -337,6 +348,7 @@ name_owner_cb (GDBusProxy *proxy, GParamSpec *pspec, gpointer user_data)
 
 		priv->ap_support = NM_SUPPLICANT_FEATURE_UNKNOWN;
 		priv->fast_support = NM_SUPPLICANT_FEATURE_UNKNOWN;
+		priv->pmf_support = NM_SUPPLICANT_FEATURE_UNKNOWN;
 
 		set_running (self, FALSE);
 	}
diff --git a/src/supplicant/nm-supplicant-settings-verify.c b/src/supplicant/nm-supplicant-settings-verify.c
index ce3e46d8..14daf693 100644
--- a/src/supplicant/nm-supplicant-settings-verify.c
+++ b/src/supplicant/nm-supplicant-settings-verify.c
@@ -71,7 +71,9 @@ static const struct validate_entry validate_table[] = {
 const char * pairwise_allowed[] = { "CCMP", "TKIP", "NONE", NULL };
 const char * group_allowed[] =    { "CCMP", "TKIP", "WEP104", "WEP40", NULL };
 const char * proto_allowed[] =    { "WPA", "RSN", NULL };
-const char * key_mgmt_allowed[] = { "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
+const char * key_mgmt_allowed[] = { "WPA-PSK", "WPA-PSK-SHA256",
+                                    "WPA-EAP", "WPA-EAP-SHA256",
+                                    "IEEE8021X", "WPA-NONE",
                                     "NONE", NULL };
 const char * auth_alg_allowed[] = { "OPEN", "SHARED", "LEAP", NULL };
 const char * eap_allowed[] =      { "LEAP", "MD5", "TLS", "PEAP", "TTLS", "SIM",
@@ -149,6 +151,7 @@ static const struct Opt opt_table[] = {
 	{ "mka_cak",            TYPE_BYTES,   0, 65536, FALSE, NULL },
 	{ "mka_ckn",            TYPE_BYTES,   0, 65536, FALSE, NULL },
 	{ "macsec_port",        TYPE_INT,     1, 65534, FALSE, NULL },
+	{ "ieee80211w",         TYPE_INT,     0, 2, FALSE, NULL },
 };
 
 
diff --git a/src/supplicant/tests/test-supplicant-config.c b/src/supplicant/tests/test-supplicant-config.c
index ef6f2c64..4b4a4935 100644
--- a/src/supplicant/tests/test-supplicant-config.c
+++ b/src/supplicant/tests/test-supplicant-config.c
@@ -42,16 +42,11 @@ validate_opt (const char *detail,
               GVariant *config,
               const char *key,
               OptType val_type,
-              gconstpointer expected,
-              size_t expected_len)
+              gconstpointer expected)
 {
 	char *config_key;
 	GVariant *config_value;
 	gboolean found = FALSE;
-	const guint8 *bytes;
-	gsize len;
-	const char *s;
-	const unsigned char *expected_array = expected;
 	GVariantIter iter;
 
 	g_assert (g_variant_is_of_type (config, G_VARIANT_TYPE_VARDICT));
@@ -61,25 +56,33 @@ validate_opt (const char *detail,
 		if (!strcmp (key, config_key)) {
 			found = TRUE;
 			switch (val_type) {
-			case TYPE_INT:
+			case TYPE_INT: {
 				g_assert (g_variant_is_of_type (config_value, G_VARIANT_TYPE_INT32));
 				g_assert_cmpint (g_variant_get_int32 (config_value), ==, GPOINTER_TO_INT (expected));
 				break;
-			case TYPE_BYTES:
+			}
+			case TYPE_BYTES: {
+				const guint8 *expected_bytes;
+				gsize expected_len = 0;
+				const guint8 *config_bytes;
+				gsize config_len = 0;
+
+				expected_bytes = g_bytes_get_data ((GBytes *) expected, &expected_len);
 				g_assert (g_variant_is_of_type (config_value, G_VARIANT_TYPE_BYTESTRING));
-				bytes = g_variant_get_fixed_array (config_value, &len, 1);
-				g_assert_cmpint (len, ==, expected_len);
-				g_assert (memcmp (bytes, expected_array, expected_len) == 0);
+				config_bytes = g_variant_get_fixed_array (config_value, &config_len, 1);
+				g_assert_cmpmem (config_bytes, config_len, expected_bytes, expected_len);
 				break;
+			}
 			case TYPE_KEYWORD:
-			case TYPE_STRING:
+			case TYPE_STRING: {
+				const char *expected_str = expected;
+				const char *config_str;
+
 				g_assert (g_variant_is_of_type (config_value, G_VARIANT_TYPE_STRING));
-				if (expected_len == -1)
-					expected_len = strlen ((const char *) expected);
-				s = g_variant_get_string (config_value, NULL);
-				g_assert_cmpint (strlen (s), ==, expected_len);
-				g_assert_cmpstr (s, ==, expected);
+				config_str = g_variant_get_string (config_value, NULL);
+				g_assert_cmpstr (config_str, ==, expected_str);
 				break;
+			}
 			default:
 				g_assert_not_reached ();
 				break;
@@ -91,43 +94,80 @@ validate_opt (const char *detail,
 	return found;
 }
 
-static void
-test_wifi_open (void)
+static GVariant *
+build_supplicant_config (NMConnection *connection, guint mtu, guint fixed_freq)
 {
-	gs_unref_object NMConnection *connection = NULL;
 	gs_unref_object NMSupplicantConfig *config = NULL;
-	gs_unref_variant GVariant *config_dict = NULL;
+	gs_free_error GError *error = NULL;
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	NMSetting8021x *s_8021x;
+	gboolean success;
+
+	config = nm_supplicant_config_new ();
+
+	s_wifi = nm_connection_get_setting_wireless (connection);
+	g_assert (s_wifi);
+	success = nm_supplicant_config_add_setting_wireless (config,
+	                                                     s_wifi,
+	                                                     fixed_freq,
+	                                                     &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	if (s_wsec) {
+		NMSettingWirelessSecurityPmf pmf = nm_setting_wireless_security_get_pmf (s_wsec);
+		s_8021x = nm_connection_get_setting_802_1x (connection);
+		success = nm_supplicant_config_add_setting_wireless_security (config,
+			                                                          s_wsec,
+			                                                          s_8021x,
+			                                                          nm_connection_get_uuid (connection),
+			                                                          mtu,
+			                                                          pmf,
+			                                                          &error);
+	} else {
+		success = nm_supplicant_config_add_no_security (config, &error);
+	}
+	g_assert_no_error (error);
+	g_assert (success);
+
+
+	success = nm_supplicant_config_add_bgscan (config, connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	return nm_supplicant_config_to_variant (config);
+}
+
+#define EXPECT(msg) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, msg)
+
+static NMConnection *
+new_basic_connection (const char *id,
+                      GBytes *ssid,
+                      const char *bssid_str)
+{
+	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wifi;
 	NMSettingIPConfig *s_ip4;
-	char *uuid;
-	gboolean success;
-	GError *error = NULL;
-	GBytes *ssid;
-	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
-	const char *bssid_str = "11:22:33:44:55:66";
+	gs_free char *uuid = nm_utils_uuid_generate ();
 
 	connection = nm_simple_connection_new ();
 
 	/* Connection setting */
 	s_con = (NMSettingConnection *) nm_setting_connection_new ();
 	nm_connection_add_setting (connection, NM_SETTING (s_con));
-
-	uuid = nm_utils_uuid_generate ();
 	g_object_set (s_con,
-	              NM_SETTING_CONNECTION_ID, "Test Wifi Open",
+	              NM_SETTING_CONNECTION_ID, id,
 	              NM_SETTING_CONNECTION_UUID, uuid,
 	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
 	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
 	              NULL);
-	g_free (uuid);
 
 	/* Wifi setting */
 	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
 	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
-
-	ssid = g_bytes_new (ssid_data, sizeof (ssid_data));
-
 	g_object_set (s_wifi,
 	              NM_SETTING_WIRELESS_SSID, ssid,
 	              NM_SETTING_WIRELESS_BSSID, bssid_str,
@@ -135,162 +175,106 @@ test_wifi_open (void)
 	              NM_SETTING_WIRELESS_BAND, "bg",
 	              NULL);
 
-	g_bytes_unref (ssid);
-
 	/* IP4 setting */
 	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
 	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
-
 	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
 
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	return connection;
+}
 
-	config = nm_supplicant_config_new ();
+static void
+test_wifi_open (void)
+{
+	gs_unref_object NMConnection *connection = NULL;
+	gs_unref_variant GVariant *config_dict = NULL;
+	gboolean success;
+	GError *error = NULL;
+	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
+	gs_unref_bytes GBytes *ssid = g_bytes_new (ssid_data, sizeof (ssid_data));
+	const char *bssid_str = "11:22:33:44:55:66";
 
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'ssid' value 'Test SSID'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'scan_ssid' value '1'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'bssid' value '11:22:33:44:55:66'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'freq_list' value *");
-	g_assert (nm_supplicant_config_add_setting_wireless (config,
-	                                                     s_wifi,
-	                                                     0,
-	                                                     &error));
+	connection = new_basic_connection ("Test Wifi Open", ssid, bssid_str);
+	success = nm_connection_verify (connection, &error);
 	g_assert_no_error (error);
-	g_test_assert_expected_messages ();
+	g_assert (success);
 
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'key_mgmt' value 'NONE'");
-	g_assert (nm_supplicant_config_add_no_security (config, &error));
-	g_assert_no_error (error);
+	EXPECT ("*added 'ssid' value 'Test SSID'*");
+	EXPECT ("*added 'scan_ssid' value '1'*");
+	EXPECT ("*added 'bssid' value '11:22:33:44:55:66'*");
+	EXPECT ("*added 'freq_list' value *");
+	EXPECT ("*added 'key_mgmt' value 'NONE'");
+	config_dict = build_supplicant_config (connection, 1500, 0);
 	g_test_assert_expected_messages ();
-
-	config_dict = nm_supplicant_config_to_variant (config);
 	g_assert (config_dict);
 
-	validate_opt ("wifi-open", config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1);
-	validate_opt ("wifi-open", config_dict, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data));
-	validate_opt ("wifi-open", config_dict, "bssid", TYPE_KEYWORD, bssid_str, -1);
-	validate_opt ("wifi-open", config_dict, "key_mgmt", TYPE_KEYWORD, "NONE", -1);
+	validate_opt ("wifi-open", config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1));
+	validate_opt ("wifi-open", config_dict, "ssid", TYPE_BYTES, ssid);
+	validate_opt ("wifi-open", config_dict, "bssid", TYPE_KEYWORD, bssid_str);
+	validate_opt ("wifi-open", config_dict, "key_mgmt", TYPE_KEYWORD, "NONE");
 }
 
 static void
 test_wifi_wep_key (const char *detail,
+                   gboolean test_bssid,
                    NMWepKeyType wep_type,
                    const char *key_data,
                    const unsigned char *expected,
                    size_t expected_size)
 {
 	gs_unref_object NMConnection *connection = NULL;
-	gs_unref_object NMSupplicantConfig *config = NULL;
 	gs_unref_variant GVariant *config_dict = NULL;
-	NMSettingConnection *s_con;
-	NMSettingWireless *s_wifi;
 	NMSettingWirelessSecurity *s_wsec;
-	NMSettingIPConfig *s_ip4;
-	char *uuid;
 	gboolean success;
 	GError *error = NULL;
-	GBytes *ssid;
 	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
+	gs_unref_bytes GBytes *ssid = g_bytes_new (ssid_data, sizeof (ssid_data));
 	const char *bssid_str = "11:22:33:44:55:66";
+	gs_unref_bytes GBytes *wep_key_bytes = g_bytes_new (expected, expected_size);
+	const char *bgscan_data = "simple:30:-80:86400";
+	gs_unref_bytes GBytes *bgscan = g_bytes_new (bgscan_data, strlen (bgscan_data));
 
-	connection = nm_simple_connection_new ();
-
-	/* Connection setting */
-	s_con = (NMSettingConnection *) nm_setting_connection_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_con));
-
-	uuid = nm_utils_uuid_generate ();
-	g_object_set (s_con,
-	              NM_SETTING_CONNECTION_ID, "Test Wifi WEP Key",
-	              NM_SETTING_CONNECTION_UUID, uuid,
-	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
-	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
-	              NULL);
-	g_free (uuid);
-
-	/* Wifi setting */
-	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
-
-	ssid = g_bytes_new (ssid_data, sizeof (ssid_data));
-
-	g_object_set (s_wifi,
-	              NM_SETTING_WIRELESS_SSID, ssid,
-	              NM_SETTING_WIRELESS_BSSID, bssid_str,
-	              NM_SETTING_WIRELESS_MODE, "infrastructure",
-	              NM_SETTING_WIRELESS_BAND, "bg",
-	              NULL);
-
-	g_bytes_unref (ssid);
+	connection = new_basic_connection ("Test Wifi WEP Key", ssid, test_bssid ? bssid_str : NULL);
 
 	/* Wifi Security setting */
 	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
 	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
-
 	g_object_set (s_wsec,
 	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
 	              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, wep_type,
 	              NULL);
-	nm_setting_wireless_security_set_wep_key (s_wsec, 0, key_data);	
-
-	/* IP4 setting */
-	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
-
-	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+	nm_setting_wireless_security_set_wep_key (s_wsec, 0, key_data);
 
 	success = nm_connection_verify (connection, &error);
 	g_assert_no_error (error);
 	g_assert (success);
 
-	config = nm_supplicant_config_new ();
+	EXPECT ("*added 'ssid' value 'Test SSID'*");
+	EXPECT ("*added 'scan_ssid' value '1'*");
+	if (test_bssid)
+		EXPECT ("*added 'bssid' value '11:22:33:44:55:66'*");
 
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'ssid' value 'Test SSID'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'scan_ssid' value '1'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'bssid' value '11:22:33:44:55:66'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'freq_list' value *");
-	g_assert (nm_supplicant_config_add_setting_wireless (config,
-	                                                     s_wifi,
-	                                                     0,
-	                                                     &error));
-	g_assert_no_error (error);
-	g_test_assert_expected_messages ();
+	EXPECT ("*added 'freq_list' value *");
+	EXPECT ("*added 'key_mgmt' value 'NONE'");
+	EXPECT ("*added 'wep_key0' value *");
+	EXPECT ("*added 'wep_tx_keyidx' value '0'");
+	if (!test_bssid)
+		EXPECT ("*added 'bgscan' value 'simple:30:-80:86400'*");
 
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'key_mgmt' value 'NONE'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'wep_key0' value *");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'wep_tx_keyidx' value '0'");
-	g_assert (nm_supplicant_config_add_setting_wireless_security (config,
-	                                                              s_wsec,
-	                                                              NULL,
-	                                                              "376aced7-b28c-46be-9a62-fcdf072571da",
-	                                                              1500,
-	                                                              &error));
-	g_assert_no_error (error);
+	config_dict = build_supplicant_config (connection, 1500, 0);
 	g_test_assert_expected_messages ();
-
-	config_dict = nm_supplicant_config_to_variant (config);
 	g_assert (config_dict);
 
-	validate_opt (detail, config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1);
-	validate_opt (detail, config_dict, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data));
-	validate_opt (detail, config_dict, "bssid", TYPE_KEYWORD, bssid_str, -1);
-	validate_opt (detail, config_dict, "key_mgmt", TYPE_KEYWORD, "NONE", -1);
-	validate_opt (detail, config_dict, "wep_tx_keyidx", TYPE_INT, GINT_TO_POINTER (0), -1);
-	validate_opt (detail, config_dict, "wep_key0", TYPE_BYTES, expected, expected_size);
+	validate_opt (detail, config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1));
+	validate_opt (detail, config_dict, "ssid", TYPE_BYTES, ssid);
+	if (test_bssid)
+		validate_opt (detail, config_dict, "bssid", TYPE_KEYWORD, bssid_str);
+	else
+		validate_opt (detail, config_dict, "bgscan", TYPE_BYTES, bgscan);
+
+	validate_opt (detail, config_dict, "key_mgmt", TYPE_KEYWORD, "NONE");
+	validate_opt (detail, config_dict, "wep_tx_keyidx", TYPE_INT, GINT_TO_POINTER (0));
+	validate_opt (detail, config_dict, "wep_key0", TYPE_BYTES, wep_key_bytes);
 }
 
 static void
@@ -307,13 +291,16 @@ test_wifi_wep (void)
 	const char *key5 = "r34lly l33t w3p p4ssphr4s3 for t3st1ng";
 	const unsigned char key5_expected[] = { 0xce, 0x68, 0x8b, 0x35, 0xf6, 0x0a, 0x2b, 0xbf, 0xc9, 0x8f, 0xed, 0x10, 0xda };
 
-	test_wifi_wep_key ("wifi-wep-ascii-40", NM_WEP_KEY_TYPE_KEY, key1, key1_expected, sizeof (key1_expected));
-	test_wifi_wep_key ("wifi-wep-ascii-104", NM_WEP_KEY_TYPE_KEY, key2, key2_expected, sizeof (key2_expected));
-	test_wifi_wep_key ("wifi-wep-hex-40", NM_WEP_KEY_TYPE_KEY, key3, key3_expected, sizeof (key3_expected));
-	test_wifi_wep_key ("wifi-wep-hex-104", NM_WEP_KEY_TYPE_KEY, key4, key4_expected, sizeof (key4_expected));
-	test_wifi_wep_key ("wifi-wep-passphrase-104", NM_WEP_KEY_TYPE_PASSPHRASE, key5, key5_expected, sizeof (key5_expected));
+	test_wifi_wep_key ("wifi-wep-ascii-40", TRUE, NM_WEP_KEY_TYPE_KEY, key1, key1_expected, sizeof (key1_expected));
+	test_wifi_wep_key ("wifi-wep-ascii-104", TRUE, NM_WEP_KEY_TYPE_KEY, key2, key2_expected, sizeof (key2_expected));
+	test_wifi_wep_key ("wifi-wep-hex-40", TRUE, NM_WEP_KEY_TYPE_KEY, key3, key3_expected, sizeof (key3_expected));
+	test_wifi_wep_key ("wifi-wep-hex-104", TRUE, NM_WEP_KEY_TYPE_KEY, key4, key4_expected, sizeof (key4_expected));
+	test_wifi_wep_key ("wifi-wep-passphrase-104", TRUE, NM_WEP_KEY_TYPE_PASSPHRASE, key5, key5_expected, sizeof (key5_expected));
+
+	test_wifi_wep_key ("wifi-wep-old-hex-104", TRUE, NM_WEP_KEY_TYPE_UNKNOWN, key4, key4_expected, sizeof (key4_expected));
 
-	test_wifi_wep_key ("wifi-wep-old-hex-104", NM_WEP_KEY_TYPE_UNKNOWN, key4, key4_expected, sizeof (key4_expected));
+	/* Unlocked BSSID to test bgscan */
+	test_wifi_wep_key ("wifi-wep-hex-40", FALSE, NM_WEP_KEY_TYPE_KEY, key3, key3_expected, sizeof (key3_expected));
 }
 
 static void
@@ -324,58 +311,25 @@ test_wifi_wpa_psk (const char *detail,
                    size_t expected_size)
 {
 	gs_unref_object NMConnection *connection = NULL;
-	gs_unref_object NMSupplicantConfig *config = NULL;
 	gs_unref_variant GVariant *config_dict = NULL;
-	NMSettingConnection *s_con;
-	NMSettingWireless *s_wifi;
 	NMSettingWirelessSecurity *s_wsec;
-	NMSettingIPConfig *s_ip4;
-	char *uuid;
 	gboolean success;
 	GError *error = NULL;
-	GBytes *ssid;
 	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
+	gs_unref_bytes GBytes *ssid = g_bytes_new (ssid_data, sizeof (ssid_data));
 	const char *bssid_str = "11:22:33:44:55:66";
+	gs_unref_bytes GBytes *wpa_psk_bytes = g_bytes_new (expected, expected_size);
 
-	connection = nm_simple_connection_new ();
-
-	/* Connection setting */
-	s_con = (NMSettingConnection *) nm_setting_connection_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_con));
-
-	uuid = nm_utils_uuid_generate ();
-	g_object_set (s_con,
-	              NM_SETTING_CONNECTION_ID, "Test Wifi WEP Key",
-	              NM_SETTING_CONNECTION_UUID, uuid,
-	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
-	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
-	              NULL);
-	g_free (uuid);
-
-	/* Wifi setting */
-	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
-
-	ssid = g_bytes_new (ssid_data, sizeof (ssid_data));
-
-	g_object_set (s_wifi,
-	              NM_SETTING_WIRELESS_SSID, ssid,
-	              NM_SETTING_WIRELESS_BSSID, bssid_str,
-	              NM_SETTING_WIRELESS_MODE, "infrastructure",
-	              NM_SETTING_WIRELESS_BAND, "bg",
-	              NULL);
-
-	g_bytes_unref (ssid);
+	connection = new_basic_connection ("Test Wifi WPA PSK", ssid, bssid_str);
 
 	/* Wifi Security setting */
 	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
 	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
-
 	g_object_set (s_wsec,
 	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
 	              NM_SETTING_WIRELESS_SECURITY_PSK, key_data,
+	              NM_SETTING_WIRELESS_SECURITY_PMF, (int) NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL,
 	              NULL);
-
 	nm_setting_wireless_security_add_proto (s_wsec, "wpa");
 	nm_setting_wireless_security_add_proto (s_wsec, "rsn");
 	nm_setting_wireless_security_add_pairwise (s_wsec, "tkip");
@@ -383,63 +337,38 @@ test_wifi_wpa_psk (const char *detail,
 	nm_setting_wireless_security_add_group (s_wsec, "tkip");
 	nm_setting_wireless_security_add_group (s_wsec, "ccmp");
 
-	/* IP4 setting */
-	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
-
-	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
-
 	success = nm_connection_verify (connection, &error);
 	g_assert_no_error (error);
 	g_assert (success);
 
-	config = nm_supplicant_config_new ();
-
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'ssid' value 'Test SSID'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'scan_ssid' value '1'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'bssid' value '11:22:33:44:55:66'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'freq_list' value *");
-	g_assert (nm_supplicant_config_add_setting_wireless (config,
-	                                                     s_wifi,
-	                                                     0,
-	                                                     &error));
-	g_assert_no_error (error);
-	g_test_assert_expected_messages ();
+	EXPECT ("*added 'ssid' value 'Test SSID'*");
+	EXPECT ("*added 'scan_ssid' value '1'*");
+	EXPECT ("*added 'bssid' value '11:22:33:44:55:66'*");
+	EXPECT ("*added 'freq_list' value *");
+	EXPECT ("*added 'key_mgmt' value 'WPA-PSK WPA-PSK-SHA256'");
+	EXPECT ("*added 'psk' value *");
+	EXPECT ("*added 'proto' value 'WPA RSN'");
+	EXPECT ("*added 'pairwise' value 'TKIP CCMP'");
+	EXPECT ("*added 'group' value 'TKIP CCMP'");
+	EXPECT ("*added 'ieee80211w' value '1'");
+	config_dict = build_supplicant_config (connection, 1500, 0);
 
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'key_mgmt' value 'WPA-PSK'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'psk' value *");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'proto' value 'WPA RSN'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'pairwise' value 'TKIP CCMP'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'group' value 'TKIP CCMP'");
-	g_assert (nm_supplicant_config_add_setting_wireless_security (config,
-	                                                              s_wsec,
-	                                                              NULL,
-	                                                              "376aced7-b28c-46be-9a62-fcdf072571da",
-	                                                              1500,
-	                                                              &error));
-	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
-
-	config_dict = nm_supplicant_config_to_variant (config);
 	g_assert (config_dict);
 
-	validate_opt (detail, config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1);
-	validate_opt (detail, config_dict, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data));
-	validate_opt (detail, config_dict, "bssid", TYPE_KEYWORD, bssid_str, -1);
-	validate_opt (detail, config_dict, "key_mgmt", TYPE_KEYWORD, "WPA-PSK", -1);
-	validate_opt (detail, config_dict, "proto", TYPE_KEYWORD, "WPA RSN", -1);
-	validate_opt (detail, config_dict, "pairwise", TYPE_KEYWORD, "TKIP CCMP", -1);
-	validate_opt (detail, config_dict, "group", TYPE_KEYWORD, "TKIP CCMP", -1);
-	validate_opt (detail, config_dict, "psk", key_type, expected, expected_size);
+	validate_opt (detail, config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1));
+	validate_opt (detail, config_dict, "ssid", TYPE_BYTES, ssid);
+	validate_opt (detail, config_dict, "bssid", TYPE_KEYWORD, bssid_str);
+	validate_opt (detail, config_dict, "key_mgmt", TYPE_KEYWORD, "WPA-PSK WPA-PSK-SHA256");
+	validate_opt (detail, config_dict, "proto", TYPE_KEYWORD, "WPA RSN");
+	validate_opt (detail, config_dict, "pairwise", TYPE_KEYWORD, "TKIP CCMP");
+	validate_opt (detail, config_dict, "group", TYPE_KEYWORD, "TKIP CCMP");
+	if (key_type == TYPE_BYTES)
+		validate_opt (detail, config_dict, "psk", key_type, wpa_psk_bytes);
+	else if (key_type == TYPE_STRING)
+		validate_opt (detail, config_dict, "psk", key_type, expected);
+	else
+		g_assert_not_reached ();
 }
 
 static void
@@ -456,63 +385,23 @@ test_wifi_wpa_psk_types (void)
 	test_wifi_wpa_psk ("wifi-wep-psk-passphrase", TYPE_STRING, key2, (gconstpointer) key2, strlen (key2));
 }
 
-static void
-test_wifi_eap (void)
+static NMConnection *
+generate_wifi_eap_connection (const char *id, GBytes *ssid, const char *bssid_str)
 {
-	gs_unref_object NMConnection *connection = NULL;
-	gs_unref_object NMSupplicantConfig *config = NULL;
-	gs_unref_variant GVariant *config_dict = NULL;
-	NMSettingConnection *s_con;
-	NMSettingWireless *s_wifi;
+	NMConnection *connection = NULL;
 	NMSettingWirelessSecurity *s_wsec;
 	NMSetting8021x *s_8021x;
-	NMSettingIPConfig *s_ip4;
-	char *uuid;
 	gboolean success;
 	GError *error = NULL;
-	GBytes *ssid;
-	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
-	const char *bssid_str = "11:22:33:44:55:66";
-	guint32 mtu = 1100;
 
-	connection = nm_simple_connection_new ();
-
-	/* Connection setting */
-	s_con = (NMSettingConnection *) nm_setting_connection_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_con));
-
-	uuid = nm_utils_uuid_generate ();
-	g_object_set (s_con,
-	              NM_SETTING_CONNECTION_ID, "Test Wifi EAP-TLS",
-	              NM_SETTING_CONNECTION_UUID, uuid,
-	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
-	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
-	              NULL);
-	g_free (uuid);
-
-	/* Wifi setting */
-	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
-
-	ssid = g_bytes_new (ssid_data, sizeof (ssid_data));
-
-	g_object_set (s_wifi,
-	              NM_SETTING_WIRELESS_SSID, ssid,
-	              NM_SETTING_WIRELESS_BSSID, bssid_str,
-	              NM_SETTING_WIRELESS_MODE, "infrastructure",
-	              NM_SETTING_WIRELESS_BAND, "bg",
-	              NULL);
-
-	g_bytes_unref (ssid);
+	connection = new_basic_connection (id, ssid, bssid_str);
 
 	/* Wifi Security setting */
 	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
 	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
-
 	g_object_set (s_wsec,
 	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
 	              NULL);
-
 	nm_setting_wireless_security_add_proto (s_wsec, "wpa");
 	nm_setting_wireless_security_add_proto (s_wsec, "rsn");
 	nm_setting_wireless_security_add_pairwise (s_wsec, "tkip");
@@ -528,74 +417,92 @@ test_wifi_eap (void)
 	g_assert (nm_setting_802_1x_set_ca_cert (s_8021x, TEST_CERT_DIR "/test-ca-cert.pem", NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, NULL));
 	nm_setting_802_1x_set_private_key (s_8021x, TEST_CERT_DIR "/test-cert.p12", NULL, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, NULL);
 
-	/* IP4 setting */
-	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
-
-	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
-
 	success = nm_connection_verify (connection, &error);
 	g_assert_no_error (error);
 	g_assert (success);
 
-	config = nm_supplicant_config_new ();
+	return connection;
+}
 
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'ssid' value 'Test SSID'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'scan_ssid' value '1'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'bssid' value '11:22:33:44:55:66'*");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'freq_list' value *");
-	g_assert (nm_supplicant_config_add_setting_wireless (config,
-	                                                     s_wifi,
-	                                                     0,
-	                                                     &error));
-	g_assert_no_error (error);
-	g_test_assert_expected_messages ();
+static void
+test_wifi_eap_locked_bssid (void)
+{
+	gs_unref_object NMConnection *connection = NULL;
+	gs_unref_variant GVariant *config_dict = NULL;
+	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
+	gs_unref_bytes GBytes *ssid = g_bytes_new (ssid_data, sizeof (ssid_data));
+	const char *bssid_str = "11:22:33:44:55:66";
+	guint32 mtu = 1100;
 
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'key_mgmt' value 'WPA-EAP'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'proto' value 'WPA RSN'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'pairwise' value 'TKIP CCMP'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*added 'group' value 'TKIP CCMP'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*Config: added 'eap' value 'TLS'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*Config: added 'fragment_size' value '1086'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "* Config: added 'ca_cert' value '*/test-ca-cert.pem'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "* Config: added 'private_key' value '*/test-cert.p12'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*Config: added 'bgscan' value 'simple:30:-65:300'");
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
-	                       "*Config: added 'proactive_key_caching' value '1'");
-	g_assert (nm_supplicant_config_add_setting_wireless_security (config,
-	                                                              s_wsec,
-	                                                              s_8021x,
-	                                                              "d5b488af-9cab-41ed-bad4-97709c58430f",
-	                                                              mtu,
-	                                                              &error));
-	g_assert_no_error (error);
+	connection = generate_wifi_eap_connection ("Test Wifi EAP-TLS Locked", ssid, bssid_str);
+
+	EXPECT ("*added 'ssid' value 'Test SSID'*");
+	EXPECT ("*added 'scan_ssid' value '1'*");
+	EXPECT ("*added 'bssid' value '11:22:33:44:55:66'*");
+	EXPECT ("*added 'freq_list' value *");
+	EXPECT ("*added 'key_mgmt' value 'WPA-EAP'");
+	EXPECT ("*added 'proto' value 'WPA RSN'");
+	EXPECT ("*added 'pairwise' value 'TKIP CCMP'");
+	EXPECT ("*added 'group' value 'TKIP CCMP'");
+	EXPECT ("*Config: added 'eap' value 'TLS'");
+	EXPECT ("*Config: added 'fragment_size' value '1086'");
+	EXPECT ("* Config: added 'ca_cert' value '*/test-ca-cert.pem'");
+	EXPECT ("* Config: added 'private_key' value '*/test-cert.p12'");
+	EXPECT ("*Config: added 'proactive_key_caching' value '1'");
+	config_dict = build_supplicant_config (connection, mtu, 0);
 	g_test_assert_expected_messages ();
+	g_assert (config_dict);
+
+	validate_opt ("wifi-eap", config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1));
+	validate_opt ("wifi-eap", config_dict, "ssid", TYPE_BYTES, ssid);
+	validate_opt ("wifi-eap", config_dict, "bssid", TYPE_KEYWORD, bssid_str);
+	validate_opt ("wifi-eap", config_dict, "key_mgmt", TYPE_KEYWORD, "WPA-EAP");
+	validate_opt ("wifi-eap", config_dict, "eap", TYPE_KEYWORD, "TLS");
+	validate_opt ("wifi-eap", config_dict, "proto", TYPE_KEYWORD, "WPA RSN");
+	validate_opt ("wifi-eap", config_dict, "pairwise", TYPE_KEYWORD, "TKIP CCMP");
+	validate_opt ("wifi-eap", config_dict, "group", TYPE_KEYWORD, "TKIP CCMP");
+	validate_opt ("wifi-eap", config_dict, "fragment_size", TYPE_INT, GINT_TO_POINTER(mtu-14));
+}
 
-	config_dict = nm_supplicant_config_to_variant (config);
+static void
+test_wifi_eap_unlocked_bssid (void)
+{
+	gs_unref_object NMConnection *connection = NULL;
+	gs_unref_variant GVariant *config_dict = NULL;
+	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
+	gs_unref_bytes GBytes *ssid = g_bytes_new (ssid_data, sizeof (ssid_data));
+	const char *bgscan_data = "simple:30:-65:300";
+	gs_unref_bytes GBytes *bgscan = g_bytes_new (bgscan_data, strlen (bgscan_data));
+	guint32 mtu = 1100;
+
+	connection = generate_wifi_eap_connection ("Test Wifi EAP-TLS Unlocked", ssid, NULL);
+
+	EXPECT ("*added 'ssid' value 'Test SSID'*");
+	EXPECT ("*added 'scan_ssid' value '1'*");
+	EXPECT ("*added 'freq_list' value *");
+	EXPECT ("*added 'key_mgmt' value 'WPA-EAP'");
+	EXPECT ("*added 'proto' value 'WPA RSN'");
+	EXPECT ("*added 'pairwise' value 'TKIP CCMP'");
+	EXPECT ("*added 'group' value 'TKIP CCMP'");
+	EXPECT ("*Config: added 'eap' value 'TLS'");
+	EXPECT ("*Config: added 'fragment_size' value '1086'");
+	EXPECT ("* Config: added 'ca_cert' value '*/test-ca-cert.pem'");
+	EXPECT ("* Config: added 'private_key' value '*/test-cert.p12'");
+	EXPECT ("*Config: added 'proactive_key_caching' value '1'");
+	EXPECT ("*Config: added 'bgscan' value 'simple:30:-65:300'");
+	config_dict = build_supplicant_config (connection, mtu, 0);
+	g_test_assert_expected_messages ();
 	g_assert (config_dict);
 
-	validate_opt ("wifi-eap", config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1);
-	validate_opt ("wifi-eap", config_dict, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data));
-	validate_opt ("wifi-eap", config_dict, "bssid", TYPE_KEYWORD, bssid_str, -1);
-	validate_opt ("wifi-eap", config_dict, "key_mgmt", TYPE_KEYWORD, "WPA-EAP", -1);
-	validate_opt ("wifi-eap", config_dict, "eap", TYPE_KEYWORD, "TLS", -1);
-	validate_opt ("wifi-eap", config_dict, "proto", TYPE_KEYWORD, "WPA RSN", -1);
-	validate_opt ("wifi-eap", config_dict, "pairwise", TYPE_KEYWORD, "TKIP CCMP", -1);
-	validate_opt ("wifi-eap", config_dict, "group", TYPE_KEYWORD, "TKIP CCMP", -1);
-	validate_opt ("wifi-eap", config_dict, "fragment_size", TYPE_INT, GINT_TO_POINTER(mtu-14), -1);
+	validate_opt ("wifi-eap", config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1));
+	validate_opt ("wifi-eap", config_dict, "ssid", TYPE_BYTES, ssid);
+	validate_opt ("wifi-eap", config_dict, "key_mgmt", TYPE_KEYWORD, "WPA-EAP");
+	validate_opt ("wifi-eap", config_dict, "eap", TYPE_KEYWORD, "TLS");
+	validate_opt ("wifi-eap", config_dict, "proto", TYPE_KEYWORD, "WPA RSN");
+	validate_opt ("wifi-eap", config_dict, "pairwise", TYPE_KEYWORD, "TKIP CCMP");
+	validate_opt ("wifi-eap", config_dict, "group", TYPE_KEYWORD, "TKIP CCMP");
+	validate_opt ("wifi-eap", config_dict, "fragment_size", TYPE_INT, GINT_TO_POINTER(mtu-14));
+	validate_opt ("wifi-eap", config_dict, "bgscan", TYPE_BYTES, bgscan);
 }
 
 NMTST_DEFINE ();
@@ -607,8 +514,8 @@ int main (int argc, char **argv)
 	g_test_add_func ("/supplicant-config/wifi-open", test_wifi_open);
 	g_test_add_func ("/supplicant-config/wifi-wep", test_wifi_wep);
 	g_test_add_func ("/supplicant-config/wifi-wpa-psk-types", test_wifi_wpa_psk_types);
-	g_test_add_func ("/supplicant-config/wifi-eap", test_wifi_eap);
+	g_test_add_func ("/supplicant-config/wifi-eap/locked-bssid", test_wifi_eap_locked_bssid);
+	g_test_add_func ("/supplicant-config/wifi-eap/unlocked-bssid", test_wifi_eap_unlocked_bssid);
 
 	return g_test_run ();
 }
-