static gboolean is_available (NMSupplicantManager *self) { g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), FALSE); if (die_count_exceeded (NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->die_count)) return FALSE; return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->running; }
void nm_supplicant_manager_iface_release (NMSupplicantManager *self, NMSupplicantInterface *iface) { 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); } g_hash_table_remove (priv->ifaces, ifname); }
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); 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 (self, ifname, is_wireless, start_now); if (iface) g_hash_table_insert (priv->ifaces, g_strdup (ifname), iface); } else { nm_log_dbg (LOGD_SUPPLICANT, "(%s): returning existing supplicant interface", ifname); } return iface; }
static void dispose (GObject *object) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object); if (priv->disposed) goto out; priv->disposed = TRUE; if (priv->die_count_reset_id) g_source_remove (priv->die_count_reset_id); 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)); } g_hash_table_destroy (priv->ifaces); 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); }
static void dispose (GObject *object) { NMSupplicantManager *self = (NMSupplicantManager *) object; NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); GSList *ifaces; nm_clear_g_source (&priv->die_count_reset_id); if (priv->cancellable) { g_cancellable_cancel (priv->cancellable); g_clear_object (&priv->cancellable); } 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); }
void nm_supplicant_manager_iface_release (NMSupplicantManager *self, NMSupplicantInterface *iface) { 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) { g_dbus_proxy_call (priv->proxy, "RemoveInterface", g_variant_new ("(o)", op), G_DBUS_CALL_FLAGS_NONE, 3000, NULL, NULL, NULL); } g_hash_table_remove (priv->ifaces, ifname); }
static gboolean is_available (NMSupplicantManager *self) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); return priv->running && !die_count_exceeded (priv->die_count); }
static void update_capabilities (NMSupplicantManager *self) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); NMSupplicantInterface *iface; GHashTableIter hash_iter; const char **array; GVariant *value; /* The supplicant only advertises global capabilities if the following * commit has been applied: * * commit 1634ac0654eba8d458640a115efc0a6cde3bac4d * Author: Dan Williams <*****@*****.**> * Date: Sat Sep 29 19:06:30 2012 +0300 * * dbus: Add global capabilities property */ priv->ap_support = AP_SUPPORT_UNKNOWN; value = g_dbus_proxy_get_cached_property (priv->proxy, "Capabilities"); if (value) { if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY)) { array = g_variant_get_strv (value, NULL); priv->ap_support = AP_SUPPORT_NO; if (_nm_utils_string_in_list ("ap", array)) priv->ap_support = AP_SUPPORT_YES; g_free (array); } g_variant_unref (value); } /* 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); nm_log_dbg (LOGD_SUPPLICANT, "AP mode is %ssupported", (priv->ap_support == AP_SUPPORT_YES) ? "" : (priv->ap_support == AP_SUPPORT_NO) ? "not " : "possibly "); /* EAP-FAST */ priv->fast_supported = FALSE; value = g_dbus_proxy_get_cached_property (priv->proxy, "EapMethods"); if (value) { if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY)) { array = g_variant_get_strv (value, NULL); if (_nm_utils_string_in_list ("fast", array)) priv->fast_supported = TRUE; g_free (array); } g_variant_unref (value); } nm_log_dbg (LOGD_SUPPLICANT, "EAP-FAST is %ssupported", priv->fast_supported ? "" : "not "); }
static void set_running (NMSupplicantManager *self, gboolean now_running) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); gboolean old_available = nm_supplicant_manager_available (self); priv->running = now_running; if (old_available != nm_supplicant_manager_available (self)) g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_AVAILABLE); }
static void set_die_count (NMSupplicantManager *self, guint new_die_count) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); gboolean old_available = nm_supplicant_manager_available (self); priv->die_count = new_die_count; if (old_available != nm_supplicant_manager_available (self)) g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_AVAILABLE); }
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 set_die_count (NMSupplicantManager *self, guint new_die_count) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); gboolean old_available = is_available (self); gboolean new_available; priv->die_count = new_die_count; new_available = is_available (self); if (old_available != new_available) availability_changed (self, new_available); }
static void set_running (NMSupplicantManager *self, gboolean now_running) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); gboolean old_available = is_available (self); gboolean new_available; priv->running = now_running; new_available = is_available (self); if (old_available != new_available) availability_changed (self, new_available); }
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); }
static void nm_supplicant_manager_init (NMSupplicantManager *self) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); priv->cancellable = g_cancellable_new (); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, WPAS_DBUS_SERVICE, WPAS_DBUS_PATH, WPAS_DBUS_INTERFACE, priv->cancellable, (GAsyncReadyCallback) on_proxy_acquired, self); }
static void availability_changed (NMSupplicantManager *self, gboolean available) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); GSList *ifaces, *iter; if (!priv->ifaces) return; /* 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 dispose (GObject *object) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object); if (priv->die_count_reset_id) { g_source_remove (priv->die_count_reset_id); priv->die_count_reset_id = 0; } if (priv->cancellable) { g_cancellable_cancel (priv->cancellable); g_clear_object (&priv->cancellable); } g_clear_pointer (&priv->ifaces, g_hash_table_unref); g_clear_object (&priv->proxy); G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object); }
static void 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); 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 */ 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"); /* 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); } set_running (self, FALSE); } }
static void nm_supplicant_manager_init (NMSupplicantManager * self) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); DBusGConnection *bus; 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); }
/** * 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). * * Retruns: (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 name_owner_cb (GDBusProxy *proxy, GParamSpec *pspec, gpointer user_data) { NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data); NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); char *owner; g_return_if_fail (proxy == priv->proxy); owner = g_dbus_proxy_get_name_owner (proxy); nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant %s", owner ? "running" : "stopped"); if (owner) { set_running (self, TRUE); update_capabilities (self); } else if (priv->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); } set_running (self, FALSE); priv->fast_supported = FALSE; } g_free (owner); }
static void _sup_iface_last_ref (gpointer data, GObject *object, gboolean is_last_ref) { NMSupplicantManager *self = data; NMSupplicantManagerPrivate *priv; 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 (sup_iface)); g_return_if_fail (is_last_ref); priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); if (!g_slist_find (priv->ifaces, sup_iface)) g_return_if_reached (); /* Ask wpa_supplicant to remove this interface */ 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), G_DBUS_CALL_FLAGS_NONE, 3000, NULL, NULL, NULL); } priv->ifaces = g_slist_remove (priv->ifaces, sup_iface); g_object_remove_toggle_ref ((GObject *) sup_iface, _sup_iface_last_ref, self); }
static void on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data) { NMSupplicantManager *self; NMSupplicantManagerPrivate *priv; GError *error = NULL; GDBusProxy *proxy; proxy = g_dbus_proxy_new_for_bus_finish (result, &error); if (!proxy) { nm_log_warn (LOGD_SUPPLICANT, "Failed to acquire wpa_supplicant proxy: Wi-Fi and 802.1x will not be available (%s)", error->message); g_clear_error (&error); return; } self = NM_SUPPLICANT_MANAGER (user_data); priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); priv->proxy = proxy; g_signal_connect (priv->proxy, "notify::g-name-owner", G_CALLBACK (name_owner_cb), self); name_owner_cb (priv->proxy, NULL, self); }