diff options
-rw-r--r-- | src/devices/nm-device.c | 20 | ||||
-rw-r--r-- | src/devices/nm-device.h | 8 | ||||
-rw-r--r-- | src/nm-manager.c | 118 |
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 * |