mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-03 20:40:34 +01:00
rfkill: port rfkill to libgudev
This commit is contained in:
parent
6029288ffb
commit
f8026260c6
7 changed files with 432 additions and 395 deletions
|
|
@ -189,6 +189,10 @@ PKG_CHECK_MODULES(GMODULE, gmodule-2.0)
|
|||
AC_SUBST(GMODULE_CFLAGS)
|
||||
AC_SUBST(GMODULE_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(GUDEV, gudev-1.0)
|
||||
AC_SUBST(GUDEV_CFLAGS)
|
||||
AC_SUBST(GUDEV_LIBS)
|
||||
|
||||
PKG_CHECK_EXISTS(gio-2.0,[have_gio=yes],[have_gio=no])
|
||||
if test x"$have_gio" = "xno"; then
|
||||
AC_DEFINE([NO_GIO],[1],[Define if you don't have GIO])
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ NetworkManager_SOURCES = \
|
|||
nm-dbus-manager.c \
|
||||
nm-hal-manager.c \
|
||||
nm-hal-manager.h \
|
||||
nm-udev-manager.c \
|
||||
nm-udev-manager.h \
|
||||
nm-hostname-provider.c \
|
||||
nm-hostname-provider.h \
|
||||
nm-ip4-config.c \
|
||||
|
|
@ -145,6 +147,7 @@ NetworkManager_CPPFLAGS = \
|
|||
$(DBUS_CFLAGS) \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(HAL_CFLAGS) \
|
||||
$(GUDEV_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS) \
|
||||
$(LIBNL_CFLAGS) \
|
||||
-DG_DISABLE_DEPRECATED \
|
||||
|
|
@ -162,6 +165,7 @@ NetworkManager_LDADD = \
|
|||
$(DBUS_LIBS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(HAL_LIBS) \
|
||||
$(GUDEV_LIBS) \
|
||||
$(LIBNL_LIBS) \
|
||||
$(top_builddir)/marshallers/libmarshallers.la \
|
||||
./named-manager/libnamed-manager.la \
|
||||
|
|
|
|||
|
|
@ -34,47 +34,13 @@
|
|||
#include "nm-device-wifi.h"
|
||||
#include "nm-device-ethernet.h"
|
||||
|
||||
/* Killswitch poll frequency in seconds */
|
||||
#define RFKILL_POLL_FREQUENCY 6
|
||||
|
||||
#define HAL_DBUS_SERVICE "org.freedesktop.Hal"
|
||||
|
||||
typedef struct {
|
||||
char *udi;
|
||||
gboolean polled;
|
||||
RfKillState state;
|
||||
|
||||
/* For polling */
|
||||
DBusGProxy *proxy;
|
||||
|
||||
NMHalManager *self;
|
||||
} Killswitch;
|
||||
|
||||
typedef struct {
|
||||
LibHalContext *hal_ctx;
|
||||
NMDBusManager *dbus_mgr;
|
||||
GSList *device_creators;
|
||||
|
||||
/* Authoritative rfkill state (RFKILL_* enum)
|
||||
*/
|
||||
RfKillState rfkill_state;
|
||||
|
||||
/* Killswitch handling:
|
||||
* There are two types of killswitches:
|
||||
* a) old-style: require polling
|
||||
* b) new-style: requires hal 0.5.12 as of 2008-11-19, and 2.6.27 kernel
|
||||
* or later; emit PropertyChanged for the 'state' property when the
|
||||
* rfkill status changes
|
||||
*
|
||||
* If new-style switches are found, they are used. Otherwise, old-style
|
||||
* switches are used.
|
||||
*/
|
||||
GSList *killswitches;
|
||||
|
||||
/* Old-style killswitch polling stuff */
|
||||
guint32 killswitch_poll_id;
|
||||
char *kswitch_err;
|
||||
|
||||
gboolean disposed;
|
||||
} NMHalManagerPrivate;
|
||||
|
||||
|
|
@ -85,7 +51,6 @@ G_DEFINE_TYPE (NMHalManager, nm_hal_manager, G_TYPE_OBJECT)
|
|||
enum {
|
||||
UDI_ADDED,
|
||||
UDI_REMOVED,
|
||||
RFKILL_CHANGED,
|
||||
HAL_REAPPEARED,
|
||||
|
||||
LAST_SIGNAL
|
||||
|
|
@ -94,8 +59,6 @@ enum {
|
|||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
static gboolean poll_killswitches (gpointer user_data);
|
||||
|
||||
/* Device creators */
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -351,75 +314,6 @@ device_new_capability (LibHalContext *ctx, const char *udi, const char *capabili
|
|||
emit_udi_added (self, udi, creator);
|
||||
}
|
||||
|
||||
static RfKillState
|
||||
hal_to_nm_rfkill_state (int hal_state)
|
||||
{
|
||||
switch (hal_state) {
|
||||
case 0:
|
||||
return RFKILL_SOFT_BLOCKED;
|
||||
case 2:
|
||||
return RFKILL_HARD_BLOCKED;
|
||||
case 1:
|
||||
default:
|
||||
return RFKILL_UNBLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
device_property_changed (LibHalContext *ctx,
|
||||
const char *udi,
|
||||
const char *key,
|
||||
dbus_bool_t is_removed,
|
||||
dbus_bool_t is_added)
|
||||
{
|
||||
NMHalManager *self = NM_HAL_MANAGER (libhal_ctx_get_user_data (ctx));
|
||||
NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
|
||||
GSList *iter;
|
||||
gboolean found = FALSE;
|
||||
DBusError error;
|
||||
int state;
|
||||
RfKillState new_state = RFKILL_UNBLOCKED;
|
||||
|
||||
/* Ignore event if it's not a killswitch state change */
|
||||
if (strcmp (key, "killswitch.state") || is_removed)
|
||||
return;
|
||||
|
||||
/* Check all killswitches, and if any switch is blocked, the new rfkill
|
||||
* state becomes blocked.
|
||||
*/
|
||||
for (iter = priv->killswitches; iter; iter = iter->next) {
|
||||
Killswitch *ks = iter->data;
|
||||
|
||||
if (!strcmp (ks->udi, udi)) {
|
||||
found = TRUE;
|
||||
|
||||
/* Get switch state */
|
||||
dbus_error_init (&error);
|
||||
state = libhal_device_get_property_int (ctx, ks->udi, "killswitch.state", &error);
|
||||
if (dbus_error_is_set (&error)) {
|
||||
nm_warning ("(%s) Error reading killswitch state: %s.",
|
||||
ks->udi,
|
||||
error.message ? error.message : "unknown");
|
||||
dbus_error_free (&error);
|
||||
} else
|
||||
ks->state = hal_to_nm_rfkill_state (state);
|
||||
}
|
||||
|
||||
/* If any switch is blocked, overall state is blocked */
|
||||
if (ks->state > new_state)
|
||||
new_state = ks->state;
|
||||
}
|
||||
|
||||
/* Notify of new rfkill state change; but only if the killswitch which
|
||||
* this event is for was one we care about
|
||||
*/
|
||||
if (found && (new_state != priv->rfkill_state)) {
|
||||
priv->rfkill_state = new_state;
|
||||
g_signal_emit (self, signals[RFKILL_CHANGED], 0, priv->rfkill_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_initial_devices (NMHalManager *self)
|
||||
{
|
||||
|
|
@ -456,230 +350,6 @@ add_initial_devices (NMHalManager *self)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
killswitch_getpower_done (gpointer user_data)
|
||||
{
|
||||
Killswitch *ks = user_data;
|
||||
NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (ks->self);
|
||||
GSList *iter;
|
||||
RfKillState new_state = RFKILL_UNBLOCKED;
|
||||
|
||||
if (ks->proxy) {
|
||||
g_object_unref (ks->proxy);
|
||||
ks->proxy = NULL;
|
||||
}
|
||||
|
||||
/* Check all killswitches, and if any switch is blocked, the new rfkill
|
||||
* state becomes blocked. But emit final state until the last killswitch
|
||||
* has been updated.
|
||||
*/
|
||||
for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
|
||||
Killswitch *candidate = iter->data;
|
||||
|
||||
/* If any GetPower call has yet to complete; don't emit final state */
|
||||
if (candidate->proxy)
|
||||
return;
|
||||
|
||||
if (candidate->state > new_state)
|
||||
new_state = candidate->state;
|
||||
}
|
||||
|
||||
if (new_state != priv->rfkill_state) {
|
||||
priv->rfkill_state = new_state;
|
||||
g_signal_emit (ks->self, signals[RFKILL_CHANGED], 0, priv->rfkill_state);
|
||||
}
|
||||
|
||||
/* Schedule next poll */
|
||||
priv->killswitch_poll_id = g_timeout_add_seconds (RFKILL_POLL_FREQUENCY,
|
||||
poll_killswitches,
|
||||
ks->self);
|
||||
}
|
||||
|
||||
static void
|
||||
killswitch_getpower_reply (DBusGProxy *proxy,
|
||||
DBusGProxyCall *call_id,
|
||||
gpointer user_data)
|
||||
{
|
||||
Killswitch *ks = user_data;
|
||||
NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (ks->self);
|
||||
int power = 1;
|
||||
GError *err = NULL;
|
||||
|
||||
if (dbus_g_proxy_end_call (proxy, call_id, &err,
|
||||
G_TYPE_INT, &power,
|
||||
G_TYPE_INVALID)) {
|
||||
if (power == 0)
|
||||
ks->state = RFKILL_HARD_BLOCKED;
|
||||
} else {
|
||||
if (err->message) {
|
||||
/* Only print the error if we haven't seen it before */
|
||||
if (!priv->kswitch_err || strcmp (priv->kswitch_err, err->message) != 0) {
|
||||
nm_warning ("Error getting killswitch power: %s.", err->message);
|
||||
g_free (priv->kswitch_err);
|
||||
priv->kswitch_err = g_strdup (err->message);
|
||||
|
||||
/* If there was an error talking to HAL, treat that as rfkilled.
|
||||
* See rh #448889. On some Dell laptops, dellWirelessCtl
|
||||
* may not be present, but HAL still advertises a killswitch,
|
||||
* and calls to GetPower() will fail. Thus we cannot assume
|
||||
* that a failure of GetPower() automatically means the wireless
|
||||
* is rfkilled, because in this situation NM would never bring
|
||||
* the radio up. Only assume failures between NM and HAL should
|
||||
* block the radio, not failures of the HAL killswitch callout
|
||||
* itself.
|
||||
*/
|
||||
if (strstr (err->message, "Did not receive a reply")) {
|
||||
nm_warning ("HAL did not reply to killswitch power request;"
|
||||
" assuming radio is blocked.");
|
||||
ks->state = RFKILL_HARD_BLOCKED;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_error_free (err);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
poll_killswitches (gpointer user_data)
|
||||
{
|
||||
NMHalManager *self = NM_HAL_MANAGER (user_data);
|
||||
NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
|
||||
GSList *iter;
|
||||
|
||||
for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
|
||||
Killswitch *ks = iter->data;
|
||||
|
||||
ks->state = RFKILL_UNBLOCKED;
|
||||
ks->proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
|
||||
"org.freedesktop.Hal",
|
||||
ks->udi,
|
||||
"org.freedesktop.Hal.Device.KillSwitch");
|
||||
dbus_g_proxy_begin_call (ks->proxy, "GetPower",
|
||||
killswitch_getpower_reply,
|
||||
ks,
|
||||
killswitch_getpower_done,
|
||||
G_TYPE_INVALID);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static Killswitch *
|
||||
killswitch_new (const char *udi,
|
||||
int state,
|
||||
gboolean polled,
|
||||
NMHalManager *self)
|
||||
{
|
||||
Killswitch *ks;
|
||||
|
||||
ks = g_malloc0 (sizeof (Killswitch));
|
||||
ks->udi = g_strdup (udi);
|
||||
ks->state = state;
|
||||
ks->self = self;
|
||||
ks->polled = polled;
|
||||
|
||||
return ks;
|
||||
}
|
||||
|
||||
static void
|
||||
killswitch_free (gpointer user_data)
|
||||
{
|
||||
Killswitch *ks = user_data;
|
||||
|
||||
if (ks->proxy)
|
||||
g_object_unref (ks->proxy);
|
||||
g_free (ks->udi);
|
||||
g_free (ks);
|
||||
}
|
||||
|
||||
static void
|
||||
add_killswitch_devices (NMHalManager *self)
|
||||
{
|
||||
NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
|
||||
char **udis;
|
||||
int num_udis, i;
|
||||
DBusError err;
|
||||
GSList *polled = NULL, *active = NULL, *iter;
|
||||
|
||||
dbus_error_init (&err);
|
||||
udis = libhal_find_device_by_capability (priv->hal_ctx, "killswitch", &num_udis, &err);
|
||||
if (!udis)
|
||||
return;
|
||||
|
||||
if (dbus_error_is_set (&err)) {
|
||||
nm_warning ("Could not find killswitch devices: %s", err.message);
|
||||
dbus_error_free (&err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* filter switches we care about */
|
||||
for (i = 0; i < num_udis; i++) {
|
||||
Killswitch *ks;
|
||||
char *type;
|
||||
int state;
|
||||
gboolean found = FALSE;
|
||||
|
||||
type = libhal_device_get_property_string (priv->hal_ctx, udis[i], "killswitch.type", NULL);
|
||||
if (!type)
|
||||
continue;
|
||||
|
||||
/* Only care about WLAN for now */
|
||||
if (strcmp (type, "wlan")) {
|
||||
libhal_free_string (type);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* see if it's already in the list */
|
||||
for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
|
||||
ks = iter->data;
|
||||
if (!strcmp (udis[i], ks->udi)) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
dbus_error_init (&err);
|
||||
state = libhal_device_get_property_int (priv->hal_ctx, udis[i], "killswitch.state", &err);
|
||||
if (dbus_error_is_set (&err)) {
|
||||
dbus_error_free (&err);
|
||||
nm_info ("Found radio killswitch %s (polled)", udis[i]);
|
||||
ks = killswitch_new (udis[i], RFKILL_UNBLOCKED, TRUE, self);
|
||||
polled = g_slist_append (polled, ks);
|
||||
} else {
|
||||
nm_info ("Found radio killswitch %s (monitored)", udis[i]);
|
||||
ks = killswitch_new (udis[i], hal_to_nm_rfkill_state (state), FALSE, self);
|
||||
active = g_slist_append (active, ks);
|
||||
}
|
||||
}
|
||||
|
||||
/* Active killswitches are used in preference to polled killswitches */
|
||||
if (active) {
|
||||
for (iter = active; iter; iter = g_slist_next (iter))
|
||||
priv->killswitches = g_slist_append (priv->killswitches, iter->data);
|
||||
|
||||
if (priv->killswitches)
|
||||
nm_info ("Watching killswitches for radio status");
|
||||
|
||||
/* Dispose of any polled killswitches found */
|
||||
g_slist_foreach (polled, (GFunc) killswitch_free, NULL);
|
||||
} else {
|
||||
for (iter = polled; iter; iter = g_slist_next (iter))
|
||||
priv->killswitches = g_slist_append (priv->killswitches, iter->data);
|
||||
|
||||
/* Poll switches if this is the first switch we've found */
|
||||
if (priv->killswitches) {
|
||||
if (!priv->killswitch_poll_id)
|
||||
priv->killswitch_poll_id = g_idle_add (poll_killswitches, self);
|
||||
nm_info ("Polling killswitches for radio status");
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_free (active);
|
||||
g_slist_free (polled);
|
||||
libhal_free_string_array (udis);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
hal_init (NMHalManager *self)
|
||||
{
|
||||
|
|
@ -709,7 +379,6 @@ hal_init (NMHalManager *self)
|
|||
libhal_ctx_set_device_added (priv->hal_ctx, device_added);
|
||||
libhal_ctx_set_device_removed (priv->hal_ctx, device_removed);
|
||||
libhal_ctx_set_device_new_capability (priv->hal_ctx, device_new_capability);
|
||||
libhal_ctx_set_device_property_modified (priv->hal_ctx, device_property_changed);
|
||||
|
||||
libhal_device_property_watch_all (priv->hal_ctx, &error);
|
||||
if (dbus_error_is_set (&error)) {
|
||||
|
|
@ -736,17 +405,6 @@ hal_deinit (NMHalManager *self)
|
|||
NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
|
||||
DBusError error;
|
||||
|
||||
if (priv->killswitch_poll_id) {
|
||||
g_source_remove (priv->killswitch_poll_id);
|
||||
priv->killswitch_poll_id = 0;
|
||||
}
|
||||
|
||||
if (priv->killswitches) {
|
||||
g_slist_foreach (priv->killswitches, (GFunc) killswitch_free, NULL);
|
||||
g_slist_free (priv->killswitches);
|
||||
priv->killswitches = NULL;
|
||||
}
|
||||
|
||||
if (!priv->hal_ctx)
|
||||
return;
|
||||
|
||||
|
|
@ -814,10 +472,8 @@ nm_hal_manager_query_devices (NMHalManager *self)
|
|||
NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
/* Find hardware we care about */
|
||||
if (priv->hal_ctx) {
|
||||
add_killswitch_devices (self);
|
||||
if (priv->hal_ctx)
|
||||
add_initial_devices (self);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -855,8 +511,6 @@ nm_hal_manager_init (NMHalManager *self)
|
|||
{
|
||||
NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
priv->rfkill_state = RFKILL_UNBLOCKED;
|
||||
|
||||
priv->dbus_mgr = nm_dbus_manager_get ();
|
||||
|
||||
register_built_in_creators (self);
|
||||
|
|
@ -903,17 +557,6 @@ dispose (GObject *object)
|
|||
G_OBJECT_CLASS (nm_hal_manager_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
finalize (GObject *object)
|
||||
{
|
||||
NMHalManager *self = NM_HAL_MANAGER (object);
|
||||
NMHalManagerPrivate *priv = NM_HAL_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
g_free (priv->kswitch_err);
|
||||
|
||||
G_OBJECT_CLASS (nm_hal_manager_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_hal_manager_class_init (NMHalManagerClass *klass)
|
||||
{
|
||||
|
|
@ -923,7 +566,6 @@ nm_hal_manager_class_init (NMHalManagerClass *klass)
|
|||
|
||||
/* virtual methods */
|
||||
object_class->dispose = dispose;
|
||||
object_class->finalize = finalize;
|
||||
|
||||
/* Signals */
|
||||
signals[UDI_ADDED] =
|
||||
|
|
@ -946,16 +588,6 @@ nm_hal_manager_class_init (NMHalManagerClass *klass)
|
|||
G_TYPE_NONE, 1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
signals[RFKILL_CHANGED] =
|
||||
g_signal_new ("rfkill-changed",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMHalManagerClass, rfkill_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__UINT,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_UINT);
|
||||
|
||||
signals[HAL_REAPPEARED] =
|
||||
g_signal_new ("hal-reappeared",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
|
|
|
|||
|
|
@ -25,12 +25,6 @@
|
|||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
typedef enum {
|
||||
RFKILL_UNBLOCKED = 0,
|
||||
RFKILL_SOFT_BLOCKED = 1,
|
||||
RFKILL_HARD_BLOCKED = 2
|
||||
} RfKillState;
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define NM_TYPE_HAL_MANAGER (nm_hal_manager_get_type ())
|
||||
|
|
@ -61,15 +55,12 @@ typedef struct {
|
|||
|
||||
void (*udi_removed) (NMHalManager *manager, const char *udi);
|
||||
|
||||
void (*rfkill_changed) (NMHalManager *manager, RfKillState state);
|
||||
|
||||
void (*hal_reappeared) (NMHalManager *manager);
|
||||
} NMHalManagerClass;
|
||||
|
||||
GType nm_hal_manager_get_type (void);
|
||||
|
||||
NMHalManager *nm_hal_manager_new (void);
|
||||
gboolean nm_hal_manager_get_rfkilled (NMHalManager *manager);
|
||||
void nm_hal_manager_query_devices (NMHalManager *manager);
|
||||
gboolean nm_hal_manager_udi_exists (NMHalManager *manager, const char *udi);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "nm-marshal.h"
|
||||
#include "nm-dbus-glib-types.h"
|
||||
#include "nm-hal-manager.h"
|
||||
#include "nm-udev-manager.h"
|
||||
#include "nm-hostname-provider.h"
|
||||
#include "nm-bluez-manager.h"
|
||||
#include "nm-bluez-common.h"
|
||||
|
|
@ -93,9 +94,9 @@ static void hal_manager_udi_removed_cb (NMHalManager *hal_mgr,
|
|||
const char *udi,
|
||||
gpointer user_data);
|
||||
|
||||
static void hal_manager_rfkill_changed_cb (NMHalManager *hal_mgr,
|
||||
RfKillState state,
|
||||
gpointer user_data);
|
||||
static void udev_manager_rfkill_changed_cb (NMHalManager *hal_mgr,
|
||||
RfKillState state,
|
||||
gpointer user_data);
|
||||
|
||||
static void hal_manager_hal_reappeared_cb (NMHalManager *hal_mgr,
|
||||
gpointer user_data);
|
||||
|
|
@ -140,6 +141,7 @@ typedef struct {
|
|||
|
||||
NMDBusManager *dbus_mgr;
|
||||
NMHalManager *hal_mgr;
|
||||
NMUdevManager *udev_mgr;
|
||||
NMBluezManager *bluez_mgr;
|
||||
|
||||
GHashTable *user_connections;
|
||||
|
|
@ -1578,6 +1580,7 @@ nm_manager_get (void)
|
|||
{
|
||||
static NMManager *singleton = NULL;
|
||||
NMManagerPrivate *priv;
|
||||
gboolean enabled;
|
||||
|
||||
if (singleton)
|
||||
return g_object_ref (singleton);
|
||||
|
|
@ -1611,16 +1614,38 @@ nm_manager_get (void)
|
|||
G_CALLBACK (hal_manager_udi_removed_cb),
|
||||
singleton);
|
||||
|
||||
g_signal_connect (priv->hal_mgr,
|
||||
"rfkill-changed",
|
||||
G_CALLBACK (hal_manager_rfkill_changed_cb),
|
||||
singleton);
|
||||
|
||||
g_signal_connect (priv->hal_mgr,
|
||||
"hal-reappeared",
|
||||
G_CALLBACK (hal_manager_hal_reappeared_cb),
|
||||
singleton);
|
||||
|
||||
priv->udev_mgr = nm_udev_manager_new ();
|
||||
g_signal_connect (priv->udev_mgr,
|
||||
"rfkill-changed",
|
||||
G_CALLBACK (udev_manager_rfkill_changed_cb),
|
||||
singleton);
|
||||
|
||||
switch (nm_udev_manager_get_rfkill_state (priv->udev_mgr)) {
|
||||
case RFKILL_UNBLOCKED:
|
||||
priv->wireless_enabled = TRUE;
|
||||
priv->wireless_hw_enabled = TRUE;
|
||||
break;
|
||||
case RFKILL_SOFT_BLOCKED:
|
||||
priv->wireless_enabled = FALSE;
|
||||
priv->wireless_hw_enabled = TRUE;
|
||||
break;
|
||||
case RFKILL_HARD_BLOCKED:
|
||||
priv->wireless_enabled = FALSE;
|
||||
priv->wireless_hw_enabled = FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
enabled = (priv->wireless_enabled && priv->wireless_hw_enabled);
|
||||
nm_info ("Wireless now %s by radio killswitch", enabled ? "enabled" : "disabled");
|
||||
manager_set_wireless_enabled (singleton, enabled);
|
||||
|
||||
priv->bluez_mgr = nm_bluez_manager_get ();
|
||||
|
||||
g_signal_connect (priv->bluez_mgr,
|
||||
|
|
@ -2040,21 +2065,38 @@ hal_manager_udi_removed_cb (NMHalManager *manager,
|
|||
}
|
||||
|
||||
static void
|
||||
hal_manager_rfkill_changed_cb (NMHalManager *hal_mgr,
|
||||
RfKillState state,
|
||||
gpointer user_data)
|
||||
udev_manager_rfkill_changed_cb (NMHalManager *hal_mgr,
|
||||
RfKillState state,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMManager *self = NM_MANAGER (user_data);
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
gboolean enabled = (state == RFKILL_UNBLOCKED);
|
||||
gboolean new_we = TRUE, new_whe = TRUE;
|
||||
|
||||
if (priv->wireless_hw_enabled != enabled) {
|
||||
nm_info ("Wireless now %s by radio killswitch", enabled ? "enabled" : "disabled");
|
||||
priv->wireless_hw_enabled = enabled;
|
||||
switch (state) {
|
||||
case RFKILL_UNBLOCKED:
|
||||
new_we = TRUE;
|
||||
new_whe = TRUE;
|
||||
break;
|
||||
case RFKILL_SOFT_BLOCKED:
|
||||
new_we = FALSE;
|
||||
new_whe = TRUE;
|
||||
break;
|
||||
case RFKILL_HARD_BLOCKED:
|
||||
new_we = FALSE;
|
||||
new_whe = FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
nm_info ("Wireless now %s by radio killswitch",
|
||||
(new_we && new_whe) ? "enabled" : "disabled");
|
||||
if (new_whe != priv->wireless_hw_enabled) {
|
||||
priv->wireless_hw_enabled = new_whe;
|
||||
g_object_notify (G_OBJECT (self), NM_MANAGER_WIRELESS_HARDWARE_ENABLED);
|
||||
|
||||
manager_set_wireless_enabled (self, enabled);
|
||||
}
|
||||
manager_set_wireless_enabled (self, new_we);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
305
src/nm-udev-manager.c
Normal file
305
src/nm-udev-manager.c
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
/* -*- 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 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
|
||||
#include <gudev/gudev.h>
|
||||
|
||||
#include "nm-udev-manager.h"
|
||||
#include "nm-marshal.h"
|
||||
#include "nm-utils.h"
|
||||
|
||||
typedef struct {
|
||||
GUdevClient *client;
|
||||
|
||||
/* Authoritative rfkill state (RFKILL_* enum)
|
||||
*/
|
||||
RfKillState rfkill_state;
|
||||
GSList *killswitches;
|
||||
|
||||
gboolean disposed;
|
||||
} NMUdevManagerPrivate;
|
||||
|
||||
#define NM_UDEV_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_UDEV_MANAGER, NMUdevManagerPrivate))
|
||||
|
||||
G_DEFINE_TYPE (NMUdevManager, nm_udev_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;
|
||||
gint state;
|
||||
} Killswitch;
|
||||
|
||||
RfKillState
|
||||
nm_udev_manager_get_rfkill_state (NMUdevManager *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, RFKILL_UNBLOCKED);
|
||||
|
||||
return NM_UDEV_MANAGER_GET_PRIVATE (self)->rfkill_state;
|
||||
}
|
||||
|
||||
static Killswitch *
|
||||
killswitch_new (GUdevDevice *device)
|
||||
{
|
||||
Killswitch *ks;
|
||||
GUdevDevice *parent = NULL;
|
||||
const char *driver;
|
||||
|
||||
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));
|
||||
|
||||
driver = g_udev_device_get_property (device, "DRIVER");
|
||||
if (!driver) {
|
||||
parent = g_udev_device_get_parent (device);
|
||||
if (parent)
|
||||
driver = g_udev_device_get_property (parent, "DRIVER");
|
||||
}
|
||||
if (driver)
|
||||
ks->driver = g_strdup (driver);
|
||||
|
||||
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_HARD_BLOCKED;
|
||||
case 1:
|
||||
return RFKILL_UNBLOCKED;
|
||||
case 2:
|
||||
return RFKILL_SOFT_BLOCKED;
|
||||
default:
|
||||
g_warning ("%s: Unhandled rfkill state %d", __func__, sysfs_state);
|
||||
break;
|
||||
}
|
||||
return RFKILL_UNBLOCKED;
|
||||
}
|
||||
|
||||
static void
|
||||
recheck_killswitches (NMUdevManager *self)
|
||||
{
|
||||
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
||||
GSList *iter;
|
||||
RfKillState poll_state = RFKILL_UNBLOCKED;
|
||||
|
||||
for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
|
||||
Killswitch *ks = iter->data;
|
||||
GUdevDevice *device;
|
||||
RfKillState dev_state;
|
||||
|
||||
device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
|
||||
if (!device)
|
||||
continue;
|
||||
|
||||
dev_state = sysfs_state_to_nm_state (g_udev_device_get_property_as_int (device, "RFKILL_STATE"));
|
||||
if (dev_state > poll_state)
|
||||
poll_state = dev_state;
|
||||
|
||||
g_object_unref (device);
|
||||
}
|
||||
|
||||
if (poll_state != priv->rfkill_state) {
|
||||
priv->rfkill_state = poll_state;
|
||||
g_signal_emit (self, signals[RFKILL_CHANGED], 0, priv->rfkill_state);
|
||||
}
|
||||
}
|
||||
|
||||
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 void
|
||||
add_one_killswitch (NMUdevManager *self, GUdevDevice *device)
|
||||
{
|
||||
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
||||
const char *type;
|
||||
Killswitch *ks;
|
||||
|
||||
type = g_udev_device_get_property (device, "RFKILL_TYPE");
|
||||
if (!type || strcmp (type, "wlan"))
|
||||
return;
|
||||
|
||||
ks = killswitch_new (device);
|
||||
priv->killswitches = g_slist_prepend (priv->killswitches, ks);
|
||||
|
||||
nm_info ("Found radio killswitch %s (at %s) (driver %s)",
|
||||
ks->name,
|
||||
ks->path,
|
||||
ks->driver ? ks->driver : "<unknown>");
|
||||
}
|
||||
|
||||
static void
|
||||
handle_uevent (GUdevClient *client,
|
||||
const char *action,
|
||||
GUdevDevice *device,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMUdevManager *self = NM_UDEV_MANAGER (user_data);
|
||||
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
||||
const char *name, *subsys;
|
||||
|
||||
g_return_if_fail (action != NULL);
|
||||
|
||||
name = g_udev_device_get_name (device);
|
||||
g_return_if_fail (name != NULL);
|
||||
|
||||
/* A bit paranoid */
|
||||
subsys = g_udev_device_get_subsystem (device);
|
||||
g_return_if_fail (subsys && !strcmp (subsys, "rfkill"));
|
||||
|
||||
if (!strcmp (action, "add")) {
|
||||
if (!killswitch_find_by_name (self, name))
|
||||
add_one_killswitch (self, device);
|
||||
} else if (!strcmp (action, "remove")) {
|
||||
GSList *iter;
|
||||
|
||||
for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
|
||||
Killswitch *ks = iter->data;
|
||||
|
||||
if (!strcmp (ks->name, name)) {
|
||||
nm_info ("Radio killswitch %s disappeared", ks->path);
|
||||
priv->killswitches = g_slist_remove (priv->killswitches, iter);
|
||||
killswitch_destroy (iter->data);
|
||||
g_slist_free (iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: check sequence #s to ensure events don't arrive out of order
|
||||
|
||||
recheck_killswitches (self);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_udev_manager_init (NMUdevManager *self)
|
||||
{
|
||||
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
||||
const char *subsys[2] = { "rfkill", NULL };
|
||||
GList *switches, *iter;
|
||||
|
||||
priv->rfkill_state = 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)
|
||||
{
|
||||
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_OBJECT_CLASS (nm_udev_manager_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_udev_manager_class_init (NMUdevManagerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (NMUdevManagerPrivate));
|
||||
|
||||
/* 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 (NMUdevManagerClass, rfkill_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__UINT,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_UINT);
|
||||
}
|
||||
|
||||
59
src/nm-udev-manager.h
Normal file
59
src/nm-udev-manager.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- 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) 2007 - 2008 Novell, Inc.
|
||||
* Copyright (C) 2007 - 2008 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef NM_UDEV_MANAGER_H
|
||||
#define NM_UDEV_MANAGER_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
typedef enum {
|
||||
RFKILL_UNBLOCKED = 0,
|
||||
RFKILL_SOFT_BLOCKED = 1,
|
||||
RFKILL_HARD_BLOCKED = 2
|
||||
} RfKillState;
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define NM_TYPE_UDEV_MANAGER (nm_udev_manager_get_type ())
|
||||
#define NM_UDEV_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_UDEV_MANAGER, NMUdevManager))
|
||||
#define NM_UDEV_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_UDEV_MANAGER, NMUdevManagerClass))
|
||||
#define NM_IS_UDEV_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_UDEV_MANAGER))
|
||||
#define NM_IS_UDEV_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_UDEV_MANAGER))
|
||||
#define NM_UDEV_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_UDEV_MANAGER, NMUdevManagerClass))
|
||||
|
||||
typedef struct {
|
||||
GObject parent;
|
||||
} NMUdevManager;
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent;
|
||||
|
||||
/* Virtual functions */
|
||||
void (*rfkill_changed) (NMUdevManager *manager, RfKillState state);
|
||||
} NMUdevManagerClass;
|
||||
|
||||
GType nm_udev_manager_get_type (void);
|
||||
|
||||
NMUdevManager *nm_udev_manager_new (void);
|
||||
RfKillState nm_udev_manager_get_rfkill_state (NMUdevManager *manager);
|
||||
|
||||
#endif /* NM_UDEV_MANAGER_H */
|
||||
Loading…
Add table
Reference in a new issue