summaryrefslogtreecommitdiff
path: root/src/supplicant-manager/nm-supplicant-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/supplicant-manager/nm-supplicant-manager.c')
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.c427
1 files changed, 227 insertions, 200 deletions
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c
index 8209da21d..a2cf58eb8 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";
}
+