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, 200 insertions, 227 deletions
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c index a2cf58eb..8209da21 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 - 2008 Red Hat, Inc. + * Copyright (C) 2006 - 2010 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ @@ -26,19 +26,7 @@ #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, \ @@ -46,298 +34,283 @@ typedef struct { G_DEFINE_TYPE (NMSupplicantManager, nm_supplicant_manager, G_TYPE_OBJECT) +/* Properties */ +enum { + PROP_0 = 0, + PROP_AVAILABLE, + LAST_PROP +}; -static void nm_supplicant_manager_name_owner_changed (NMDBusManager *dbus_mgr, - const char *name, - const char *old, - const char *new, - gpointer user_data); +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_set_state (NMSupplicantManager * self, - guint32 new_state); +/********************************************************************/ -static gboolean nm_supplicant_manager_startup (NMSupplicantManager * self); +static inline gboolean +die_count_exceeded (guint32 count) +{ + return count > 2; +} +NMSupplicantInterface * +nm_supplicant_manager_iface_get (NMSupplicantManager * self, + const char *ifname, + gboolean is_wireless) +{ + NMSupplicantManagerPrivate *priv; + NMSupplicantInterface *iface = NULL; + gboolean start_now; -/* Signals */ -enum { - STATE, /* change in the manager's state */ - LAST_SIGNAL -}; -static guint nm_supplicant_manager_signals[LAST_SIGNAL] = { 0 }; + 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); -NMSupplicantManager * -nm_supplicant_manager_get (void) -{ - static NMSupplicantManager * singleton = NULL; + 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); - if (!singleton) { - singleton = NM_SUPPLICANT_MANAGER (g_object_new (NM_TYPE_SUPPLICANT_MANAGER, 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); } else { - g_object_ref (singleton); + nm_log_dbg (LOGD_SUPPLICANT, "(%s): returning existing supplicant interface", ifname); } - g_assert (singleton); - return singleton; + return iface; } -static gboolean -poke_supplicant_cb (gpointer user_data) +void +nm_supplicant_manager_iface_release (NMSupplicantManager *self, + NMSupplicantInterface *iface) { - 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; - } + NMSupplicantManagerPrivate *priv; + const char *ifname, *op; - 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); + g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (self)); + g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (iface)); -out: - /* Reschedule the poke */ - priv->poke_id = g_timeout_add_seconds (SUPPLICANT_POKE_INTERVAL, - poke_supplicant_cb, - (gpointer) self); + ifname = nm_supplicant_interface_get_ifname (iface); + g_assert (ifname); - return FALSE; -} + priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); -static void -nm_supplicant_manager_init (NMSupplicantManager * self) -{ - NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - gboolean running; + g_return_if_fail (g_hash_table_lookup (priv->ifaces, ifname) == iface); - priv->dispose_has_run = FALSE; - priv->state = NM_SUPPLICANT_MANAGER_STATE_DOWN; - priv->dbus_mgr = nm_dbus_manager_get (); - priv->poke_id = 0; + /* 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); + } - running = nm_supplicant_manager_startup (self); + g_hash_table_remove (priv->ifaces, ifname); +} - g_signal_connect (priv->dbus_mgr, - "name-owner-changed", - G_CALLBACK (nm_supplicant_manager_name_owner_changed), - self); +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); - if (!running) { - /* Try to activate the supplicant */ - priv->poke_id = g_idle_add (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; } static void -nm_supplicant_manager_dispose (GObject *object) +set_running (NMSupplicantManager *self, gboolean now_running) { - 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; - } + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + gboolean old_available = nm_supplicant_manager_available (self); - /* Chain up to the parent class */ - G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object); + priv->running = now_running; + if (old_available != nm_supplicant_manager_available (self)) + g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_AVAILABLE); } static void -nm_supplicant_manager_class_init (NMSupplicantManagerClass *klass) +set_die_count (NMSupplicantManager *self, guint new_die_count) { - GObjectClass * object_class = G_OBJECT_CLASS (klass); + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + gboolean old_available = nm_supplicant_manager_available (self); - g_type_class_add_private (object_class, sizeof (NMSupplicantManagerPrivate)); + priv->die_count = new_die_count; + if (old_available != nm_supplicant_manager_available (self)) + g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_AVAILABLE); +} - 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 gboolean +wpas_die_count_reset_cb (gpointer user_data) +{ + NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data); + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + + /* 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; } static void -nm_supplicant_manager_name_owner_changed (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, - gpointer user_data) +name_owner_changed (NMDBusManager *dbus_mgr, + const char *name, + const char *old_owner, + const char *new_owner, + gpointer user_data) { - NMSupplicantManager * self = (NMSupplicantManager *) user_data; + NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (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)); - /* Can't handle the signal if its not from the supplicant service */ + /* We only care about the supplicant here */ if (strcmp (WPAS_DBUS_SERVICE, name) != 0) return; if (!old_owner_good && new_owner_good) { - gboolean running; - - running = nm_supplicant_manager_startup (self); - - if (running && priv->poke_id) { - g_source_remove (priv->poke_id); - priv->poke_id = 0; - } + nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant started"); + set_running (self, TRUE); } else if (old_owner_good && !new_owner_good) { - nm_supplicant_manager_set_state (self, NM_SUPPLICANT_MANAGER_STATE_DOWN); + nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant stopped"); - if (priv->poke_id) - g_source_remove (priv->poke_id); - - /* Poke the supplicant so that it gets activated by dbus system bus - * activation. + /* 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. */ - priv->poke_id = g_idle_add (poke_supplicant_cb, (gpointer) self); + 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); + } + + set_running (self, FALSE); } } +/*******************************************************************/ -guint32 -nm_supplicant_manager_get_state (NMSupplicantManager * self) +NMSupplicantManager * +nm_supplicant_manager_get (void) { - g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), FALSE); + static NMSupplicantManager *singleton = NULL; - return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->state; + if (!singleton) + singleton = NM_SUPPLICANT_MANAGER (g_object_new (NM_TYPE_SUPPLICANT_MANAGER, NULL)); + else + g_object_ref (singleton); + + g_assert (singleton); + return singleton; } static void -nm_supplicant_manager_set_state (NMSupplicantManager * self, guint32 new_state) +nm_supplicant_manager_init (NMSupplicantManager * self) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - guint32 old_state; - - if (new_state == priv->state) - return; + DBusGConnection *bus; - old_state = priv->state; - priv->state = new_state; - g_signal_emit (self, - nm_supplicant_manager_signals[STATE], - 0, - priv->state, - 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); } -static gboolean -nm_supplicant_manager_startup (NMSupplicantManager * self) +static void +set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - 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; + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } -NMSupplicantInterface * -nm_supplicant_manager_get_iface (NMSupplicantManager * self, - const char *ifname, - gboolean is_wireless) +static void +get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMSupplicantManagerPrivate *priv; - NMSupplicantInterface * iface = NULL; - GSList * elt; + 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; + } +} - g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL); - g_return_val_if_fail (ifname != NULL, NULL); +static void +dispose (GObject *object) +{ + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object); - priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + if (priv->disposed) + goto out; + priv->disposed = TRUE; - /* Ensure we don't already have this interface */ - for (elt = priv->ifaces; elt; elt = g_slist_next (elt)) { - NMSupplicantInterface * if_tmp = (NMSupplicantInterface *) elt->data; + if (priv->die_count_reset_id) + g_source_remove (priv->die_count_reset_id); - if (!strcmp (ifname, nm_supplicant_interface_get_device (if_tmp))) { - iface = if_tmp; - break; - } + 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)); } - 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); - } + g_hash_table_destroy (priv->ifaces); - return iface; + if (priv->proxy) + g_object_unref (priv->proxy); + +out: + /* Chain up to the parent class */ + G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object); } -void -nm_supplicant_manager_release_iface (NMSupplicantManager * self, - NMSupplicantInterface * iface) +static void +nm_supplicant_manager_class_init (NMSupplicantManagerClass *klass) { - NMSupplicantManagerPrivate *priv; - GSList * elt; + GObjectClass *object_class = G_OBJECT_CLASS (klass); - 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); + g_type_class_add_private (object_class, sizeof (NMSupplicantManagerPrivate)); - 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; - } - } -} + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->dispose = dispose; -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"; + g_object_class_install_property (object_class, PROP_AVAILABLE, + g_param_spec_boolean (NM_SUPPLICANT_MANAGER_AVAILABLE, + "Available", + "Available", + FALSE, + G_PARAM_READABLE)); } - |