From 2226a00cc2400a4150a83c119c8bfcc06ff2e988 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 24 Apr 2013 10:40:58 -0400 Subject: [PATCH] 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.) --- src/nm-device.c | 128 ++++++++++++++++++++++++++++++++++++++--------- src/nm-device.h | 10 ++-- src/nm-manager.c | 44 ++++++---------- src/nm-policy.c | 4 +- 4 files changed, 126 insertions(+), 60 deletions(-) diff --git a/src/nm-device.c b/src/nm-device.c index 37fcfb7868..f7c420ca73 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -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 diff --git a/src/nm-device.h b/src/nm-device.h index ea3cc0e706..f6b4f95f4f 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -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); diff --git a/src/nm-manager.c b/src/nm-manager.c index 057bc3c1b7..a82d741ade 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -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); } } diff --git a/src/nm-policy.c b/src/nm-policy.c index 8c034ea6a1..faa9648fa1 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -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))