summary refs log tree commit diff
path: root/src/supplicant-manager
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2011-04-21 10:42:53 +0200
committerMichael Biebl <biebl@debian.org>2011-04-21 10:42:53 +0200
commit8baa1aca8dfd35e3190d7d5655eb83b5b901e263 (patch)
treea9ac1e67d0c22a48330c76f08fc5291f85307055 /src/supplicant-manager
parentf75dd6fd1975146623052b843b182dc32c3fbe46 (diff)
Imported Upstream version 0.8.4.0 upstream/0.8.4.0
Diffstat (limited to 'src/supplicant-manager')
-rw-r--r--src/supplicant-manager/Makefile.in50
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.c1588
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.h78
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.c427
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.h44
-rw-r--r--src/supplicant-manager/tests/Makefile.in50
6 files changed, 1246 insertions, 991 deletions
diff --git a/src/supplicant-manager/Makefile.in b/src/supplicant-manager/Makefile.in
index cfee4510..08ffaece 100644
--- a/src/supplicant-manager/Makefile.in
+++ b/src/supplicant-manager/Makefile.in
@@ -38,16 +38,11 @@ subdir = src/supplicant-manager
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
-	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
-	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
-	$(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/introspection.m4 \
-	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
-	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libnl-check.m4 \
-	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
-	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
-	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
-	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/intltool.m4 \
+	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -71,7 +66,7 @@ AM_V_lt = $(am__v_lt_$(V))
 am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
 am__v_lt_0 = --silent
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
-depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
 am__mv = mv -f
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
@@ -140,6 +135,7 @@ am__relativize = \
   done; \
   reldir="$$dir2"
 ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
 ALL_LINGUAS = @ALL_LINGUAS@
 AMTAR = @AMTAR@
 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
@@ -148,6 +144,8 @@ AUTOCONF = @AUTOCONF@
 AUTOHEADER = @AUTOHEADER@
 AUTOMAKE = @AUTOMAKE@
 AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
@@ -164,7 +162,6 @@ DHCLIENT_PATH = @DHCLIENT_PATH@
 DHCLIENT_VERSION = @DHCLIENT_VERSION@
 DHCPCD_PATH = @DHCPCD_PATH@
 DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
-DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
 ECHO_C = @ECHO_C@
@@ -173,7 +170,6 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
-GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
 GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
 GIO_CFLAGS = @GIO_CFLAGS@
 GIO_LIBS = @GIO_LIBS@
@@ -182,8 +178,8 @@ GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
+GMOFILES = @GMOFILES@
 GMSGFMT = @GMSGFMT@
-GMSGFMT_015 = @GMSGFMT_015@
 GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
@@ -198,23 +194,13 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
 INTLLIBS = @INTLLIBS@
 INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
-INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
-INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
-INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
-INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
-INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
-INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
-INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
-INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
-INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
 IPTABLES_PATH = @IPTABLES_PATH@
-IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
-IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
 KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
@@ -222,8 +208,6 @@ LIBDL = @LIBDL@
 LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
 LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
 LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
-LIBICONV = @LIBICONV@
-LIBINTL = @LIBINTL@
 LIBM = @LIBM@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
@@ -232,15 +216,13 @@ LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
-LTLIBICONV = @LTLIBICONV@
-LTLIBINTL = @LTLIBINTL@
 LTLIBOBJS = @LTLIBOBJS@
 MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
 MSGFMT = @MSGFMT@
-MSGFMT_015 = @MSGFMT_015@
+MSGFMT_OPTS = @MSGFMT_OPTS@
 MSGMERGE = @MSGMERGE@
 NM = @NM@
 NMEDIT = @NMEDIT@
@@ -266,9 +248,12 @@ PKGCONFIG_PATH = @PKGCONFIG_PATH@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
 POLKIT_CFLAGS = @POLKIT_CFLAGS@
 POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
 RANLIB = @RANLIB@
 RESOLVCONF_PATH = @RESOLVCONF_PATH@
@@ -283,13 +268,10 @@ UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
-XGETTEXT_015 = @XGETTEXT_015@
-XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
 abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
 am__include = @am__include@
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c
index e9e58f39..a65a458f 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/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 - 2010 Red Hat, Inc.
+ * Copyright (C) 2006 - 2008 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -34,48 +34,73 @@
 #include "nm-glib-compat.h"
 
 #define WPAS_DBUS_IFACE_INTERFACE   WPAS_DBUS_INTERFACE ".Interface"
-#define WPAS_DBUS_IFACE_BSS         WPAS_DBUS_INTERFACE ".BSS"
+#define WPAS_DBUS_IFACE_BSSID       WPAS_DBUS_INTERFACE ".BSSID"
 #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_ERROR_EXISTS_ERROR     WPAS_DBUS_INTERFACE ".ExistsError"
 
-G_DEFINE_TYPE (NMSupplicantInterface, nm_supplicant_interface, G_TYPE_OBJECT)
 
-static void wpas_iface_properties_changed (DBusGProxy *proxy,
-                                           GHashTable *props,
-                                           gpointer user_data);
+G_DEFINE_TYPE (NMSupplicantInterface, nm_supplicant_interface, G_TYPE_OBJECT)
 
-static void wpas_iface_scan_done (DBusGProxy *proxy,
-                                  gboolean success,
-                                  gpointer user_data);
 
 #define NM_SUPPLICANT_INTERFACE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
                                                  NM_TYPE_SUPPLICANT_INTERFACE, \
                                                  NMSupplicantInterfacePrivate))
 
+static void nm_supplicant_interface_set_property (GObject *      object,
+                                                  guint          prop_id,
+                                                  const GValue * value,
+                                                  GParamSpec *   pspec);
+
+static void nm_supplicant_interface_get_property (GObject *      object,
+                                                  guint          prop_id,
+                                                  GValue *       value,
+                                                  GParamSpec *   pspec);
+
+static void nm_supplicant_interface_start (NMSupplicantInterface *self);
+
+static void nm_supplicant_interface_add_to_supplicant (NMSupplicantInterface *self,
+                                                       gboolean get_only);
+
+static void nm_supplicant_interface_smgr_state_changed (NMSupplicantManager *smgr,
+                                                        guint32 new_state,
+                                                        guint32 old_state,
+                                                        gpointer user_data);
+
+static void nm_supplicant_interface_set_state (NMSupplicantInterface *self,
+                                               guint32 new_state);
+
+
 /* 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 */
+	SCANNED_AP,        /* interface saw a new access point from a scan */
+	SCAN_REQ_RESULT,   /* result of a wireless scan request */
+	SCAN_RESULTS,      /* scan results returned from supplicant */
+	CONNECTION_STATE,  /* link state of the device's connection */
 	CONNECTION_ERROR,  /* an error occurred during a connection request */
 	LAST_SIGNAL
 };
-static guint signals[LAST_SIGNAL] = { 0 };
+static guint nm_supplicant_interface_signals[LAST_SIGNAL] = { 0 };
 
 
 /* Properties */
 enum {
 	PROP_0 = 0,
+	PROP_SUPPLICANT_MANAGER,
+	PROP_DEVICE,
+	PROP_STATE,
+	PROP_CONNECTION_STATE,
 	PROP_SCANNING,
 	LAST_PROP
 };
 
 
-typedef struct {
+typedef struct
+{
 	NMSupplicantManager * smgr;
-	gulong                smgr_avail_id;
+	gulong                smgr_state_sig_handler;
 	NMDBusManager *       dbus_mgr;
 	char *                dev;
 	gboolean              is_wireless;
@@ -85,19 +110,18 @@ typedef struct {
 	NMCallStore *         assoc_pcalls;
 	NMCallStore *         other_pcalls;
 
+	guint32               con_state;
 	gboolean              scanning;
 
-	DBusGProxy *          wpas_proxy;
 	DBusGProxy *          iface_proxy;
-	DBusGProxy *          props_proxy;
-	char *                net_path;
-	guint32               blobs_left;
+	DBusGProxy *          net_proxy;
 
+	guint                 scan_results_timeout;
 	guint32               last_scan;
 
 	NMSupplicantConfig *  cfg;
 
-	gboolean              disposed;
+	gboolean              dispose_has_run;
 } NMSupplicantInterfacePrivate;
 
 static gboolean
@@ -179,488 +203,827 @@ nm_supplicant_info_destroy (gpointer user_data)
 	}
 }
 
-static void
-emit_error_helper (NMSupplicantInterface *self,
-				   GError *err)
-{
-	const char *name = NULL;
 
-	if (err->domain == DBUS_GERROR && err->code == DBUS_GERROR_REMOTE_EXCEPTION)
-		name = dbus_g_error_get_name (err);
+NMSupplicantInterface *
+nm_supplicant_interface_new (NMSupplicantManager * smgr, const char *ifname, gboolean is_wireless)
+{
+	NMSupplicantInterface * iface;
 
-	g_signal_emit (self, signals[CONNECTION_ERROR], 0, name, err->message);
-}
+	g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (smgr), NULL);
+	g_return_val_if_fail (ifname != NULL, NULL);
 
-static void
-bssid_properties_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
-{
-	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
-	GError *error = NULL;
-	GHashTable *props = NULL;
-
-	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);
-		g_hash_table_destroy (props);
-	} else {
-		if (!strstr (error->message, "The BSSID requested was invalid")) {
-			nm_log_warn (LOGD_SUPPLICANT, "Couldn't retrieve BSSID properties: %s.",
-			             error->message);
-		}
-		g_error_free (error);
+	iface = g_object_new (NM_TYPE_SUPPLICANT_INTERFACE,
+	                      "supplicant-manager", smgr,
+	                      "device", ifname,
+	                      NULL);
+	if (iface) {
+		NM_SUPPLICANT_INTERFACE_GET_PRIVATE (iface)->is_wireless = is_wireless;
+		nm_supplicant_interface_start (iface);
 	}
+
+	return iface;
 }
 
 static void
-request_bss_properties (NMSupplicantInterface *self,
-                        GPtrArray *paths)
+nm_supplicant_interface_init (NMSupplicantInterface * self)
 {
 	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;
+	priv->state = NM_SUPPLICANT_INTERFACE_STATE_INIT;
+	priv->con_state = NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED;
+	priv->assoc_pcalls = nm_call_store_new ();
+	priv->other_pcalls = nm_call_store_new ();
 
-		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);
-		nm_supplicant_info_set_call (info, call);
-		g_object_unref (proxy);
-	}
+	priv->dispose_has_run = FALSE;
+
+	priv->dbus_mgr = nm_dbus_manager_get ();
 }
 
+
 static void
-wpas_iface_bss_added (DBusGProxy *proxy,
-                      const char *object_path,
-                      GHashTable *props,
-                      gpointer user_data)
+nm_supplicant_interface_set_property (GObject *      object,
+                                      guint          prop_id,
+                                      const GValue * value,
+                                      GParamSpec *   pspec)
 {
-	g_signal_emit (NM_SUPPLICANT_INTERFACE (user_data), signals[NEW_BSS], 0, props);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);
+	gulong id;
+
+	switch (prop_id) {
+		case PROP_SUPPLICANT_MANAGER:
+			priv->smgr = NM_SUPPLICANT_MANAGER (g_value_get_object (value));
+			g_object_ref (G_OBJECT (priv->smgr));
+			
+			id = g_signal_connect (priv->smgr,
+			                       "state",
+			                       G_CALLBACK (nm_supplicant_interface_smgr_state_changed),
+			                       object);
+			priv->smgr_state_sig_handler = id;
+			break;
+		case PROP_DEVICE:
+			/* Construct-only */
+			priv->dev = g_strdup (g_value_get_string (value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
 }
 
-static int
-wpas_state_string_to_enum (const char *str_state)
+static void
+nm_supplicant_interface_get_property (GObject *     object,
+                                      guint         prop_id,
+                                      GValue *      value,
+                                      GParamSpec *  pspec)
 {
-	if (!strcmp (str_state, "disconnected"))
-		return NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED;
-	else if (!strcmp (str_state, "inactive"))
-		return NM_SUPPLICANT_INTERFACE_STATE_INACTIVE;
-	else if (!strcmp (str_state, "scanning"))
-		return NM_SUPPLICANT_INTERFACE_STATE_SCANNING;
-	else if (!strcmp (str_state, "authenticating"))
-		return NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING;
-	else if (!strcmp (str_state, "associating"))
-		return NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING;
-	else if (!strcmp (str_state, "associated"))
-		return NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED;
-	else if (!strcmp (str_state, "4way_handshake"))
-		return NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE;
-	else if (!strcmp (str_state, "group_handshake"))
-		return NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE;
-	else if (!strcmp (str_state, "completed"))
-		return NM_SUPPLICANT_INTERFACE_STATE_COMPLETED;
-
-	nm_log_warn (LOGD_SUPPLICANT, "Unknown supplicant state '%s'", str_state);
-	return -1;
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);
+
+	switch (prop_id) {
+		case PROP_SUPPLICANT_MANAGER:
+			g_value_set_object (value, G_OBJECT (priv->smgr));
+			break;
+		case PROP_DEVICE:
+			g_value_set_string (value, priv->dev);
+			break;
+		case PROP_STATE:
+			g_value_set_uint (value, priv->state);
+			break;
+		case PROP_CONNECTION_STATE:
+			g_value_set_uint (value, priv->con_state);
+			break;
+		case PROP_SCANNING:
+			g_value_set_boolean (value, priv->scanning);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
 }
 
 static void
-set_state (NMSupplicantInterface *self, guint32 new_state)
+try_remove_iface (DBusGConnection *g_connection,
+                  const char *path)
 {
-	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	guint32 old_state = priv->state;
+	DBusGProxy *proxy;
 
-	g_return_if_fail (new_state < NM_SUPPLICANT_INTERFACE_STATE_LAST);
+	g_return_if_fail (g_connection != NULL);
+	g_return_if_fail (path != NULL);
 
-	if (new_state == priv->state)
+	proxy = dbus_g_proxy_new_for_name (g_connection,
+	                                   WPAS_DBUS_SERVICE,
+	                                   WPAS_DBUS_PATH,
+	                                   WPAS_DBUS_INTERFACE);
+	if (!proxy)
 		return;
 
-	/* DOWN is a terminal state */
-	g_return_if_fail (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+	dbus_g_proxy_call_no_reply (proxy, "removeInterface", 
+	                            DBUS_TYPE_G_OBJECT_PATH, path,
+	                            G_TYPE_INVALID);
+	g_object_unref (proxy);
+}
 
-	/* Cannot regress to READY, STARTING, or INIT from higher states */
-	if (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY)
-		g_return_if_fail (new_state > NM_SUPPLICANT_INTERFACE_STATE_READY);
+static void
+nm_supplicant_interface_dispose (GObject *object)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);
+	guint32 sm_state;
 
-	if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
-		/* Cancel all pending calls when going down */
-		cancel_all_callbacks (priv->other_pcalls);
-		cancel_all_callbacks (priv->assoc_pcalls);
+	if (priv->dispose_has_run) {
+		G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->dispose (object);
+		return;
+	}
 
-		/* Disconnect supplicant manager state listeners since we're done */
-		if (priv->smgr_avail_id) {
-			g_signal_handler_disconnect (priv->smgr, priv->smgr_avail_id);
-			priv->smgr_avail_id = 0;
-		}
+	priv->dispose_has_run = TRUE;
 
-		if (priv->iface_proxy) {
-			dbus_g_proxy_disconnect_signal (priv->iface_proxy,
-			                                "PropertiesChanged",
-			                                G_CALLBACK (wpas_iface_properties_changed),
-			                                self);
-			dbus_g_proxy_disconnect_signal (priv->iface_proxy,
-			                                "ScanDone",
-			                                G_CALLBACK (wpas_iface_scan_done),
-			                                self);
-			dbus_g_proxy_disconnect_signal (priv->iface_proxy,
-			                                "BSSAdded",
-			                                G_CALLBACK (wpas_iface_bss_added),
-			                                self);
+	/* Ask wpa_supplicant to remove this interface */
+	sm_state = nm_supplicant_manager_get_state (priv->smgr);
+	if (sm_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) {
+		if (priv->object_path) {
+			try_remove_iface (nm_dbus_manager_get_connection (priv->dbus_mgr),
+			                  priv->object_path);
 		}
 	}
 
-	priv->state = new_state;
-	g_signal_emit (self, signals[STATE], 0, priv->state, old_state);
+	if (priv->iface_proxy)
+		g_object_unref (priv->iface_proxy);
+
+	if (priv->net_proxy)
+		g_object_unref (priv->net_proxy);
+
+	if (priv->scan_results_timeout)
+		g_source_remove (priv->scan_results_timeout);
+
+	if (priv->smgr) {
+		g_signal_handler_disconnect (priv->smgr,
+		                             priv->smgr_state_sig_handler);
+		g_object_unref (priv->smgr);
+	}
+
+	g_free (priv->dev);
+
+	/* Cancel pending calls before unrefing the dbus manager */
+	cancel_all_callbacks (priv->other_pcalls);
+	nm_call_store_destroy (priv->other_pcalls);
+
+	cancel_all_callbacks (priv->assoc_pcalls);
+	nm_call_store_destroy (priv->assoc_pcalls);
+
+	if (priv->dbus_mgr)
+		g_object_unref (priv->dbus_mgr);
+
+	if (priv->cfg)
+		g_object_unref (priv->cfg);
+
+	g_free (priv->object_path);
+
+	/* Chain up to the parent class */
+	G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->dispose (object);
 }
 
 static void
-set_state_from_string (NMSupplicantInterface *self, const char *new_state)
+nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 {
-	int state;
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMSupplicantInterfacePrivate));
 
-	state = wpas_state_string_to_enum (new_state);
-	g_warn_if_fail (state > 0);
-	if (state > 0)
-		set_state (self, (guint32) state);
+	object_class->dispose = nm_supplicant_interface_dispose;
+	object_class->set_property = nm_supplicant_interface_set_property;
+	object_class->get_property = nm_supplicant_interface_get_property;
+
+	/* Properties */
+	g_object_class_install_property (object_class,
+	                                 PROP_SUPPLICANT_MANAGER,
+	                                 g_param_spec_object ("supplicant-manager",
+	                                                      "Supplicant Manager",
+	                                                      "Supplicant manager to which this interface belongs",
+	                                                      NM_TYPE_SUPPLICANT_MANAGER,
+	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  
+	g_object_class_install_property (object_class,
+	                                 PROP_DEVICE,
+	                                 g_param_spec_string ("device",
+	                                                      "Device",
+	                                                      "Device which this interface represents to the supplicant",
+	                                                      NULL,
+	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (object_class,
+	                                 PROP_STATE,
+	                                 g_param_spec_uint ("state",
+	                                                    "State",
+	                                                    "State of the supplicant interface; INIT, READY, or DOWN",
+	                                                    NM_SUPPLICANT_INTERFACE_STATE_INIT,
+	                                                    NM_SUPPLICANT_INTERFACE_STATE_LAST - 1,
+	                                                    NM_SUPPLICANT_INTERFACE_STATE_INIT,
+	                                                    G_PARAM_READABLE));
+
+	g_object_class_install_property (object_class,
+	                                 PROP_SCANNING,
+	                                 g_param_spec_boolean ("scanning",
+	                                                    "Scanning",
+	                                                    "Scanning",
+	                                                    FALSE,
+	                                                    G_PARAM_READABLE));
+
+	/* Signals */
+	nm_supplicant_interface_signals[STATE] =
+		g_signal_new ("state",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, state),
+		              NULL, NULL,
+		              _nm_marshal_VOID__UINT_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+
+	nm_supplicant_interface_signals[REMOVED] =
+		g_signal_new ("removed",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, removed),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__VOID,
+		              G_TYPE_NONE, 0);
+
+	nm_supplicant_interface_signals[SCANNED_AP] =
+		g_signal_new ("scanned-ap",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, scanned_ap),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__POINTER,
+		              G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	nm_supplicant_interface_signals[SCAN_REQ_RESULT] =
+		g_signal_new ("scan-req-result",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, scan_req_result),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__BOOLEAN,
+		              G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+	nm_supplicant_interface_signals[SCAN_RESULTS] =
+		g_signal_new ("scan-results",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, scan_results),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__UINT,
+		              G_TYPE_NONE, 1, G_TYPE_UINT);
+
+	nm_supplicant_interface_signals[CONNECTION_STATE] =
+		g_signal_new ("connection-state",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, connection_state),
+		              NULL, NULL,
+		              _nm_marshal_VOID__UINT_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+
+	nm_supplicant_interface_signals[CONNECTION_ERROR] =
+		g_signal_new ("connection-error",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, connection_error),
+		              NULL, NULL,
+		              _nm_marshal_VOID__STRING_STRING,
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
 }
 
 static void
-set_scanning (NMSupplicantInterface *self, gboolean new_scanning)
+emit_error_helper (NMSupplicantInterface *self,
+				   GError *err)
 {
-	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	GTimeVal cur_time;
+	const char *name = NULL;
 
-	if (priv->scanning != new_scanning) {
-		priv->scanning = new_scanning;
+	if (err->domain == DBUS_GERROR && err->code == DBUS_GERROR_REMOTE_EXCEPTION)
+		name = dbus_g_error_get_name (err);
 
-		/* Cache time of last scan completion */
-		if (priv->scanning == FALSE) {
-			g_get_current_time (&cur_time);
-			priv->last_scan = cur_time.tv_sec;
+	g_signal_emit (self,
+	               nm_supplicant_interface_signals[CONNECTION_ERROR],
+	               0,
+	               name,
+	               err->message);
+}
+
+static void
+bssid_properties_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
+	GError *err = NULL;
+	GHashTable *hash = NULL;
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
+	                            DBUS_TYPE_G_MAP_OF_VARIANT, &hash,
+	                            G_TYPE_INVALID)) {
+		if (!strstr (err->message, "The BSSID requested was invalid")) {
+			nm_log_warn (LOGD_SUPPLICANT, "Couldn't retrieve BSSID properties: %s.",
+			             err->message);
 		}
+		g_error_free (err);
+	} else {
+		g_signal_emit (info->interface,
+		               nm_supplicant_interface_signals[SCANNED_AP],
+		               0,
+		               hash);
 
-		g_object_notify (G_OBJECT (self), "scanning");
+		g_hash_table_destroy (hash);
 	}
 }
 
-gboolean
-nm_supplicant_interface_get_scanning (NMSupplicantInterface *self)
+static void
+request_bssid_properties (NMSupplicantInterface * self,
+                          const char * op)
 {
-	NMSupplicantInterfacePrivate *priv;
-
-	g_return_val_if_fail (self != NULL, FALSE);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	NMSupplicantInfo *info;
+	DBusGProxy *proxy;
+	DBusGProxyCall *call;
 
-	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	if (priv->scanning)
-		return TRUE;
-	if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
-		return TRUE;
-	return FALSE;
+	proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	                                   WPAS_DBUS_SERVICE,
+	                                   op,
+	                                   WPAS_DBUS_IFACE_BSSID);
+	info = nm_supplicant_info_new (self, proxy, priv->other_pcalls);
+	call = dbus_g_proxy_begin_call (proxy, "properties",
+	                                bssid_properties_cb,
+	                                info,
+	                                nm_supplicant_info_destroy,
+	                                G_TYPE_INVALID);
+	nm_supplicant_info_set_call (info, call);
+	g_object_unref (proxy);
 }
 
 static void
-wpas_iface_scan_done (DBusGProxy *proxy,
-                      gboolean success,
-                      gpointer user_data)
+scan_results_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	GError *err = NULL;
+	GPtrArray *array = NULL;
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
+	                            DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &array,
+	                            G_TYPE_INVALID)) {
+		nm_log_warn (LOGD_SUPPLICANT, "could not get scan results: %s.", err->message);
+		g_error_free (err);
+	} else {
+		int i;
+		NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
+
+		/* Notify listeners of the result of the scan */
+		g_signal_emit (info->interface,
+		               nm_supplicant_interface_signals[SCAN_RESULTS],
+		               0,
+		               array->len);
+
+		/* Fire off a "properties" call for each returned BSSID */
+		for (i = 0; i < array->len; i++) {
+			char *op = g_ptr_array_index (array, i);
+
+			request_bssid_properties (info->interface, op);
+			g_free (op);
+		}
+
+		g_ptr_array_free (array, TRUE);
+	}
+}
+
+static gboolean
+request_scan_results (gpointer user_data)
 {
 	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	NMSupplicantInfo *info;
+	DBusGProxyCall *call;
 	GTimeVal cur_time;
 
-	/* Cache last scan completed time */
+	priv->scan_results_timeout = 0;
+
+	g_return_val_if_fail (priv->iface_proxy != NULL, FALSE);
+
+	info = nm_supplicant_info_new (self, priv->iface_proxy, priv->other_pcalls);
+	call = dbus_g_proxy_begin_call (priv->iface_proxy, "scanResults",
+	                                scan_results_cb, 
+	                                info,
+	                                nm_supplicant_info_destroy,
+	                                G_TYPE_INVALID);
+	nm_supplicant_info_set_call (info, call);
+
 	g_get_current_time (&cur_time);
 	priv->last_scan = cur_time.tv_sec;
-
-	g_signal_emit (self, signals[SCAN_DONE], 0, success);
+	return FALSE;
 }
 
 static void
-wpas_iface_properties_changed (DBusGProxy *proxy,
-                               GHashTable *props,
-                               gpointer user_data)
+wpas_iface_query_scan_results (DBusGProxy *proxy, gpointer user_data)
 {
-	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
-	GValue *value;
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (user_data);
+	GTimeVal cur_time;
 
-	value = g_hash_table_lookup (props, "Scanning");
-	if (value && G_VALUE_HOLDS_BOOLEAN (value))
-		set_scanning (self, g_value_get_boolean (value));
+	/* Only query scan results if a query is not queued */
+	if (priv->scan_results_timeout)
+		return;
+
+	g_get_current_time (&cur_time);
 
-	value = g_hash_table_lookup (props, "State");
-	if (value && G_VALUE_HOLDS_STRING (value))
-		set_state_from_string (self, g_value_get_string (value));
+	/* Only fetch scan results every 4s max, but initially do it right away */
+	if (priv->last_scan + 4 < cur_time.tv_sec) {
+		priv->scan_results_timeout = g_idle_add (request_scan_results,
+		                                         user_data);
+	} else {
+		priv->scan_results_timeout =
+			g_timeout_add_seconds ((4 - (cur_time.tv_sec - priv->last_scan)),
+			               request_scan_results, user_data);
+	}
+}
 
-	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));
+static guint32
+wpas_state_string_to_enum (const char * str_state)
+{
+	guint32 enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED;
+
+	if (!strcmp (str_state, "DISCONNECTED"))
+		enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED;
+	else if (!strcmp (str_state, "INACTIVE"))
+		enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE;
+	else if (!strcmp (str_state, "SCANNING"))
+		enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING;
+	else if (!strcmp (str_state, "ASSOCIATING"))
+		enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATING;
+	else if (!strcmp (str_state, "ASSOCIATED"))
+		enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED;
+	else if (!strcmp (str_state, "4WAY_HANDSHAKE"))
+		enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE;
+	else if (!strcmp (str_state, "GROUP_HANDSHAKE"))
+		enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE;
+	else if (!strcmp (str_state, "COMPLETED"))
+		enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED;
+
+	return enum_state;
 }
 
 static void
-iface_get_props_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+wpas_iface_handle_state_change (DBusGProxy *proxy,
+                                const char *str_new_state,
+                                const char *str_old_state,
+                                gpointer user_data)
 {
-	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
-	GHashTable *props = NULL;
-	GError *error = NULL;
-
-	if (dbus_g_proxy_end_call (proxy, call_id, &error,
-	                           DBUS_TYPE_G_MAP_OF_VARIANT, &props,
-	                           G_TYPE_INVALID)) {
-		wpas_iface_properties_changed (NULL, props, info->interface);
-		g_hash_table_destroy (props);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (user_data);
+	guint32 old_state, enum_new_state;
+
+	enum_new_state = wpas_state_string_to_enum (str_new_state);
+	old_state = priv->con_state;
+	priv->con_state = enum_new_state;
+	if (priv->con_state != old_state) {
+		g_signal_emit (user_data,
+		               nm_supplicant_interface_signals[CONNECTION_STATE],
+		               0,
+		               priv->con_state,
+		               old_state);
+	}
+}
+
+
+static void
+iface_state_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	GError *err = NULL;
+	char *state_str = NULL;
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
+	                            G_TYPE_STRING, &state_str,
+	                            G_TYPE_INVALID)) {
+		nm_log_warn (LOGD_SUPPLICANT, "could not get interface state: %s.", err->message);
+		g_error_free (err);
 	} else {
-		nm_log_warn (LOGD_SUPPLICANT, "could not get interface properties: %s.",
-		             error && error->message ? error->message : "(unknown)");
-		g_clear_error (&error);
+		NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
+		NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
+
+		priv->con_state = wpas_state_string_to_enum (state_str);
+		g_free (state_str);
+		nm_supplicant_interface_set_state (info->interface, NM_SUPPLICANT_INTERFACE_STATE_READY);
 	}
 }
 
 static void
-wpas_iface_get_props (NMSupplicantInterface *self)
+wpas_iface_get_state (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->props_proxy, "GetAll",
-	                                iface_get_props_cb,
+	info = nm_supplicant_info_new (self, priv->iface_proxy, priv->other_pcalls);
+	call = dbus_g_proxy_begin_call (priv->iface_proxy, "state",
+	                                iface_state_cb,
 	                                info,
 	                                nm_supplicant_info_destroy,
-	                                G_TYPE_STRING, WPAS_DBUS_IFACE_INTERFACE,
 	                                G_TYPE_INVALID);
 	nm_supplicant_info_set_call (info, call);
 }
 
 static void
-interface_add_done (NMSupplicantInterface *self, char *path)
-{
-	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-
-	nm_log_dbg (LOGD_SUPPLICANT, "(%s): interface added to supplicant", priv->dev);
-
-	priv->object_path = path;
-
-	priv->iface_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
-	                                               WPAS_DBUS_SERVICE,
-	                                               path,
-	                                               WPAS_DBUS_IFACE_INTERFACE);
-
-	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 (priv->iface_proxy, "PropertiesChanged",
-	                         DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->iface_proxy, "PropertiesChanged",
-	                             G_CALLBACK (wpas_iface_properties_changed),
-	                             self, NULL);
-
-	dbus_g_proxy_add_signal (priv->iface_proxy, "ScanDone", G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->iface_proxy, "ScanDone",
-	                             G_CALLBACK (wpas_iface_scan_done),
-	                             self,
-	                             NULL);
-
-	dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED,
-	                                   G_TYPE_NONE,
-	                                   G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT,
-	                                   G_TYPE_INVALID);
-	dbus_g_proxy_add_signal (priv->iface_proxy, "BSSAdded", G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->iface_proxy, "BSSAdded",
-	                             G_CALLBACK (wpas_iface_bss_added),
-	                             self,
-	                             NULL);
-
-	priv->props_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
-	                                               WPAS_DBUS_SERVICE,
-	                                               path,
-	                                               DBUS_INTERFACE_PROPERTIES);
-	/* Get initial properties */
-	wpas_iface_get_props (self);
-
-	set_state (self, NM_SUPPLICANT_INTERFACE_STATE_READY);
-}
-
-static void
-interface_get_cb (DBusGProxy *proxy,
-                  DBusGProxyCall *call_id,
-                  gpointer user_data)
+iface_scanning_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;
-	char *path = NULL;
+	gboolean scanning = FALSE;
 
-	if (dbus_g_proxy_end_call (proxy, call_id, &error,
-	                           DBUS_TYPE_G_OBJECT_PATH, &path,
-	                           G_TYPE_INVALID)) {
-		interface_add_done (info->interface, path);
-	} else {
-		nm_log_err (LOGD_SUPPLICANT, "(%s): error getting interface: %s",
-		            priv->dev, error->message);
-		g_clear_error (&error);
-		set_state (info->interface, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+	if (dbus_g_proxy_end_call (proxy, call_id, NULL,
+	                            G_TYPE_BOOLEAN, &scanning,
+	                            G_TYPE_INVALID)) {
+		if (scanning != priv->scanning) {
+			priv->scanning = scanning;
+			g_object_notify (G_OBJECT (info->interface), "scanning");
+		}
 	}
 }
 
 static void
-interface_get (NMSupplicantInterface *self)
+wpas_iface_get_scanning (NMSupplicantInterface *self)
 {
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 	NMSupplicantInfo *info;
 	DBusGProxyCall *call;
 
-	info = nm_supplicant_info_new (self, priv->wpas_proxy, priv->other_pcalls);
-	call = dbus_g_proxy_begin_call (priv->wpas_proxy, "GetInterface",
-	                                interface_get_cb,
+	info = nm_supplicant_info_new (self, priv->iface_proxy, priv->other_pcalls);
+	call = dbus_g_proxy_begin_call (priv->iface_proxy, "scanning",
+	                                iface_scanning_cb,
 	                                info,
 	                                nm_supplicant_info_destroy,
-	                                G_TYPE_STRING, priv->dev,
 	                                G_TYPE_INVALID);
 	nm_supplicant_info_set_call (info, call);
 }
 
 static void
-interface_add_cb (DBusGProxy *proxy,
-                  DBusGProxyCall *call_id,
-                  gpointer user_data)
+wpas_iface_handle_scanning (DBusGProxy *proxy,
+                            gboolean scanning,
+                            gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	if (scanning != priv->scanning) {
+		priv->scanning = scanning;
+		g_object_notify (G_OBJECT (self), "scanning");
+	}
+}
+
+gboolean
+nm_supplicant_interface_get_scanning (NMSupplicantInterface *self)
+{
+	NMSupplicantInterfacePrivate *priv;
+
+	g_return_val_if_fail (self != NULL, FALSE);
+
+	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	if (priv->scanning)
+		return TRUE;
+	if (priv->con_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING)
+		return TRUE;
+	return FALSE;
+}
+
+static void
+nm_supplicant_interface_add_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;
+	GError *err = NULL;
 	char *path = NULL;
 
-	if (dbus_g_proxy_end_call (proxy, call_id, &error,
-	                           DBUS_TYPE_G_OBJECT_PATH, &path,
-	                           G_TYPE_INVALID)) {
-		interface_add_done (info->interface, path);
-	} else {
-		if (dbus_g_error_has_name (error, WPAS_ERROR_EXISTS_ERROR)) {
-			/* Interface already added, just get its object path */
-			interface_get (info->interface);
-		} else if (   g_error_matches (error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)
-		           || dbus_g_error_has_name (error, DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) {
-			/* Supplicant wasn't running and could be launched via service
-			 * activation.  Wait for it to start by moving back to the INIT
-			 * state.
-			 */
-			nm_log_dbg (LOGD_SUPPLICANT, "(%s): failed to activate supplicant: %s",
-			            priv->dev, error->message);
-			set_state (info->interface, NM_SUPPLICANT_INTERFACE_STATE_INIT);
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
+	                            DBUS_TYPE_G_OBJECT_PATH, &path,
+	                            G_TYPE_INVALID)) {
+
+		if (dbus_g_error_has_name (err, WPAS_ERROR_INVALID_IFACE)) {
+			/* Interface not added, try to add it */
+			nm_supplicant_interface_add_to_supplicant (info->interface, FALSE);
+		} else if (dbus_g_error_has_name (err, WPAS_ERROR_EXISTS_ERROR)) {
+			/* Interface already added, just try to get the interface */
+			nm_supplicant_interface_add_to_supplicant (info->interface, TRUE);
 		} else {
-			nm_log_err (LOGD_SUPPLICANT, "(%s): error adding interface: %s",
-			            priv->dev, error->message);
-			set_state (info->interface, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+			nm_log_err (LOGD_SUPPLICANT, "(%s): error getting interface: %s",
+			            priv->dev, err->message);
 		}
-		g_clear_error (&error);
+
+		g_error_free (err);
+	} else {
+		nm_log_dbg (LOGD_SUPPLICANT, "(%s): interface added to supplicant", priv->dev);
+
+		priv->object_path = path;
+
+		priv->iface_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
+		                                               WPAS_DBUS_SERVICE,
+		                                               path,
+		                                               WPAS_DBUS_IFACE_INTERFACE);
+
+		dbus_g_proxy_add_signal (priv->iface_proxy, "ScanResultsAvailable", G_TYPE_INVALID);
+
+		dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING,
+		                                   G_TYPE_NONE,
+		                                   G_TYPE_STRING, G_TYPE_STRING,
+		                                   G_TYPE_INVALID);
+
+		dbus_g_proxy_add_signal (priv->iface_proxy, "StateChange", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+
+		dbus_g_proxy_connect_signal (priv->iface_proxy, "ScanResultsAvailable",
+		                             G_CALLBACK (wpas_iface_query_scan_results),
+		                             info->interface,
+		                             NULL);
+
+		dbus_g_proxy_connect_signal (priv->iface_proxy, "StateChange",
+		                             G_CALLBACK (wpas_iface_handle_state_change),
+		                             info->interface,
+		                             NULL);
+
+		dbus_g_proxy_add_signal (priv->iface_proxy, "Scanning", G_TYPE_BOOLEAN, G_TYPE_INVALID);
+
+		dbus_g_proxy_connect_signal (priv->iface_proxy, "Scanning",
+		                             G_CALLBACK (wpas_iface_handle_scanning),
+		                             info->interface,
+		                             NULL);
+
+		/* Interface added to the supplicant; get its initial state. */
+		wpas_iface_get_state (info->interface);
+		wpas_iface_get_scanning (info->interface);
 	}
 }
 
 static void
-interface_add (NMSupplicantInterface *self, gboolean is_wireless)
+nm_supplicant_interface_add_to_supplicant (NMSupplicantInterface * self,
+                                           gboolean get_only)
 {
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	DBusGProxyCall *call;
 	NMSupplicantInfo *info;
-	GHashTable *hash;
-	GValue *driver, *ifname;
+	DBusGProxy *proxy;
+	DBusGProxyCall *call;
+
+	proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	                                   WPAS_DBUS_SERVICE,
+	                                   WPAS_DBUS_PATH,
+	                                   WPAS_DBUS_INTERFACE);
+	info = nm_supplicant_info_new (self, proxy, priv->other_pcalls);
+
+	if (get_only) {
+		call = dbus_g_proxy_begin_call (proxy, "getInterface",
+		                                nm_supplicant_interface_add_cb,
+		                                info,
+		                                nm_supplicant_info_destroy,
+		                                G_TYPE_STRING, priv->dev,
+		                                G_TYPE_INVALID);
+	} else {
+		GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
+		GValue *driver;
+
+		driver = g_new0 (GValue, 1);
+		g_value_init (driver, G_TYPE_STRING);
+		g_value_set_string (driver, priv->is_wireless ? "wext" : "wired");
+		g_hash_table_insert (hash, "driver", driver);
+
+		call = dbus_g_proxy_begin_call (proxy, "addInterface",
+		                                nm_supplicant_interface_add_cb,
+		                                info,
+		                                nm_supplicant_info_destroy,
+		                                G_TYPE_STRING, priv->dev,
+		                                DBUS_TYPE_G_MAP_OF_VARIANT, hash,
+		                                G_TYPE_INVALID);
+
+		g_value_unset (driver);
+		g_free (driver);
+		g_hash_table_destroy (hash);
+	}
+
+	g_object_unref (proxy);
+
+	nm_supplicant_info_set_call (info, call);
+}
+
+static void
+nm_supplicant_interface_start (NMSupplicantInterface * self)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	guint32          state;
 
 	/* Can only start the interface from INIT state */
 	g_return_if_fail (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT);
 
 	nm_log_dbg (LOGD_SUPPLICANT, "(%s): adding interface to supplicant", priv->dev);
 
-	/* Move to starting to prevent double-calls of interface_add() */
-	set_state (self, NM_SUPPLICANT_INTERFACE_STATE_STARTING);
-
-	/* Try to add the interface to the supplicant.  If the supplicant isn't
-	 * running, this will start it via D-Bus activation and return the response
-	 * when the supplicant has started.
-	 */
+	state = nm_supplicant_manager_get_state (priv->smgr);
+	if (state == NM_SUPPLICANT_MANAGER_STATE_IDLE) {
+		nm_supplicant_interface_set_state (self, NM_SUPPLICANT_INTERFACE_STATE_STARTING);
+		nm_supplicant_interface_add_to_supplicant (self, FALSE);
+	} else if (state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
+		/* Don't do anything; wait for signal from supplicant manager
+		 * that its state has changed.
+		 */
+	} else
+		nm_log_warn (LOGD_SUPPLICANT, "Unknown supplicant manager state!");
+}
 
-	info = nm_supplicant_info_new (self, priv->wpas_proxy, priv->other_pcalls);
+static void
+nm_supplicant_interface_handle_supplicant_manager_idle_state (NMSupplicantInterface * self)
+{
+	switch (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->state) {
+		case NM_SUPPLICANT_INTERFACE_STATE_INIT:
+			/* Move to STARTING state when supplicant is ready */
+			nm_supplicant_interface_start (self);
+			break;
+		case NM_SUPPLICANT_INTERFACE_STATE_STARTING:
+			/* Don't do anything here, though we should never hit this */
+			break;
+		case NM_SUPPLICANT_INTERFACE_STATE_READY:
+			/* Don't do anything here, though we should never hit this */
+			break;
+		case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
+			/* Don't do anything here; interface can't get out of DOWN state */
+			break;
+		default:
+			nm_log_warn (LOGD_SUPPLICANT, "Unknown supplicant interface state!");
+			break;
+	}
+}
 
-	hash = g_hash_table_new (g_str_hash, g_str_equal);
 
-	driver = g_new0 (GValue, 1);
-	g_value_init (driver, G_TYPE_STRING);
-	g_value_set_string (driver, is_wireless ? "nl80211,wext" : "wired");
-	g_hash_table_insert (hash, "Driver", driver);
+static void
+nm_supplicant_interface_set_state (NMSupplicantInterface * self,
+                                   guint32 new_state)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	guint32 old_state;
 
-	ifname = g_new0 (GValue, 1);
-	g_value_init (ifname, G_TYPE_STRING);
-	g_value_set_string (ifname, priv->dev);
-	g_hash_table_insert (hash, "Ifname", ifname);
+	g_return_if_fail (new_state < NM_SUPPLICANT_INTERFACE_STATE_LAST);
 
-	call = dbus_g_proxy_begin_call (priv->wpas_proxy, "CreateInterface",
-	                                interface_add_cb,
-	                                info,
-	                                nm_supplicant_info_destroy,
-	                                DBUS_TYPE_G_MAP_OF_VARIANT, hash,
-	                                G_TYPE_INVALID);
+	if (new_state == priv->state)
+		return;
 
-	g_hash_table_destroy (hash);
-	g_value_unset (driver);
-	g_free (driver);
-	g_value_unset (ifname);
-	g_free (ifname);
+	old_state = priv->state;
+	if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
+		/* If the interface is transitioning to DOWN and there's are
+		 * in-progress pending calls, cancel them.
+		 */
+		cancel_all_callbacks (priv->other_pcalls);
+		cancel_all_callbacks (priv->assoc_pcalls);
+	}
 
-	nm_supplicant_info_set_call (info, call);
+	priv->state = new_state;
+	g_signal_emit (self,
+	               nm_supplicant_interface_signals[STATE],
+	               0,
+	               priv->state,
+	               old_state);
 }
 
 static void
-smgr_avail_cb (NMSupplicantManager *smgr,
-               GParamSpec *pspec,
-               gpointer user_data)
+nm_supplicant_interface_smgr_state_changed (NMSupplicantManager * smgr,
+                                            guint32 new_state,
+                                            guint32 old_state,
+                                            gpointer user_data)
 {
-	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
-	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (user_data);
+	NMSupplicantInterface * self = NM_SUPPLICANT_INTERFACE (user_data);
 
-	if (nm_supplicant_manager_available (smgr)) {
-		/* This can happen if the supplicant couldn't be activated but
-		 * for some reason was started after the activation failure.
-		 */
-		if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT)
-			interface_add (self, priv->is_wireless);
-	} else {
-		/* The supplicant stopped; so we must tear down the interface */
-		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+	switch (new_state) {
+		case NM_SUPPLICANT_MANAGER_STATE_DOWN:
+			/* The supplicant went away, likely the connection to it is also
+			 * gone.  Therefore, this interface must move to the DOWN state
+			 * and be disposed of.
+			 */
+			nm_supplicant_interface_set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+			break;
+		case NM_SUPPLICANT_MANAGER_STATE_IDLE:
+			/* Handle the supplicant now being available. */
+			nm_supplicant_interface_handle_supplicant_manager_idle_state (self);
+			break;
+		default:
+			nm_log_warn (LOGD_SUPPLICANT, "Unknown supplicant manager state!");
+			break;
 	}
 }
 
+
 static void
 remove_network_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
-	GError *error = NULL;
+	GError *err = NULL;
+	guint tmp;
 
-	if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) {
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err, G_TYPE_UINT, &tmp, G_TYPE_INVALID)) {
 		nm_log_dbg (LOGD_SUPPLICANT, "Couldn't remove network from supplicant interface: %s.",
-		             error && error->message ? error->message : "(unknown)");
-		g_clear_error (&error);
+		            err->message);
+		g_error_free (err);
 	}
 }
 
 static void
 disconnect_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
-	GError *error = NULL;
+	GError *err = NULL;
+	guint tmp;
 
-	if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) {
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err, G_TYPE_UINT, &tmp, G_TYPE_INVALID)) {
 		nm_log_warn (LOGD_SUPPLICANT, "Couldn't disconnect supplicant interface: %s.",
-		             error && error->message ? error->message : "(unknown)");
-		g_clear_error (&error);
+		             err->message);
+		g_error_free (err);
 	}
 }
 
@@ -682,26 +1045,32 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self)
 	if (!priv->iface_proxy)
 		return;
 
-	/* Don't try to disconnect if the supplicant interface is already disconnected */
-	if (   priv->state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED
-	    || priv->state == NM_SUPPLICANT_INTERFACE_STATE_INACTIVE) {
-		g_free (priv->net_path);
-		priv->net_path = NULL;
+	/* Don't try to disconnect if the supplicant interface is already
+	 * disconnected.
+	 */
+	if (priv->con_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED
+	    || priv->con_state == NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE) {
+		if (priv->net_proxy) {
+			g_object_unref (priv->net_proxy);
+			priv->net_proxy = NULL;
+		}
+
 		return;
 	}
 
 	/* Remove any network that was added by NetworkManager */
-	if (priv->net_path) {
-		dbus_g_proxy_begin_call (priv->iface_proxy, "RemoveNetwork",
+	if (priv->net_proxy) {
+		dbus_g_proxy_begin_call (priv->iface_proxy, "removeNetwork",
 		                         remove_network_cb,
 		                         NULL, NULL,
-		                         DBUS_TYPE_G_OBJECT_PATH, priv->net_path,
+		                         DBUS_TYPE_G_OBJECT_PATH, dbus_g_proxy_get_path (priv->net_proxy),
 		                         G_TYPE_INVALID);
-		g_free (priv->net_path);
-		priv->net_path = NULL;
+
+		g_object_unref (priv->net_proxy);
+		priv->net_proxy = NULL;
 	}
 
-	dbus_g_proxy_begin_call (priv->iface_proxy, "Disconnect",
+	dbus_g_proxy_begin_call (priv->iface_proxy, "disconnect",
 	                         disconnect_cb,
 	                         NULL, NULL,
 	                         G_TYPE_INVALID);
@@ -712,8 +1081,9 @@ select_network_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_dat
 {
 	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
 	GError *err = NULL;
+	guint tmp;
 
-	if (!dbus_g_proxy_end_call (proxy, call_id, &err, G_TYPE_INVALID)) {
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err, G_TYPE_UINT, &tmp, G_TYPE_INVALID)) {
 		nm_log_warn (LOGD_SUPPLICANT, "Couldn't select network config: %s.", err->message);
 		emit_error_helper (info->interface, err);
 		g_error_free (err);
@@ -721,86 +1091,163 @@ select_network_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_dat
 }
 
 static void
-call_select_network (NMSupplicantInterface *self)
+set_network_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
-	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	DBusGProxyCall *call;
-	NMSupplicantInfo *info;
+	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
+	GError *err = NULL;
+	guint tmp;
 
-	/* We only select the network after all blobs (if any) have been set */
-	if (priv->blobs_left > 0)
-		return;
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err, G_TYPE_UINT, &tmp, G_TYPE_INVALID)) {
+		nm_log_warn (LOGD_SUPPLICANT, "Couldn't set network config: %s.", err->message);
+		emit_error_helper (info->interface, err);
+		g_error_free (err);
+	} else {
+		DBusGProxyCall *call;
 
-	info = nm_supplicant_info_new (self, priv->iface_proxy, priv->assoc_pcalls);
-	call = dbus_g_proxy_begin_call (priv->iface_proxy, "SelectNetwork",
-	                                select_network_cb,
+		info = nm_supplicant_info_new (info->interface, priv->iface_proxy, priv->assoc_pcalls);
+		call = dbus_g_proxy_begin_call (priv->iface_proxy, "selectNetwork",
+		                                select_network_cb,
+		                                info,
+		                                nm_supplicant_info_destroy,
+		                                DBUS_TYPE_G_OBJECT_PATH, dbus_g_proxy_get_path (proxy),
+		                                G_TYPE_INVALID);
+		nm_supplicant_info_set_call (info, call);
+	}
+}
+
+static void
+call_set_network (NMSupplicantInfo *info)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
+	GHashTable *config_hash;
+	DBusGProxyCall *call;
+
+	config_hash = nm_supplicant_config_get_hash (priv->cfg);
+	call = dbus_g_proxy_begin_call (priv->net_proxy, "set",
+	                                set_network_cb,
 	                                info,
 	                                nm_supplicant_info_destroy,
-	                                DBUS_TYPE_G_OBJECT_PATH, priv->net_path,
+	                                DBUS_TYPE_G_MAP_OF_VARIANT, config_hash,
 	                                G_TYPE_INVALID);
 	nm_supplicant_info_set_call (info, call);
+	g_hash_table_destroy (config_hash);
 }
 
 static void
-add_blob_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+set_blobs_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
 	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
 	GError *err = NULL;
 	guint tmp;
 
-	priv->blobs_left--;
-
 	if (!dbus_g_proxy_end_call (proxy, call_id, &err, G_TYPE_UINT, &tmp, G_TYPE_INVALID)) {
 		nm_log_warn (LOGD_SUPPLICANT, "Couldn't set network certificates: %s.", err->message);
 		emit_error_helper (info->interface, err);
 		g_error_free (err);
-	} else
-		call_select_network (info->interface);
+	} else {
+		info = nm_supplicant_info_new (info->interface, priv->iface_proxy, priv->assoc_pcalls);
+		call_set_network (info);
+	}
+}
+
+static GValue *
+byte_array_to_gvalue (const GByteArray *array)
+{
+	GValue *val;
+
+	val = g_slice_new0 (GValue);
+	g_value_init (val, DBUS_TYPE_G_UCHAR_ARRAY);
+	g_value_set_boxed (val, array);
+
+	return val;
 }
 
 static void
-add_network_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+blob_free (GValue *val)
+{
+	g_value_unset (val);
+	g_slice_free (GValue, val);
+}
+
+static void
+convert_blob (const char *key, const GByteArray *value, GHashTable *hash)
+{
+	GValue *val;
+
+	val = byte_array_to_gvalue (value);
+	g_hash_table_insert (hash, g_strdup (key), val);
+}
+
+static void
+call_set_blobs (NMSupplicantInfo *info, GHashTable *orig_blobs)
 {
-	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
-	GError *err = NULL;
-	GHashTable *blobs;
-	GHashTableIter iter;
-	gpointer name, data;
 	DBusGProxyCall *call;
-	NMSupplicantInfo *blob_info;
+	GHashTable *blobs;
+
+	blobs = g_hash_table_new_full (g_str_hash, g_str_equal,
+	                               (GDestroyNotify) g_free,
+	                               (GDestroyNotify) blob_free);
+	if (!blobs) {
+		const char *msg = "Not enough memory to create blob table.";
 
-	g_free (priv->net_path);
-	priv->net_path = NULL;
+		nm_log_warn (LOGD_SUPPLICANT, "%s", msg);
+		g_signal_emit (info->interface,
+		               nm_supplicant_interface_signals[CONNECTION_ERROR],
+		               0, "SendBlobError", msg);
+		return;
+	}
+
+	g_hash_table_foreach (orig_blobs, (GHFunc) convert_blob, blobs);
+
+	call = dbus_g_proxy_begin_call (priv->iface_proxy, "setBlobs",
+	                                set_blobs_cb,
+	                                info,
+	                                nm_supplicant_info_destroy,
+	                                DBUS_TYPE_G_MAP_OF_VARIANT, blobs,
+	                                G_TYPE_INVALID);
+	nm_supplicant_info_set_call (info, call);
+	g_hash_table_destroy (blobs);
+}
+
+static void
+add_network_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
+	GError *err = NULL;
+	char *path = NULL;
 
 	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
-	                            DBUS_TYPE_G_OBJECT_PATH, &priv->net_path,
+	                            DBUS_TYPE_G_OBJECT_PATH, &path,
 	                            G_TYPE_INVALID)) {
 		nm_log_warn (LOGD_SUPPLICANT, "Couldn't add a network to the supplicant interface: %s.",
 		             err->message);
 		emit_error_helper (info->interface, err);
 		g_error_free (err);
-		return;
-	}
-
-	/* Send blobs first; otherwise jump to sending the config settings */
-	blobs = nm_supplicant_config_get_blobs (priv->cfg);
-	priv->blobs_left = g_hash_table_size (blobs);
-	g_hash_table_iter_init (&iter, blobs);
-	while (g_hash_table_iter_next (&iter, &name, &data)) {
-		blob_info = nm_supplicant_info_new (info->interface, priv->iface_proxy, priv->assoc_pcalls);
-		call = dbus_g_proxy_begin_call (priv->iface_proxy, "AddBlob",
-			                            add_blob_cb,
-			                            blob_info,
-			                            nm_supplicant_info_destroy,
-			                            DBUS_TYPE_STRING, name,
-			                            DBUS_TYPE_G_UCHAR_ARRAY, blobs,
-			                            G_TYPE_INVALID);
-		nm_supplicant_info_set_call (blob_info, call);
+	} else {
+		NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
+		GHashTable *blobs;
+
+		priv->net_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
+		                                             WPAS_DBUS_SERVICE,
+		                                             path,
+		                                             WPAS_DBUS_IFACE_NETWORK);
+		g_free (path);
+
+		info = nm_supplicant_info_new (info->interface,
+		                               priv->net_proxy,
+		                               priv->assoc_pcalls);
+		/* Send any blobs first; if there aren't any jump to sending the
+		 * config settings.
+		 */
+		blobs = nm_supplicant_config_get_blobs (priv->cfg);
+		if (g_hash_table_size (blobs) > 0)
+			call_set_blobs (info, blobs);
+		else
+			call_set_network (info);
 	}
-
-	call_select_network (info->interface);
 }
 
 static void
@@ -809,10 +1256,10 @@ set_ap_scan_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
 	GError *err = NULL;
+	guint32 tmp;
 	DBusGProxyCall *call;
-	GHashTable *config_hash;
 
-	if (!dbus_g_proxy_end_call (proxy, call_id, &err, G_TYPE_INVALID)) {
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err, G_TYPE_UINT, &tmp, G_TYPE_INVALID)) {
 		nm_log_warn (LOGD_SUPPLICANT, "Couldn't send AP scan mode to the supplicant interface: %s.",
 		             err->message);
 		emit_error_helper (info->interface, err);
@@ -823,15 +1270,12 @@ set_ap_scan_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 	nm_log_info (LOGD_SUPPLICANT, "Config: set interface ap_scan to %d",
 	             nm_supplicant_config_get_ap_scan (priv->cfg));
 
-	info = nm_supplicant_info_new (info->interface, priv->iface_proxy, info->store);
-	config_hash = nm_supplicant_config_get_hash (priv->cfg);
-	call = dbus_g_proxy_begin_call (priv->iface_proxy, "AddNetwork",
+	info = nm_supplicant_info_new (info->interface, proxy, info->store);
+	call = dbus_g_proxy_begin_call (proxy, "addNetwork",
 	                                add_network_cb,
 	                                info,
 	                                nm_supplicant_info_destroy,
-	                                DBUS_TYPE_G_MAP_OF_VARIANT, config_hash,
 	                                G_TYPE_INVALID);
-	g_hash_table_destroy (config_hash);
 	nm_supplicant_info_set_call (info, call);
 }
 
@@ -842,7 +1286,7 @@ nm_supplicant_interface_set_config (NMSupplicantInterface * self,
 	NMSupplicantInterfacePrivate *priv;
 	NMSupplicantInfo *info;
 	DBusGProxyCall *call;
-	GValue value = { 0, };
+	guint32 ap_scan;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE);
 
@@ -859,54 +1303,46 @@ nm_supplicant_interface_set_config (NMSupplicantInterface * self,
 
 	g_object_ref (priv->cfg);
 
-	g_value_init (&value, G_TYPE_UINT);
-	g_value_set_uint (&value, nm_supplicant_config_get_ap_scan (priv->cfg));
-
-	info = nm_supplicant_info_new (self, priv->props_proxy, priv->other_pcalls);
-	call = dbus_g_proxy_begin_call (priv->props_proxy, "Set",
+	info = nm_supplicant_info_new (self, priv->iface_proxy, priv->other_pcalls);
+	ap_scan = nm_supplicant_config_get_ap_scan (priv->cfg);
+	call = dbus_g_proxy_begin_call (priv->iface_proxy, "setAPScan",
 	                                set_ap_scan_cb,
 	                                info,
 	                                nm_supplicant_info_destroy,
-	                                G_TYPE_STRING, WPAS_DBUS_IFACE_INTERFACE,
-	                                G_TYPE_STRING, "ApScan",
-	                                G_TYPE_VALUE, &value,
+	                                G_TYPE_UINT, ap_scan,
 	                                G_TYPE_INVALID);
 	nm_supplicant_info_set_call (info, call);
 
-	g_value_unset (&value);
 	return call != NULL;
 }
 
+const char *
+nm_supplicant_interface_get_device (NMSupplicantInterface * self)
+{
+	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
+
+	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev;
+}
+
 static void
 scan_request_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
 	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
 	GError *err = NULL;
+	guint32 success = 0;
 
-	if (!dbus_g_proxy_end_call (proxy, call_id, &err, G_TYPE_INVALID)) {
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
+	                            G_TYPE_UINT, &success,
+	                            G_TYPE_INVALID)) {
 		nm_log_warn (LOGD_SUPPLICANT, "Could not get scan request result: %s", err->message);
+		g_error_free (err);
 	} 
-	g_signal_emit (info->interface, signals[SCAN_DONE], 0, err ? FALSE : TRUE);
-	g_clear_error (&err);
-}
-
-static void
-destroy_gvalue (gpointer data)
-{
-	GValue *value = (GValue *) data;
-
-	g_value_unset (value);
-	g_slice_free (GValue, value);
-}
-
-static GValue *
-string_to_gvalue (const char *str)
-{
-	GValue *val = g_slice_new0 (GValue);
 
-	g_value_init (val, G_TYPE_STRING);
-	g_value_set_string (val, str);
-	return val;
+	/* Notify listeners of the result of the scan */
+	g_signal_emit (info->interface,
+	               nm_supplicant_interface_signals[SCAN_REQ_RESULT],
+	               0,
+	               success ? TRUE : FALSE);
 }
 
 gboolean
@@ -915,24 +1351,17 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface * self)
 	NMSupplicantInterfacePrivate *priv;
 	NMSupplicantInfo *info;
 	DBusGProxyCall *call;
-	GHashTable *hash;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE);
 
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-	/* Scan parameters */
-	hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, destroy_gvalue);
-	g_hash_table_insert (hash, "Type", string_to_gvalue ("active"));
-
 	info = nm_supplicant_info_new (self, priv->iface_proxy, priv->other_pcalls);
-	call = dbus_g_proxy_begin_call (priv->iface_proxy, "Scan",
+	call = dbus_g_proxy_begin_call (priv->iface_proxy, "scan",
 	                                scan_request_cb,
 	                                info,
 	                                nm_supplicant_info_destroy,
-	                                DBUS_TYPE_G_MAP_OF_VARIANT, hash,
 	                                G_TYPE_INVALID);
-	g_hash_table_destroy (hash);
 	nm_supplicant_info_set_call (info, call);
 
 	return call != NULL;
@@ -946,6 +1375,14 @@ nm_supplicant_interface_get_state (NMSupplicantInterface * self)
 	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->state;
 }
 
+guint32
+nm_supplicant_interface_get_connection_state (NMSupplicantInterface * self)
+{
+	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED);
+
+	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->con_state;
+}
+
 const char *
 nm_supplicant_interface_state_to_string (guint32 state)
 {
@@ -956,24 +1393,6 @@ nm_supplicant_interface_state_to_string (guint32 state)
 		return "starting";
 	case NM_SUPPLICANT_INTERFACE_STATE_READY:
 		return "ready";
-	case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED:
-		return "disconnected";
-	case NM_SUPPLICANT_INTERFACE_STATE_INACTIVE:
-		return "inactive";
-	case NM_SUPPLICANT_INTERFACE_STATE_SCANNING:
-		return "scanning";
-	case NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING:
-		return "authenticating";
-	case NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING:
-		return "associating";
-	case NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED:
-		return "associated";
-	case NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE:
-		return "4-way handshake";
-	case NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE:
-		return "group handshake";
-	case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
-		return "completed";
 	case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
 		return "down";
 	default:
@@ -983,227 +1402,28 @@ nm_supplicant_interface_state_to_string (guint32 state)
 }
 
 const char *
-nm_supplicant_interface_get_device (NMSupplicantInterface * self)
-{
-	g_return_val_if_fail (self != NULL, NULL);
-	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
-
-	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev;
-}
-
-const char *
-nm_supplicant_interface_get_object_path (NMSupplicantInterface *self)
-{
-	g_return_val_if_fail (self != NULL, NULL);
-	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
-
-	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->object_path;
-}
-
-const char *
-nm_supplicant_interface_get_ifname (NMSupplicantInterface *self)
-{
-	g_return_val_if_fail (self != NULL, NULL);
-	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
-
-	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev;
-}
-
-/*******************************************************************/
-
-NMSupplicantInterface *
-nm_supplicant_interface_new (NMSupplicantManager *smgr,
-                             const char *ifname,
-                             gboolean is_wireless,
-                             gboolean start_now)
-{
-	NMSupplicantInterface *self;
-	NMSupplicantInterfacePrivate *priv;
-	guint id;
-
-	g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (smgr), NULL);
-	g_return_val_if_fail (ifname != NULL, NULL);
-
-	self = g_object_new (NM_TYPE_SUPPLICANT_INTERFACE, NULL);
-	if (self) {
-		priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-
-		priv->smgr = g_object_ref (smgr);
-		id = g_signal_connect (priv->smgr,
-		                       "notify::" NM_SUPPLICANT_MANAGER_AVAILABLE,
-		                       G_CALLBACK (smgr_avail_cb),
-		                       self);
-		priv->smgr_avail_id = id;
-
-		priv->dev = g_strdup (ifname);
-		priv->is_wireless = is_wireless;
-
-		if (start_now)
-			interface_add (self, priv->is_wireless);
-	}
-
-	return self;
-}
-
-static void
-nm_supplicant_interface_init (NMSupplicantInterface * self)
+nm_supplicant_interface_connection_state_to_string (guint32 state)
 {
-	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	DBusGConnection *bus;
-
-	priv->state = NM_SUPPLICANT_INTERFACE_STATE_INIT;
-	priv->assoc_pcalls = nm_call_store_new ();
-	priv->other_pcalls = nm_call_store_new ();
-	priv->dbus_mgr = nm_dbus_manager_get ();
-
-	bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
-	priv->wpas_proxy = dbus_g_proxy_new_for_name (bus,
-	                                              WPAS_DBUS_SERVICE,
-	                                              WPAS_DBUS_PATH,
-	                                              WPAS_DBUS_INTERFACE);
-}
-
-static void
-set_property (GObject *object,
-              guint prop_id,
-              const GValue *value,
-              GParamSpec *pspec)
-{
-	switch (prop_id) {
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-static void
-get_property (GObject *object,
-              guint prop_id,
-              GValue *value,
-              GParamSpec *pspec)
-{
-	switch (prop_id) {
-	case PROP_SCANNING:
-		g_value_set_boolean (value, NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object)->scanning);
-		break;
+	switch (state) {
+	case NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED:
+		return "disconnected";
+	case NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE:
+		return "inactive";
+	case NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING:
+		return "scanning";
+	case NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATING:
+		return "associating";
+	case NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED:
+		return "associated";
+	case NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE:
+		return "4-way handshake";
+	case NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE:
+		return "group handshake";
+	case NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED:
+		return "completed";
 	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
 	}
-}
-
-static void
-dispose (GObject *object)
-{
-	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);
-
-	if (priv->disposed) {
-		G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->dispose (object);
-		return;
-	}
-	priv->disposed = TRUE;
-
-	/* Cancel pending calls before unrefing the dbus manager */
-	cancel_all_callbacks (priv->other_pcalls);
-	nm_call_store_destroy (priv->other_pcalls);
-
-	cancel_all_callbacks (priv->assoc_pcalls);
-	nm_call_store_destroy (priv->assoc_pcalls);
-
-	if (priv->props_proxy)
-		g_object_unref (priv->props_proxy);
-
-	if (priv->iface_proxy)
-		g_object_unref (priv->iface_proxy);
-
-	g_free (priv->net_path);
-
-	if (priv->wpas_proxy)
-		g_object_unref (priv->wpas_proxy);
-
-	if (priv->smgr) {
-		if (priv->smgr_avail_id)
-			g_signal_handler_disconnect (priv->smgr, priv->smgr_avail_id);
-		g_object_unref (priv->smgr);
-	}
-
-	g_free (priv->dev);
-
-	if (priv->dbus_mgr)
-		g_object_unref (priv->dbus_mgr);
-
-	if (priv->cfg)
-		g_object_unref (priv->cfg);
-
-	g_free (priv->object_path);
-
-	/* Chain up to the parent class */
-	G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->dispose (object);
-}
-
-static void
-nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	g_type_class_add_private (object_class, sizeof (NMSupplicantInterfacePrivate));
-
-	object_class->dispose = dispose;
-	object_class->set_property = set_property;
-	object_class->get_property = get_property;
-
-	/* Properties */
-	g_object_class_install_property (object_class, PROP_SCANNING,
-		g_param_spec_boolean ("scanning",
-		                      "Scanning",
-		                      "Scanning",
-		                      FALSE,
-		                      G_PARAM_READABLE));
-
-	/* Signals */
-	signals[STATE] =
-		g_signal_new (NM_SUPPLICANT_INTERFACE_STATE,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_LAST,
-		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, state),
-		              NULL, NULL,
-		              _nm_marshal_VOID__UINT_UINT,
-		              G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
-
-	signals[REMOVED] =
-		g_signal_new (NM_SUPPLICANT_INTERFACE_REMOVED,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_LAST,
-		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, removed),
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__VOID,
-		              G_TYPE_NONE, 0);
-
-	signals[NEW_BSS] =
-		g_signal_new (NM_SUPPLICANT_INTERFACE_NEW_BSS,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_LAST,
-		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, new_bss),
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__POINTER,
-		              G_TYPE_NONE, 1, G_TYPE_POINTER);
-
-	signals[SCAN_DONE] =
-		g_signal_new (NM_SUPPLICANT_INTERFACE_SCAN_DONE,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_LAST,
-		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, scan_done),
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__BOOLEAN,
-		              G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
-	signals[CONNECTION_ERROR] =
-		g_signal_new (NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_LAST,
-		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, connection_error),
-		              NULL, NULL,
-		              _nm_marshal_VOID__STRING_STRING,
-		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+	return "unknown";
 }
 
diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h
index e32411d7..bee5436f 100644
--- a/src/supplicant-manager/nm-supplicant-interface.h
+++ b/src/supplicant-manager/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 - 2008 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -26,27 +26,47 @@
 #include <dbus/dbus.h>
 #include "nm-supplicant-types.h"
 
+G_BEGIN_DECLS
+
 /*
  * Supplicant interface states
- *   A mix of wpa_supplicant interface states and internal states.
+ *   The states are linear, ie INIT -> READY -> DOWN and state may only be
+ *   changed in one direction.  If an interface reaches the DOWN state, it
+ *   cannot be re-initialized; it must be torn down and a new one created.
+ *
+ * INIT:  interface has been created, but cannot be used yet; it is waiting
+ *             for pending requests of the supplicant to complete.
+ * READY: interface is ready for use
+ * DOWN:  interface has been removed or has otherwise been made invalid; it
+ *             must be torn down.
+ *
+ * Note: LAST is an invalid state and only used for boundary checking.
  */
 enum {
 	NM_SUPPLICANT_INTERFACE_STATE_INIT = 0,
 	NM_SUPPLICANT_INTERFACE_STATE_STARTING,
 	NM_SUPPLICANT_INTERFACE_STATE_READY,
-	NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED,
-	NM_SUPPLICANT_INTERFACE_STATE_INACTIVE,
-	NM_SUPPLICANT_INTERFACE_STATE_SCANNING,
-	NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING,
-	NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING,
-	NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED,
-	NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE,
-	NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE,
-	NM_SUPPLICANT_INTERFACE_STATE_COMPLETED,
 	NM_SUPPLICANT_INTERFACE_STATE_DOWN,
 	NM_SUPPLICANT_INTERFACE_STATE_LAST
 };
 
+
+/*
+ * Supplicant interface connection states
+ *   The wpa_supplicant state for the connection.
+ */
+enum {
+	NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED = 0,
+	NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE,
+	NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING,
+	NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATING,
+	NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED,
+	NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE,
+	NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE,
+	NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED,
+	NM_SUPPLICANT_INTERFACE_CON_STATE_LAST
+};
+
 #define NM_TYPE_SUPPLICANT_INTERFACE            (nm_supplicant_interface_get_type ())
 #define NM_SUPPLICANT_INTERFACE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterface))
 #define NM_SUPPLICANT_INTERFACE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass))
@@ -54,12 +74,6 @@ enum {
 #define NM_IS_SUPPLICANT_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_SUPPLICANT_INTERFACE))
 #define NM_SUPPLICANT_INTERFACE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass))
 
-#define NM_SUPPLICANT_INTERFACE_STATE            "state"
-#define NM_SUPPLICANT_INTERFACE_REMOVED          "removed"
-#define NM_SUPPLICANT_INTERFACE_NEW_BSS          "new-bss"
-#define NM_SUPPLICANT_INTERFACE_SCAN_DONE        "scan-done"
-#define NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR "connection-error"
-
 struct _NMSupplicantInterface {
 	GObject parent;
 };
@@ -77,14 +91,23 @@ typedef struct {
 	/* interface was removed by the supplicant */
 	void (*removed)          (NMSupplicantInterface * iface);
 
-	/* interface saw a new BSS */
-	void (*new_bss)          (NMSupplicantInterface *iface,
-	                          GHashTable *props);
+	/* interface saw a new access point from a scan */
+	void (*scanned_ap)       (NMSupplicantInterface * iface,
+	                          DBusMessage * message);
 
-	/* wireless scan is done */
-	void (*scan_done)        (NMSupplicantInterface *iface,
+	/* result of a wireless scan request */
+	void (*scan_req_result)  (NMSupplicantInterface * iface,
 	                          gboolean success);
 
+	/* scan results returned from supplicant */
+	void (*scan_results)     (NMSupplicantInterface * iface,
+	                          guint num_bssids);
+
+	/* link state of the device's connection */
+	void (*connection_state) (NMSupplicantInterface * iface,
+	                          guint32 new_state,
+	                          guint32 old_state);
+
 	/* an error occurred during a connection request */
 	void (*connection_error) (NMSupplicantInterface * iface,
 	                          const char * name,
@@ -96,8 +119,7 @@ GType nm_supplicant_interface_get_type (void);
 
 NMSupplicantInterface * nm_supplicant_interface_new (NMSupplicantManager * smgr,
                                                      const char *ifname,
-                                                     gboolean is_wireless,
-                                                     gboolean start_now);
+                                                     gboolean is_wireless);
 
 gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface,
                                              NMSupplicantConfig * cfg);
@@ -106,16 +128,18 @@ void nm_supplicant_interface_disconnect (NMSupplicantInterface * iface);
 
 const char * nm_supplicant_interface_get_device (NMSupplicantInterface * iface);
 
-const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface);
-
 gboolean nm_supplicant_interface_request_scan (NMSupplicantInterface * self);
 
 guint32 nm_supplicant_interface_get_state (NMSupplicantInterface * self);
 
+guint32 nm_supplicant_interface_get_connection_state (NMSupplicantInterface * self);
+
 const char *nm_supplicant_interface_state_to_string (guint32 state);
 
+const char *nm_supplicant_interface_connection_state_to_string (guint32 state);
+
 gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self);
 
-const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self);
+G_END_DECLS
 
 #endif	/* NM_SUPPLICANT_INTERFACE_H */
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c
index 8209da21..a2cf58eb 100644
--- a/src/supplicant-manager/nm-supplicant-manager.c
+++ b/src/supplicant-manager/nm-supplicant-manager.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 - 2008 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -26,7 +26,19 @@
 #include "nm-supplicant-manager.h"
 #include "nm-supplicant-interface.h"
 #include "nm-dbus-manager.h"
+#include "nm-marshal.h"
 #include "nm-logging.h"
+#include "nm-glib-compat.h"
+
+#define SUPPLICANT_POKE_INTERVAL 120
+
+typedef struct {
+	NMDBusManager *	dbus_mgr;
+	guint32         state;
+	GSList *        ifaces;
+	gboolean        dispose_has_run;
+	guint			poke_id;
+} NMSupplicantManagerPrivate;
 
 #define NM_SUPPLICANT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
                                               NM_TYPE_SUPPLICANT_MANAGER, \
@@ -34,283 +46,298 @@
 
 G_DEFINE_TYPE (NMSupplicantManager, nm_supplicant_manager, G_TYPE_OBJECT)
 
-/* Properties */
-enum {
-	PROP_0 = 0,
-	PROP_AVAILABLE,
-	LAST_PROP
-};
 
-typedef struct {
-	NMDBusManager * dbus_mgr;
-	guint           name_owner_id;
-	DBusGProxy *    proxy;
-	gboolean        running;
-	GHashTable *    ifaces;
-	guint           die_count_reset_id;
-	guint           die_count;
-	gboolean        disposed;
-} NMSupplicantManagerPrivate;
+static void nm_supplicant_manager_name_owner_changed (NMDBusManager *dbus_mgr,
+                                                      const char *name,
+                                                      const char *old,
+                                                      const char *new,
+                                                      gpointer user_data);
 
-/********************************************************************/
+static void nm_supplicant_manager_set_state (NMSupplicantManager * self,
+                                             guint32 new_state);
 
-static inline gboolean
-die_count_exceeded (guint32 count)
-{
-	return count > 2;
-}
+static gboolean nm_supplicant_manager_startup (NMSupplicantManager * self);
 
-NMSupplicantInterface *
-nm_supplicant_manager_iface_get (NMSupplicantManager * self,
-                                 const char *ifname,
-                                 gboolean is_wireless)
-{
-	NMSupplicantManagerPrivate *priv;
-	NMSupplicantInterface *iface = NULL;
-	gboolean start_now;
 
-	g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
-	g_return_val_if_fail (ifname != NULL, NULL);
+/* Signals */
+enum {
+	STATE,       /* change in the manager's state */
+	LAST_SIGNAL
+};
+static guint nm_supplicant_manager_signals[LAST_SIGNAL] = { 0 };
 
-	priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
 
-	iface = g_hash_table_lookup (priv->ifaces, ifname);
-	if (!iface) {
-		/* If we're making the supplicant take a time out for a bit, don't
-		 * let the supplicant interface start immediately, just let it hang
-		 * around in INIT state until we're ready to talk to the supplicant
-		 * again.
-		 */
-		start_now = !die_count_exceeded (priv->die_count);
+NMSupplicantManager *
+nm_supplicant_manager_get (void)
+{
+	static NMSupplicantManager * singleton = NULL;
 
-		nm_log_dbg (LOGD_SUPPLICANT, "(%s): creating new supplicant interface", ifname);
-		iface = nm_supplicant_interface_new (self, ifname, is_wireless, start_now);
-		if (iface)
-			g_hash_table_insert (priv->ifaces, g_strdup (ifname), iface);
+	if (!singleton) {
+		singleton = NM_SUPPLICANT_MANAGER (g_object_new (NM_TYPE_SUPPLICANT_MANAGER, NULL));
 	} else {
-		nm_log_dbg (LOGD_SUPPLICANT, "(%s): returning existing supplicant interface", ifname);
+		g_object_ref (singleton);
 	}
 
-	return iface;
+	g_assert (singleton);
+	return singleton;
 }
 
-void
-nm_supplicant_manager_iface_release (NMSupplicantManager *self,
-                                     NMSupplicantInterface *iface)
+static gboolean
+poke_supplicant_cb (gpointer user_data)
 {
-	NMSupplicantManagerPrivate *priv;
-	const char *ifname, *op;
-
-	g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (self));
-	g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (iface));
-
-	ifname = nm_supplicant_interface_get_ifname (iface);
-	g_assert (ifname);
-
-	priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
-
-	g_return_if_fail (g_hash_table_lookup (priv->ifaces, ifname) == iface);
-
-	/* Ask wpa_supplicant to remove this interface */
-	op = nm_supplicant_interface_get_object_path (iface);
-	if (priv->running && priv->proxy && op) {
-		dbus_g_proxy_call_no_reply (priv->proxy, "RemoveInterface",
-			                        DBUS_TYPE_G_OBJECT_PATH, op,
-			                        G_TYPE_INVALID);
+	NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data);
+	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+	DBusGConnection *g_connection;
+	DBusGProxy *proxy;
+	const char *tmp = "ignoreme";
+
+	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	proxy = dbus_g_proxy_new_for_name (g_connection,
+	                                   WPAS_DBUS_SERVICE,
+	                                   WPAS_DBUS_PATH,
+	                                   WPAS_DBUS_INTERFACE);
+	if (!proxy) {
+		nm_log_warn (LOGD_SUPPLICANT, "Error: could not init wpa_supplicant proxy");
+		goto out;
 	}
 
-	g_hash_table_remove (priv->ifaces, ifname);
-}
+	nm_log_info (LOGD_SUPPLICANT, "Trying to start the supplicant...");
+	dbus_g_proxy_call_no_reply (proxy, "getInterface", G_TYPE_STRING, tmp, G_TYPE_INVALID);
+	g_object_unref (proxy);
 
-gboolean
-nm_supplicant_manager_available (NMSupplicantManager *self)
-{
-	g_return_val_if_fail (self != NULL, FALSE);
-	g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), FALSE);
+out:
+	/* Reschedule the poke */	
+	priv->poke_id = g_timeout_add_seconds (SUPPLICANT_POKE_INTERVAL,
+	                               poke_supplicant_cb,
+	                               (gpointer) self);
 
-	if (die_count_exceeded (NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->die_count))
-		return FALSE;
-	return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->running;
+	return FALSE;
 }
 
 static void
-set_running (NMSupplicantManager *self, gboolean now_running)
+nm_supplicant_manager_init (NMSupplicantManager * self)
 {
 	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
-	gboolean old_available = nm_supplicant_manager_available (self);
+	gboolean running;
 
-	priv->running = now_running;
-	if (old_available != nm_supplicant_manager_available (self))
-		g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_AVAILABLE);
+	priv->dispose_has_run = FALSE;
+	priv->state = NM_SUPPLICANT_MANAGER_STATE_DOWN;
+	priv->dbus_mgr = nm_dbus_manager_get ();
+	priv->poke_id = 0;
+
+	running = nm_supplicant_manager_startup (self);
+
+	g_signal_connect (priv->dbus_mgr,
+	                  "name-owner-changed",
+	                  G_CALLBACK (nm_supplicant_manager_name_owner_changed),
+	                  self);
+
+	if (!running) {
+		/* Try to activate the supplicant */
+		priv->poke_id = g_idle_add (poke_supplicant_cb, (gpointer) self);
+	}
 }
 
 static void
-set_die_count (NMSupplicantManager *self, guint new_die_count)
+nm_supplicant_manager_dispose (GObject *object)
 {
-	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
-	gboolean old_available = nm_supplicant_manager_available (self);
+	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object);
+
+	if (priv->dispose_has_run) {
+		G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
+		return;
+	}
+
+	priv->dispose_has_run = TRUE;
+
+	if (priv->poke_id) {
+		g_source_remove (priv->poke_id);
+		priv->poke_id = 0;
+	}
+
+	if (priv->dbus_mgr) {
+		g_object_unref (G_OBJECT (priv->dbus_mgr));
+		priv->dbus_mgr = NULL;
+	}
 
-	priv->die_count = new_die_count;
-	if (old_available != nm_supplicant_manager_available (self))
-		g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_AVAILABLE);
+	/* Chain up to the parent class */
+	G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
 }
 
-static gboolean
-wpas_die_count_reset_cb (gpointer user_data)
+static void
+nm_supplicant_manager_class_init (NMSupplicantManagerClass *klass)
 {
-	NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data);
-	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+	GObjectClass * object_class = G_OBJECT_CLASS (klass);
 
-	/* Reset the die count back to zero, which allows use of the supplicant again */
-	priv->die_count_reset_id = 0;
-	set_die_count (self, 0);
-	nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant die count reset");
-	return FALSE;
+	g_type_class_add_private (object_class, sizeof (NMSupplicantManagerPrivate));
+
+	object_class->dispose = nm_supplicant_manager_dispose;
+
+	/* Signals */
+	nm_supplicant_manager_signals[STATE] =
+		g_signal_new ("state",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantManagerClass, state),
+		              NULL, NULL,
+		              _nm_marshal_VOID__UINT_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
 }
 
 static void
-name_owner_changed (NMDBusManager *dbus_mgr,
-                    const char *name,
-                    const char *old_owner,
-                    const char *new_owner,
-                    gpointer user_data)
+nm_supplicant_manager_name_owner_changed (NMDBusManager *dbus_mgr,
+                                          const char *name,
+										  const char *old_owner,
+										  const char *new_owner,
+                                          gpointer user_data)
 {
-	NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data);
+	NMSupplicantManager * self = (NMSupplicantManager *) user_data;
 	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
 	gboolean old_owner_good = (old_owner && strlen (old_owner));
 	gboolean new_owner_good = (new_owner && strlen (new_owner));
 
-	/* We only care about the supplicant here */
+	/* Can't handle the signal if its not from the supplicant service */
 	if (strcmp (WPAS_DBUS_SERVICE, name) != 0)
 		return;
 
 	if (!old_owner_good && new_owner_good) {
-		nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant started");
-		set_running (self, TRUE);
-	} else if (old_owner_good && !new_owner_good) {
-		nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant stopped");
+		gboolean running;
 
-		/* Reschedule the die count reset timeout.  Every time the supplicant
-		 * dies we wait 10 seconds before resetting the counter.  If the
-		 * supplicant died more than twice before the timer is reset, then
-		 * we don't try to talk to the supplicant for a while.
-		 */
-		if (priv->die_count_reset_id)
-			g_source_remove (priv->die_count_reset_id);
-		priv->die_count_reset_id = g_timeout_add_seconds (10, wpas_die_count_reset_cb, self);
-		set_die_count (self, priv->die_count + 1);
-
-		if (die_count_exceeded (priv->die_count)) {
-			nm_log_info (LOGD_SUPPLICANT,
-			             "wpa_supplicant die count %d; ignoring for 10 seconds",
-			             priv->die_count);
+		running = nm_supplicant_manager_startup (self);
+
+		if (running && priv->poke_id) {
+			g_source_remove (priv->poke_id);
+			priv->poke_id = 0;
 		}
+	} else if (old_owner_good && !new_owner_good) {
+		nm_supplicant_manager_set_state (self, NM_SUPPLICANT_MANAGER_STATE_DOWN);
+
+		if (priv->poke_id)
+			g_source_remove (priv->poke_id);
 
-		set_running (self, FALSE);
+		/* Poke the supplicant so that it gets activated by dbus system bus
+		 * activation.
+		 */
+		priv->poke_id = g_idle_add (poke_supplicant_cb, (gpointer) self);
 	}
 }
 
-/*******************************************************************/
 
-NMSupplicantManager *
-nm_supplicant_manager_get (void)
+guint32
+nm_supplicant_manager_get_state (NMSupplicantManager * self)
 {
-	static NMSupplicantManager *singleton = NULL;
-
-	if (!singleton)
-		singleton = NM_SUPPLICANT_MANAGER (g_object_new (NM_TYPE_SUPPLICANT_MANAGER, NULL));
-	else
-		g_object_ref (singleton);
+	g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), FALSE);
 
-	g_assert (singleton);
-	return singleton;
+	return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->state;
 }
 
 static void
-nm_supplicant_manager_init (NMSupplicantManager * self)
+nm_supplicant_manager_set_state (NMSupplicantManager * self, guint32 new_state)
 {
 	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
-	DBusGConnection *bus;
+	guint32 old_state;
 
-	priv->dbus_mgr = nm_dbus_manager_get ();
-	priv->name_owner_id = g_signal_connect (priv->dbus_mgr,
-	                                        NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
-	                                        G_CALLBACK (name_owner_changed),
-	                                        self);
-	priv->running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, WPAS_DBUS_SERVICE);
-
-	bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
-	priv->proxy = dbus_g_proxy_new_for_name (bus,
-	                                         WPAS_DBUS_SERVICE,
-	                                         WPAS_DBUS_PATH,
-	                                         WPAS_DBUS_INTERFACE);
-
-	priv->ifaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-}
+	if (new_state == priv->state)
+		return;
 
-static void
-set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
-	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	old_state = priv->state;
+	priv->state = new_state;
+	g_signal_emit (self,
+	               nm_supplicant_manager_signals[STATE],
+	               0,
+	               priv->state,
+	               old_state);
 }
 
-static void
-get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+static gboolean
+nm_supplicant_manager_startup (NMSupplicantManager * self)
 {
-	switch (prop_id) {
-	case PROP_AVAILABLE:
-		g_value_set_boolean (value, nm_supplicant_manager_available (NM_SUPPLICANT_MANAGER (object)));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	gboolean running;
+
+	/* FIXME: convert to pending call */
+	running = nm_dbus_manager_name_has_owner (NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->dbus_mgr,
+	                                          WPAS_DBUS_SERVICE);
+	if (running)
+		nm_supplicant_manager_set_state (self, NM_SUPPLICANT_MANAGER_STATE_IDLE);
+
+	return running;
 }
 
-static void
-dispose (GObject *object)
+NMSupplicantInterface *
+nm_supplicant_manager_get_iface (NMSupplicantManager * self,
+								 const char *ifname,
+								 gboolean is_wireless)
 {
-	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object);
+	NMSupplicantManagerPrivate *priv;
+	NMSupplicantInterface * iface = NULL;
+	GSList * elt;
 
-	if (priv->disposed)
-		goto out;
-	priv->disposed = TRUE;
+	g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
+	g_return_val_if_fail (ifname != NULL, NULL);
 
-	if (priv->die_count_reset_id)
-		g_source_remove (priv->die_count_reset_id);
+	priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
 
-	if (priv->dbus_mgr) {
-		if (priv->name_owner_id)
-			g_signal_handler_disconnect (priv->dbus_mgr, priv->name_owner_id);
-		g_object_unref (G_OBJECT (priv->dbus_mgr));
-	}
+	/* Ensure we don't already have this interface */
+	for (elt = priv->ifaces; elt; elt = g_slist_next (elt)) {
+		NMSupplicantInterface * if_tmp = (NMSupplicantInterface *) elt->data;
 
-	g_hash_table_destroy (priv->ifaces);
+		if (!strcmp (ifname, nm_supplicant_interface_get_device (if_tmp))) {
+			iface = if_tmp;
+			break;
+		}
+	}
 
-	if (priv->proxy)
-		g_object_unref (priv->proxy);
+	if (!iface) {
+		nm_log_dbg (LOGD_SUPPLICANT, "(%s): creating new supplicant interface", ifname);
+		iface = nm_supplicant_interface_new (self, ifname, is_wireless);
+		if (iface)
+			priv->ifaces = g_slist_append (priv->ifaces, iface);
+	} else {
+		nm_log_dbg (LOGD_SUPPLICANT, "(%s): returning existing supplicant interface", ifname);
+	}
 
-out:
-	/* Chain up to the parent class */
-	G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
+	return iface;
 }
 
-static void
-nm_supplicant_manager_class_init (NMSupplicantManagerClass *klass)
+void
+nm_supplicant_manager_release_iface (NMSupplicantManager * self,
+                                     NMSupplicantInterface * iface)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMSupplicantManagerPrivate *priv;
+	GSList * elt;
 
-	g_type_class_add_private (object_class, sizeof (NMSupplicantManagerPrivate));
+	g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (self));
+	g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (iface));
+
+	priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
 
-	object_class->get_property = get_property;
-	object_class->set_property = set_property;
-	object_class->dispose = dispose;
+	for (elt = priv->ifaces; elt; elt = g_slist_next (elt)) {
+		NMSupplicantInterface * if_tmp = (NMSupplicantInterface *) elt->data;
+
+		if (if_tmp == iface) {
+			/* Remove the iface from the supplicant manager's list and
+			 * dereference to match additional reference in get_iface.
+			 */
+			priv->ifaces = g_slist_remove_link (priv->ifaces, elt);
+			g_slist_free_1 (elt);
+			g_object_unref (iface);
+			break;
+		}
+	}
+}
 
-	g_object_class_install_property (object_class, PROP_AVAILABLE,
-		g_param_spec_boolean (NM_SUPPLICANT_MANAGER_AVAILABLE,
-		                      "Available",
-		                      "Available",
-		                      FALSE,
-		                      G_PARAM_READABLE));
+const char *
+nm_supplicant_manager_state_to_string (guint32 state)
+{
+	switch (state) {
+	case NM_SUPPLICANT_MANAGER_STATE_DOWN:
+		return "down";
+	case NM_SUPPLICANT_MANAGER_STATE_IDLE:
+		return "idle";
+	default:
+		break;
+	}
+	return "unknown";
 }
 
+
diff --git a/src/supplicant-manager/nm-supplicant-manager.h b/src/supplicant-manager/nm-supplicant-manager.h
index 9e2f3b21..fef2a774 100644
--- a/src/supplicant-manager/nm-supplicant-manager.h
+++ b/src/supplicant-manager/nm-supplicant-manager.h
@@ -26,13 +26,30 @@
 #include "nm-supplicant-types.h"
 #include "nm-device.h"
 
-#define WPAS_DBUS_SERVICE	"fi.w1.wpa_supplicant1"
-#define WPAS_DBUS_PATH		"/fi/w1/wpa_supplicant1"
-#define WPAS_DBUS_INTERFACE	"fi.w1.wpa_supplicant1"
+#define WPAS_DBUS_SERVICE	"fi.epitest.hostap.WPASupplicant"
+#define WPAS_DBUS_PATH		"/fi/epitest/hostap/WPASupplicant"
+#define WPAS_DBUS_INTERFACE	"fi.epitest.hostap.WPASupplicant"
 
 
 G_BEGIN_DECLS
 
+/*
+ * Supplicant manager states
+ *   Either state may transition to the other state at any time.
+ *
+ * DOWN: supplicant manager has been created, but cannot be used; the supplicant
+ *           is either not running or has not yet been fully initialized.
+ * IDLE: supplicant manager is ready for use
+ *
+ * Note: LAST is an invalid state and only used for boundary checking.
+ */
+enum {
+	NM_SUPPLICANT_MANAGER_STATE_DOWN = 0,
+	NM_SUPPLICANT_MANAGER_STATE_IDLE,
+	NM_SUPPLICANT_MANAGER_STATE_LAST
+};
+
+
 #define NM_TYPE_SUPPLICANT_MANAGER				(nm_supplicant_manager_get_type ())
 #define NM_SUPPLICANT_MANAGER(obj)				(G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManager))
 #define NM_SUPPLICANT_MANAGER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManagerClass))
@@ -40,8 +57,6 @@ G_BEGIN_DECLS
 #define NM_IS_SUPPLICANT_MANAGER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_SUPPLICANT_MANAGER))
 #define NM_SUPPLICANT_MANAGER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManagerClass))
 
-#define NM_SUPPLICANT_MANAGER_AVAILABLE "available"
-
 struct _NMSupplicantManager
 {
 	GObject parent;
@@ -50,19 +65,24 @@ struct _NMSupplicantManager
 typedef struct
 {
 	GObjectClass parent;
+
+	/* class members */
+	void (* state)  (NMSupplicantManager * mgr, guint32 new_state, guint32 old_state);
 } NMSupplicantManagerClass;
 
 GType nm_supplicant_manager_get_type (void);
 
-NMSupplicantManager *nm_supplicant_manager_get (void);
+NMSupplicantManager * nm_supplicant_manager_get (void);
+
+guint32 nm_supplicant_manager_get_state (NMSupplicantManager * mgr);
 
-NMSupplicantInterface *nm_supplicant_manager_iface_get (NMSupplicantManager *mgr,
-                                                        const char *ifname,
-                                                        gboolean is_wireless);
+NMSupplicantInterface * nm_supplicant_manager_get_iface (NMSupplicantManager * mgr,
+                                                         const char *ifname,
+														 gboolean is_wireless);
 
-void nm_supplicant_manager_iface_release (NMSupplicantManager *mgr,
-                                          NMSupplicantInterface *iface);
+void nm_supplicant_manager_release_iface (NMSupplicantManager * mgr,
+                                          NMSupplicantInterface * iface);
 
-gboolean nm_supplicant_manager_available (NMSupplicantManager *mgr);
+const char *nm_supplicant_manager_state_to_string (guint32 state);
 
 #endif /* NM_SUPPLICANT_MANAGER_H */
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index 58cb15f3..ac812e2e 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/tests/Makefile.in
@@ -39,16 +39,11 @@ subdir = src/supplicant-manager/tests
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
-	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
-	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
-	$(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/introspection.m4 \
-	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
-	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libnl-check.m4 \
-	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
-	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
-	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
-	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/intltool.m4 \
+	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -68,7 +63,7 @@ AM_V_lt = $(am__v_lt_$(V))
 am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
 am__v_lt_0 = --silent
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
-depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
 am__mv = mv -f
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
@@ -99,6 +94,7 @@ ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
 ALL_LINGUAS = @ALL_LINGUAS@
 AMTAR = @AMTAR@
 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
@@ -107,6 +103,8 @@ AUTOCONF = @AUTOCONF@
 AUTOHEADER = @AUTOHEADER@
 AUTOMAKE = @AUTOMAKE@
 AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
@@ -123,7 +121,6 @@ DHCLIENT_PATH = @DHCLIENT_PATH@
 DHCLIENT_VERSION = @DHCLIENT_VERSION@
 DHCPCD_PATH = @DHCPCD_PATH@
 DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
-DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
 ECHO_C = @ECHO_C@
@@ -132,7 +129,6 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
-GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
 GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
 GIO_CFLAGS = @GIO_CFLAGS@
 GIO_LIBS = @GIO_LIBS@
@@ -141,8 +137,8 @@ GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
+GMOFILES = @GMOFILES@
 GMSGFMT = @GMSGFMT@
-GMSGFMT_015 = @GMSGFMT_015@
 GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
@@ -157,23 +153,13 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
 INTLLIBS = @INTLLIBS@
 INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
-INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
-INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
-INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
-INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
-INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
-INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
-INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
-INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
-INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
 IPTABLES_PATH = @IPTABLES_PATH@
-IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
-IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
 KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
@@ -181,8 +167,6 @@ LIBDL = @LIBDL@
 LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
 LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
 LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
-LIBICONV = @LIBICONV@
-LIBINTL = @LIBINTL@
 LIBM = @LIBM@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
@@ -191,15 +175,13 @@ LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
-LTLIBICONV = @LTLIBICONV@
-LTLIBINTL = @LTLIBINTL@
 LTLIBOBJS = @LTLIBOBJS@
 MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
 MSGFMT = @MSGFMT@
-MSGFMT_015 = @MSGFMT_015@
+MSGFMT_OPTS = @MSGFMT_OPTS@
 MSGMERGE = @MSGMERGE@
 NM = @NM@
 NMEDIT = @NMEDIT@
@@ -225,9 +207,12 @@ PKGCONFIG_PATH = @PKGCONFIG_PATH@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
 POLKIT_CFLAGS = @POLKIT_CFLAGS@
 POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
 RANLIB = @RANLIB@
 RESOLVCONF_PATH = @RESOLVCONF_PATH@
@@ -242,13 +227,10 @@ UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
-XGETTEXT_015 = @XGETTEXT_015@
-XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
 abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
 am__include = @am__include@