mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-04 15:20:28 +01:00
core: split NMRfkillManager out of NMUdevManager
Split the rfkill-monitoring parts of NMUdevManager into a separate class. Now NMUdevManager only handles device enumeration.
This commit is contained in:
parent
c3706810ef
commit
b15fb8641e
11 changed files with 479 additions and 361 deletions
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#include <dbus/dbus.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "nm-rfkill.h"
|
||||
#include "nm-rfkill-manager.h"
|
||||
#include "nm-device.h"
|
||||
#include "nm-wifi-ap.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
422
src/nm-rfkill-manager.c
Normal file
422
src/nm-rfkill-manager.c
Normal file
|
|
@ -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 <config.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <gudev/gudev.h>
|
||||
|
||||
#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 : "<unknown>");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -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 <glib-object.h>
|
||||
|
||||
#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 */
|
||||
|
||||
|
|
@ -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 <config.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include <gmodule.h>
|
||||
#include <gudev/gudev.h>
|
||||
|
||||
#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 : "<unknown>");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@
|
|||
|
||||
#include <gudev/gudev.h>
|
||||
|
||||
#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 */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue