summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/devices/nm-device.c20
-rw-r--r--src/devices/nm-device.h8
-rw-r--r--src/nm-manager.c118
3 files changed, 104 insertions, 42 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 430363495f..4b23d8b777 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -105,6 +105,7 @@ enum {
IP6_CONFIG_CHANGED,
REMOVED,
RECHECK_AUTO_ACTIVATE,
+ ADMIN_UP,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -235,6 +236,7 @@ typedef struct {
gpointer act_source6_func;
/* Link stuff */
+ gboolean admin_up; /* IFF_UP */
guint link_connected_id;
guint link_disconnected_id;
guint carrier_defer_id;
@@ -1196,6 +1198,15 @@ 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) {
+ priv->admin_up = info->up;
+
+ /* If this is the first time a device that we're waiting to come up
+ * has come up, notify the manager.
+ */
+ if (priv->admin_up && !nm_device_get_managed_flag (device, NM_MANAGED_ADMIN_UP))
+ g_signal_emit (device, signals[ADMIN_UP], 0);
+ }
} else if (priv->ip_iface && ifindex == nm_device_get_ip_ifindex (device)) {
if (info->name[0] && strcmp (priv->ip_iface, info->name)) {
nm_log_info (LOGD_DEVICE, "(%s): interface index %d renamed ip_iface (%d) from '%s' to '%s'",
@@ -6376,6 +6387,13 @@ nm_device_class_init (NMDeviceClass *klass)
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
+ signals[ADMIN_UP] =
+ g_signal_new (NM_DEVICE_ADMIN_UP,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
G_TYPE_FROM_CLASS (klass),
&dbus_glib_nm_device_object_info);
@@ -7165,6 +7183,8 @@ nm_device_get_managed_flag (NMDevice *device, NMManagedFlags flag)
return FALSE;
else if (!(priv->managed_flags & NM_MANAGED_USER))
return FALSE;
+ else if (!(priv->managed_flags & NM_MANAGED_ADMIN_UP))
+ return FALSE;
else if (!(priv->managed_flags & NM_MANAGED_DEFAULT))
return (priv->state != NM_DEVICE_STATE_UNMANAGED);
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 35f0f49240..9ca1b5b3df 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -76,6 +76,7 @@
#define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed"
#define NM_DEVICE_REMOVED "removed"
#define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate"
+#define NM_DEVICE_ADMIN_UP "admin-up"
G_BEGIN_DECLS
@@ -303,6 +304,8 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device);
* @NM_MANAGED_INTERNAL: whether managed by internal decision (ie, because NM
* is sleeping or not managed the device for some other reason)
* @NM_MANAGED_USER: whether managed by user decision (ie, not in unmanaged-specs)
+ * @NM_MANAGED_ADMIN_UP: whether managed because device is administratively
+ * enabled (IFF_UP)
*/
typedef enum {
NM_MANAGED_UNKNOWN = 0x00,
@@ -310,10 +313,11 @@ typedef enum {
NM_MANAGED_DEFAULT = 0x01,
NM_MANAGED_INTERNAL = 0x02,
NM_MANAGED_USER = 0x04,
+ NM_MANAGED_ADMIN_UP = 0x08,
/* Boundary values */
- NM_MANAGED_LAST = NM_MANAGED_USER,
- NM_MANAGED_ALL = NM_MANAGED_DEFAULT | NM_MANAGED_INTERNAL | NM_MANAGED_USER,
+ NM_MANAGED_LAST = NM_MANAGED_ADMIN_UP,
+ NM_MANAGED_ALL = NM_MANAGED_DEFAULT | NM_MANAGED_INTERNAL | NM_MANAGED_USER | NM_MANAGED_ADMIN_UP,
} NMManagedFlags;
gboolean nm_device_get_managed (NMDevice *device);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index a92aa34dec..050a104bb6 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -1735,6 +1735,64 @@ 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, gpointer user_data)
+{
+ NMManager *self = NM_MANAGER (user_data);
+ NMConnection *connection = NULL;
+
+ if (nm_device_get_managed_flag (device, NM_MANAGED_USER) &&
+ nm_device_get_managed_flag (device, NM_MANAGED_INTERNAL))
+ connection = get_existing_connection (self, device);
+
+ nm_device_set_managed (device,
+ NM_MANAGED_ADMIN_UP,
+ TRUE,
+ connection ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
+ NM_DEVICE_STATE_REASON_NOW_MANAGED);
+ if (nm_device_get_managed (device) && connection)
+ assume_connection (self, device, connection);
+}
+
/**
* add_device:
* @self: the #NMManager
@@ -1752,12 +1810,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, wait_for_up;
NMConnection *connection = NULL;
gboolean enabled = FALSE;
RfKillType rtype;
NMDeviceType devtype;
GSList *iter, *remove = NULL;
+ int ifindex;
devtype = nm_device_get_device_type (device);
@@ -1795,6 +1854,10 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
G_CALLBACK (device_removed_cb),
self);
+ g_signal_connect (device, NM_DEVICE_ADMIN_UP,
+ G_CALLBACK (device_admin_up),
+ self);
+
if (priv->startup) {
g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION,
G_CALLBACK (device_has_pending_action_changed),
@@ -1838,17 +1901,26 @@ 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_specs = nm_settings_get_unmanaged_specs (priv->settings);
user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs);
sleeping = manager_sleeping (self);
+
+ /* Don't manage downed software devices until the user brings them up */
+ wait_for_up = (generate_con &&
+ nm_device_is_software (device) &&
+ !nm_platform_link_is_up (ifindex) &&
+ !nm_device_get_default_unmanaged (device));
+
nm_device_set_initial_managed_flags (device,
NM_MANAGED_USER, !user_unmanaged,
NM_MANAGED_INTERNAL, !sleeping,
+ NM_MANAGED_ADMIN_UP, !wait_for_up,
NM_MANAGED_UNKNOWN);
path = g_strdup_printf ("/org/freedesktop/NetworkManager/Devices/%d", devcount++);
@@ -1858,8 +1930,8 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
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)
+ * for the loopback, or when we're not managing the device yet. */
+ if (generate_con && !user_unmanaged && !sleeping && !wait_for_up)
connection = get_existing_connection (self, device);
/* Start the device if it'supposed to be managed. Note that this will
@@ -1882,42 +1954,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 *