diff options
Diffstat (limited to 'src/supplicant-manager/nm-supplicant-manager.c')
-rw-r--r-- | src/supplicant-manager/nm-supplicant-manager.c | 427 |
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"; } + |