summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-09-26 15:06:46 +0200
committerThomas Haller <thaller@redhat.com>2016-10-06 21:11:20 +0200
commit5d9cef48c7960dd77a1f6424814179d3647fe4d7 (patch)
tree19e0614d1e10a56ad3dc4b588859f21989814a27
parent4f6f7e883e0b462138e7b4c61a207aee1478fc05 (diff)
downloadNetworkManager-th/assume-vs-unmanaged-bgo746440-1.tar.gz
device: pass connection-uuid to NetworkManager to assume itth/assume-vs-unmanaged-bgo746440-1
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.
-rw-r--r--src/devices/nm-device.c53
-rw-r--r--src/devices/nm-device.h4
-rw-r--r--src/nm-act-request.c5
-rw-r--r--src/nm-act-request.h3
-rw-r--r--src/nm-active-connection.c33
-rw-r--r--src/nm-active-connection.h3
-rw-r--r--src/nm-checkpoint.c1
-rw-r--r--src/nm-core-utils.c6
-rw-r--r--src/nm-core-utils.h2
-rw-r--r--src/nm-manager.c55
-rw-r--r--src/nm-manager.h4
-rw-r--r--src/nm-policy.c104
-rw-r--r--src/nm-types.h11
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 */