From b15fb8641e26eb63c2d83d9dcc9510705086e2f2 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 9 May 2013 10:24:08 -0400 Subject: [PATCH] core: split NMRfkillManager out of NMUdevManager Split the rfkill-monitoring parts of NMUdevManager into a separate class. Now NMUdevManager only handles device enumeration. --- src/Makefile.am | 3 +- src/devices/nm-device-modem.c | 2 +- src/devices/nm-device-wifi.h | 2 +- src/devices/nm-device.c | 2 +- src/devices/nm-device.h | 2 +- src/devices/wimax/nm-device-wimax.c | 2 +- src/nm-manager.c | 20 +- src/nm-rfkill-manager.c | 422 +++++++++++++++++++++++ src/{nm-rfkill.h => nm-rfkill-manager.h} | 35 +- src/nm-udev-manager.c | 342 +----------------- src/nm-udev-manager.h | 8 +- 11 files changed, 479 insertions(+), 361 deletions(-) create mode 100644 src/nm-rfkill-manager.c rename src/{nm-rfkill.h => nm-rfkill-manager.h} (51%) diff --git a/src/Makefile.am b/src/Makefile.am index a3ca443af9..ba0408f7d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -243,7 +243,8 @@ nm_sources = \ nm-policy.h \ nm-properties-changed-signal.c \ nm-properties-changed-signal.h \ - nm-rfkill.h \ + nm-rfkill-manager.c \ + nm-rfkill-manager.h \ nm-session-monitor.h \ nm-session-utils.c \ nm-session-utils.h \ diff --git a/src/devices/nm-device-modem.c b/src/devices/nm-device-modem.c index 72cef2b390..727e6f9e48 100644 --- a/src/devices/nm-device-modem.c +++ b/src/devices/nm-device-modem.c @@ -26,7 +26,7 @@ #include "nm-modem.h" #include "nm-modem-old.h" #include "nm-device-private.h" -#include "nm-rfkill.h" +#include "nm-rfkill-manager.h" #include "nm-logging.h" #include "nm-system.h" #include "nm-dbus-manager.h" diff --git a/src/devices/nm-device-wifi.h b/src/devices/nm-device-wifi.h index 5731ac203b..0326fa98fd 100644 --- a/src/devices/nm-device-wifi.h +++ b/src/devices/nm-device-wifi.h @@ -26,7 +26,7 @@ #include #include -#include "nm-rfkill.h" +#include "nm-rfkill-manager.h" #include "nm-device.h" #include "nm-wifi-ap.h" diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5c63da404a..28295d486e 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -55,7 +55,7 @@ #include "nm-dnsmasq-manager.h" #include "nm-dhcp4-config.h" #include "nm-ip6-manager.h" -#include "nm-rfkill.h" +#include "nm-rfkill-manager.h" #include "nm-firewall-manager.h" #include "nm-properties-changed-signal.h" #include "nm-enum-types.h" diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index fd9b79379d..c2f6344978 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -34,7 +34,7 @@ #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" #include "nm-connection.h" -#include "nm-rfkill.h" +#include "nm-rfkill-manager.h" #include "nm-connection-provider.h" /* Properties */ diff --git a/src/devices/wimax/nm-device-wimax.c b/src/devices/wimax/nm-device-wimax.c index 565fa2b569..c055578be7 100644 --- a/src/devices/wimax/nm-device-wimax.c +++ b/src/devices/wimax/nm-device-wimax.c @@ -42,7 +42,7 @@ #include "nm-setting-connection.h" #include "nm-setting-wimax.h" #include "nm-utils.h" -#include "nm-rfkill.h" +#include "nm-rfkill-manager.h" #include "iwmxsdk.h" #include "nm-enum-types.h" diff --git a/src/nm-manager.c b/src/nm-manager.c index 0bef71540e..b98b66e7e8 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -64,6 +64,7 @@ #include "nm-dbus-glib-types.h" #include "nm-platform.h" #include "nm-udev-manager.h" +#include "nm-rfkill-manager.h" #include "nm-hostname-provider.h" #include "nm-bluez-manager.h" #include "nm-bluez-common.h" @@ -223,6 +224,7 @@ typedef struct { NMDBusManager *dbus_mgr; guint dbus_connection_changed_id; NMUdevManager *udev_mgr; + NMRfkillManager *rfkill_mgr; NMBluezManager *bluez_mgr; /* List of NMDeviceFactoryFunc pointers sorted in priority order */ @@ -1641,7 +1643,7 @@ manager_rfkill_update_one_type (NMManager *self, old_rfkilled = rstate->hw_enabled && rstate->sw_enabled; old_hwe = rstate->hw_enabled; - udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, rtype); + udev_state = nm_rfkill_manager_get_rfkill_state (priv->rfkill_mgr, rtype); if (rstate->other_enabled_func) other_state = rstate->other_enabled_func (self); @@ -2360,10 +2362,10 @@ udev_device_removed_cb (NMUdevManager *manager, } static void -udev_manager_rfkill_changed_cb (NMUdevManager *udev_mgr, - RfKillType rtype, - RfKillState udev_state, - gpointer user_data) +rfkill_manager_rfkill_changed_cb (NMRfkillManager *rfkill_mgr, + RfKillType rtype, + RfKillState udev_state, + gpointer user_data) { nm_manager_rfkill_update (NM_MANAGER (user_data), rtype); } @@ -3713,7 +3715,7 @@ nm_manager_start (NMManager *self) if (!rstate->desc) continue; - udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, i); + udev_state = nm_rfkill_manager_get_rfkill_state (priv->rfkill_mgr, i); update_rstate_from_rfkill (rstate, udev_state); if (rstate->desc) { @@ -4070,9 +4072,11 @@ nm_manager_new (NMSettings *settings, "device-removed", G_CALLBACK (udev_device_removed_cb), singleton); - g_signal_connect (priv->udev_mgr, + + priv->rfkill_mgr = nm_rfkill_manager_new (); + g_signal_connect (priv->rfkill_mgr, "rfkill-changed", - G_CALLBACK (udev_manager_rfkill_changed_cb), + G_CALLBACK (rfkill_manager_rfkill_changed_cb), singleton); priv->bluez_mgr = nm_bluez_manager_get (NM_CONNECTION_PROVIDER (priv->settings)); diff --git a/src/nm-rfkill-manager.c b/src/nm-rfkill-manager.c new file mode 100644 index 0000000000..b02f85f549 --- /dev/null +++ b/src/nm-rfkill-manager.c @@ -0,0 +1,422 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2009 - 2013 Red Hat, Inc. + */ + +#include + +#include +#include + +#include "nm-rfkill-manager.h" +#include "nm-logging.h" + +typedef struct { + GUdevClient *client; + + /* Authoritative rfkill state (RFKILL_* enum) */ + RfKillState rfkill_states[RFKILL_TYPE_MAX]; + GSList *killswitches; + +} NMRfkillManagerPrivate; + +#define NM_RFKILL_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_RFKILL_MANAGER, NMRfkillManagerPrivate)) + +G_DEFINE_TYPE (NMRfkillManager, nm_rfkill_manager, G_TYPE_OBJECT) + +enum { + RFKILL_CHANGED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + + +typedef struct { + char *name; + guint64 seqnum; + char *path; + char *driver; + RfKillType rtype; + gint state; + gboolean platform; +} Killswitch; + +RfKillState +nm_rfkill_manager_get_rfkill_state (NMRfkillManager *self, RfKillType rtype) +{ + g_return_val_if_fail (self != NULL, RFKILL_UNBLOCKED); + g_return_val_if_fail (rtype < RFKILL_TYPE_MAX, RFKILL_UNBLOCKED); + + return NM_RFKILL_MANAGER_GET_PRIVATE (self)->rfkill_states[rtype]; +} + +static const char * +rfkill_type_to_desc (RfKillType rtype) +{ + if (rtype == 0) + return "WiFi"; + else if (rtype == 1) + return "WWAN"; + else if (rtype == 2) + return "WiMAX"; + return "unknown"; +} + +static const char * +rfkill_state_to_desc (RfKillState rstate) +{ + if (rstate == 0) + return "unblocked"; + else if (rstate == 1) + return "soft-blocked"; + else if (rstate == 2) + return "hard-blocked"; + return "unknown"; +} + +static Killswitch * +killswitch_new (GUdevDevice *device, RfKillType rtype) +{ + Killswitch *ks; + GUdevDevice *parent = NULL, *grandparent = NULL; + const char *driver, *subsys, *parent_subsys = NULL; + + ks = g_malloc0 (sizeof (Killswitch)); + ks->name = g_strdup (g_udev_device_get_name (device)); + ks->seqnum = g_udev_device_get_seqnum (device); + ks->path = g_strdup (g_udev_device_get_sysfs_path (device)); + ks->rtype = rtype; + + driver = g_udev_device_get_property (device, "DRIVER"); + subsys = g_udev_device_get_subsystem (device); + + /* Check parent for various attributes */ + parent = g_udev_device_get_parent (device); + if (parent) { + parent_subsys = g_udev_device_get_subsystem (parent); + if (!driver) + driver = g_udev_device_get_property (parent, "DRIVER"); + if (!driver) { + /* Sigh; try the grandparent */ + grandparent = g_udev_device_get_parent (parent); + if (grandparent) + driver = g_udev_device_get_property (grandparent, "DRIVER"); + } + } + + if (!driver) + driver = "(unknown)"; + ks->driver = g_strdup (driver); + + if ( g_strcmp0 (subsys, "platform") == 0 + || g_strcmp0 (parent_subsys, "platform") == 0 + || g_strcmp0 (subsys, "acpi") == 0 + || g_strcmp0 (parent_subsys, "acpi") == 0) + ks->platform = TRUE; + + if (grandparent) + g_object_unref (grandparent); + if (parent) + g_object_unref (parent); + return ks; +} + +static void +killswitch_destroy (Killswitch *ks) +{ + g_return_if_fail (ks != NULL); + + g_free (ks->name); + g_free (ks->path); + g_free (ks->driver); + memset (ks, 0, sizeof (Killswitch)); + g_free (ks); +} + +NMRfkillManager * +nm_rfkill_manager_new (void) +{ + return NM_RFKILL_MANAGER (g_object_new (NM_TYPE_RFKILL_MANAGER, NULL)); +} + +static RfKillState +sysfs_state_to_nm_state (gint sysfs_state) +{ + switch (sysfs_state) { + case 0: + return RFKILL_SOFT_BLOCKED; + case 1: + return RFKILL_UNBLOCKED; + case 2: + return RFKILL_HARD_BLOCKED; + default: + nm_log_warn (LOGD_RFKILL, "unhandled rfkill state %d", sysfs_state); + break; + } + return RFKILL_UNBLOCKED; +} + +static void +recheck_killswitches (NMRfkillManager *self) +{ + NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); + GSList *iter; + RfKillState poll_states[RFKILL_TYPE_MAX]; + RfKillState platform_states[RFKILL_TYPE_MAX]; + gboolean platform_checked[RFKILL_TYPE_MAX]; + int i; + + /* Default state is unblocked */ + for (i = 0; i < RFKILL_TYPE_MAX; i++) { + poll_states[i] = RFKILL_UNBLOCKED; + platform_states[i] = RFKILL_UNBLOCKED; + platform_checked[i] = FALSE; + } + + /* Poll the states of all killswitches */ + for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) { + Killswitch *ks = iter->data; + GUdevDevice *device; + RfKillState dev_state; + int sysfs_state; + + device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name); + if (device) { + sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE"); + dev_state = sysfs_state_to_nm_state (sysfs_state); + + nm_log_dbg (LOGD_RFKILL, "%s rfkill%s switch %s state now %d/%u", + rfkill_type_to_desc (ks->rtype), + ks->platform ? " platform" : "", + ks->name, + sysfs_state, + dev_state); + + if (ks->platform == FALSE) { + if (dev_state > poll_states[ks->rtype]) + poll_states[ks->rtype] = dev_state; + } else { + platform_checked[ks->rtype] = TRUE; + if (dev_state > platform_states[ks->rtype]) + platform_states[ks->rtype] = dev_state; + } + g_object_unref (device); + } + } + + /* Log and emit change signal for final rfkill states */ + for (i = 0; i < RFKILL_TYPE_MAX; i++) { + if (platform_checked[i] == TRUE) { + /* blocked platform switch state overrides device state, otherwise + * let the device state stand. (bgo #655773) + */ + if (platform_states[i] != RFKILL_UNBLOCKED) + poll_states[i] = platform_states[i]; + } + + if (poll_states[i] != priv->rfkill_states[i]) { + nm_log_dbg (LOGD_RFKILL, "%s rfkill state now '%s'", + rfkill_type_to_desc (i), + rfkill_state_to_desc (poll_states[i])); + + priv->rfkill_states[i] = poll_states[i]; + g_signal_emit (self, signals[RFKILL_CHANGED], 0, i, priv->rfkill_states[i]); + } + } +} + +static Killswitch * +killswitch_find_by_name (NMRfkillManager *self, const char *name) +{ + NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); + GSList *iter; + + g_return_val_if_fail (name != NULL, NULL); + + for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) { + Killswitch *candidate = iter->data; + + if (!strcmp (name, candidate->name)) + return candidate; + } + return NULL; +} + +static const RfKillType +rfkill_type_to_enum (const char *str) +{ + g_return_val_if_fail (str != NULL, RFKILL_TYPE_UNKNOWN); + + if (!strcmp (str, "wlan")) + return RFKILL_TYPE_WLAN; + else if (!strcmp (str, "wwan")) + return RFKILL_TYPE_WWAN; + else if (!strcmp (str, "wimax")) + return RFKILL_TYPE_WIMAX; + + return RFKILL_TYPE_UNKNOWN; +} + +static void +add_one_killswitch (NMRfkillManager *self, GUdevDevice *device) +{ + NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); + const char *str_type; + RfKillType rtype; + Killswitch *ks; + + str_type = g_udev_device_get_property (device, "RFKILL_TYPE"); + rtype = rfkill_type_to_enum (str_type); + if (rtype == RFKILL_TYPE_UNKNOWN) + return; + + ks = killswitch_new (device, rtype); + priv->killswitches = g_slist_prepend (priv->killswitches, ks); + + nm_log_info (LOGD_RFKILL, "%s: found %s radio killswitch (at %s) (%sdriver %s)", + ks->name, + rfkill_type_to_desc (rtype), + ks->path, + ks->platform ? "platform " : "", + ks->driver ? ks->driver : ""); +} + +static void +rfkill_add (NMRfkillManager *self, GUdevDevice *device) +{ + const char *name; + + g_return_if_fail (device != NULL); + name = g_udev_device_get_name (device); + g_return_if_fail (name != NULL); + + if (!killswitch_find_by_name (self, name)) + add_one_killswitch (self, device); +} + +static void +rfkill_remove (NMRfkillManager *self, + GUdevDevice *device) +{ + NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); + GSList *iter; + const char *name; + + g_return_if_fail (device != NULL); + name = g_udev_device_get_name (device); + g_return_if_fail (name != NULL); + + for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) { + Killswitch *ks = iter->data; + + if (!strcmp (ks->name, name)) { + nm_log_info (LOGD_RFKILL, "radio killswitch %s disappeared", ks->path); + priv->killswitches = g_slist_remove (priv->killswitches, ks); + killswitch_destroy (ks); + break; + } + } +} + +static void +handle_uevent (GUdevClient *client, + const char *action, + GUdevDevice *device, + gpointer user_data) +{ + NMRfkillManager *self = NM_RFKILL_MANAGER (user_data); + const char *subsys; + + g_return_if_fail (action != NULL); + + /* A bit paranoid */ + subsys = g_udev_device_get_subsystem (device); + g_return_if_fail (!g_strcmp0 (subsys, "rfkill")); + + nm_log_dbg (LOGD_HW, "udev rfkill event: action '%s' device '%s'", + action, g_udev_device_get_name (device)); + + if (!strcmp (action, "add")) + rfkill_add (self, device); + else if (!strcmp (action, "remove")) + rfkill_remove (self, device); + + recheck_killswitches (self); +} + +static void +nm_rfkill_manager_init (NMRfkillManager *self) +{ + NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); + const char *subsys[] = { "rfkill", NULL }; + GList *switches, *iter; + guint32 i; + + for (i = 0; i < RFKILL_TYPE_MAX; i++) + priv->rfkill_states[i] = RFKILL_UNBLOCKED; + + priv->client = g_udev_client_new (subsys); + g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); + + switches = g_udev_client_query_by_subsystem (priv->client, "rfkill"); + for (iter = switches; iter; iter = g_list_next (iter)) { + add_one_killswitch (self, G_UDEV_DEVICE (iter->data)); + g_object_unref (G_UDEV_DEVICE (iter->data)); + } + g_list_free (switches); + + recheck_killswitches (self); +} + +static void +dispose (GObject *object) +{ + NMRfkillManager *self = NM_RFKILL_MANAGER (object); + NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->client); + + if (priv->killswitches) { + g_slist_free_full (priv->killswitches, (GDestroyNotify) killswitch_destroy); + priv->killswitches = NULL; + } + + G_OBJECT_CLASS (nm_rfkill_manager_parent_class)->dispose (object); +} + +static void +nm_rfkill_manager_class_init (NMRfkillManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMRfkillManagerPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; + + /* Signals */ + signals[RFKILL_CHANGED] = + g_signal_new ("rfkill-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMRfkillManagerClass, rfkill_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); +} diff --git a/src/nm-rfkill.h b/src/nm-rfkill-manager.h similarity index 51% rename from src/nm-rfkill.h rename to src/nm-rfkill-manager.h index d3cd77744b..b26261b83f 100644 --- a/src/nm-rfkill.h +++ b/src/nm-rfkill-manager.h @@ -16,11 +16,13 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2013 Red Hat, Inc. */ -#ifndef NM_RFKILL_H -#define NM_RFKILL_H +#include + +#ifndef NM_RFKILL_MANAGER_H +#define NM_RFKILL_MANAGER_H typedef enum { RFKILL_UNBLOCKED = 0, @@ -41,5 +43,30 @@ typedef enum { RFKILL_TYPE_MAX = RFKILL_TYPE_UNKNOWN } RfKillType; -#endif /* NM_RFKILL_H */ + +#define NM_TYPE_RFKILL_MANAGER (nm_rfkill_manager_get_type ()) +#define NM_RFKILL_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_RFKILL_MANAGER, NMRfkillManager)) +#define NM_RFKILL_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_RFKILL_MANAGER, NMRfkillManagerClass)) +#define NM_IS_RFKILL_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_RFKILL_MANAGER)) +#define NM_IS_RFKILL_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_RFKILL_MANAGER)) +#define NM_RFKILL_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_RFKILL_MANAGER, NMRfkillManagerClass)) + +typedef struct { + GObject parent; +} NMRfkillManager; + +typedef struct { + GObjectClass parent; + + /* signals */ + void (*rfkill_changed) (NMRfkillManager *manager, RfKillType rtype, RfKillState state); +} NMRfkillManagerClass; + +GType nm_rfkill_manager_get_type (void); + +NMRfkillManager *nm_rfkill_manager_new (void); + +RfKillState nm_rfkill_manager_get_rfkill_state (NMRfkillManager *manager, RfKillType rtype); + +#endif /* NM_RFKILL_MANAGER_H */ diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c index 5759394c7e..93739e8dba 100644 --- a/src/nm-udev-manager.c +++ b/src/nm-udev-manager.c @@ -15,15 +15,11 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2009 - 2012 Red Hat, Inc. + * Copyright (C) 2009 - 2013 Red Hat, Inc. */ #include -#include -#include - -#include #include #include "nm-udev-manager.h" @@ -34,11 +30,6 @@ typedef struct { GUdevClient *client; - /* Authoritative rfkill state (RFKILL_* enum) */ - RfKillState rfkill_states[RFKILL_TYPE_MAX]; - GSList *killswitches; - - gboolean disposed; } NMUdevManagerPrivate; #define NM_UDEV_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_UDEV_MANAGER, NMUdevManagerPrivate)) @@ -48,301 +39,18 @@ G_DEFINE_TYPE (NMUdevManager, nm_udev_manager, G_TYPE_OBJECT) enum { DEVICE_ADDED, DEVICE_REMOVED, - RFKILL_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct { - char *name; - guint64 seqnum; - char *path; - char *driver; - RfKillType rtype; - gint state; - gboolean platform; -} Killswitch; - -RfKillState -nm_udev_manager_get_rfkill_state (NMUdevManager *self, RfKillType rtype) -{ - g_return_val_if_fail (self != NULL, RFKILL_UNBLOCKED); - g_return_val_if_fail (rtype < RFKILL_TYPE_MAX, RFKILL_UNBLOCKED); - - return NM_UDEV_MANAGER_GET_PRIVATE (self)->rfkill_states[rtype]; -} - -static const char * -rfkill_type_to_desc (RfKillType rtype) -{ - if (rtype == 0) - return "WiFi"; - else if (rtype == 1) - return "WWAN"; - else if (rtype == 2) - return "WiMAX"; - return "unknown"; -} - -static const char * -rfkill_state_to_desc (RfKillState rstate) -{ - if (rstate == 0) - return "unblocked"; - else if (rstate == 1) - return "soft-blocked"; - else if (rstate == 2) - return "hard-blocked"; - return "unknown"; -} - -static Killswitch * -killswitch_new (GUdevDevice *device, RfKillType rtype) -{ - Killswitch *ks; - GUdevDevice *parent = NULL, *grandparent = NULL; - const char *driver, *subsys, *parent_subsys = NULL; - - ks = g_malloc0 (sizeof (Killswitch)); - ks->name = g_strdup (g_udev_device_get_name (device)); - ks->seqnum = g_udev_device_get_seqnum (device); - ks->path = g_strdup (g_udev_device_get_sysfs_path (device)); - ks->rtype = rtype; - - driver = g_udev_device_get_property (device, "DRIVER"); - subsys = g_udev_device_get_subsystem (device); - - /* Check parent for various attributes */ - parent = g_udev_device_get_parent (device); - if (parent) { - parent_subsys = g_udev_device_get_subsystem (parent); - if (!driver) - driver = g_udev_device_get_property (parent, "DRIVER"); - if (!driver) { - /* Sigh; try the grandparent */ - grandparent = g_udev_device_get_parent (parent); - if (grandparent) - driver = g_udev_device_get_property (grandparent, "DRIVER"); - } - } - - if (!driver) - driver = "(unknown)"; - ks->driver = g_strdup (driver); - - if ( g_strcmp0 (subsys, "platform") == 0 - || g_strcmp0 (parent_subsys, "platform") == 0 - || g_strcmp0 (subsys, "acpi") == 0 - || g_strcmp0 (parent_subsys, "acpi") == 0) - ks->platform = TRUE; - - if (grandparent) - g_object_unref (grandparent); - if (parent) - g_object_unref (parent); - return ks; -} - -static void -killswitch_destroy (Killswitch *ks) -{ - g_return_if_fail (ks != NULL); - - g_free (ks->name); - g_free (ks->path); - g_free (ks->driver); - memset (ks, 0, sizeof (Killswitch)); - g_free (ks); -} - NMUdevManager * nm_udev_manager_new (void) { return NM_UDEV_MANAGER (g_object_new (NM_TYPE_UDEV_MANAGER, NULL)); } -static RfKillState -sysfs_state_to_nm_state (gint sysfs_state) -{ - switch (sysfs_state) { - case 0: - return RFKILL_SOFT_BLOCKED; - case 1: - return RFKILL_UNBLOCKED; - case 2: - return RFKILL_HARD_BLOCKED; - default: - nm_log_warn (LOGD_RFKILL, "unhandled rfkill state %d", sysfs_state); - break; - } - return RFKILL_UNBLOCKED; -} - -static void -recheck_killswitches (NMUdevManager *self) -{ - NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self); - GSList *iter; - RfKillState poll_states[RFKILL_TYPE_MAX]; - RfKillState platform_states[RFKILL_TYPE_MAX]; - gboolean platform_checked[RFKILL_TYPE_MAX]; - int i; - - /* Default state is unblocked */ - for (i = 0; i < RFKILL_TYPE_MAX; i++) { - poll_states[i] = RFKILL_UNBLOCKED; - platform_states[i] = RFKILL_UNBLOCKED; - platform_checked[i] = FALSE; - } - - /* Poll the states of all killswitches */ - for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) { - Killswitch *ks = iter->data; - GUdevDevice *device; - RfKillState dev_state; - int sysfs_state; - - device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name); - if (device) { - sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE"); - dev_state = sysfs_state_to_nm_state (sysfs_state); - - nm_log_dbg (LOGD_RFKILL, "%s rfkill%s switch %s state now %d/%u", - rfkill_type_to_desc (ks->rtype), - ks->platform ? " platform" : "", - ks->name, - sysfs_state, - dev_state); - - if (ks->platform == FALSE) { - if (dev_state > poll_states[ks->rtype]) - poll_states[ks->rtype] = dev_state; - } else { - platform_checked[ks->rtype] = TRUE; - if (dev_state > platform_states[ks->rtype]) - platform_states[ks->rtype] = dev_state; - } - g_object_unref (device); - } - } - - /* Log and emit change signal for final rfkill states */ - for (i = 0; i < RFKILL_TYPE_MAX; i++) { - if (platform_checked[i] == TRUE) { - /* blocked platform switch state overrides device state, otherwise - * let the device state stand. (bgo #655773) - */ - if (platform_states[i] != RFKILL_UNBLOCKED) - poll_states[i] = platform_states[i]; - } - - if (poll_states[i] != priv->rfkill_states[i]) { - nm_log_dbg (LOGD_RFKILL, "%s rfkill state now '%s'", - rfkill_type_to_desc (i), - rfkill_state_to_desc (poll_states[i])); - - priv->rfkill_states[i] = poll_states[i]; - g_signal_emit (self, signals[RFKILL_CHANGED], 0, i, priv->rfkill_states[i]); - } - } -} - -static Killswitch * -killswitch_find_by_name (NMUdevManager *self, const char *name) -{ - NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self); - GSList *iter; - - g_return_val_if_fail (name != NULL, NULL); - - for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) { - Killswitch *candidate = iter->data; - - if (!strcmp (name, candidate->name)) - return candidate; - } - return NULL; -} - -static const RfKillType -rfkill_type_to_enum (const char *str) -{ - g_return_val_if_fail (str != NULL, RFKILL_TYPE_UNKNOWN); - - if (!strcmp (str, "wlan")) - return RFKILL_TYPE_WLAN; - else if (!strcmp (str, "wwan")) - return RFKILL_TYPE_WWAN; - else if (!strcmp (str, "wimax")) - return RFKILL_TYPE_WIMAX; - - return RFKILL_TYPE_UNKNOWN; -} - -static void -add_one_killswitch (NMUdevManager *self, GUdevDevice *device) -{ - NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self); - const char *str_type; - RfKillType rtype; - Killswitch *ks; - - str_type = g_udev_device_get_property (device, "RFKILL_TYPE"); - rtype = rfkill_type_to_enum (str_type); - if (rtype == RFKILL_TYPE_UNKNOWN) - return; - - ks = killswitch_new (device, rtype); - priv->killswitches = g_slist_prepend (priv->killswitches, ks); - - nm_log_info (LOGD_RFKILL, "%s: found %s radio killswitch (at %s) (%sdriver %s)", - ks->name, - rfkill_type_to_desc (rtype), - ks->path, - ks->platform ? "platform " : "", - ks->driver ? ks->driver : ""); -} - -static void -rfkill_add (NMUdevManager *self, GUdevDevice *device) -{ - const char *name; - - g_return_if_fail (device != NULL); - name = g_udev_device_get_name (device); - g_return_if_fail (name != NULL); - - if (!killswitch_find_by_name (self, name)) - add_one_killswitch (self, device); -} - -static void -rfkill_remove (NMUdevManager *self, - GUdevDevice *device) -{ - NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self); - GSList *iter; - const char *name; - - g_return_if_fail (device != NULL); - name = g_udev_device_get_name (device); - g_return_if_fail (name != NULL); - - for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) { - Killswitch *ks = iter->data; - - if (!strcmp (ks->name, name)) { - nm_log_info (LOGD_RFKILL, "radio killswitch %s disappeared", ks->path); - priv->killswitches = g_slist_remove (priv->killswitches, ks); - killswitch_destroy (ks); - break; - } - } -} - static gboolean dev_get_attrs (GUdevDevice *udev_device, const char **out_ifname, @@ -546,50 +254,29 @@ handle_uevent (GUdevClient *client, nm_log_dbg (LOGD_HW, "UDEV event: action '%s' subsys '%s' device '%s'", action, subsys, g_udev_device_get_name (device)); - g_return_if_fail (!strcmp (subsys, "rfkill") || !strcmp (subsys, "net") || - !strcmp (subsys, "atm")); + g_return_if_fail (!strcmp (subsys, "net") || !strcmp (subsys, "atm")); if (!strcmp (action, "add")) { - if (!strcmp (subsys, "rfkill")) - rfkill_add (self, device); - else if (!strcmp (subsys, "net")) + if (!strcmp (subsys, "net")) net_add (self, device); else if (!strcmp (subsys, "atm")) adsl_add (self, device); } else if (!strcmp (action, "remove")) { - if (!strcmp (subsys, "rfkill")) - rfkill_remove (self, device); - else if (!strcmp (subsys, "net")) + if (!strcmp (subsys, "net")) net_remove (self, device); else if (!strcmp (subsys, "atm")) adsl_remove (self, device); } - - recheck_killswitches (self); } static void nm_udev_manager_init (NMUdevManager *self) { NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self); - const char *subsys[4] = { "rfkill", "net", "atm", NULL }; - GList *switches, *iter; - guint32 i; - - for (i = 0; i < RFKILL_TYPE_MAX; i++) - priv->rfkill_states[i] = RFKILL_UNBLOCKED; + const char *subsys[] = { "net", "atm", NULL }; priv->client = g_udev_client_new (subsys); g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); - - switches = g_udev_client_query_by_subsystem (priv->client, "rfkill"); - for (iter = switches; iter; iter = g_list_next (iter)) { - add_one_killswitch (self, G_UDEV_DEVICE (iter->data)); - g_object_unref (G_UDEV_DEVICE (iter->data)); - } - g_list_free (switches); - - recheck_killswitches (self); } static void @@ -598,16 +285,7 @@ dispose (GObject *object) NMUdevManager *self = NM_UDEV_MANAGER (object); NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self); - if (priv->disposed) { - G_OBJECT_CLASS (nm_udev_manager_parent_class)->dispose (object); - return; - } - priv->disposed = TRUE; - - g_object_unref (priv->client); - - g_slist_foreach (priv->killswitches, (GFunc) killswitch_destroy, NULL); - g_slist_free (priv->killswitches); + g_clear_object (&priv->client); G_OBJECT_CLASS (nm_udev_manager_parent_class)->dispose (object); } @@ -638,13 +316,5 @@ nm_udev_manager_class_init (NMUdevManagerClass *klass) G_STRUCT_OFFSET (NMUdevManagerClass, device_removed), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[RFKILL_CHANGED] = - g_signal_new ("rfkill-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMUdevManagerClass, rfkill_changed), - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); } diff --git a/src/nm-udev-manager.h b/src/nm-udev-manager.h index 2c982e6d06..ab3323d017 100644 --- a/src/nm-udev-manager.h +++ b/src/nm-udev-manager.h @@ -27,8 +27,6 @@ #include -#include "nm-rfkill.h" - G_BEGIN_DECLS #define NM_TYPE_UDEV_MANAGER (nm_udev_manager_get_type ()) @@ -49,7 +47,7 @@ typedef GObject *(*NMDeviceCreatorFn) (NMUdevManager *manager, typedef struct { GObjectClass parent; - /* Virtual functions */ + /* signals */ void (*device_added) (NMUdevManager *manager, GUdevDevice *device, const char *iface, @@ -58,8 +56,6 @@ typedef struct { int ifindex); void (*device_removed) (NMUdevManager *manager, GUdevDevice *device); - - void (*rfkill_changed) (NMUdevManager *manager, RfKillType rtype, RfKillState state); } NMUdevManagerClass; GType nm_udev_manager_get_type (void); @@ -68,7 +64,5 @@ NMUdevManager *nm_udev_manager_new (void); void nm_udev_manager_query_devices (NMUdevManager *manager); -RfKillState nm_udev_manager_get_rfkill_state (NMUdevManager *manager, RfKillType rtype); - #endif /* NM_UDEV_MANAGER_H */