core: add networking enable/disable knob distinct from sleep/wake (rh #589108) (bgo #346615)

Since forever we've used sleep/wake as the way to implement
Networking Enabled.  When the state file was introduced to make the
networking and wifi states persistent, we ran into a bug where
a failed suspend (like if the machine ran out of power while
suspended) would result in networking being disabled on reboot
since suspend/resume used the same knob as enable/disable.

This patch adds a distinct call for enable/disable networking
which changes the state file, while sleep/wake no longer change
the state file.
This commit is contained in:
Dan Williams 2010-05-22 08:55:30 -07:00
parent c1b3b137d9
commit fa70542c61
8 changed files with 220 additions and 68 deletions

View file

@ -39,6 +39,12 @@ object. dbus-glib generates the same bound function names for D-Bus the methods
<arg name="sleep" type="b" direction="in"/>
</method>
<method name="Enable">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_enable"/>
<arg name="enable" type="b" direction="in"/>
</method>
<property name="NetworkingEnabled" type="b" access="read"/>
<property name="WirelessEnabled" type="b" access="readwrite"/>
<property name="WirelessHardwareEnabled" type="b" access="read"/>
<property name="WwanEnabled" type="b" access="readwrite"/>

View file

@ -87,7 +87,10 @@
<method name="Sleep">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_sleep"/>
<tp:docstring>
Control the NetworkManager daemon's sleep state. When asleep, all interfaces that it manages are deactivated. When awake, devices are available to be activated.
Control the NetworkManager daemon's sleep state. When asleep, all
interfaces that it manages are deactivated. When awake, devices are
available to be activated. This command should not be called directly
by users or clients; it is intended for system suspend/resume tracking.
</tp:docstring>
<arg name="sleep" type="b" direction="in">
<tp:docstring>
@ -96,6 +99,23 @@
</arg>
</method>
<method name="Enable">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_enable"/>
<tp:docstring>
Control whether overall networking is enabled or disabled. When
disabled, all interfaces that NM manages are deactivated. When enabled,
all managed interfaces are re-enabled and available to be activated.
This command should be used by clients that provide to users the ability
to enable/disable all networking.
</tp:docstring>
<arg name="enable" type="b" direction="in">
<tp:docstring>
If FALSE, indicates that all networking should be disabled. If TRUE,
indicates that NetworkManager should begin managing network devices.
</tp:docstring>
</arg>
</method>
<method name="SetLogging">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_set_logging"/>
<tp:docstring>
@ -118,6 +138,13 @@
</arg>
</method>
<property name="NetworkingEnabled" type="b" access="read">
<tp:docstring>
Indicates if overall networking is currently enabled or not. See the
Enable() method.
</tp:docstring>
</property>
<property name="WirelessEnabled" type="b" access="readwrite">
<tp:docstring>
Indicates if wireless is currently enabled or not.

View file

@ -36,6 +36,8 @@ global:
nm_client_get_manager_running;
nm_client_get_state;
nm_client_get_type;
nm_client_networking_get_enabled;
nm_client_networking_set_enabled;
nm_client_new;
nm_client_sleep;
nm_client_wireless_get_enabled;

View file

@ -18,7 +18,7 @@
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2008 Novell, Inc.
* Copyright (C) 2007 - 2008 Red Hat, Inc.
* Copyright (C) 2007 - 2010 Red Hat, Inc.
*/
#include <dbus/dbus-glib.h>
@ -58,6 +58,7 @@ typedef struct {
GPtrArray *devices;
GPtrArray *active_connections;
gboolean networking_enabled;
gboolean wireless_enabled;
gboolean wireless_hw_enabled;
@ -69,6 +70,7 @@ enum {
PROP_0,
PROP_STATE,
PROP_MANAGER_RUNNING,
PROP_NETWORKING_ENABLED,
PROP_WIRELESS_ENABLED,
PROP_WIRELESS_HARDWARE_ENABLED,
PROP_WWAN_ENABLED,
@ -250,6 +252,7 @@ register_for_property_changed (NMClient *client)
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
const NMPropertiesChangedInfo property_changed_info[] = {
{ NM_CLIENT_STATE, _nm_object_demarshal_generic, &priv->state },
{ NM_CLIENT_NETWORKING_ENABLED, _nm_object_demarshal_generic, &priv->networking_enabled },
{ NM_CLIENT_WIRELESS_ENABLED, _nm_object_demarshal_generic, &priv->wireless_enabled },
{ NM_CLIENT_WIRELESS_HARDWARE_ENABLED, _nm_object_demarshal_generic, &priv->wireless_hw_enabled },
{ NM_CLIENT_WWAN_ENABLED, _nm_object_demarshal_generic, &priv->wwan_enabled },
@ -427,6 +430,9 @@ get_property (GObject *object,
case PROP_MANAGER_RUNNING:
g_value_set_boolean (value, priv->manager_running);
break;
case PROP_NETWORKING_ENABLED:
g_value_set_boolean (value, priv->networking_enabled);
break;
case PROP_WIRELESS_ENABLED:
g_value_set_boolean (value, priv->wireless_enabled);
break;
@ -489,6 +495,19 @@ nm_client_class_init (NMClientClass *client_class)
FALSE,
G_PARAM_READABLE));
/**
* NMClient::networking-enabled:
*
* Whether networking is enabled.
**/
g_object_class_install_property
(object_class, PROP_NETWORKING_ENABLED,
g_param_spec_boolean (NM_CLIENT_NETWORKING_ENABLED,
"NetworkingEnabled",
"Is networking enabled",
TRUE,
G_PARAM_READABLE));
/**
* NMClient::wireless-enabled:
*
@ -1042,26 +1061,40 @@ nm_client_get_state (NMClient *client)
}
/**
* nm_client_sleep:
* nm_client_networking_set_enabled:
* @client: a #NMClient
* @sleep: %TRUE to put the daemon to sleep
* @enabled: %TRUE to set networking enabled, %FALSE to set networking disabled
*
* Enables or disables networking. When the daemon is put to sleep, it'll deactivate and disable
* all the active devices.
* Enables or disables networking. When networking is disabled, all controlled
* interfaces are disconnected and deactivated. When networking is enabled,
* all controlled interfaces are available for activation.
**/
void
nm_client_sleep (NMClient *client, gboolean sleep)
nm_client_networking_set_enabled (NMClient *client, gboolean enable)
{
GError *err = NULL;
g_return_if_fail (NM_IS_CLIENT (client));
if (!org_freedesktop_NetworkManager_sleep (NM_CLIENT_GET_PRIVATE (client)->client_proxy, sleep, &err)) {
g_warning ("Error in sleep: %s", err->message);
if (!org_freedesktop_NetworkManager_enable (NM_CLIENT_GET_PRIVATE (client)->client_proxy, enable, &err)) {
g_warning ("Error enabling/disabling networking: %s", err->message);
g_error_free (err);
}
}
/**
* nm_client_sleep:
* @client: a #NMClient
* @sleep: %TRUE to put the daemon to sleep
*
* Deprecated; use nm_client_networking_set_enabled() instead.
**/
void
nm_client_sleep (NMClient *client, gboolean sleep)
{
nm_client_networking_set_enabled (client, !sleep);
}
/**
* nm_client_get_manager_running:
* @client: a #NMClient

View file

@ -18,7 +18,7 @@
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2008 Novell, Inc.
* Copyright (C) 2007 - 2008 Red Hat, Inc.
* Copyright (C) 2007 - 2010 Red Hat, Inc.
*/
#ifndef NM_CLIENT_H
@ -43,6 +43,7 @@ G_BEGIN_DECLS
#define NM_CLIENT_STATE "state"
#define NM_CLIENT_MANAGER_RUNNING "manager-running"
#define NM_CLIENT_NETWORKING_ENABLED "networking-enabled"
#define NM_CLIENT_WIRELESS_ENABLED "wireless-enabled"
#define NM_CLIENT_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled"
#define NM_CLIENT_WWAN_ENABLED "wwan-enabled"
@ -88,6 +89,9 @@ void nm_client_activate_connection (NMClient *client,
void nm_client_deactivate_connection (NMClient *client, NMActiveConnection *active);
gboolean nm_client_networking_get_enabled (NMClient *client);
void nm_client_networking_set_enabled (NMClient *client, gboolean enabled);
gboolean nm_client_wireless_get_enabled (NMClient *client);
void nm_client_wireless_set_enabled (NMClient *client, gboolean enabled);
gboolean nm_client_wireless_hardware_get_enabled (NMClient *client);

View file

@ -58,13 +58,6 @@
#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
#define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd"
#define NM_MANAGER_STATE "state"
#define NM_MANAGER_WIRELESS_ENABLED "wireless-enabled"
#define NM_MANAGER_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled"
#define NM_MANAGER_WWAN_ENABLED "wwan-enabled"
#define NM_MANAGER_WWAN_HARDWARE_ENABLED "wwan-hardware-enabled"
#define NM_MANAGER_ACTIVE_CONNECTIONS "active-connections"
static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err);
static void impl_manager_activate_connection (NMManager *manager,
const char *service_name,
@ -79,6 +72,8 @@ static gboolean impl_manager_deactivate_connection (NMManager *manager,
static gboolean impl_manager_sleep (NMManager *manager, gboolean sleep, GError **err);
static gboolean impl_manager_enable (NMManager *manager, gboolean enable, GError **err);
static gboolean impl_manager_set_logging (NMManager *manager,
const char *level,
const char *domains,
@ -190,6 +185,7 @@ typedef struct {
RadioState radio_states[RFKILL_TYPE_MAX];
gboolean sleeping;
gboolean net_enabled;
NMVPNManager *vpn_manager;
guint vpn_manager_id;
@ -228,6 +224,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
enum {
PROP_0,
PROP_STATE,
PROP_NETWORKING_ENABLED,
PROP_WIRELESS_ENABLED,
PROP_WIRELESS_HARDWARE_ENABLED,
PROP_WWAN_ENABLED,
@ -251,6 +248,7 @@ typedef enum
NM_MANAGER_ERROR_PERMISSION_DENIED,
NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
} NMManagerError;
#define NM_MANAGER_ERROR (nm_manager_error_quark ())
@ -293,6 +291,8 @@ nm_manager_error_get_type (void)
ENUM_ENTRY (NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, "ConnectionNotActive"),
/* The manager is already in the requested sleep state */
ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE, "AlreadyAsleepOrAwake"),
/* The manager is already in the requested enabled/disabled state */
ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, "AlreadyEnabledOrDisabled"),
{ 0, 0, 0 },
};
etype = g_enum_register_static ("NMManagerError", values);
@ -300,6 +300,16 @@ nm_manager_error_get_type (void)
return etype;
}
static gboolean
manager_sleeping (NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
if (priv->sleeping || !priv->net_enabled)
return TRUE;
return FALSE;
}
static void
vpn_manager_connection_deactivated_cb (NMVPNManager *manager,
NMVPNConnection *vpn,
@ -372,9 +382,9 @@ nm_manager_update_state (NMManager *manager)
priv = NM_MANAGER_GET_PRIVATE (manager);
if (priv->sleeping) {
if (manager_sleeping (manager))
new_state = NM_STATE_ASLEEP;
} else {
else {
GSList *iter;
for (iter = priv->devices; iter; iter = iter->next) {
@ -1239,7 +1249,7 @@ manager_set_radio_enabled (NMManager *manager,
}
/* Don't touch devices if asleep/networking disabled */
if (priv->sleeping)
if (manager_sleeping (manager))
return;
/* enable/disable wireless devices as required */
@ -1559,7 +1569,7 @@ add_device (NMManager *self, NMDevice *device)
/* Start the device if it's supposed to be managed */
unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings);
if ( !priv->sleeping
if ( !manager_sleeping (self)
&& !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) {
nm_device_set_managed (device,
TRUE,
@ -1810,7 +1820,6 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GObject *device;
guint32 ifindex;
@ -1818,7 +1827,7 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
if (find_device_by_ifindex (self, ifindex))
return;
device = creator_fn (udev_mgr, udev_device, priv->sleeping);
device = creator_fn (udev_mgr, udev_device, manager_sleeping (self));
if (device)
add_device (self, NM_DEVICE (device));
}
@ -2646,54 +2655,25 @@ impl_manager_deactivate_connection (NMManager *manager,
error);
}
static gboolean
impl_manager_sleep (NMManager *self, gboolean sleep, GError **error)
static void
do_sleep_wake (NMManager *self)
{
NMManagerPrivate *priv;
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
const GSList *unmanaged_specs;
GSList *iter;
g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
priv = NM_MANAGER_GET_PRIVATE (self);
if (priv->sleeping == sleep) {
g_set_error (error,
NM_MANAGER_ERROR, NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
"Already %s", sleep ? "asleep" : "awake");
return FALSE;
}
priv->sleeping = sleep;
/* Update "NetworkingEnabled" key in state file */
if (priv->state_file) {
GError *err = NULL;
gboolean networking_enabled = !sleep;
if (!write_value_to_state_file (priv->state_file,
"main", "NetworkingEnabled",
G_TYPE_BOOLEAN, (gpointer) &networking_enabled,
&err)) {
nm_log_warn (LOGD_SUSPEND, "writing to state file %s failed: (%d) %s.",
priv->state_file,
err ? err->code : -1,
(err && err->message) ? err->message : "unknown");
}
}
if (sleep) {
nm_log_info (LOGD_SUSPEND, "sleeping...");
if (manager_sleeping (self)) {
nm_log_info (LOGD_SUSPEND, "sleeping or disabling...");
/* Just deactivate and down all devices from the device list,
* we'll remove them in 'wake' for speed's sake.
* to keep things fast the device list will get resynced when
* the manager wakes up.
*/
for (iter = priv->devices; iter; iter = iter->next)
nm_device_set_managed (NM_DEVICE (iter->data), FALSE, NM_DEVICE_STATE_REASON_SLEEPING);
} else {
const GSList *unmanaged_specs;
nm_log_info (LOGD_SUSPEND, "waking up...");
} else {
nm_log_info (LOGD_SUSPEND, "waking up and re-enabling...");
unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings);
@ -2738,11 +2718,82 @@ impl_manager_sleep (NMManager *self, gboolean sleep, GError **error)
}
nm_manager_update_state (self);
}
static gboolean
impl_manager_sleep (NMManager *self, gboolean sleep, GError **error)
{
NMManagerPrivate *priv;
g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
priv = NM_MANAGER_GET_PRIVATE (self);
if (priv->sleeping == sleep) {
g_set_error (error,
NM_MANAGER_ERROR, NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
"Already %s", sleep ? "asleep" : "awake");
return FALSE;
}
nm_log_info (LOGD_SUSPEND, "%s requested (sleeping: %s enabled: %s)",
sleep ? "sleep" : "wake",
priv->sleeping ? "yes" : "no",
priv->net_enabled ? "yes" : "no");
priv->sleeping = sleep;
do_sleep_wake (self);
g_object_notify (G_OBJECT (self), NM_MANAGER_SLEEPING);
return TRUE;
}
static gboolean
impl_manager_enable (NMManager *self, gboolean enable, GError **error)
{
NMManagerPrivate *priv;
g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
priv = NM_MANAGER_GET_PRIVATE (self);
if (priv->net_enabled == enable) {
g_set_error (error,
NM_MANAGER_ERROR, NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
"Already %s", enable ? "enabled" : "disabled");
return FALSE;
}
/* Update "NetworkingEnabled" key in state file */
if (priv->state_file) {
GError *err = NULL;
if (!write_value_to_state_file (priv->state_file,
"main", "NetworkingEnabled",
G_TYPE_BOOLEAN, (gpointer) &enable,
&err)) {
/* Not a hard error */
nm_log_warn (LOGD_SUSPEND, "writing to state file %s failed: (%d) %s.",
priv->state_file,
err ? err->code : -1,
(err && err->message) ? err->message : "unknown");
}
}
nm_log_info (LOGD_SUSPEND, "%s requested (sleeping: %s enabled: %s)",
enable ? "enable" : "disable",
priv->sleeping ? "yes" : "no",
priv->net_enabled ? "yes" : "no");
priv->net_enabled = enable;
do_sleep_wake (self);
g_object_notify (G_OBJECT (self), NM_MANAGER_NETWORKING_ENABLED);
return TRUE;
}
/* Legacy 0.6 compatibility interface */
static gboolean
@ -2910,9 +2961,9 @@ nm_manager_start (NMManager *self)
manager_set_radio_enabled (self, rstate, rstate->enabled && enabled);
}
/* Log overall networking status - asleep/running */
/* Log overall networking status - enabled/disabled */
nm_log_info (LOGD_CORE, "Networking is %s by state file",
priv->sleeping ? "disabled" : "enabled");
priv->net_enabled ? "enabled" : "disabled");
system_unmanaged_devices_changed_cb (priv->sys_settings, NULL, self);
system_hostname_changed_cb (priv->sys_settings, NULL, self);
@ -2964,7 +3015,7 @@ nm_manager_get (const char *config_file,
priv->state_file = g_strdup (state_file);
priv->sleeping = !initial_net_enabled;
priv->net_enabled = initial_net_enabled;
priv->radio_states[RFKILL_TYPE_WLAN].enabled = initial_wifi_enabled;
priv->radio_states[RFKILL_TYPE_WWAN].enabled = initial_wwan_enabled;
@ -3088,6 +3139,10 @@ set_property (GObject *object, guint prop_id,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
switch (prop_id) {
case PROP_NETWORKING_ENABLED:
/* Construct only for now */
priv->net_enabled = g_value_get_boolean (value);
break;
case PROP_WIRELESS_ENABLED:
manager_set_radio_enabled (NM_MANAGER (object),
&priv->radio_states[RFKILL_TYPE_WLAN],
@ -3116,6 +3171,9 @@ get_property (GObject *object, guint prop_id,
nm_manager_update_state (self);
g_value_set_uint (value, priv->state);
break;
case PROP_NETWORKING_ENABLED:
g_value_set_boolean (value, priv->net_enabled);
break;
case PROP_WIRELESS_ENABLED:
g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].enabled);
break;
@ -3255,6 +3313,14 @@ nm_manager_class_init (NMManagerClass *manager_class)
0, NM_STATE_DISCONNECTED, 0,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_NETWORKING_ENABLED,
g_param_spec_boolean (NM_MANAGER_NETWORKING_ENABLED,
"NetworkingEnabled",
"Is networking enabled",
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_WIRELESS_ENABLED,
g_param_spec_boolean (NM_MANAGER_WIRELESS_ENABLED,
@ -3304,6 +3370,7 @@ nm_manager_class_init (NMManagerClass *manager_class)
NULL,
G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT));
/* Sleeping is not exported over D-Bus */
g_object_class_install_property
(object_class, PROP_SLEEPING,
g_param_spec_boolean (NM_MANAGER_SLEEPING,

View file

@ -16,7 +16,7 @@
* 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 - 2010 Red Hat, Inc.
*/
#ifndef NM_MANAGER_H
@ -35,6 +35,14 @@
#define NM_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_MANAGER))
#define NM_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MANAGER, NMManagerClass))
#define NM_MANAGER_STATE "state"
#define NM_MANAGER_NETWORKING_ENABLED "networking-enabled"
#define NM_MANAGER_WIRELESS_ENABLED "wireless-enabled"
#define NM_MANAGER_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled"
#define NM_MANAGER_WWAN_ENABLED "wwan-enabled"
#define NM_MANAGER_WWAN_HARDWARE_ENABLED "wwan-hardware-enabled"
#define NM_MANAGER_ACTIVE_CONNECTIONS "active-connections"
/* Not exported */
#define NM_MANAGER_HOSTNAME "hostname"
#define NM_MANAGER_SLEEPING "sleeping"

View file

@ -718,13 +718,14 @@ hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
static void
sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
{
gboolean sleeping = FALSE;
gboolean sleeping = FALSE, enabled = FALSE;
GSList *connections, *iter;
g_object_get (G_OBJECT (manager), NM_MANAGER_SLEEPING, &sleeping, NULL);
g_object_get (G_OBJECT (manager), NM_MANAGER_NETWORKING_ENABLED, &enabled, NULL);
/* Clear the invalid flag on all connections so they'll get retried on wakeup */
if (sleeping) {
if (sleeping || !enabled) {
connections = nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_SYSTEM);
connections = g_slist_concat (connections, nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_USER));
for (iter = connections; iter; iter = g_slist_next (iter))
@ -1055,6 +1056,10 @@ nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager)
G_CALLBACK (sleeping_changed), policy);
policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
id = g_signal_connect (manager, "notify::" NM_MANAGER_NETWORKING_ENABLED,
G_CALLBACK (sleeping_changed), policy);
policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
id = g_signal_connect (manager, "device-added",
G_CALLBACK (device_added), policy);
policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);