summary refs log tree commit diff
path: root/src/supplicant-manager
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2012-03-24 01:37:02 +0100
committerMichael Biebl <biebl@debian.org>2012-03-24 01:37:02 +0100
commitde06e5715e780baade318f3490ac7a4c9ce84e32 (patch)
tree23fbc3fafc12072476eff98bee60100eb54c29db /src/supplicant-manager
parentb436a68a20ff3114ded32a7a3d70cdd4954039f9 (diff)
Imported Upstream version 0.9.4.0 upstream/0.9.4.0
Diffstat (limited to 'src/supplicant-manager')
-rw-r--r--src/supplicant-manager/Makefile.am6
-rw-r--r--src/supplicant-manager/Makefile.in16
-rw-r--r--src/supplicant-manager/nm-supplicant-config.c105
-rw-r--r--src/supplicant-manager/nm-supplicant-config.h8
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.c353
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.h26
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.c2
-rw-r--r--src/supplicant-manager/nm-supplicant-settings-verify.c34
-rw-r--r--src/supplicant-manager/nm-supplicant-settings-verify.h3
-rw-r--r--src/supplicant-manager/tests/Makefile.am2
-rw-r--r--src/supplicant-manager/tests/Makefile.in11
11 files changed, 498 insertions, 68 deletions
diff --git a/src/supplicant-manager/Makefile.am b/src/supplicant-manager/Makefile.am
index 359fc70a..e8a2ce74 100644
--- a/src/supplicant-manager/Makefile.am
+++ b/src/supplicant-manager/Makefile.am
@@ -2,10 +2,13 @@ SUBDIRS=. tests
 
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_builddir}/libnm-util
 
 noinst_LTLIBRARIES = libsupplicant-manager.la
 
@@ -27,7 +30,6 @@ libsupplicant_manager_la_CPPFLAGS = \
 	-DNM_LOCALSTATEDIR=\"$(localstatedir)\"
 
 libsupplicant_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/supplicant-manager/Makefile.in b/src/supplicant-manager/Makefile.in
index 5a7a2f2f..fbb43bde 100644
--- a/src/supplicant-manager/Makefile.in
+++ b/src/supplicant-manager/Makefile.in
@@ -57,7 +57,6 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libsupplicant_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libsupplicant_manager_la_OBJECTS =  \
@@ -184,6 +183,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -238,11 +239,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -253,6 +258,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -292,6 +298,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -358,10 +366,13 @@ top_srcdir = @top_srcdir@
 SUBDIRS = . tests
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_builddir}/libnm-util
 
 noinst_LTLIBRARIES = libsupplicant-manager.la
 libsupplicant_manager_la_SOURCES = \
@@ -382,7 +393,6 @@ libsupplicant_manager_la_CPPFLAGS = \
 	-DNM_LOCALSTATEDIR=\"$(localstatedir)\"
 
 libsupplicant_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index 4860314b..a8e4ab9d 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.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 - 2010 Red Hat, Inc.
+ * Copyright (C) 2006 - 2012 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -54,6 +54,7 @@ typedef struct
 	GHashTable *config;
 	GHashTable *blobs;
 	guint32    ap_scan;
+	gboolean   fast_required;
 	gboolean   dispose_has_run;
 } NMSupplicantConfigPrivate;
 
@@ -278,6 +279,14 @@ nm_supplicant_config_set_ap_scan (NMSupplicantConfig * self,
 	NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->ap_scan = ap_scan;
 }
 
+gboolean
+nm_supplicant_config_fast_required (NMSupplicantConfig *self)
+{
+	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
+
+	return NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->fast_required;
+}
+
 static void
 get_hash_cb (gpointer key, gpointer value, gpointer user_data)
 {
@@ -293,6 +302,7 @@ get_hash_cb (gpointer key, gpointer value, gpointer user_data)
 		g_value_set_int (variant, atoi (opt->value));
 		break;
 	case TYPE_BYTES:
+	case TYPE_UTF8:
 		array = g_byte_array_sized_new (opt->len);
 		g_byte_array_append (array, (const guint8 *) opt->value, opt->len);
 		g_value_init (variant, DBUS_TYPE_G_UCHAR_ARRAY);
@@ -583,7 +593,7 @@ gboolean
 nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                     NMSettingWirelessSecurity *setting,
                                                     NMSetting8021x *setting_8021x,
-                                                    const char *connection_uid)
+                                                    const char *con_uuid)
 {
 	char *value;
 	gboolean success;
@@ -592,7 +602,7 @@ nm_supplicant_config_add_setting_wireless_security (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 (connection_uid != NULL, FALSE);
+	g_return_val_if_fail (con_uuid != NULL, FALSE);
 
 	key_mgmt = nm_setting_wireless_security_get_key_mgmt (setting);
 	if (!add_string_val (self, key_mgmt, "key_mgmt", TRUE, FALSE))
@@ -692,7 +702,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 		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, connection_uid, FALSE))
+			if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, con_uuid, FALSE))
 				return FALSE;
 		}
 
@@ -711,24 +721,43 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 gboolean
 nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                         NMSetting8021x *setting,
-                                        const char *connection_uid,
+                                        const char *con_uuid,
                                         gboolean wired)
 {
+	NMSupplicantConfigPrivate *priv;
 	char *tmp;
 	const char *peapver, *value, *path;
 	gboolean success, added;
 	GString *phase1, *phase2;
 	const GByteArray *array;
-	gboolean peap = FALSE;
+	gboolean peap = FALSE, fast = FALSE;
 	guint32 i, num_eap;
+	gboolean fast_provisoning_allowed = FALSE;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
 	g_return_val_if_fail (setting != NULL, FALSE);
-	g_return_val_if_fail (connection_uid != NULL, FALSE);
+	g_return_val_if_fail (con_uuid != NULL, FALSE);
+
+	priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self);
 
 	value = nm_setting_802_1x_get_password (setting);
-	if (!add_string_val (self, value, "password", FALSE, TRUE))
-		return FALSE;
+	if (value) {
+		if (!add_string_val (self, value, "password", FALSE, TRUE))
+			return FALSE;
+	} else {
+		array = nm_setting_802_1x_get_password_raw (setting);
+		if (array) {
+			success = nm_supplicant_config_add_option (self,
+			                                           "password",
+			                                           (const char *)array->data,
+			                                           array->len,
+			                                           TRUE);
+			if (!success) {
+				nm_log_warn (LOGD_SUPPLICANT, "Error adding password-raw to supplicant config.");
+				return FALSE;
+			}
+		}
+	}
 	value = nm_setting_802_1x_get_pin (setting);
 	if (!add_string_val (self, value, "pin", FALSE, TRUE))
 		return FALSE;
@@ -744,14 +773,16 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 
 	ADD_STRING_LIST_VAL (setting, 802_1x, eap_method, eap_methods, "eap", ' ', TRUE, FALSE);
 
-	/* Check for PEAP + GTC */
+	/* Check EAP method for special handling: PEAP + GTC, FAST */
 	num_eap = nm_setting_802_1x_get_num_eap_methods (setting);
 	for (i = 0; i < num_eap; i++) {
 		const char *method = nm_setting_802_1x_get_eap_method (setting, i);
 
-		if (method && (strcasecmp (method, "peap") == 0)) {
+		if (method && (strcasecmp (method, "peap") == 0))
 			peap = TRUE;
-			break;
+		if (method && (strcasecmp (method, "fast") == 0)) {
+			fast = TRUE;
+			priv->fast_required = TRUE;
 		}
 	}
 
@@ -785,6 +816,16 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		g_string_append_printf (phase1, "peaplabel=%s", nm_setting_802_1x_get_phase1_peaplabel (setting));
 	}
 
+	value = nm_setting_802_1x_get_phase1_fast_provisioning (setting);
+	if (value) {
+		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)) {
 			g_string_free (phase1, TRUE);
@@ -794,7 +835,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	g_string_free (phase1, TRUE);
 
 	phase2 = g_string_new (NULL);
-	if (nm_setting_802_1x_get_phase2_auth (setting)) {
+	if (nm_setting_802_1x_get_phase2_auth (setting) && !fast_provisoning_allowed) {
 		tmp = g_ascii_strup (nm_setting_802_1x_get_phase2_auth (setting), -1);
 		g_string_append_printf (phase2, "auth=%s", tmp);
 		g_free (tmp);
@@ -816,6 +857,32 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	}
 	g_string_free (phase2, TRUE);
 
+	/* PAC file */
+	path = nm_setting_802_1x_get_pac_file (setting);
+	if (path) {
+		if (!add_string_val (self, path, "pac_file", FALSE, FALSE))
+			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);
+				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.");
+				return FALSE;
+			}
+		}
+	}
+
 	/* CA path */
 	path = nm_setting_802_1x_get_ca_path (setting);
 	if (nm_setting_802_1x_get_system_ca_certs (setting))
@@ -838,7 +905,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	switch (nm_setting_802_1x_get_ca_cert_scheme (setting)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 		array = nm_setting_802_1x_get_ca_cert_blob (setting);
-		ADD_BLOB_VAL (array, "ca_cert", connection_uid);
+		ADD_BLOB_VAL (array, "ca_cert", con_uuid);
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
 		path = nm_setting_802_1x_get_ca_cert_path (setting);
@@ -853,7 +920,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	switch (nm_setting_802_1x_get_phase2_ca_cert_scheme (setting)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 		array = nm_setting_802_1x_get_phase2_ca_cert_blob (setting);
-		ADD_BLOB_VAL (array, "ca_cert2", connection_uid);
+		ADD_BLOB_VAL (array, "ca_cert2", con_uuid);
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
 		path = nm_setting_802_1x_get_phase2_ca_cert_path (setting);
@@ -881,7 +948,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	switch (nm_setting_802_1x_get_private_key_scheme (setting)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 		array = nm_setting_802_1x_get_private_key_blob (setting);
-		ADD_BLOB_VAL (array, "private_key", connection_uid);
+		ADD_BLOB_VAL (array, "private_key", con_uuid);
 		added = TRUE;
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
@@ -919,7 +986,7 @@ 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:
 				array = nm_setting_802_1x_get_client_cert_blob (setting);
-				ADD_BLOB_VAL (array, "client_cert", connection_uid);
+				ADD_BLOB_VAL (array, "client_cert", con_uuid);
 				break;
 			case NM_SETTING_802_1X_CK_SCHEME_PATH:
 				path = nm_setting_802_1x_get_client_cert_path (setting);
@@ -937,7 +1004,7 @@ 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:
 		array = nm_setting_802_1x_get_phase2_private_key_blob (setting);
-		ADD_BLOB_VAL (array, "private_key2", connection_uid);
+		ADD_BLOB_VAL (array, "private_key2", con_uuid);
 		added = TRUE;
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
@@ -975,7 +1042,7 @@ 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:
 				array = nm_setting_802_1x_get_phase2_client_cert_blob (setting);
-				ADD_BLOB_VAL (array, "client_cert2", connection_uid);
+				ADD_BLOB_VAL (array, "client_cert2", con_uuid);
 				break;
 			case NM_SETTING_802_1X_CK_SCHEME_PATH:
 				path = nm_setting_802_1x_get_phase2_client_cert_path (setting);
diff --git a/src/supplicant-manager/nm-supplicant-config.h b/src/supplicant-manager/nm-supplicant-config.h
index dad23e29..a8d30470 100644
--- a/src/supplicant-manager/nm-supplicant-config.h
+++ b/src/supplicant-manager/nm-supplicant-config.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 - 2008 Red Hat, Inc.
+ * Copyright (C) 2006 - 2012 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -57,6 +57,8 @@ guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self);
 void nm_supplicant_config_set_ap_scan (NMSupplicantConfig *self,
                                        guint32 ap_scan);
 
+gboolean nm_supplicant_config_fast_required (NMSupplicantConfig *self);
+
 GHashTable *nm_supplicant_config_get_hash (NMSupplicantConfig *self);
 
 GHashTable *nm_supplicant_config_get_blobs (NMSupplicantConfig *self);
@@ -70,13 +72,13 @@ gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self,
 gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                              NMSettingWirelessSecurity *setting,
                                                              NMSetting8021x *setting_8021x,
-                                                             const char *connection_uid);
+                                                             const char *con_uuid);
 
 gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self);
 
 gboolean nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                                  NMSetting8021x *setting,
-                                                 const char *connection_uid,
+                                                 const char *con_uuid,
                                                  gboolean wired);
 
 G_END_DECLS
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c
index 857cde51..f8ad8f18 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/nm-supplicant-interface.c
@@ -15,10 +15,11 @@
  * 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 - 2012 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
+#include <config.h>
 #include <stdio.h>
 #include <string.h>
 #include <glib.h>
@@ -55,11 +56,14 @@ static void wpas_iface_scan_done (DBusGProxy *proxy,
 
 /* Signals */
 enum {
-	STATE,             /* change in the interface's state */
-	REMOVED,           /* interface was removed by the supplicant */
-	NEW_BSS,           /* interface saw a new access point from a scan */
-	SCAN_DONE,         /* wifi scan is complete */
-	CONNECTION_ERROR,  /* an error occurred during a connection request */
+	STATE,               /* change in the interface's state */
+	REMOVED,             /* interface was removed by the supplicant */
+	NEW_BSS,             /* interface saw a new access point from a scan */
+	BSS_UPDATED,         /* a BSS property changed */
+	BSS_REMOVED,         /* supplicant removed BSS from its scan list */
+	SCAN_DONE,           /* wifi scan is complete */
+	CONNECTION_ERROR,    /* an error occurred during a connection request */
+	CREDENTIALS_REQUEST, /* 802.1x identity or password requested */
 	LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -79,6 +83,8 @@ typedef struct {
 	NMDBusManager *       dbus_mgr;
 	char *                dev;
 	gboolean              is_wireless;
+	gboolean              has_credreq;  /* Whether querying 802.1x credentials is supported */
+	gboolean              fast_supported;
 
 	char *                object_path;
 	guint32               state;
@@ -92,6 +98,7 @@ typedef struct {
 	DBusGProxy *          props_proxy;
 	char *                net_path;
 	guint32               blobs_left;
+	GHashTable *          bss_proxies;
 
 	guint32               last_scan;
 
@@ -100,6 +107,28 @@ typedef struct {
 	gboolean              disposed;
 } NMSupplicantInterfacePrivate;
 
+/* FIXME: remove this and just store the standard D-Bus properties
+ * proxy object in bss_proxies when we drop support for wpa_supplicant
+ * 0.7.x.
+ */
+typedef struct {
+	/* Proxy for standard D-Bus Properties interface */
+	DBusGProxy *props;
+	/* Proxy for old wpa_supplicant-specific PropertiesChanged signal */
+	DBusGProxy *old_props;
+} BssProxies;
+
+static void
+bss_proxies_free (gpointer data)
+{
+	BssProxies *proxies = data;
+
+	g_object_unref (proxies->props);
+	g_object_unref (proxies->old_props);
+	memset (proxies, 0, sizeof (*proxies));
+	g_free (proxies);
+}
+
 static gboolean
 cancel_all_cb (GObject *object, gpointer call_id, gpointer user_data)
 {
@@ -192,6 +221,14 @@ emit_error_helper (NMSupplicantInterface *self,
 }
 
 static void
+signal_new_bss (NMSupplicantInterface *self,
+                const char *object_path,
+                GHashTable *props)
+{
+	g_signal_emit (self, signals[NEW_BSS], 0, object_path, props);
+}
+
+static void
 bssid_properties_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
 	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
@@ -201,7 +238,7 @@ bssid_properties_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_
 	if (dbus_g_proxy_end_call (proxy, call_id, &error,
 	                           DBUS_TYPE_G_MAP_OF_VARIANT, &props,
 	                           G_TYPE_INVALID)) {
-		g_signal_emit (info->interface, signals[NEW_BSS], 0, props);
+		signal_new_bss (info->interface, dbus_g_proxy_get_path (proxy), props);
 		g_hash_table_destroy (props);
 	} else {
 		if (!strstr (error->message, "The BSSID requested was invalid")) {
@@ -213,31 +250,93 @@ bssid_properties_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_
 }
 
 static void
-request_bss_properties (NMSupplicantInterface *self,
-                        GPtrArray *paths)
+bss_properties_changed (DBusGProxy *proxy,
+                        const char *interface,
+                        GHashTable *props,
+                        const char **unused,
+                        gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+
+	if (g_strcmp0 (interface, WPAS_DBUS_IFACE_BSS) == 0)
+		g_signal_emit (self, signals[BSS_UPDATED], 0, dbus_g_proxy_get_path (proxy), props);
+}
+
+static void
+old_bss_properties_changed (DBusGProxy *proxy,
+                            GHashTable *props,
+                            gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+
+	g_signal_emit (self, signals[BSS_UPDATED], 0, dbus_g_proxy_get_path (proxy), props);
+}
+
+static void
+handle_new_bss (NMSupplicantInterface *self,
+                const char *object_path,
+                GHashTable *props)
 {
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	int i;
-
-	/* Fire off a "properties" call for each returned BSSID */
-	for (i = 0; i < paths->len; i++) {
-		NMSupplicantInfo *info;
-		DBusGProxy *proxy;
-		DBusGProxyCall *call;
-
-		proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
-			                               WPAS_DBUS_SERVICE,
-			                               g_ptr_array_index (paths, i),
-			                               DBUS_INTERFACE_PROPERTIES);
-		info = nm_supplicant_info_new (self, proxy, priv->other_pcalls);
-		call = dbus_g_proxy_begin_call (proxy, "GetAll",
-			                            bssid_properties_cb,
-			                            info,
-			                            nm_supplicant_info_destroy,
-			                            G_TYPE_STRING, WPAS_DBUS_IFACE_BSS,
-			                            G_TYPE_INVALID);
+	NMSupplicantInfo *info;
+	DBusGProxyCall *call;
+	BssProxies *proxies;
+
+	g_return_if_fail (object_path != NULL);
+
+	if (g_hash_table_lookup (priv->bss_proxies, object_path))
+		return;
+
+	proxies = g_malloc0 (sizeof (*proxies));
+	proxies->props = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	                                            WPAS_DBUS_SERVICE,
+	                                            object_path,
+	                                            DBUS_INTERFACE_PROPERTIES);
+	proxies->old_props = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	                                                WPAS_DBUS_SERVICE,
+	                                                object_path,
+	                                                WPAS_DBUS_IFACE_BSS);
+	g_hash_table_insert (priv->bss_proxies,
+	                     (gpointer) dbus_g_proxy_get_path (proxies->props),
+	                     proxies);
+
+	/* Standard D-Bus PropertiesChanged signal */
+	dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED_BOXED,
+	                                   G_TYPE_NONE,
+	                                   G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_STRV,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (proxies->props, "PropertiesChanged",
+	                         G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_STRV,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (proxies->props, "PropertiesChanged",
+	                             G_CALLBACK (bss_properties_changed),
+	                             self, NULL);
+
+	/* Old wpa_supplicant-specific PropertiesChanged signal; since it's using
+	 * a different interface, we have to use a different DBusGProxy
+	 */
+	dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
+	                                   G_TYPE_NONE,
+	                                   DBUS_TYPE_G_MAP_OF_VARIANT,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (proxies->old_props, "PropertiesChanged",
+	                         DBUS_TYPE_G_MAP_OF_VARIANT,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (proxies->old_props, "PropertiesChanged",
+	                             G_CALLBACK (old_bss_properties_changed),
+	                             self, NULL);
+
+	if (props) {
+		signal_new_bss (self, object_path, props);
+	} else {
+		info = nm_supplicant_info_new (self, proxies->props, priv->other_pcalls);
+		call = dbus_g_proxy_begin_call (proxies->props, "GetAll",
+		                                bssid_properties_cb,
+		                                info,
+		                                nm_supplicant_info_destroy,
+		                                G_TYPE_STRING, WPAS_DBUS_IFACE_BSS,
+		                                G_TYPE_INVALID);
 		nm_supplicant_info_set_call (info, call);
-		g_object_unref (proxy);
 	}
 }
 
@@ -247,7 +346,20 @@ wpas_iface_bss_added (DBusGProxy *proxy,
                       GHashTable *props,
                       gpointer user_data)
 {
-	g_signal_emit (NM_SUPPLICANT_INTERFACE (user_data), signals[NEW_BSS], 0, props);
+	handle_new_bss (NM_SUPPLICANT_INTERFACE (user_data), object_path, props);
+}
+
+static void
+wpas_iface_bss_removed (DBusGProxy *proxy,
+                        const char *object_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, object_path);
+
+	g_hash_table_remove (priv->bss_proxies, object_path);
 }
 
 static int
@@ -318,6 +430,10 @@ set_state (NMSupplicantInterface *self, guint32 new_state)
 			                                "BSSAdded",
 			                                G_CALLBACK (wpas_iface_bss_added),
 			                                self);
+			dbus_g_proxy_disconnect_signal (priv->iface_proxy,
+			                                "BSSRemoved",
+			                                G_CALLBACK (wpas_iface_bss_removed),
+			                                self);
 		}
 	}
 
@@ -403,8 +519,13 @@ wpas_iface_properties_changed (DBusGProxy *proxy,
 		set_state_from_string (self, g_value_get_string (value));
 
 	value = g_hash_table_lookup (props, "BSSs");
-	if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH))
-		request_bss_properties (self, g_value_get_boxed (value));
+	if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH)) {
+		GPtrArray *paths = g_value_get_boxed (value);
+		int i;
+
+		for (i = 0; paths && (i < paths->len); i++)
+			handle_new_bss (self, g_ptr_array_index (paths, i), NULL);
+	}
 }
 
 static void
@@ -443,6 +564,92 @@ wpas_iface_get_props (NMSupplicantInterface *self)
 	nm_supplicant_info_set_call (info, call);
 }
 
+gboolean
+nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self,
+                                           const char *field,
+                                           const char *value,
+                                           GError **error)
+{
+	NMSupplicantInterfacePrivate *priv;
+
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE);
+	g_return_val_if_fail (field != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	g_return_val_if_fail (priv->has_credreq == TRUE, FALSE);
+
+	/* Need a network block object path */
+	g_return_val_if_fail (priv->net_path, FALSE);
+	return dbus_g_proxy_call_with_timeout (priv->iface_proxy, "NetworkReply",
+	                                       5000,
+	                                       error,
+	                                       DBUS_TYPE_G_OBJECT_PATH, priv->net_path,
+	                                       G_TYPE_STRING, field,
+	                                       G_TYPE_STRING, value,
+	                                       G_TYPE_INVALID);
+}
+
+static void
+wpas_iface_network_request (DBusGProxy *proxy,
+                            const char *object_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);
+
+	g_return_if_fail (priv->has_credreq == TRUE);
+	g_return_if_fail (priv->net_path != NULL);
+	g_return_if_fail (g_strcmp0 (object_path, priv->net_path) == 0);
+
+	g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message);
+}
+
+static void
+iface_check_netreply_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
+	GError *error = NULL;
+
+	if (   dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)
+	    || dbus_g_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs")) {
+		/* We know NetworkReply is supported if the NetworkReply method returned
+		 * successfully (which is unexpected since we sent a bogus network
+		 * object path) or if we got an "InvalidArgs" (which indicates NetworkReply
+		 * is supported).  We know it's not supported if we get an
+		 * "UnknownMethod" error.
+		 */
+		priv->has_credreq = TRUE;
+
+		nm_log_dbg (LOGD_SUPPLICANT, "Supplicant %s network credentials requests",
+			        priv->has_credreq ? "supports" : "does not support");
+	}
+	g_clear_error (&error);
+}
+
+static void
+wpas_iface_check_network_reply (NMSupplicantInterface *self)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	NMSupplicantInfo *info;
+	DBusGProxyCall *call;
+
+	info = nm_supplicant_info_new (self, priv->props_proxy, priv->other_pcalls);
+	call = dbus_g_proxy_begin_call (priv->iface_proxy, "NetworkReply",
+	                                iface_check_netreply_cb,
+	                                info,
+	                                nm_supplicant_info_destroy,
+	                                DBUS_TYPE_G_OBJECT_PATH, "/foobaraasdfasdf",
+	                                G_TYPE_STRING, "foobar",
+	                                G_TYPE_STRING, "foobar",
+	                                G_TYPE_INVALID);
+	nm_supplicant_info_set_call (info, call);
+}
+
 static void
 interface_add_done (NMSupplicantInterface *self, char *path)
 {
@@ -486,6 +693,30 @@ interface_add_done (NMSupplicantInterface *self, char *path)
 	                             self,
 	                             NULL);
 
+	dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
+	                                   G_TYPE_NONE,
+	                                   DBUS_TYPE_G_OBJECT_PATH,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (priv->iface_proxy, "BSSRemoved",
+	                         DBUS_TYPE_G_OBJECT_PATH,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->iface_proxy, "BSSRemoved",
+	                             G_CALLBACK (wpas_iface_bss_removed),
+	                             self,
+	                             NULL);
+
+	dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING_STRING,
+	                                   G_TYPE_NONE,
+	                                   DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (priv->iface_proxy, "NetworkRequest",
+	                         DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->iface_proxy, "NetworkRequest",
+	                             G_CALLBACK (wpas_iface_network_request),
+	                             self,
+	                             NULL);
+
 	priv->props_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
 	                                               WPAS_DBUS_SERVICE,
 	                                               path,
@@ -493,6 +724,9 @@ interface_add_done (NMSupplicantInterface *self, char *path)
 	/* Get initial properties */
 	wpas_iface_get_props (self);
 
+	/* Check whether NetworkReply is supported */
+	wpas_iface_check_network_reply (self);
+
 	set_state (self, NM_SUPPLICANT_INTERFACE_STATE_READY);
 }
 
@@ -574,6 +808,12 @@ interface_add_cb (DBusGProxy *proxy,
 	}
 }
 
+#if HAVE_WEXT
+#define DEFAULT_WIFI_DRIVER "nl80211,wext"
+#else
+#define DEFAULT_WIFI_DRIVER "nl80211"
+#endif
+
 static void
 interface_add (NMSupplicantInterface *self, gboolean is_wireless)
 {
@@ -602,7 +842,7 @@ interface_add (NMSupplicantInterface *self, gboolean is_wireless)
 
 	driver = g_new0 (GValue, 1);
 	g_value_init (driver, G_TYPE_STRING);
-	g_value_set_string (driver, is_wireless ? "nl80211,wext" : "wired");
+	g_value_set_string (driver, is_wireless ? DEFAULT_WIFI_DRIVER : "wired");
 	g_hash_table_insert (hash, "Driver", driver);
 
 	ifname = g_new0 (GValue, 1);
@@ -851,7 +1091,15 @@ nm_supplicant_interface_set_config (NMSupplicantInterface * self,
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
 	nm_supplicant_interface_disconnect (self);
-	
+
+	/* Make sure the supplicant supports EAP-FAST before trying to send
+	 * 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");
+		return FALSE;
+	}
+
 	if (priv->cfg)
 		g_object_unref (priv->cfg);
 	priv->cfg = cfg;
@@ -1017,6 +1265,7 @@ NMSupplicantInterface *
 nm_supplicant_interface_new (NMSupplicantManager *smgr,
                              const char *ifname,
                              gboolean is_wireless,
+                             gboolean fast_supported,
                              gboolean start_now)
 {
 	NMSupplicantInterface *self;
@@ -1039,6 +1288,7 @@ nm_supplicant_interface_new (NMSupplicantManager *smgr,
 
 		priv->dev = g_strdup (ifname);
 		priv->is_wireless = is_wireless;
+		priv->fast_supported = fast_supported;
 
 		if (start_now)
 			interface_add (self, priv->is_wireless);
@@ -1063,6 +1313,8 @@ nm_supplicant_interface_init (NMSupplicantInterface * self)
 	                                              WPAS_DBUS_SERVICE,
 	                                              WPAS_DBUS_PATH,
 	                                              WPAS_DBUS_INTERFACE);
+
+	priv->bss_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, bss_proxies_free);
 }
 
 static void
@@ -1123,6 +1375,8 @@ dispose (GObject *object)
 	if (priv->wpas_proxy)
 		g_object_unref (priv->wpas_proxy);
 
+	g_hash_table_destroy (priv->bss_proxies);
+
 	if (priv->smgr) {
 		if (priv->smgr_avail_id)
 			g_signal_handler_disconnect (priv->smgr, priv->smgr_avail_id);
@@ -1187,8 +1441,26 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 		              G_SIGNAL_RUN_LAST,
 		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, new_bss),
 		              NULL, NULL,
-		              g_cclosure_marshal_VOID__POINTER,
-		              G_TYPE_NONE, 1, G_TYPE_POINTER);
+		              _nm_marshal_VOID__STRING_POINTER,
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+
+	signals[BSS_UPDATED] =
+		g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_UPDATED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, bss_updated),
+		              NULL, NULL,
+		              _nm_marshal_VOID__STRING_POINTER,
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+
+	signals[BSS_REMOVED] =
+		g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_REMOVED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, bss_removed),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__STRING,
+		              G_TYPE_NONE, 1, G_TYPE_STRING);
 
 	signals[SCAN_DONE] =
 		g_signal_new (NM_SUPPLICANT_INTERFACE_SCAN_DONE,
@@ -1207,5 +1479,14 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 		              NULL, NULL,
 		              _nm_marshal_VOID__STRING_STRING,
 		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+
+	signals[CREDENTIALS_REQUEST] =
+		g_signal_new (NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, credentials_request),
+		              NULL, NULL,
+		              _nm_marshal_VOID__STRING_STRING,
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
 }
 
diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h
index e32411d7..608ee059 100644
--- a/src/supplicant-manager/nm-supplicant-interface.h
+++ b/src/supplicant-manager/nm-supplicant-interface.h
@@ -57,8 +57,11 @@ enum {
 #define NM_SUPPLICANT_INTERFACE_STATE            "state"
 #define NM_SUPPLICANT_INTERFACE_REMOVED          "removed"
 #define NM_SUPPLICANT_INTERFACE_NEW_BSS          "new-bss"
+#define NM_SUPPLICANT_INTERFACE_BSS_UPDATED      "bss-updated"
+#define NM_SUPPLICANT_INTERFACE_BSS_REMOVED      "bss-removed"
 #define NM_SUPPLICANT_INTERFACE_SCAN_DONE        "scan-done"
 #define NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR "connection-error"
+#define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request"
 
 struct _NMSupplicantInterface {
 	GObject parent;
@@ -79,8 +82,18 @@ typedef struct {
 
 	/* interface saw a new BSS */
 	void (*new_bss)          (NMSupplicantInterface *iface,
+	                          const char *object_path,
 	                          GHashTable *props);
 
+	/* a BSS property changed */
+	void (*bss_updated)      (NMSupplicantInterface *iface,
+	                          const char *object_path,
+	                          GHashTable *props);
+
+	/* supplicant removed a BSS from its scan list */
+	void (*bss_removed)      (NMSupplicantInterface *iface,
+	                          const char *object_path);
+
 	/* wireless scan is done */
 	void (*scan_done)        (NMSupplicantInterface *iface,
 	                          gboolean success);
@@ -89,6 +102,11 @@ typedef struct {
 	void (*connection_error) (NMSupplicantInterface * iface,
 	                          const char * name,
 	                          const char * message);
+
+	/* 802.1x credentials requested */
+	void (*credentials_request) (NMSupplicantInterface *iface,
+	                             const char *field,
+	                             const char *message);
 } NMSupplicantInterfaceClass;
 
 
@@ -97,6 +115,7 @@ GType nm_supplicant_interface_get_type (void);
 NMSupplicantInterface * nm_supplicant_interface_new (NMSupplicantManager * smgr,
                                                      const char *ifname,
                                                      gboolean is_wireless,
+                                                     gboolean fast_supported,
                                                      gboolean start_now);
 
 gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface,
@@ -118,4 +137,11 @@ gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self);
 
 const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self);
 
+gboolean nm_supplicant_interface_get_has_credentials_request (NMSupplicantInterface *self);
+
+gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self,
+                                                    const char *field,
+                                                    const char *value,
+                                                    GError **error);
+
 #endif	/* NM_SUPPLICANT_INTERFACE_H */
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c
index 349f722a..ae150865 100644
--- a/src/supplicant-manager/nm-supplicant-manager.c
+++ b/src/supplicant-manager/nm-supplicant-manager.c
@@ -86,7 +86,7 @@ nm_supplicant_manager_iface_get (NMSupplicantManager * self,
 		start_now = !die_count_exceeded (priv->die_count);
 
 		nm_log_dbg (LOGD_SUPPLICANT, "(%s): creating new supplicant interface", ifname);
-		iface = nm_supplicant_interface_new (self, ifname, is_wireless, start_now);
+		iface = nm_supplicant_interface_new (self, ifname, is_wireless, priv->fast_supported, start_now);
 		if (iface)
 			g_hash_table_insert (priv->ifaces, g_strdup (ifname), iface);
 	} else {
diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.c b/src/supplicant-manager/nm-supplicant-settings-verify.c
index aea5bfec..76de84d8 100644
--- a/src/supplicant-manager/nm-supplicant-settings-verify.c
+++ b/src/supplicant-manager/nm-supplicant-settings-verify.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 - 2008 Red Hat, Inc.
+ * Copyright (C) 2006 - 2012 Red Hat, Inc.
  */
 
 #include <glib.h>
@@ -44,6 +44,10 @@ static gboolean validate_type_bytes   (const struct Opt * opt,
                                        const char * value,
                                        const guint32 len);
 
+static gboolean validate_type_utf8    (const struct Opt *opt,
+                                       const char * value,
+                                       const guint32 len);
+
 static gboolean validate_type_keyword (const struct Opt * opt,
                                        const char * value,
                                        const guint32 len);
@@ -58,6 +62,7 @@ struct validate_entry {
 static const struct validate_entry validate_table[] = {
 	{ TYPE_INT,     validate_type_int     },
 	{ TYPE_BYTES,   validate_type_bytes   },
+	{ TYPE_UTF8,    validate_type_utf8    },
 	{ TYPE_KEYWORD, validate_type_keyword },
 };
 
@@ -73,7 +78,9 @@ const char * eap_allowed[] =      { "LEAP", "MD5", "TLS", "PEAP", "TTLS", "SIM",
 
 const char * phase1_allowed[] =   {"peapver=0", "peapver=1", "peaplabel=1",
                                     "peap_outer_success=0", "include_tls_length=1",
-                                    "sim_min_num_chal=3", NULL };
+                                    "sim_min_num_chal=3", "fast_provisioning=0",
+                                    "fast_provisioning=1", "fast_provisioning=2",
+                                    "fast_provisioning=3", NULL };
 const char * phase2_allowed[] =   {"auth=PAP", "auth=CHAP", "auth=MSCHAP",
                                    "auth=MSCHAPV2", "auth=GTC", "auth=OTP",
                                    "auth=MD5", "auth=TLS", "autheap=MD5",
@@ -100,7 +107,7 @@ static const struct Opt opt_table[] = {
 	{ "eapol_flags",        TYPE_INT,     0, 3, FALSE,  NULL },
 	{ "eap",                TYPE_KEYWORD, 0, 0, FALSE,  eap_allowed },
 	{ "identity",           TYPE_BYTES,   0, 0, FALSE,  NULL },
-	{ "password",           TYPE_BYTES,   0, 0, FALSE,  NULL },
+	{ "password",           TYPE_UTF8,    0, 0, FALSE,  NULL },
 	{ "ca_path",            TYPE_BYTES,   0, 0, FALSE,  NULL },
 	{ "subject_match",      TYPE_BYTES,   0, 0, FALSE,  NULL },
 	{ "altsubject_match",   TYPE_BYTES,   0, 0, FALSE,  NULL },
@@ -129,6 +136,7 @@ static const struct Opt opt_table[] = {
 	{ "fragment_size",      TYPE_INT,     1, 2000, FALSE,  NULL },
 	{ "proactive_key_caching", TYPE_INT,  0, 1, FALSE,  NULL },
 	{ "bgscan",             TYPE_BYTES,   0, 0, FALSE,  NULL },
+	{ "pac_file",           TYPE_BYTES,   0, 1024, FALSE,  NULL },
 };
 
 
@@ -174,6 +182,26 @@ validate_type_bytes (const struct Opt * opt,
 }
 
 static gboolean
+validate_type_utf8 (const struct Opt *opt,
+                    const char * value,
+                    const guint32 len)
+{
+	guint32 check_len;
+
+	g_return_val_if_fail (opt != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	check_len = opt->int_high ? opt->int_high : 255;
+	/* Note that we deliberately don't validate the UTF-8, because
+	   some "UTF-8" fields, such as 8021x.password, do not actually
+	   have to be valid UTF-8 */
+	if (g_utf8_strlen (value, len) > check_len)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
 validate_type_keyword (const struct Opt * opt,
                        const char * value,
                        const guint32 len)
diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.h b/src/supplicant-manager/nm-supplicant-settings-verify.h
index 0939ebdb..eb213e0e 100644
--- a/src/supplicant-manager/nm-supplicant-settings-verify.h
+++ b/src/supplicant-manager/nm-supplicant-settings-verify.h
@@ -21,10 +21,11 @@
 #ifndef NM_SUPPLICANT_SETTINGS_VERIFY_H
 #define NM_SUPPLICANT_SETTINGS_VERIFY_H
 
-typedef enum OptType {
+typedef enum {
 	TYPE_INVALID = 0,
 	TYPE_INT,
 	TYPE_BYTES,
+	TYPE_UTF8,
 	TYPE_KEYWORD,
 	TYPE_STRING
 } OptType;
diff --git a/src/supplicant-manager/tests/Makefile.am b/src/supplicant-manager/tests/Makefile.am
index b5e4db61..47ae66c5 100644
--- a/src/supplicant-manager/tests/Makefile.am
+++ b/src/supplicant-manager/tests/Makefile.am
@@ -1,6 +1,8 @@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util \
 	-I$(top_srcdir)/src \
 	-I$(top_srcdir)/src/supplicant-manager
 
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index 25e60e86..65be2b39 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/tests/Makefile.in
@@ -143,6 +143,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -197,11 +199,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -212,6 +218,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -251,6 +258,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -316,7 +325,9 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util \
 	-I$(top_srcdir)/src \
 	-I$(top_srcdir)/src/supplicant-manager