From 5d9cef48c7960dd77a1f6424814179d3647fe4d7 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 26 Sep 2016 15:06:46 +0200 Subject: device: pass connection-uuid to NetworkManager to assume it The meaning of "assuming connections" will soon change. It will mean: seamlessly, gracefully activate a connection on a possibly already configured device. We only do that once, when NetworkManager starts. Then we pass on the connection-uuid from the last run, and try to take over that one gracefully. --- src/devices/nm-device.c | 53 +++++++++++++++++++++++ src/devices/nm-device.h | 4 ++ src/nm-act-request.c | 5 ++- src/nm-act-request.h | 3 +- src/nm-active-connection.c | 33 +++++++++++++- src/nm-active-connection.h | 3 ++ src/nm-checkpoint.c | 1 + src/nm-core-utils.c | 6 +++ src/nm-core-utils.h | 2 + src/nm-manager.c | 55 ++++++++++++++++++++---- src/nm-manager.h | 4 ++ src/nm-policy.c | 104 ++++++++++++++++++++++++++++++++++++--------- src/nm-types.h | 11 +++++ 13 files changed, 253 insertions(+), 31 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 8b6b7e4466..a0e4b5fdaa 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -220,6 +220,13 @@ typedef struct _NMDevicePrivate { NMDeviceState state; NMDeviceStateReason state_reason; QueuedState queued_state; + + /* The connection-uuid we preferrably try to autoactivate in a non-destructive way + * (that is: assuming the connection). + * The value is only piggy-backed here and used by NMPolicy to find the connection + * to assume. */ + char *connection_uuid_to_assume; + guint queued_ip4_config_id; guint queued_ip6_config_id; GSList *pending_actions; @@ -3469,6 +3476,48 @@ nm_device_check_slave_connection_compatible (NMDevice *self, NMConnection *slave return strcmp (connection_type, slave_type) == 0; } +void +nm_device_set_connection_uuid_to_assume (NMDevice *self, + const char *connection_uuid_to_assume) +{ + NMDevicePrivate *priv; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + + if (!connection_uuid_to_assume) { + if (priv->connection_uuid_to_assume) { + _LOGD (LOGD_DEVICE, "connection-uuid-to-assume: clear %s", + priv->connection_uuid_to_assume); + nm_clear_g_free (&priv->connection_uuid_to_assume); + } + } else if ( !priv->connection_uuid_to_assume + || !nm_streq (priv->connection_uuid_to_assume, connection_uuid_to_assume)) { + _LOGD (LOGD_DEVICE, "connection-uuid-to-assume: set %s%s%s%s", + connection_uuid_to_assume, + NM_PRINT_FMT_QUOTED (priv->connection_uuid_to_assume, " (was \"", priv->connection_uuid_to_assume, ")", "")); + g_free (priv->connection_uuid_to_assume); + priv->connection_uuid_to_assume = g_strdup (connection_uuid_to_assume); + } +} + +char * +nm_device_steal_connection_uuid_to_assume (NMDevice *self) +{ + NMDevicePrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + + priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->connection_uuid_to_assume) { + _LOGD (LOGD_DEVICE, "connection-uuid-to-assume: return %s", + priv->connection_uuid_to_assume); + } + return g_steal_pointer (&priv->connection_uuid_to_assume); +} + /** * nm_device_can_assume_connections: * @self: #NMDevice instance @@ -11140,6 +11189,9 @@ _set_state_full (NMDevice *self, old_state = priv->state; + if (state > NM_DEVICE_STATE_DISCONNECTED) + nm_device_set_connection_uuid_to_assume (self, NULL); + /* Do nothing if state isn't changing, but as a special case allow * re-setting UNAVAILABLE if the device is missing firmware so that we * can retry device initialization. @@ -12367,6 +12419,7 @@ finalize (GObject *object) g_free (priv->type_desc); g_free (priv->type_description); g_free (priv->dhcp_anycast_address); + g_free (priv->connection_uuid_to_assume); g_hash_table_unref (priv->ip6_saved_properties); g_hash_table_unref (priv->available_connections); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 85939d58c3..c4db534078 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -419,6 +419,10 @@ gboolean nm_device_complete_connection (NMDevice *device, gboolean nm_device_check_connection_compatible (NMDevice *device, NMConnection *connection); gboolean nm_device_check_slave_connection_compatible (NMDevice *device, NMConnection *connection); +void nm_device_set_connection_uuid_to_assume (NMDevice *self, + const char *connection_uuid_to_assume); +char *nm_device_steal_connection_uuid_to_assume (NMDevice *self); + gboolean nm_device_uses_assumed_connection (NMDevice *device); gboolean nm_device_unmanage_on_quit (NMDevice *self); diff --git a/src/nm-act-request.c b/src/nm-act-request.c index 40c1efa2e6..264a85f45b 100644 --- a/src/nm-act-request.c +++ b/src/nm-act-request.c @@ -511,6 +511,7 @@ nm_act_request_init (NMActRequest *req) * etc) that will be used to activate @connection and @device * @subject: the #NMAuthSubject representing the requestor of the activation * @device: the device/interface to configure according to @connection + * @activation_type: the activation type, whether to assume of fully configure. * * Creates a new device-based activation request. If an applied connection is * supplied, it shall not be modified by the caller afterwards. @@ -522,7 +523,8 @@ nm_act_request_new (NMSettingsConnection *settings_connection, NMConnection *applied_connection, const char *specific_object, NMAuthSubject *subject, - NMDevice *device) + NMDevice *device, + NMActivationType activation_type) { g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); g_return_val_if_fail (NM_IS_DEVICE (device), NULL); @@ -534,6 +536,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection, NM_ACTIVE_CONNECTION_INT_DEVICE, device, NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, + NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE, (guint) activation_type, NULL); } diff --git a/src/nm-act-request.h b/src/nm-act-request.h index 2443633f00..c0be131eaa 100644 --- a/src/nm-act-request.h +++ b/src/nm-act-request.h @@ -40,7 +40,8 @@ NMActRequest *nm_act_request_new (NMSettingsConnection *settings_connec NMConnection *applied_connection, const char *specific_object, NMAuthSubject *subject, - NMDevice *device); + NMDevice *device, + NMActivationType activation_type); NMSettingsConnection *nm_act_request_get_settings_connection (NMActRequest *req); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 1eba44959f..b294d73f08 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -58,6 +58,8 @@ typedef struct _NMActiveConnectionPrivate { gboolean assumed; + NMActivationType activation_type; + NMAuthChain *chain; const char *wifi_shared_permission; NMActiveConnectionAuthResultFunc result_func; @@ -88,6 +90,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMActiveConnection, PROP_INT_SUBJECT, PROP_INT_MASTER, PROP_INT_MASTER_READY, + PROP_INT_ACTIVATION_TYPE, ); enum { @@ -779,6 +782,16 @@ nm_active_connection_set_parent (NMActiveConnection *self, NMActiveConnection *p g_object_weak_ref ((GObject *) priv->parent, parent_destroyed, self); } +void +nm_active_connection_set_activation_type_full (NMActiveConnection *self) +{ + NMActiveConnectionPrivate *priv; + + g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); + + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); +} + /*****************************************************************************/ static void @@ -1041,6 +1054,7 @@ set_property (GObject *object, guint prop_id, const char *tmp; NMSettingsConnection *con; NMConnection *acon; + NMActivationType activation_type; switch (prop_id) { case PROP_INT_SETTINGS_CONNECTION: @@ -1082,6 +1096,13 @@ set_property (GObject *object, guint prop_id, break; case PROP_MASTER: break; + case PROP_INT_ACTIVATION_TYPE: + /* construct-only */ + activation_type = g_value_get_uint (value); + if (!NM_IN_SET (activation_type, NM_ACTIVATION_TYPE_FULL, NM_ACTIVATION_TYPE_ASSUME)) + g_return_if_reached (); + priv->activation_type = activation_type; + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1101,6 +1122,7 @@ nm_active_connection_init (NMActiveConnection *self) _LOGT ("creating"); priv->version_id = _version_id_new (); + priv->activation_type = NM_ACTIVATION_TYPE_FULL; } static void @@ -1119,7 +1141,9 @@ constructed (GObject *object) if (priv->applied_connection) nm_connection_clear_secrets (priv->applied_connection); - _LOGD ("constructed (%s, version-id %llu)", G_OBJECT_TYPE_NAME (self), (long long unsigned) priv->version_id); + _LOGD ("constructed (%s, version-id %llu, activation-type %s)", + G_OBJECT_TYPE_NAME (self), (long long unsigned) priv->version_id, + nm_activation_type_to_string (priv->activation_type)); g_return_if_fail (priv->subject); } @@ -1304,6 +1328,13 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_INT_ACTIVATION_TYPE] = + g_param_spec_uint (NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE, "", "", + 0, G_MAXUINT32, NM_ACTIVATION_TYPE_FULL, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[DEVICE_CHANGED] = diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index d87a30b540..6b213639a1 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -55,6 +55,7 @@ #define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject" #define NM_ACTIVE_CONNECTION_INT_MASTER "int-master" #define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready" +#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE "int-activation-type" /* Internal signals*/ #define NM_ACTIVE_CONNECTION_DEVICE_CHANGED "device-changed" @@ -165,4 +166,6 @@ gboolean nm_active_connection_get_assumed (NMActiveConnection *self); void nm_active_connection_clear_secrets (NMActiveConnection *self); +void nm_active_connection_set_activation_type_full (NMActiveConnection *self); + #endif /* __NETWORKMANAGER_ACTIVE_CONNECTION_H__ */ diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index 1ee8026842..4d2ff35314 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -220,6 +220,7 @@ activate: NULL, device, subject, + FALSE, &local_error)) { _LOGW ("rollback: reactivation of connection %s/%s failed: %s", nm_connection_get_id ((NMConnection *) connection), diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 00ab2d3800..cebf678bee 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -3657,3 +3657,9 @@ nm_utils_get_reverse_dns_domains_ip6 (const struct in6_addr *ip, guint8 plen, GP #undef N_SHIFT } + +NM_UTILS_LOOKUP_STR_DEFINE (nm_activation_type_to_string, NMActivationType, + NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), + NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVATION_TYPE_FULL, "full"), + NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVATION_TYPE_ASSUME, "assume"), +); diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 3ef960bb6d..8178080bc2 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -428,4 +428,6 @@ const char *nm_utils_dnsmasq_status_to_string (int status, char *dest, gsize siz void nm_utils_get_reverse_dns_domains_ip4 (guint32 ip, guint8 plen, GPtrArray *domains); void nm_utils_get_reverse_dns_domains_ip6 (const struct in6_addr *ip, guint8 plen, GPtrArray *domains); +const char *nm_activation_type_to_string (NMActivationType activation_type); + #endif /* __NM_CORE_UTILS_H__ */ diff --git a/src/nm-manager.c b/src/nm-manager.c index fc10bb234a..0506147f2d 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -68,6 +68,7 @@ static NMActiveConnection *_new_active_connection (NMManager *self, const char *specific_object, NMDevice *device, NMAuthSubject *subject, + NMActivationType activation_type, GError **error); static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); @@ -1695,6 +1696,23 @@ get_existing_connection (NMManager *self, NMDevice *device, gboolean *out_genera nm_device_get_ip6_route_metric (device), match_connection_filter, device)); + + + /* TODO: connection assumption as it existed is going away. For now, just short-cut + * it. Afterwards, a lot of code can be removed. */ + if (matched) { + _LOGI (LOGD_DEVICE, "(%s): would assume connection '%s', but no", + nm_device_get_iface (device), + nm_settings_connection_get_id (matched)); + } else { + _LOGI (LOGD_DEVICE, "(%s): would assume generated connection '%s', but no", + nm_device_get_iface (device), + nm_connection_get_id (connection)); + } + g_object_unref (connection); + return NULL; + + if (matched) { _LOGI (LOGD_DEVICE, "(%s): found matching connection '%s'", nm_device_get_iface (device), @@ -1746,7 +1764,7 @@ assume_connection (NMManager *self, NMDevice *device, NMSettingsConnection *conn g_return_val_if_fail (nm_device_get_state (device) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); subject = nm_auth_subject_new_internal (); - active = _new_active_connection (self, NM_CONNECTION (connection), NULL, NULL, device, subject, &error); + active = _new_active_connection (self, NM_CONNECTION (connection), NULL, NULL, device, subject, NM_ACTIVATION_TYPE_ASSUME, &error); g_object_unref (subject); if (!active) { @@ -1880,7 +1898,10 @@ device_realized (NMDevice *device, } static void -_device_realize_finish (NMManager *self, NMDevice *device, const NMPlatformLink *plink) +_device_realize_finish (NMManager *self, + NMDevice *device, + const NMPlatformLink *plink, + const char *connection_uuid_to_assume) { g_return_if_fail (NM_IS_MANAGER (self)); g_return_if_fail (NM_IS_DEVICE (device)); @@ -1893,6 +1914,8 @@ _device_realize_finish (NMManager *self, NMDevice *device, const NMPlatformLink if (recheck_assume_connection (self, device)) return; + nm_device_set_connection_uuid_to_assume (device, connection_uuid_to_assume); + /* if we failed to assume a connection for the managed device, but the device * is still unavailable. Set UNAVAILABLE state again, this time with NOW_MANAGED. */ nm_device_state_changed (device, @@ -2043,7 +2066,7 @@ factory_device_added_cb (NMDeviceFactory *factory, NULL, &error)) { add_device (self, device, NULL); - _device_realize_finish (self, device, NULL); + _device_realize_finish (self, device, NULL, NULL); } else { _LOGW (LOGD_DEVICE, "(%s): failed to realize device: %s", nm_device_get_iface (device), error->message); @@ -2120,7 +2143,7 @@ platform_link_added (NMManager *self, &compatible, &error)) { /* Success */ - _device_realize_finish (self, candidate, plink); + _device_realize_finish (self, candidate, plink, NULL); return; } @@ -2184,7 +2207,8 @@ platform_link_added (NMManager *self, NULL, &error)) { add_device (self, device, NULL); - _device_realize_finish (self, device, plink); + _device_realize_finish (self, device, plink, + dev_state ? dev_state->connection_uuid : NULL); } else { _LOGW (LOGD_DEVICE, "%s: failed to realize device: %s", plink->name, error->message); @@ -2330,7 +2354,7 @@ nm_manager_get_device_paths (NMManager *self) return (const char **) g_ptr_array_free (paths, FALSE); } -static NMDevice * +NMDevice * nm_manager_get_connection_device (NMManager *self, NMConnection *connection) { @@ -2657,6 +2681,7 @@ ensure_master_active_connection (NMManager *self, NULL, master_device, subject, + NM_ACTIVATION_TYPE_FULL, error); g_slist_free (connections); return master_ac; @@ -2704,6 +2729,7 @@ ensure_master_active_connection (NMManager *self, NULL, candidate, subject, + NM_ACTIVATION_TYPE_FULL, error); return master_ac; } @@ -2829,6 +2855,7 @@ autoconnect_slaves (NMManager *self, NULL, nm_manager_get_best_device_for_connection (self, NM_CONNECTION (slave_connection), FALSE), subject, + NM_ACTIVATION_TYPE_FULL, &local_err); if (local_err) { _LOGW (LOGD_CORE, "Slave connection activation failed: %s", local_err->message); @@ -2986,7 +3013,8 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * return FALSE; } - parent_ac = nm_manager_activate_connection (self, parent_con, NULL, NULL, parent, subject, error); + parent_ac = nm_manager_activate_connection (self, parent_con, NULL, NULL, parent, + subject, NM_ACTIVATION_TYPE_FULL, error); if (!parent_ac) { g_prefix_error (error, "%s failed to activate parent: ", nm_device_get_iface (device)); return FALSE; @@ -3172,6 +3200,7 @@ _new_active_connection (NMManager *self, const char *specific_object, NMDevice *device, NMAuthSubject *subject, + NMActivationType activation_type, GError **error) { NMSettingsConnection *settings_connection = NULL; @@ -3196,6 +3225,9 @@ _new_active_connection (NMManager *self, is_vpn = nm_connection_is_type (NM_CONNECTION (connection), NM_SETTING_VPN_SETTING_NAME); + if (is_vpn && activation_type != NM_ACTIVATION_TYPE_FULL) + g_return_val_if_reached (NULL); + if (NM_IS_SETTINGS_CONNECTION (connection)) settings_connection = (NMSettingsConnection *) connection; @@ -3211,7 +3243,8 @@ _new_active_connection (NMManager *self, applied, specific_object, subject, - device); + device, + activation_type); } static void @@ -3263,6 +3296,8 @@ _internal_activation_auth_done (NMActiveConnection *active, * @specific_object: the specific object path, if any, for the activation * @device: the #NMDevice to activate @connection on * @subject: the subject which requested activation + * @activation_type: whether to assume the connection. That is, take over gracefully, + * non-destructible. * @error: return location for an error * * Begins a new internally-initiated activation of @connection on @device. @@ -3282,6 +3317,7 @@ nm_manager_activate_connection (NMManager *self, const char *specific_object, NMDevice *device, NMAuthSubject *subject, + NMActivationType activation_type, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); @@ -3328,6 +3364,7 @@ nm_manager_activate_connection (NMManager *self, specific_object, device, subject, + activation_type, error); if (active) { priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active); @@ -3583,6 +3620,7 @@ impl_manager_activate_connection (NMManager *self, specific_object_path, device, subject, + NM_ACTIVATION_TYPE_FULL, &error); if (!active) goto error; @@ -3791,6 +3829,7 @@ impl_manager_add_and_activate_connection (NMManager *self, specific_object_path, device, subject, + NM_ACTIVATION_TYPE_FULL, &error); if (!active) goto error; diff --git a/src/nm-manager.h b/src/nm-manager.h index 90041ccd7d..5c6d3ca8d4 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -86,6 +86,9 @@ NMState nm_manager_get_state (NMManager *manager); const GSList *nm_manager_get_active_connections (NMManager *manager); GSList * nm_manager_get_activatable_connections (NMManager *manager); +NMDevice * nm_manager_get_connection_device (NMManager *self, + NMConnection *connection); + void nm_manager_write_device_state (NMManager *manager); /* Device handling */ @@ -109,6 +112,7 @@ NMActiveConnection *nm_manager_activate_connection (NMManager *manager, const char *specific_object, NMDevice *device, NMAuthSubject *subject, + NMActivationType activation_type, GError **error); gboolean nm_manager_deactivate_connection (NMManager *manager, diff --git a/src/nm-policy.c b/src/nm-policy.c index ffe9203e7b..11034cb858 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -666,6 +666,59 @@ check_activating_devices (NMPolicy *self) g_object_thaw_notify (object); } +static NMSettingsConnection * +_find_connection_to_assume (NMPolicy *self, + NMDevice *device) +{ + NMPolicyPrivate *priv; + NMSettingsConnection *connection; + gs_free const char *uuid = NULL; + const NMPlatformLink *pllink; + + uuid = nm_device_steal_connection_uuid_to_assume (device); + if (!uuid) + return NULL; + + priv = NM_POLICY_GET_PRIVATE (self); + + connection = nm_settings_get_connection_by_uuid (priv->settings, uuid); + if (!connection) + return NULL; + + if (nm_manager_get_connection_device (priv->manager, NM_CONNECTION (connection))) { + /* if the connection is already active on another device, it cannot be + * activated here. */ + return NULL; + } + + if (!nm_device_check_connection_available (device, + NM_CONNECTION (connection), + NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL)) { + /* the connection must be compatible and available on the device. */ + return NULL; + } + + /* only if the device exists. */ + pllink = nm_platform_link_get (NM_PLATFORM_GET, + nm_device_get_ip_ifindex (device)); + if (!pllink) + return NULL; + + if (nm_setting_connection_get_slave_type (nm_connection_get_setting_connection (NM_CONNECTION (connection)))) { + /* a slave. Is the link still enslaved? */ + if (pllink->master <= 0) + return NULL; + } else { + /* the device must be up and not a slave. */ + if ( pllink->master > 0 + || !NM_FLAGS_HAS (pllink->n_ifi_flags, IFF_UP)) + return NULL; + } + + return connection; +} + typedef struct { NMPolicy *policy; NMDevice *device; @@ -694,8 +747,7 @@ auto_activate_device (NMPolicy *self, NMPolicyPrivate *priv; NMSettingsConnection *best_connection; gs_free char *specific_object = NULL; - GPtrArray *connections; - GSList *connection_list; + gboolean assume = FALSE; guint i; nm_assert (NM_IS_POLICY (self)); @@ -710,30 +762,37 @@ auto_activate_device (NMPolicy *self, if (nm_device_get_act_request (device)) return; - connection_list = nm_manager_get_activatable_connections (priv->manager); - if (!connection_list) - return; + best_connection = _find_connection_to_assume (self, device); + if (best_connection) + assume = TRUE; + else { + GSList *connection_list; + gs_unref_ptrarray GPtrArray *connections = NULL; - connections = _nm_utils_copy_slist_to_array (connection_list, NULL, NULL); - g_slist_free (connection_list); + connection_list = nm_manager_get_activatable_connections (priv->manager); + if (!connection_list) + return; - /* sort is stable (which is important at this point) so that connections - * with same priority are still sorted by last-connected-timestamp. */ - g_ptr_array_sort (connections, (GCompareFunc) nm_utils_cmp_connection_by_autoconnect_priority); + connections = _nm_utils_copy_slist_to_array (connection_list, NULL, NULL); + g_slist_free (connection_list); - /* Find the first connection that should be auto-activated */ - best_connection = NULL; - for (i = 0; i < connections->len; i++) { - NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (connections->pdata[i]); + /* sort is stable (which is important at this point) so that connections + * with same priority are still sorted by last-connected-timestamp. */ + g_ptr_array_sort (connections, (GCompareFunc) nm_utils_cmp_connection_by_autoconnect_priority); - if (!nm_settings_connection_can_autoconnect (candidate)) - continue; - if (nm_device_can_auto_connect (device, (NMConnection *) candidate, &specific_object)) { - best_connection = candidate; - break; + /* Find the first connection that should be auto-activated */ + best_connection = NULL; + for (i = 0; i < connections->len; i++) { + NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (connections->pdata[i]); + + if (!nm_settings_connection_can_autoconnect (candidate)) + continue; + if (nm_device_can_auto_connect (device, (NMConnection *) candidate, &specific_object)) { + best_connection = candidate; + break; + } } } - g_ptr_array_free (connections, TRUE); if (best_connection) { GError *error = NULL; @@ -748,6 +807,9 @@ auto_activate_device (NMPolicy *self, specific_object, device, subject, + assume + ? NM_ACTIVATION_TYPE_ASSUME + : NM_ACTIVATION_TYPE_FULL, &error)) { _LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: (%d) %s", nm_settings_connection_get_id (best_connection), @@ -1153,6 +1215,7 @@ activate_secondary_connections (NMPolicy *self, nm_exported_object_get_path (NM_EXPORTED_OBJECT (req)), device, nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)), + NM_ACTIVATION_TYPE_FULL, &error); if (ac) secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac)); @@ -1555,6 +1618,7 @@ vpn_connection_retry_after_failure (NMVpnConnection *vpn, NMPolicy *self) NULL, NULL, nm_active_connection_get_subject (ac), + NM_ACTIVATION_TYPE_FULL, &error)) { _LOGW (LOGD_DEVICE, "VPN '%s' reconnect failed: %s", nm_settings_connection_get_id (connection), diff --git a/src/nm-types.h b/src/nm-types.h index 45c9284f3f..5a1108bccb 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -55,6 +55,17 @@ typedef struct _NMSleepMonitor NMSleepMonitor; typedef struct _NMLldpListener NMLldpListener; typedef struct _NMConfigDeviceStateData NMConfigDeviceStateData; +/*****************************************************************************/ + +typedef enum { + /* Do a full activation. */ + NM_ACTIVATION_TYPE_FULL = 1, + + /* gracefully/seamlessly take over the device. This leaves additional + * IP addresses and does not restore missing manual addresses. */ + NM_ACTIVATION_TYPE_ASSUME = 2, +} NMActivationType; + typedef enum { /* In priority order; higher number == higher priority */ -- cgit v1.2.1