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

View file

@ -237,6 +237,8 @@ NMActRequest * nm_device_get_act_request (NMDevice *dev);
NMConnection * nm_device_get_connection (NMDevice *dev); NMConnection * nm_device_get_connection (NMDevice *dev);
gboolean nm_device_is_available (NMDevice *dev); gboolean nm_device_is_available (NMDevice *dev);
gboolean nm_device_can_activate (NMDevice *dev);
gboolean nm_device_ignore_carrier (NMDevice *dev); gboolean nm_device_ignore_carrier (NMDevice *dev);
NMConnection * nm_device_get_best_auto_connection (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); RfKillType nm_device_get_rfkill_type (NMDevice *device);
gboolean nm_device_get_managed (NMDevice *device); gboolean nm_device_get_managed (NMDevice *device);
void nm_device_set_managed (NMDevice *device, void nm_device_set_manager_managed (NMDevice *device,
gboolean managed, gboolean managed,
NMDeviceStateReason reason); NMDeviceStateReason reason);
void nm_device_set_default_unmanaged (NMDevice *device,
gboolean default_unmanaged);
gboolean nm_device_get_autoconnect (NMDevice *device); 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) if ( !nm_device_can_assume_connections (device)
|| (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED) || (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED)
|| !quitting) || !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); g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager);
@ -1362,7 +1362,7 @@ system_unmanaged_devices_changed_cb (NMSettings *settings,
gboolean managed; gboolean managed;
managed = !nm_device_spec_match_list (device, unmanaged_specs); managed = !nm_device_spec_match_list (device, unmanaged_specs);
nm_device_set_managed (device, nm_device_set_manager_managed (device,
managed, managed,
managed ? NM_DEVICE_STATE_REASON_NOW_MANAGED : managed ? NM_DEVICE_STATE_REASON_NOW_MANAGED :
NM_DEVICE_STATE_REASON_NOW_UNMANAGED); NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
@ -1788,7 +1788,7 @@ add_device (NMManager *self, NMDevice *device)
static guint32 devcount = 0; static guint32 devcount = 0;
const GSList *unmanaged_specs; const GSList *unmanaged_specs;
NMConnection *existing = NULL; NMConnection *existing = NULL;
gboolean managed = FALSE, enabled = FALSE; gboolean enabled = FALSE;
RfKillType rtype; RfKillType rtype;
NMDeviceType devtype; NMDeviceType devtype;
@ -1887,11 +1887,10 @@ add_device (NMManager *self, NMDevice *device)
unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings); unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
if ( !manager_sleeping (self) if ( !manager_sleeping (self)
&& !nm_device_spec_match_list (device, unmanaged_specs)) { && !nm_device_spec_match_list (device, unmanaged_specs)) {
nm_device_set_managed (device, nm_device_set_manager_managed (device,
TRUE, TRUE,
existing ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED : existing ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
NM_DEVICE_STATE_REASON_NOW_MANAGED); NM_DEVICE_STATE_REASON_NOW_MANAGED);
managed = TRUE;
} }
nm_settings_device_added (priv->settings, device); nm_settings_device_added (priv->settings, device);
@ -1903,7 +1902,7 @@ add_device (NMManager *self, NMDevice *device)
system_create_virtual_devices (self); system_create_virtual_devices (self);
/* If the device has a connection it can assume, do that now */ /* 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; NMActiveConnection *ac;
GError *error = NULL; GError *error = NULL;
@ -2753,7 +2752,6 @@ nm_manager_activate_connection (NMManager *manager,
NMManagerPrivate *priv; NMManagerPrivate *priv;
NMDevice *device = NULL; NMDevice *device = NULL;
gulong sender_uid = G_MAXULONG; gulong sender_uid = G_MAXULONG;
NMDeviceState state;
char *iface; char *iface;
NMDevice *master_device = NULL; NMDevice *master_device = NULL;
NMConnection *master_connection = NULL; NMConnection *master_connection = NULL;
@ -2843,22 +2841,10 @@ nm_manager_activate_connection (NMManager *manager,
"Failed to create virtual interface"); "Failed to create virtual interface");
return NULL; 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 (!nm_device_can_activate (device)) {
if (state < NM_DEVICE_STATE_DISCONNECTED) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE, g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE,
"Device not managed by NetworkManager or unavailable"); "Device not managed by NetworkManager or unavailable");
return NULL; return NULL;
@ -3245,7 +3231,7 @@ do_sleep_wake (NMManager *self)
* the manager wakes up. * the manager wakes up.
*/ */
for (iter = priv->devices; iter; iter = iter->next) 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 { } else {
nm_log_info (LOGD_SUSPEND, "waking up and re-enabling..."); 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); g_object_set (G_OBJECT (device), NM_DEVICE_AUTOCONNECT, TRUE, NULL);
if (nm_device_spec_match_list (device, unmanaged_specs)) 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 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) schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds)
{ {
ActivateData *data; ActivateData *data;
NMDeviceState state;
if (nm_manager_get_state (policy->manager) == NM_STATE_ASLEEP) if (nm_manager_get_state (policy->manager) == NM_STATE_ASLEEP)
return; return;
state = nm_device_get_state (device); if (!nm_device_can_activate (device))
if (state < NM_DEVICE_STATE_DISCONNECTED)
return; return;
if (!nm_device_get_enabled (device)) if (!nm_device_get_enabled (device))