summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/devices/nm-device.c63
-rw-r--r--src/devices/nm-device.h16
-rw-r--r--src/nm-manager.c142
3 files changed, 161 insertions, 60 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 6727e4ec4e..02ba943ead 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -1204,7 +1204,7 @@ link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMPlat
if (klass->link_changed)
klass->link_changed (device, info);
- if (priv->admin_up == !!info->up) {
+ if (priv->admin_up != !!info->up) {
priv->admin_up = !!info->up;
g_object_notify (G_OBJECT (device), NM_DEVICE_ADMIN_UP);
}
@@ -7140,6 +7140,25 @@ nm_device_queued_ip_config_change_clear (NMDevice *self)
}
}
+static gboolean
+_get_managed_from_flags (NMDevice *device, NMUnmanagedFlags flags)
+{
+ gboolean managed;
+
+ g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+
+ /* Return the composite of all managed flags. However, if the device
+ * is a default-unmanaged device, and would be managed except for the
+ * default-unmanaged flag (eg, only NM_UNMANAGED_DEFAULT is set) then
+ * the device is managed whenever it's not in the UNMANAGED state.
+ */
+ managed = !(flags & ~NM_UNMANAGED_DEFAULT);
+ if (managed && (flags & NM_UNMANAGED_DEFAULT))
+ managed = (nm_device_get_state (device) != NM_DEVICE_STATE_UNMANAGED);
+
+ return managed;
+}
+
/**
* nm_device_get_managed():
* @device: the #NMDevice
@@ -7149,23 +7168,39 @@ nm_device_queued_ip_config_change_clear (NMDevice *self)
gboolean
nm_device_get_managed (NMDevice *device)
{
- NMDevicePrivate *priv;
- gboolean managed;
-
g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
- priv = NM_DEVICE_GET_PRIVATE (device);
+ return _get_managed_from_flags (device, NM_DEVICE_GET_PRIVATE (device)->unmanaged_flags);
+}
- /* Return the composite of all managed flags. However, if the device
- * is a default-unmanaged device, and would be managed except for the
- * default-unmanaged flag (eg, only NM_UNMANAGED_DEFAULT is set) then
- * the device is managed whenever it's not in the UNMANAGED state.
- */
- managed = !(priv->unmanaged_flags & ~NM_UNMANAGED_DEFAULT);
- if (managed && (priv->unmanaged_flags & NM_UNMANAGED_DEFAULT))
- managed = (priv->state != NM_DEVICE_STATE_UNMANAGED);
+/**
+ * nm_device_would_be_managed():
+ * @device: the #NMDevice
+ * @flag: the #NMUnmanageFlag to check
+ * @unmanaged: the value for @flag
+ *
+ * Checks if a device would be managed or not if the unmanaged flag @flag
+ * was changed to @value, without actually changing @flag to @value.
+ *
+ * Returns: %TRUE if the device would be managed if @flag was changed to
+ * @value, %FALSE if not
+ */
+gboolean
+nm_device_would_be_managed (NMDevice *device,
+ NMUnmanagedFlags flag,
+ gboolean unmanaged)
+{
+ NMUnmanagedFlags new_flags;
- return managed;
+ g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+
+ new_flags = NM_DEVICE_GET_PRIVATE (device)->unmanaged_flags;
+ if (unmanaged)
+ new_flags |= flag;
+ else
+ new_flags &= ~flag;
+
+ return _get_managed_from_flags (device, new_flags);
}
/**
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 4fc59e89af..86155a83c9 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -303,19 +303,25 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device);
* @NM_UNMANAGED_INTERNAL: %TRUE when unmanaged by internal decision (ie,
* because NM is sleeping or not managed for some other reason)
* @NM_UNMANAGED_USER: %TRUE when unmanaged by user decision (via unmanaged-specs)
+ * @NM_MANAGED_ADMIN_DOWN: whether unmanaged because device is administratively
+ * down (!IFF_UP)
*/
typedef enum {
- NM_UNMANAGED_NONE = 0x00,
- NM_UNMANAGED_DEFAULT = 0x01,
- NM_UNMANAGED_INTERNAL = 0x02,
- NM_UNMANAGED_USER = 0x04,
+ NM_UNMANAGED_NONE = 0x00,
+ NM_UNMANAGED_DEFAULT = 0x01,
+ NM_UNMANAGED_INTERNAL = 0x02,
+ NM_UNMANAGED_USER = 0x04,
+ NM_UNMANAGED_ADMIN_DOWN = 0x08,
/* Boundary value */
__NM_UNMANAGED_LAST,
- NM_UNMANAGED_LAST = __NM_UNMANAGED_LAST - 1,
+ NM_UNMANAGED_LAST = __NM_UNMANAGED_LAST - 1,
} NMUnmanagedFlags;
gboolean nm_device_get_managed (NMDevice *device);
+gboolean nm_device_would_be_managed (NMDevice *device,
+ NMUnmanagedFlags flag,
+ gboolean unmanaged);
gboolean nm_device_get_default_unmanaged (NMDevice *device);
gboolean nm_device_get_unmanaged_flag (NMDevice *device, NMUnmanagedFlags flag);
void nm_device_set_unmanaged (NMDevice *device,
diff --git a/src/nm-manager.c b/src/nm-manager.c
index ea0663f5be..2989c634e2 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -1735,6 +1735,76 @@ get_existing_connection (NMManager *manager, NMDevice *device)
return added ? NM_CONNECTION (added) : NULL;
}
+static void
+assume_connection (NMManager *self, NMDevice *device, NMConnection *connection)
+{
+ NMActiveConnection *active, *master_ac = NULL;
+ NMAuthSubject *subject;
+ GError *error = NULL;
+
+ nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection '%s'",
+ nm_device_get_iface (device),
+ nm_connection_get_id (connection));
+
+ /* Move device to DISCONNECTED to activate the connection */
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
+
+ subject = nm_auth_subject_new_internal ();
+ active = _new_active_connection (self, connection, NULL, device, subject, &error);
+ if (active) {
+ /* If the device is a slave or VLAN, find the master ActiveConnection */
+ if (find_master (self, connection, device, NULL, NULL, &master_ac, NULL) && master_ac)
+ nm_active_connection_set_master (active, master_ac);
+
+ nm_active_connection_set_assumed (active, TRUE);
+ nm_active_connection_export (active);
+ active_connection_add (self, active);
+ nm_device_queue_activation (device, NM_ACT_REQUEST (active));
+ g_object_unref (active);
+ } else {
+ nm_log_warn (LOGD_DEVICE, "(%s): assumed connection '%s' failed to activate: (%d) %s",
+ nm_device_get_iface (device),
+ nm_connection_get_id (connection),
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ g_error_free (error);
+ }
+ g_object_unref (subject);
+}
+
+static void
+device_admin_up (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self)
+{
+ NMConnection *connection = NULL;
+
+ g_return_if_fail (nm_device_get_unmanaged_flag (device, NM_UNMANAGED_ADMIN_DOWN));
+ if (!nm_device_get_admin_up (device))
+ return;
+
+ /* Stop listening the first time the device comes up */
+ g_signal_handlers_disconnect_by_func (device, device_admin_up, self);
+
+ /* Generate a connection if the device will be managed when we remove
+ * the UNMANAGED_ADMIN_DOWN flag. We have to check this before clearing
+ * the flag, since clearing the flag changes device state, and we send
+ * a different device state reason if there's a connection we can assume.
+ */
+ if (nm_device_would_be_managed (device, NM_UNMANAGED_ADMIN_DOWN, FALSE))
+ connection = get_existing_connection (self, device);
+
+ nm_device_set_unmanaged (device,
+ NM_UNMANAGED_ADMIN_DOWN,
+ FALSE,
+ connection ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
+ NM_DEVICE_STATE_REASON_NOW_MANAGED);
+ if (connection)
+ assume_connection (self, device, connection);
+}
+
/**
* add_device:
* @self: the #NMManager
@@ -1752,12 +1822,13 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
char *path;
static guint32 devcount = 0;
const GSList *unmanaged_specs;
- gboolean user_unmanaged, sleeping;
+ gboolean user_unmanaged, sleeping, admin_down;
NMConnection *connection = NULL;
gboolean enabled = FALSE;
RfKillType rtype;
NMDeviceType devtype;
GSList *iter, *remove = NULL;
+ int ifindex;
devtype = nm_device_get_device_type (device);
@@ -1838,27 +1909,50 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
type_desc = nm_device_get_type_desc (device);
g_assert (type_desc);
driver = nm_device_get_driver (device);
+ ifindex = nm_device_get_ifindex (device);
if (!driver)
driver = "unknown";
nm_log_info (LOGD_HW, "(%s): new %s device (driver: '%s' ifindex: %d)",
- iface, type_desc, driver, nm_device_get_ifindex (device));
+ iface, type_desc, driver, ifindex);
+ /* Unmanaged by user? */
unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs);
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_USER, user_unmanaged);
+ /* Unmanaged by NM sleeping? */
sleeping = manager_sleeping (self);
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_INTERNAL, sleeping);
+ /* Don't manage downed software devices until the thing that created them
+ * brings them up; but for backwards compatibility's sake this doesn't
+ * apply to default-unmanaged devices.
+ */
+ admin_down = (generate_con &&
+ nm_device_is_software (device) &&
+ !nm_platform_link_is_up (ifindex) &&
+ !nm_device_get_default_unmanaged (device));
+ if (admin_down) {
+ nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_ADMIN_DOWN, admin_down);
+ /* Wait for device to come up before managing it and generating a connection */
+ g_signal_connect (device, "notify::" NM_DEVICE_ADMIN_UP,
+ G_CALLBACK (device_admin_up),
+ self);
+ }
+
+ /* Export the device */
path = g_strdup_printf ("/org/freedesktop/NetworkManager/Devices/%d", devcount++);
nm_device_set_path (device, path);
nm_dbus_manager_register_object (priv->dbus_mgr, path, device);
nm_log_info (LOGD_CORE, "(%s): exported as %s", iface, path);
g_free (path);
- /* Don't generate a connection e.g. for devices NM just created, or
- * for the loopback, or when we're sleeping. */
- if (generate_con && !user_unmanaged && !sleeping)
+ /* Generate and assume connections for fully-managed devices, and for
+ * default unmanaged devices that are not otherwise unmanaged.
+ */
+ if ( generate_con
+ && (nm_device_get_managed (device) ||
+ nm_device_would_be_managed (device, NM_UNMANAGED_DEFAULT, FALSE)))
connection = get_existing_connection (self, device);
/* Start the device if it's supposed to be managed. Note that this will
@@ -1881,42 +1975,8 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
system_create_virtual_devices (self);
/* If the device has a connection it can assume, do that now */
- if (connection) {
- NMActiveConnection *active;
- NMAuthSubject *subject;
- GError *error = NULL;
-
- nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection",
- nm_device_get_iface (device));
-
- /* Move device to DISCONNECTED to activate the connection */
- nm_device_state_changed (device,
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
-
- subject = nm_auth_subject_new_internal ();
- active = _new_active_connection (self, connection, NULL, device, subject, &error);
- if (active) {
- NMActiveConnection *master_ac = NULL;
-
- /* If the device is a slave or VLAN, find the master ActiveConnection */
- if (find_master (self, connection, device, NULL, NULL, &master_ac, NULL) && master_ac)
- nm_active_connection_set_master (active, master_ac);
-
- nm_active_connection_set_assumed (active, TRUE);
- nm_active_connection_export (active);
- active_connection_add (self, active);
- nm_device_queue_activation (device, NM_ACT_REQUEST (active));
- g_object_unref (active);
- } else {
- nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s",
- nm_connection_get_path (connection),
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- g_error_free (error);
- }
- g_object_unref (subject);
- }
+ if (connection)
+ assume_connection (self, device, connection);
}
static NMDevice *