summary refs log tree commit diff
path: root/src/supplicant-manager
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-03-01 16:55:22 +0100
committerMichael Biebl <biebl@debian.org>2016-03-01 16:55:22 +0100
commitc2de0d98ba39e0a1a970d066fd19be786092f376 (patch)
tree3838363c06a6019db6cf1f882ea34ebded63c38b /src/supplicant-manager
parent494f296a3baab08522617b24b1f126d8f9a17502 (diff)
Imported Upstream version 1.1.91 upstream/1.1.91
Diffstat (limited to 'src/supplicant-manager')
-rw-r--r--src/supplicant-manager/nm-supplicant-config.c3
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.c279
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.h10
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.c180
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.h9
-rw-r--r--src/supplicant-manager/nm-supplicant-settings-verify.c3
-rw-r--r--src/supplicant-manager/tests/test-supplicant-config.c3
7 files changed, 285 insertions, 202 deletions
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index 190ee0a7..091742e5 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -19,12 +19,11 @@
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 #include <stdlib.h>
 
-#include "nm-default.h"
 #include "nm-supplicant-config.h"
 #include "nm-supplicant-settings-verify.h"
 #include "nm-setting.h"
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c
index 9251af1f..ce7a2a2c 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/nm-supplicant-interface.c
@@ -19,12 +19,11 @@
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <stdio.h>
 #include <string.h>
 
-#include "nm-default.h"
 #include "NetworkManagerUtils.h"
 #include "nm-supplicant-interface.h"
 #include "nm-supplicant-config.h"
@@ -59,21 +58,22 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 
 /* Properties */
-enum {
-	PROP_0 = 0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface,
+	PROP_IFACE,
 	PROP_SCANNING,
 	PROP_CURRENT_BSS,
-	LAST_PROP
-};
-
+	PROP_IS_WIRELESS,
+	PROP_FAST_SUPPORTED,
+	PROP_AP_SUPPORT,
+);
 
 typedef struct {
 	char *         dev;
-	gboolean       is_wireless;
+	bool           is_wireless;
+	bool           fast_supported;
 	gboolean       has_credreq;  /* Whether querying 802.1x credentials is supported */
 	NMSupplicantFeature ap_support;   /* Lightweight AP mode support */
 	NMSupplicantFeature mac_randomization_support;
-	gboolean       fast_supported;
 	guint32        max_scan_ssids;
 	guint32        ready_count;
 
@@ -98,7 +98,27 @@ typedef struct {
 	NMSupplicantConfig *cfg;
 } NMSupplicantInterfacePrivate;
 
-/***************************************************************/
+/*********************************************************************************************/
+
+#define _NMLOG_DOMAIN           LOGD_SUPPLICANT
+#define _NMLOG_PREFIX_NAME      "sup-iface"
+#define _NMLOG(level, ...) \
+    G_STMT_START { \
+         char _sbuf[64]; \
+         \
+         nm_log ((level), _NMLOG_DOMAIN, \
+                 "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+                 _NMLOG_PREFIX_NAME, \
+                 ((self) \
+                      ? nm_sprintf_buf (_sbuf, \
+                                        "[%p,%s]", \
+                                        (self), \
+                                        NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev) \
+                      : "") \
+                 _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+    } G_STMT_END
+
+/*********************************************************************************************/
 
 static void
 emit_error_helper (NMSupplicantInterface *self, GError *error)
@@ -162,8 +182,9 @@ on_bss_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da
 
 	if (!g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error)) {
 		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-			nm_log_dbg (LOGD_SUPPLICANT, "Failed to acquire BSS proxy: (%s)", error->message);
-			g_hash_table_remove (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (user_data)->bss_proxies,
+			self = NM_SUPPLICANT_INTERFACE (user_data);
+			_LOGD ("failed to acquire BSS proxy: (%s)", error->message);
+			g_hash_table_remove (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->bss_proxies,
 			                     g_dbus_proxy_get_object_path (proxy));
 		}
 		return;
@@ -288,7 +309,6 @@ wpas_state_string_to_enum (const char *str_state)
 	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;
 }
 
@@ -298,9 +318,11 @@ set_state_from_string (NMSupplicantInterface *self, const char *new_state)
 	int state;
 
 	state = wpas_state_string_to_enum (new_state);
-	g_warn_if_fail (state > 0);
-	if (state > 0)
-		set_state (self, (guint32) state);
+	if (state == -1) {
+		_LOGW ("unknown supplicant state '%s'", new_state);
+		return;
+	}
+	set_state (self, (guint32) state);
 }
 
 static void
@@ -315,7 +337,7 @@ set_scanning (NMSupplicantInterface *self, gboolean new_scanning)
 		if (priv->scanning == FALSE)
 			priv->last_scan = nm_utils_get_monotonic_timestamp_s ();
 
-		g_object_notify (G_OBJECT (self), "scanning");
+		_notify (self, PROP_SCANNING);
 	}
 }
 
@@ -379,8 +401,7 @@ parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities)
 			 * list, we'll limit to 5.
 			 */
 			priv->max_scan_ssids = CLAMP (max_scan_ssids, 0, 5);
-			nm_log_info (LOGD_SUPPLICANT, "(%s) supports %d scan SSIDs",
-				         priv->dev, priv->max_scan_ssids);
+			_LOGI ("supports %d scan SSIDs", priv->max_scan_ssids);
 		}
 	}
 }
@@ -456,8 +477,8 @@ iface_check_netreply_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
 	if (variant || _nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs"))
 		priv->has_credreq = TRUE;
 
-	nm_log_dbg (LOGD_SUPPLICANT, "Supplicant %s network credentials requests",
-	            priv->has_credreq ? "supports" : "does not support");
+	_LOGD ("supplicant %s network credentials requests",
+	       priv->has_credreq ? "supports" : "does not support");
 
 	iface_check_ready (self);
 }
@@ -490,6 +511,7 @@ nm_supplicant_interface_get_mac_randomization_support (NMSupplicantInterface *se
 static void
 set_preassoc_scan_mac_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 {
+	NMSupplicantInterface *self;
 	gs_unref_variant GVariant *variant = NULL;
 	gs_free_error GError *error = NULL;
 
@@ -498,10 +520,11 @@ set_preassoc_scan_mac_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user
 	                                      &error);
 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
-	if (error)
-		nm_log_warn (LOGD_SUPPLICANT, "Failed to enable scan MAC address randomization");
 
-	iface_check_ready (NM_SUPPLICANT_INTERFACE (user_data));
+	self = NM_SUPPLICANT_INTERFACE (user_data);
+	if (error)
+		_LOGW ("failed to enable scan MAC address randomization (%s)", error->message);
+	iface_check_ready (self);
 }
 
 static void
@@ -665,7 +688,7 @@ props_changed_cb (GDBusProxy *proxy,
 		if (g_strcmp0 (s, priv->current_bss) != 0) {
 			g_free (priv->current_bss);
 			priv->current_bss = g_strdup (s);
-			g_object_notify (G_OBJECT (self), NM_SUPPLICANT_INTERFACE_CURRENT_BSS);
+			_notify (self, PROP_CURRENT_BSS);
 		}
 	}
 
@@ -683,10 +706,8 @@ props_changed_cb (GDBusProxy *proxy,
 		 * AP will be positive.
 		 */
 		priv->disconnect_reason = i32;
-		if (priv->disconnect_reason != 0) {
-			nm_log_warn (LOGD_SUPPLICANT, "Connection disconnected (reason %d)",
-				         priv->disconnect_reason);
-		}
+		if (priv->disconnect_reason != 0)
+			_LOGW ("connection disconnected (reason %d)", priv->disconnect_reason);
 	}
 
 	g_object_thaw_notify (G_OBJECT (self));
@@ -701,8 +722,9 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
 
 	if (!g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error)) {
 		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-			nm_log_warn (LOGD_SUPPLICANT, "Failed to acquire wpa_supplicant interface proxy: (%s)", error->message);
-			set_state (NM_SUPPLICANT_INTERFACE (user_data), NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+			self = NM_SUPPLICANT_INTERFACE (user_data);
+			_LOGW ("failed to acquire wpa_supplicant interface proxy: (%s)", error->message);
+			set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
 		}
 		return;
 	}
@@ -781,7 +803,7 @@ interface_add_done (NMSupplicantInterface *self, const char *path)
 {
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-	nm_log_dbg (LOGD_SUPPLICANT, "(%s): interface added to supplicant", priv->dev);
+	_LOGD ("interface added to supplicant");
 
 	priv->object_path = g_strdup (path);
 	priv->iface_proxy = g_object_new (G_TYPE_DBUS_PROXY,
@@ -822,7 +844,7 @@ interface_get_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 		interface_add_done (self, path);
 	} else {
 		g_dbus_error_strip_remote_error (error);
-		nm_log_err (LOGD_SUPPLICANT, "(%s): error getting interface: %s", priv->dev, error->message);
+		_LOGE ("error getting interface: %s", error->message);
 		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
 	}
 }
@@ -871,12 +893,11 @@ interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 		 * state.
 		 */
 		g_dbus_error_strip_remote_error (error);
-		nm_log_dbg (LOGD_SUPPLICANT, "(%s): failed to activate supplicant: %s",
-		            priv->dev, error->message);
+		_LOGD ("failed to activate supplicant: %s", error->message);
 		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_INIT);
 	} else {
 		g_dbus_error_strip_remote_error (error);
-		nm_log_err (LOGD_SUPPLICANT, "(%s): error adding interface: %s", priv->dev, error->message);
+		_LOGE ("error adding interface: %s", error->message);
 		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
 	}
 }
@@ -899,9 +920,9 @@ on_wpas_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d
 	wpas_proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
 	if (!wpas_proxy) {
 		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-			nm_log_warn (LOGD_SUPPLICANT, "Failed to acquire wpa_supplicant proxy: (%s)",
-			             error ? error->message : "unknown");
-			set_state (NM_SUPPLICANT_INTERFACE (user_data), NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+			self = NM_SUPPLICANT_INTERFACE (user_data);
+			_LOGW ("failed to acquire wpa_supplicant proxy: (%s)", error->message);
+			set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
 		}
 		return;
 	}
@@ -935,16 +956,14 @@ on_wpas_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d
 }
 
 static void
-interface_add (NMSupplicantInterface *self, gboolean is_wireless)
+interface_add (NMSupplicantInterface *self)
 {
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
 	/* 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);
-
-	priv->is_wireless = is_wireless;
+	_LOGD ("adding interface to supplicant");
 
 	/* Move to starting to prevent double-calls of interface_add() */
 	set_state (self, NM_SUPPLICANT_INTERFACE_STATE_STARTING);
@@ -969,14 +988,18 @@ void
 nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self,
                                                   gboolean available)
 {
-	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	NMSupplicantInterfacePrivate *priv;
+
+	g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self));
+
+	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
 	if (available) {
 		/* 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);
+			interface_add (self);
 	} else {
 		/* The supplicant stopped; so we must tear down the interface */
 		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
@@ -994,7 +1017,8 @@ log_result_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	    && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
 	    && !strstr (error->message, "fi.w1.wpa_supplicant1.NotConnected")) {
 		g_dbus_error_strip_remote_error (error);
-		nm_log_warn (LOGD_SUPPLICANT, "Failed to %s: %s.", (char *) user_data, error->message);
+		nm_log_warn (_NMLOG_DOMAIN, "%s: failed to %s: %s",
+		             _NMLOG_PREFIX_NAME, (const char *) user_data, error->message);
 	}
 }
 
@@ -1048,14 +1072,17 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self)
 static void
 select_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 {
+	NMSupplicantInterface *self;
 	gs_unref_variant GVariant *reply = NULL;
-	gs_free_error GError *err = NULL;
+	gs_free_error GError *error = NULL;
 
-	reply = g_dbus_proxy_call_finish (proxy, result, &err);
-	if (!reply && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-		g_dbus_error_strip_remote_error (err);
-		nm_log_warn (LOGD_SUPPLICANT, "Couldn't select network config: %s.", err->message);
-		emit_error_helper (NM_SUPPLICANT_INTERFACE (user_data), err);
+	reply = g_dbus_proxy_call_finish (proxy, result, &error);
+	if (   !reply
+	    && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		self = NM_SUPPLICANT_INTERFACE (user_data);
+		g_dbus_error_strip_remote_error (error);
+		_LOGW ("couldn't select network config: %s", error->message);
+		emit_error_helper (self, error);
 	}
 }
 
@@ -1083,10 +1110,10 @@ add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	NMSupplicantInterface *self;
 	NMSupplicantInterfacePrivate *priv;
 	gs_unref_variant GVariant *reply = NULL;
-	gs_free_error GError *err = NULL;
+	gs_free_error GError *error = NULL;
 
-	reply = g_dbus_proxy_call_finish (proxy, result, &err);
-	if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+	reply = g_dbus_proxy_call_finish (proxy, result, &error);
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
 
 	self = NM_SUPPLICANT_INTERFACE (user_data);
@@ -1096,9 +1123,9 @@ add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	if (reply)
 		call_select_network (self);
 	else {
-		g_dbus_error_strip_remote_error (err);
-		nm_log_warn (LOGD_SUPPLICANT, "Couldn't set network certificates: %s.", err->message);
-		emit_error_helper (self, err);
+		g_dbus_error_strip_remote_error (error);
+		_LOGW ("couldn't set network certificates: %s", error->message);
+		emit_error_helper (self, error);
 	}
 }
 
@@ -1128,7 +1155,7 @@ add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 
 	if (error) {
 		g_dbus_error_strip_remote_error (error);
-		nm_log_warn (LOGD_SUPPLICANT, "Adding network to supplicant failed: %s.", error->message);
+		_LOGW ("adding network to supplicant failed: %s", error->message);
 		emit_error_helper (self, error);
 		return;
 	}
@@ -1189,15 +1216,14 @@ set_mac_randomization_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user
 
 	if (!reply) {
 		g_dbus_error_strip_remote_error (error);
-		nm_log_warn (LOGD_SUPPLICANT, "Couldn't send MAC randomization mode to "
-		             "the supplicant interface: %s.",
-		             error->message);
+		_LOGW ("couldn't send MAC randomization mode to the supplicant interface: %s",
+		       error->message);
 		emit_error_helper (self, error);
 		return;
 	}
 
-	nm_log_info (LOGD_SUPPLICANT, "Config: set MAC randomization to %s",
-	             nm_supplicant_config_get_mac_randomization (priv->cfg));
+	_LOGI ("config: set MAC randomization to %s",
+	       nm_supplicant_config_get_mac_randomization (priv->cfg));
 
 	add_network (self);
 }
@@ -1219,14 +1245,14 @@ set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 
 	if (!reply) {
 		g_dbus_error_strip_remote_error (error);
-		nm_log_warn (LOGD_SUPPLICANT, "Couldn't send AP scan mode to the supplicant interface: %s.",
-		             error->message);
+		_LOGW ("couldn't send AP scan mode to the supplicant interface: %s",
+		       error->message);
 		emit_error_helper (self, error);
 		return;
 	}
 
-	nm_log_info (LOGD_SUPPLICANT, "Config: set interface ap_scan to %d",
-	             nm_supplicant_config_get_ap_scan (priv->cfg));
+	_LOGI ("config: set interface ap_scan to %d",
+	       nm_supplicant_config_get_ap_scan (priv->cfg));
 
 	if (priv->mac_randomization_support == NM_SUPPLICANT_FEATURE_YES) {
 		const char *mac_randomization = nm_supplicant_config_get_mac_randomization (priv->cfg);
@@ -1291,6 +1317,7 @@ nm_supplicant_interface_set_config (NMSupplicantInterface *self,
 static void
 scan_request_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 {
+	NMSupplicantInterface *self;
 	gs_unref_variant GVariant *reply = NULL;
 	gs_free_error GError *error = NULL;
 
@@ -1298,15 +1325,17 @@ scan_request_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
 
+	self = NM_SUPPLICANT_INTERFACE (user_data);
+
 	if (error) {
 		if (_nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.Interface.ScanError"))
-			nm_log_dbg (LOGD_SUPPLICANT, "Could not get scan request result: %s", error->message);
+			_LOGD ("could not get scan request result: %s", error->message);
 		else {
 			g_dbus_error_strip_remote_error (error);
-			nm_log_warn (LOGD_SUPPLICANT, "Could not get scan request result: %s", error->message);
+			_LOGW ("could not get scan request result: %s", error->message);
 		}
 	}
-	g_signal_emit (NM_SUPPLICANT_INTERFACE (user_data), signals[SCAN_DONE], 0, error ? FALSE : TRUE);
+	g_signal_emit (self, signals[SCAN_DONE], 0, error ? FALSE : TRUE);
 }
 
 gboolean
@@ -1394,14 +1423,6 @@ nm_supplicant_interface_state_to_string (guint32 state)
 }
 
 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;
-}
-
-const char *
 nm_supplicant_interface_get_object_path (NMSupplicantInterface *self)
 {
 	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
@@ -1431,26 +1452,16 @@ NMSupplicantInterface *
 nm_supplicant_interface_new (const char *ifname,
                              gboolean is_wireless,
                              gboolean fast_supported,
-                             NMSupplicantFeature ap_support,
-                             gboolean start_now)
+                             NMSupplicantFeature ap_support)
 {
-	NMSupplicantInterface *self;
-	NMSupplicantInterfacePrivate *priv;
-
 	g_return_val_if_fail (ifname != NULL, NULL);
 
-	self = g_object_new (NM_TYPE_SUPPLICANT_INTERFACE, NULL);
-	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-
-	priv->dev = g_strdup (ifname);
-	priv->is_wireless = is_wireless;
-	priv->fast_supported = fast_supported;
-	priv->ap_support = ap_support;
-
-	if (start_now)
-		interface_add (self, priv->is_wireless);
-
-	return self;
+	return g_object_new (NM_TYPE_SUPPLICANT_INTERFACE,
+	                     NM_SUPPLICANT_INTERFACE_IFACE, ifname,
+	                     NM_SUPPLICANT_INTERFACE_IS_WIRELESS, is_wireless,
+	                     NM_SUPPLICANT_INTERFACE_FAST_SUPPORTED, fast_supported,
+	                     NM_SUPPLICANT_INTERFACE_AP_SUPPORT, (int) ap_support,
+	                     NULL);
 }
 
 static void
@@ -1468,7 +1479,30 @@ set_property (GObject *object,
               const GValue *value,
               GParamSpec *pspec)
 {
-	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_IFACE:
+		/* construct-only */
+		priv->dev = g_value_dup_string (value);
+		g_return_if_fail (priv->dev);
+		break;
+	case PROP_IS_WIRELESS:
+		/* construct-only */
+		priv->is_wireless = g_value_get_boolean (value);
+		break;
+	case PROP_FAST_SUPPORTED:
+		/* construct-only */
+		priv->fast_supported = g_value_get_boolean (value);
+		break;
+	case PROP_AP_SUPPORT:
+		/* construct-only */
+		priv->ap_support = g_value_get_int (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -1535,19 +1569,44 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 	object_class->get_property = get_property;
 
 	/* Properties */
-	g_object_class_install_property
-		(object_class, PROP_SCANNING,
-		 g_param_spec_boolean ("scanning", "", "",
-		                       FALSE,
-		                       G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_CURRENT_BSS,
-		 g_param_spec_string (NM_SUPPLICANT_INTERFACE_CURRENT_BSS, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SCANNING] =
+	    g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_SCANNING, "", "",
+	                          FALSE,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_CURRENT_BSS] =
+	    g_param_spec_string (NM_SUPPLICANT_INTERFACE_CURRENT_BSS, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_IFACE] =
+	    g_param_spec_string (NM_SUPPLICANT_INTERFACE_IFACE, "", "",
+	                         NULL,
+	                         G_PARAM_WRITABLE |
+	                         G_PARAM_CONSTRUCT_ONLY |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_IS_WIRELESS] =
+	    g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_IS_WIRELESS, "", "",
+	                          TRUE,
+	                          G_PARAM_WRITABLE |
+	                          G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_FAST_SUPPORTED] =
+	    g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_FAST_SUPPORTED, "", "",
+	                          TRUE,
+	                          G_PARAM_WRITABLE |
+	                          G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_AP_SUPPORT] =
+	    g_param_spec_int (NM_SUPPLICANT_INTERFACE_AP_SUPPORT, "", "",
+	                      NM_SUPPLICANT_FEATURE_UNKNOWN,
+	                      NM_SUPPLICANT_FEATURE_YES,
+	                      NM_SUPPLICANT_FEATURE_UNKNOWN,
+	                      G_PARAM_WRITABLE |
+	                      G_PARAM_CONSTRUCT_ONLY |
+	                      G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	/* Signals */
 	signals[STATE] =
diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h
index 2f866076..dbe77b1c 100644
--- a/src/supplicant-manager/nm-supplicant-interface.h
+++ b/src/supplicant-manager/nm-supplicant-interface.h
@@ -55,7 +55,12 @@ enum {
 #define NM_SUPPLICANT_INTERFACE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass))
 
 /* Properties */
+#define NM_SUPPLICANT_INTERFACE_IFACE            "iface"
+#define NM_SUPPLICANT_INTERFACE_SCANNING         "scanning"
 #define NM_SUPPLICANT_INTERFACE_CURRENT_BSS      "current-bss"
+#define NM_SUPPLICANT_INTERFACE_IS_WIRELESS      "is-wireless"
+#define NM_SUPPLICANT_INTERFACE_FAST_SUPPORTED   "fast-supported"
+#define NM_SUPPLICANT_INTERFACE_AP_SUPPORT       "ap-support"
 
 /* Signals */
 #define NM_SUPPLICANT_INTERFACE_STATE            "state"
@@ -119,8 +124,7 @@ GType nm_supplicant_interface_get_type (void);
 NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname,
                                                      gboolean is_wireless,
                                                      gboolean fast_supported,
-                                                     NMSupplicantFeature ap_support,
-                                                     gboolean start_now);
+                                                     NMSupplicantFeature ap_support);
 
 void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self,
                                                        gboolean available);
@@ -131,8 +135,6 @@ gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface,
 
 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, const GPtrArray *ssids);
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c
index 29c0cd42..1b352527 100644
--- a/src/supplicant-manager/nm-supplicant-manager.c
+++ b/src/supplicant-manager/nm-supplicant-manager.c
@@ -19,11 +19,10 @@
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
-#include "nm-default.h"
 #include "nm-supplicant-manager.h"
 #include "nm-supplicant-interface.h"
 #include "nm-supplicant-types.h"
@@ -40,7 +39,7 @@ typedef struct {
 	GCancellable *   cancellable;
 	gboolean         running;
 
-	GHashTable *      ifaces;
+	GSList          *ifaces;
 	gboolean          fast_supported;
 	NMSupplicantFeature ap_support;
 	guint             die_count_reset_id;
@@ -59,67 +58,40 @@ die_count_exceeded (guint32 count)
 	return count > 2;
 }
 
-NMSupplicantInterface *
-nm_supplicant_manager_iface_get (NMSupplicantManager * self,
-                                 const char *ifname,
-                                 gboolean is_wireless)
+static gboolean
+is_available (NMSupplicantManager *self)
 {
-	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);
-
-	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);
-
-		nm_log_dbg (LOGD_SUPPLICANT, "(%s): creating new supplicant interface", ifname);
-		iface = nm_supplicant_interface_new (ifname,
-		                                     is_wireless,
-		                                     priv->fast_supported,
-		                                     priv->ap_support,
-		                                     start_now);
-		if (iface) {
-			g_hash_table_insert (priv->ifaces,
-			                     (char *) nm_supplicant_interface_get_ifname (iface),
-			                     iface);
-		}
-	} else {
-		nm_log_dbg (LOGD_SUPPLICANT, "(%s): returning existing supplicant interface", ifname);
-	}
+	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
 
-	return iface;
+	return    priv->running
+	       && !die_count_exceeded (priv->die_count);
 }
 
-void
-nm_supplicant_manager_iface_release (NMSupplicantManager *self,
-                                     NMSupplicantInterface *iface)
+/********************************************************************/
+
+static void
+_sup_iface_last_ref (gpointer data,
+                     GObject *object,
+                     gboolean is_last_ref)
 {
+	NMSupplicantManager *self = data;
 	NMSupplicantManagerPrivate *priv;
-	const char *ifname, *op;
+	NMSupplicantInterface *sup_iface = (NMSupplicantInterface *) object;
+	const char *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);
+	g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (sup_iface));
+	g_return_if_fail (is_last_ref);
 
 	priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
 
-	g_return_if_fail (g_hash_table_lookup (priv->ifaces, ifname) == iface);
+	if (!g_slist_find (priv->ifaces, sup_iface))
+		g_return_if_reached ();
 
 	/* Ask wpa_supplicant to remove this interface */
-	op = nm_supplicant_interface_get_object_path (iface);
-	if (priv->running && priv->proxy && op) {
+	if (   priv->running
+	    && priv->proxy
+	    && (op = nm_supplicant_interface_get_object_path (sup_iface))) {
 		g_dbus_proxy_call (priv->proxy,
 		                   "RemoveInterface",
 		                   g_variant_new ("(o)", op),
@@ -130,15 +102,69 @@ nm_supplicant_manager_iface_release (NMSupplicantManager *self,
 		                   NULL);
 	}
 
-	g_hash_table_remove (priv->ifaces, ifname);
+	priv->ifaces = g_slist_remove (priv->ifaces, sup_iface);
+	g_object_remove_toggle_ref ((GObject *) sup_iface, _sup_iface_last_ref, self);
+}
+
+/**
+ * nm_supplicant_manager_create_interface:
+ * @self: the #NMSupplicantManager
+ * @ifname: the interface for which to obtain the supplicant interface
+ * @is_wireless: whether the interface is supposed to be wireless.
+ *
+ * Note: the manager owns a reference to the instance and the only way to
+ *   get the manager to release it, is by dropping all other references
+ *   to the supplicant-interface (or destroying the manager).
+ *
+ * Returns: (transfer full): returns a #NMSupplicantInterface or %NULL.
+ *   Must be unrefed at the end.
+ * */
+NMSupplicantInterface *
+nm_supplicant_manager_create_interface (NMSupplicantManager *self,
+                                        const char *ifname,
+                                        gboolean is_wireless)
+{
+	NMSupplicantManagerPrivate *priv;
+	NMSupplicantInterface *iface;
+	GSList *ifaces;
+
+	g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
+	g_return_val_if_fail (ifname != NULL, NULL);
+
+	priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+
+	nm_log_dbg (LOGD_SUPPLICANT, "(%s): creating new supplicant interface", ifname);
+
+	/* assert against not requesting duplicate interfaces. */
+	for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) {
+		if (g_strcmp0 (nm_supplicant_interface_get_ifname (ifaces->data), ifname) == 0)
+			g_return_val_if_reached (NULL);
+	}
+
+	iface = nm_supplicant_interface_new (ifname,
+	                                     is_wireless,
+	                                     priv->fast_supported,
+	                                     priv->ap_support);
+
+	priv->ifaces = g_slist_prepend (priv->ifaces, iface);
+	g_object_add_toggle_ref ((GObject *) iface, _sup_iface_last_ref, self);
+
+	/* 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.
+	 */
+	if (is_available (self))
+		nm_supplicant_interface_set_supplicant_available (iface, TRUE);
+
+	return iface;
 }
 
 static void
 update_capabilities (NMSupplicantManager *self)
 {
 	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
-	NMSupplicantInterface *iface;
-	GHashTableIter hash_iter;
+	GSList *ifaces;
 	const char **array;
 	GVariant *value;
 
@@ -166,9 +192,8 @@ update_capabilities (NMSupplicantManager *self)
 	}
 
 	/* Tell all interfaces about results of the AP check */
-	g_hash_table_iter_init (&hash_iter, priv->ifaces);
-	while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &iface))
-		nm_supplicant_interface_set_ap_support (iface, priv->ap_support);
+	for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next)
+		nm_supplicant_interface_set_ap_support (ifaces->data, priv->ap_support);
 
 	nm_log_dbg (LOGD_SUPPLICANT, "AP mode is %ssupported",
 	            (priv->ap_support == NM_SUPPLICANT_FEATURE_YES) ? "" :
@@ -194,23 +219,20 @@ static void
 availability_changed (NMSupplicantManager *self, gboolean available)
 {
 	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
-	GList *ifaces, *iter;
-
-	/* priv->ifaces may be modified if availability changes; can't use GHashTableIter */
-	ifaces = g_hash_table_get_values (priv->ifaces);
-	for (iter = ifaces; iter; iter = iter->next)
-		nm_supplicant_interface_set_supplicant_available (NM_SUPPLICANT_INTERFACE (iter->data), available);
-	g_list_free (ifaces);
-}
+	GSList *ifaces, *iter;
 
-static gboolean
-is_available (NMSupplicantManager *self)
-{
-	g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), FALSE);
+	if (!priv->ifaces)
+		return;
 
-	if (die_count_exceeded (NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->die_count))
-		return FALSE;
-	return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->running;
+	/* setting the supplicant as unavailable might cause the caller to unref
+	 * the supplicant (and thus remove the instance from the list of interfaces.
+	 * Delay that by taking an additional reference first. */
+	ifaces = g_slist_copy (priv->ifaces);
+	for (iter = ifaces; iter; iter = iter->next)
+		g_object_ref (iter->data);
+	for (iter = ifaces; iter; iter = iter->next)
+		nm_supplicant_interface_set_supplicant_available (iter->data, available);
+	g_slist_free_full (ifaces, g_object_unref);
 }
 
 static void
@@ -326,8 +348,6 @@ nm_supplicant_manager_init (NMSupplicantManager *self)
 {
 	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
 
-	priv->ifaces = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
-
 	priv->cancellable = g_cancellable_new ();
 	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
 	                          G_DBUS_PROXY_FLAGS_NONE,
@@ -343,7 +363,9 @@ nm_supplicant_manager_init (NMSupplicantManager *self)
 static void
 dispose (GObject *object)
 {
-	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object);
+	NMSupplicantManager *self = (NMSupplicantManager *) object;
+	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+	GSList *ifaces;
 
 	nm_clear_g_source (&priv->die_count_reset_id);
 
@@ -352,7 +374,13 @@ dispose (GObject *object)
 		g_clear_object (&priv->cancellable);
 	}
 
-	g_clear_pointer (&priv->ifaces, g_hash_table_unref);
+	if (priv->ifaces) {
+		for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next)
+			g_object_remove_toggle_ref (ifaces->data, _sup_iface_last_ref, self);
+		g_slist_free (priv->ifaces);
+		priv->ifaces = NULL;
+	}
+
 	g_clear_object (&priv->proxy);
 
 	G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
diff --git a/src/supplicant-manager/nm-supplicant-manager.h b/src/supplicant-manager/nm-supplicant-manager.h
index d7456467..b0ce6a52 100644
--- a/src/supplicant-manager/nm-supplicant-manager.h
+++ b/src/supplicant-manager/nm-supplicant-manager.h
@@ -49,11 +49,8 @@ GType nm_supplicant_manager_get_type (void);
 
 NMSupplicantManager *nm_supplicant_manager_get (void);
 
-NMSupplicantInterface *nm_supplicant_manager_iface_get (NMSupplicantManager *mgr,
-                                                        const char *ifname,
-                                                        gboolean is_wireless);
-
-void nm_supplicant_manager_iface_release (NMSupplicantManager *mgr,
-                                          NMSupplicantInterface *iface);
+NMSupplicantInterface *nm_supplicant_manager_create_interface (NMSupplicantManager *mgr,
+                                                               const char *ifname,
+                                                               gboolean is_wireless);
 
 #endif /* __NETWORKMANAGER_SUPPLICANT_MANAGER_H__ */
diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.c b/src/supplicant-manager/nm-supplicant-settings-verify.c
index f2d56540..ec660d18 100644
--- a/src/supplicant-manager/nm-supplicant-settings-verify.c
+++ b/src/supplicant-manager/nm-supplicant-settings-verify.c
@@ -18,14 +18,13 @@
  * Copyright (C) 2006 - 2012 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
-#include "nm-default.h"
 #include "nm-supplicant-settings-verify.h"
 
 struct Opt {
diff --git a/src/supplicant-manager/tests/test-supplicant-config.c b/src/supplicant-manager/tests/test-supplicant-config.c
index bd532b24..0c3e9a47 100644
--- a/src/supplicant-manager/tests/test-supplicant-config.c
+++ b/src/supplicant-manager/tests/test-supplicant-config.c
@@ -18,7 +18,7 @@
  * Copyright (C) 2008 - 2011 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -34,7 +34,6 @@
 
 #include "nm-supplicant-config.h"
 #include "nm-supplicant-settings-verify.h"
-#include "nm-default.h"
 
 #include "nm-test-utils.h"