core: add a "default-unmanaged" setting for devices

Allow devices to declare themselves unmanaged-by-default, but tweak
nm-manager and nm-policy to allow activating matching connections on
those devices anyway.

(This ensures that NM keeps its hands completely off the device unless
the user explicitly asks it to do something with it.)
This commit is contained in:
Dan Winship 2013-04-24 10:40:58 -04:00
parent ab7ebead2c
commit 2226a00cc2
4 changed files with 126 additions and 60 deletions

View file

@ -184,13 +184,15 @@ typedef struct {
char * driver;
char * driver_version;
char * firmware_version;
gboolean managed; /* whether managed by NM or not */
RfKillType rfkill_type;
gboolean firmware_missing;
GHashTable * available_connections;
guint8 hw_addr[NM_UTILS_HWADDR_LEN_MAX];
guint hw_addr_len;
gboolean manager_managed; /* whether managed by NMManager or not */
gboolean default_unmanaged; /* whether unmanaged by default */
guint32 ip4_address;
NMActRequest * act_request;
@ -1342,6 +1344,22 @@ nm_device_is_available (NMDevice *self)
return TRUE;
}
gboolean
nm_device_can_activate (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (!priv->manager_managed)
return FALSE;
if (!priv->default_unmanaged && priv->state < NM_DEVICE_STATE_DISCONNECTED)
return FALSE;
if (priv->state > NM_DEVICE_STATE_DISCONNECTED)
return FALSE;
return nm_device_is_available (self);
}
gboolean
nm_device_ignore_carrier (NMDevice *dev)
{
@ -4123,6 +4141,21 @@ nm_device_activate (NMDevice *self, NMActRequest *req)
nm_device_get_iface (self),
nm_connection_get_id (connection));
if (priv->state < NM_DEVICE_STATE_DISCONNECTED) {
g_return_if_fail (nm_device_can_activate (self));
if (priv->state == NM_DEVICE_STATE_UNMANAGED) {
nm_device_state_changed (self,
NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_NONE);
}
if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) {
nm_device_state_changed (self,
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NONE);
}
}
g_warn_if_fail (priv->state == NM_DEVICE_STATE_DISCONNECTED);
priv->act_request = g_object_ref (req);
@ -4524,7 +4557,7 @@ dispose (GObject *object)
g_warn_if_fail (priv->slaves == NULL);
/* Take the device itself down and clear its IPv4 configuration */
if (priv->managed && take_down) {
if (nm_device_get_managed (self) && take_down) {
NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;
nm_device_take_down (self, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
@ -4662,9 +4695,6 @@ set_property (GObject *object, guint prop_id,
case PROP_IP4_ADDRESS:
priv->ip4_address = g_value_get_uint (value);
break;
case PROP_MANAGED:
priv->managed = g_value_get_boolean (value);
break;
case PROP_AUTOCONNECT:
priv->autoconnect = g_value_get_boolean (value);
break;
@ -4807,7 +4837,7 @@ get_property (GObject *object, guint prop_id,
g_value_set_uint (value, priv->type);
break;
case PROP_MANAGED:
g_value_set_boolean (value, priv->managed);
g_value_set_boolean (value, nm_device_get_managed (self));
break;
case PROP_AUTOCONNECT:
g_value_set_boolean (value, priv->autoconnect);
@ -5011,7 +5041,7 @@ nm_device_class_init (NMDeviceClass *klass)
"Managed",
"Managed",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_AUTOCONNECT,
@ -5385,7 +5415,8 @@ nm_device_state_changed (NMDevice *device,
* about to assume a connection since that defeats the purpose of
* assuming the device's existing connection.
*/
if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED)
if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED &&
old_state != NM_DEVICE_STATE_UNMANAGED)
nm_device_deactivate (device, reason);
break;
case NM_DEVICE_STATE_DISCONNECTED:
@ -5416,10 +5447,17 @@ nm_device_state_changed (NMDevice *device,
nm_device_get_iface (device));
nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
} else {
nm_log_dbg (LOGD_DEVICE, "(%s): device not yet available for transition to DISCONNECTED",
nm_device_get_iface (device));
if (old_state == NM_DEVICE_STATE_UNMANAGED) {
nm_log_dbg (LOGD_DEVICE, "(%s): device not yet available for transition to DISCONNECTED",
nm_device_get_iface (device));
} else if (old_state > NM_DEVICE_STATE_UNAVAILABLE && priv->default_unmanaged)
nm_device_queue_state (device, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
}
break;
case NM_DEVICE_STATE_DISCONNECTED:
if (old_state > NM_DEVICE_STATE_DISCONNECTED && priv->default_unmanaged)
nm_device_queue_state (device, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
break;
case NM_DEVICE_STATE_ACTIVATED:
nm_log_info (LOGD_DEVICE, "Activation (%s) successful, device activated.",
nm_device_get_iface (device));
@ -5633,39 +5671,79 @@ nm_device_queued_ip_config_change_clear (NMDevice *self)
gboolean
nm_device_get_managed (NMDevice *device)
{
g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
return NM_DEVICE_GET_PRIVATE (device)->managed;
}
void
nm_device_set_managed (NMDevice *device,
gboolean managed,
NMDeviceStateReason reason)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (device));
g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
priv = NM_DEVICE_GET_PRIVATE (device);
if (priv->managed == managed)
return;
priv->managed = managed;
if (!priv->manager_managed)
return FALSE;
else if (priv->default_unmanaged)
return (priv->state != NM_DEVICE_STATE_UNMANAGED);
else
return TRUE;
}
static void
nm_device_set_managed_internal (NMDevice *device,
gboolean managed,
NMDeviceStateReason reason)
{
nm_log_dbg (LOGD_DEVICE, "(%s): now %s",
nm_device_get_iface (device),
managed ? "managed" : "unmanaged");
g_object_notify (G_OBJECT (device), NM_DEVICE_MANAGED);
/* If now managed, jump to unavailable */
if (managed)
nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE, reason);
else
nm_device_state_changed (device, NM_DEVICE_STATE_UNMANAGED, reason);
}
void
nm_device_set_manager_managed (NMDevice *device,
gboolean managed,
NMDeviceStateReason reason)
{
NMDevicePrivate *priv;
gboolean was_managed, now_managed;
g_return_if_fail (NM_IS_DEVICE (device));
priv = NM_DEVICE_GET_PRIVATE (device);
was_managed = nm_device_get_managed (device);
priv->manager_managed = managed;
now_managed = nm_device_get_managed (device);
if (was_managed != now_managed)
nm_device_set_managed_internal (device, now_managed, reason);
}
void
nm_device_set_default_unmanaged (NMDevice *device,
gboolean default_unmanaged)
{
NMDevicePrivate *priv;
gboolean was_managed, now_managed;
g_return_if_fail (NM_IS_DEVICE (device));
priv = NM_DEVICE_GET_PRIVATE (device);
was_managed = nm_device_get_managed (device);
priv->default_unmanaged = default_unmanaged;
now_managed = nm_device_get_managed (device);
if (was_managed != now_managed)
nm_device_set_managed_internal (device, now_managed,
default_unmanaged ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED :
NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
/**
* nm_device_spec_match_list:
* @device: an #NMDevice

View file

@ -237,6 +237,8 @@ NMActRequest * nm_device_get_act_request (NMDevice *dev);
NMConnection * nm_device_get_connection (NMDevice *dev);
gboolean nm_device_is_available (NMDevice *dev);
gboolean nm_device_can_activate (NMDevice *dev);
gboolean nm_device_ignore_carrier (NMDevice *dev);
NMConnection * nm_device_get_best_auto_connection (NMDevice *dev,
@ -279,9 +281,11 @@ void nm_device_set_enabled (NMDevice *device, gboolean enabled);
RfKillType nm_device_get_rfkill_type (NMDevice *device);
gboolean nm_device_get_managed (NMDevice *device);
void nm_device_set_managed (NMDevice *device,
gboolean managed,
NMDeviceStateReason reason);
void nm_device_set_manager_managed (NMDevice *device,
gboolean managed,
NMDeviceStateReason reason);
void nm_device_set_default_unmanaged (NMDevice *device,
gboolean default_unmanaged);
gboolean nm_device_get_autoconnect (NMDevice *device);

View file

@ -620,7 +620,7 @@ remove_one_device (NMManager *manager,
if ( !nm_device_can_assume_connections (device)
|| (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED)
|| !quitting)
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
nm_device_set_manager_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
}
g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager);
@ -1362,10 +1362,10 @@ system_unmanaged_devices_changed_cb (NMSettings *settings,
gboolean managed;
managed = !nm_device_spec_match_list (device, unmanaged_specs);
nm_device_set_managed (device,
managed,
managed ? NM_DEVICE_STATE_REASON_NOW_MANAGED :
NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
nm_device_set_manager_managed (device,
managed,
managed ? NM_DEVICE_STATE_REASON_NOW_MANAGED :
NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
}
}
@ -1788,7 +1788,7 @@ add_device (NMManager *self, NMDevice *device)
static guint32 devcount = 0;
const GSList *unmanaged_specs;
NMConnection *existing = NULL;
gboolean managed = FALSE, enabled = FALSE;
gboolean enabled = FALSE;
RfKillType rtype;
NMDeviceType devtype;
@ -1887,11 +1887,10 @@ add_device (NMManager *self, NMDevice *device)
unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
if ( !manager_sleeping (self)
&& !nm_device_spec_match_list (device, unmanaged_specs)) {
nm_device_set_managed (device,
TRUE,
existing ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
NM_DEVICE_STATE_REASON_NOW_MANAGED);
managed = TRUE;
nm_device_set_manager_managed (device,
TRUE,
existing ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
nm_settings_device_added (priv->settings, device);
@ -1903,7 +1902,7 @@ add_device (NMManager *self, NMDevice *device)
system_create_virtual_devices (self);
/* If the device has a connection it can assume, do that now */
if (existing && managed && nm_device_is_available (device)) {
if (existing && nm_device_can_activate (device)) {
NMActiveConnection *ac;
GError *error = NULL;
@ -2753,7 +2752,6 @@ nm_manager_activate_connection (NMManager *manager,
NMManagerPrivate *priv;
NMDevice *device = NULL;
gulong sender_uid = G_MAXULONG;
NMDeviceState state;
char *iface;
NMDevice *master_device = NULL;
NMConnection *master_connection = NULL;
@ -2843,22 +2841,10 @@ nm_manager_activate_connection (NMManager *manager,
"Failed to create virtual interface");
return NULL;
}
/* A newly created device, if allowed to be managed by NM, will be
* in the UNAVAILABLE state here. Since we want to use it right
* away, we transition it immediately to DISCONNECTED.
*/
if ( nm_device_is_available (device)
&& (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) {
nm_device_state_changed (device,
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NONE);
}
}
}
state = nm_device_get_state (device);
if (state < NM_DEVICE_STATE_DISCONNECTED) {
if (!nm_device_can_activate (device)) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE,
"Device not managed by NetworkManager or unavailable");
return NULL;
@ -3245,7 +3231,7 @@ do_sleep_wake (NMManager *self)
* 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);
nm_device_set_manager_managed (NM_DEVICE (iter->data), FALSE, NM_DEVICE_STATE_REASON_SLEEPING);
} else {
nm_log_info (LOGD_SUSPEND, "waking up and re-enabling...");
@ -3282,9 +3268,9 @@ do_sleep_wake (NMManager *self)
g_object_set (G_OBJECT (device), NM_DEVICE_AUTOCONNECT, TRUE, NULL);
if (nm_device_spec_match_list (device, unmanaged_specs))
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
nm_device_set_manager_managed (device, FALSE, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
else
nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
nm_device_set_manager_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
}

View file

@ -1146,13 +1146,11 @@ static void
schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds)
{
ActivateData *data;
NMDeviceState state;
if (nm_manager_get_state (policy->manager) == NM_STATE_ASLEEP)
return;
state = nm_device_get_state (device);
if (state < NM_DEVICE_STATE_DISCONNECTED)
if (!nm_device_can_activate (device))
return;
if (!nm_device_get_enabled (device))