From 6fd76323e06e2aabb7b4e74a05986ad612637cb7 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 19 May 2014 10:24:15 -0400 Subject: [PATCH 1/7] core: tweak NMSettingIP[46]Config generation NMIP4Config and NMIP6Config had methods to update an existing NMSetting. However, the functions would really only work correctly if the passed-in setting was empty. Change them from "update_setting" to "create_setting", and have them create the NMSetting themselves, and update NMDevice for that. (If we need update_setting later, we can add it, after figuring out exactly how it's actually supposed to work.) --- src/devices/nm-device.c | 12 ++---------- src/nm-ip4-config.c | 34 +++++++++++++++++++++------------- src/nm-ip4-config.h | 2 +- src/nm-ip6-config.c | 32 ++++++++++++++++++++------------ src/nm-ip6-config.h | 2 +- 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index c4fd15a12a..acdd834f0c 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1837,19 +1837,11 @@ nm_device_generate_connection (NMDevice *device) NULL); } else { /* Only regular and master devices get IP configuration; slaves do not */ - s_ip4 = nm_setting_ip4_config_new (); + s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); nm_connection_add_setting (connection, s_ip4); - if (priv->ip4_config) - nm_ip4_config_update_setting (priv->ip4_config, (NMSettingIP4Config *) s_ip4); - else - g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NULL); - s_ip6 = nm_setting_ip6_config_new (); + s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); nm_connection_add_setting (connection, s_ip6); - if (priv->ip6_config) - nm_ip6_config_update_setting (priv->ip6_config, (NMSettingIP6Config *) s_ip6); - else - g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); } klass->update_connection (device, connection); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 12aac78519..4d149f25ab 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -379,16 +379,23 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setting) g_object_thaw_notify (G_OBJECT (config)); } -void -nm_ip4_config_update_setting (const NMIP4Config *config, NMSettingIP4Config *setting) +NMSetting * +nm_ip4_config_create_setting (const NMIP4Config *config) { + NMSettingIP4Config *s_ip4; guint32 gateway; guint naddresses, nroutes, nnameservers, nsearches; const char *method = NULL; int i; - if (!config) - return; + s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ()); + + if (!config) { + g_object_set (s_ip4, + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NULL); + return NM_SETTING (s_ip4); + } gateway = nm_ip4_config_get_gateway (config); naddresses = nm_ip4_config_get_num_addresses (config); @@ -422,17 +429,16 @@ nm_ip4_config_update_setting (const NMIP4Config *config, NMSettingIP4Config *set nm_ip4_address_set_gateway (s_addr, gateway); if (*address->label) - NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_add_address_with_label (setting, s_addr, address->label)); + NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_add_address_with_label (s_ip4, s_addr, address->label)); else - nm_setting_ip4_config_add_address (setting, s_addr); + nm_setting_ip4_config_add_address (s_ip4, s_addr); nm_ip4_address_unref (s_addr); } - /* Only use 'disabled' if the method wasn't previously set */ - if (!method && !nm_setting_ip4_config_get_method (setting)) + /* Use 'disabled' if the method wasn't previously set */ + if (!method) method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - if (method) - g_object_set (setting, NM_SETTING_IP4_CONFIG_METHOD, method, NULL); + g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, method, NULL); /* Routes */ for (i = 0; i < nroutes; i++) { @@ -449,7 +455,7 @@ nm_ip4_config_update_setting (const NMIP4Config *config, NMSettingIP4Config *set nm_ip4_route_set_next_hop (s_route, route->gateway); nm_ip4_route_set_metric (s_route, route->metric); - nm_setting_ip4_config_add_route (setting, s_route); + nm_setting_ip4_config_add_route (s_ip4, s_route); nm_ip4_route_unref (s_route); } @@ -457,13 +463,15 @@ nm_ip4_config_update_setting (const NMIP4Config *config, NMSettingIP4Config *set for (i = 0; i < nnameservers; i++) { guint32 nameserver = nm_ip4_config_get_nameserver (config, i); - nm_setting_ip4_config_add_dns (setting, nameserver); + nm_setting_ip4_config_add_dns (s_ip4, nameserver); } for (i = 0; i < nsearches; i++) { const char *search = nm_ip4_config_get_search (config, i); - nm_setting_ip4_config_add_dns_search (setting, search); + nm_setting_ip4_config_add_dns_search (s_ip4, search); } + + return NM_SETTING (s_ip4); } /******************************************************************/ diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index d57cd529b7..dfe84770a9 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -62,7 +62,7 @@ const char * nm_ip4_config_get_dbus_path (const NMIP4Config *config); NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf); gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, int priority); void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setting); -void nm_ip4_config_update_setting (const NMIP4Config *config, NMSettingIP4Config *setting); +NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config); /* Utility functions */ void nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index fd791a5f90..bbb0b1065f 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -481,16 +481,23 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting) g_object_thaw_notify (G_OBJECT (config)); } -void -nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *setting) +NMSetting * +nm_ip6_config_create_setting (const NMIP6Config *config) { + NMSettingIP6Config *s_ip6; const struct in6_addr *gateway; guint naddresses, nroutes, nnameservers, nsearches; const char *method = NULL; int i; - if (!config) - return; + s_ip6 = NM_SETTING_IP6_CONFIG (nm_setting_ip6_config_new ()); + + if (!config) { + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NULL); + return NM_SETTING (s_ip6); + } gateway = nm_ip6_config_get_gateway (config); naddresses = nm_ip6_config_get_num_addresses (config); @@ -527,15 +534,14 @@ nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *set if (gateway) nm_ip6_address_set_gateway (s_addr, gateway); - nm_setting_ip6_config_add_address (setting, s_addr); + nm_setting_ip6_config_add_address (s_ip6, s_addr); nm_ip6_address_unref (s_addr); } - /* Only use 'ignore' if the method wasn't previously set */ - if (!method && !nm_setting_ip6_config_get_method (setting)) + /* Use 'ignore' if the method wasn't previously set */ + if (!method) method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - if (method) - g_object_set (setting, NM_SETTING_IP6_CONFIG_METHOD, method, NULL); + g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, method, NULL); /* Routes */ for (i = 0; i < nroutes; i++) { @@ -557,7 +563,7 @@ nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *set nm_ip6_route_set_next_hop (s_route, &route->gateway); nm_ip6_route_set_metric (s_route, route->metric); - nm_setting_ip6_config_add_route (setting, s_route); + nm_setting_ip6_config_add_route (s_ip6, s_route); nm_ip6_route_unref (s_route); } @@ -565,13 +571,15 @@ nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *set for (i = 0; i < nnameservers; i++) { const struct in6_addr *nameserver = nm_ip6_config_get_nameserver (config, i); - nm_setting_ip6_config_add_dns (setting, nameserver); + nm_setting_ip6_config_add_dns (s_ip6, nameserver); } for (i = 0; i < nsearches; i++) { const char *search = nm_ip6_config_get_search (config, i); - nm_setting_ip6_config_add_dns_search (setting, search); + nm_setting_ip6_config_add_dns_search (s_ip6, search); } + + return NM_SETTING (s_ip6); } /******************************************************************/ diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 32a3b21fd0..07ca0e6d7f 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -61,7 +61,7 @@ const char * nm_ip6_config_get_dbus_path (const NMIP6Config *config); NMIP6Config *nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary); gboolean nm_ip6_config_commit (const NMIP6Config *config, int ifindex, int priority); void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting); -void nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *setting); +NMSetting *nm_ip6_config_create_setting (const NMIP6Config *config); /* Utility functions */ void nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src); From 14048089a1ef2f2edf65c84a631fc88895484093 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 19 May 2014 10:24:15 -0400 Subject: [PATCH 2/7] settings: add 'nm_generated' flag on NMSettingsConnection Add 'nm_generated' flag on NMSettingsConnection, and have NMManager set it on generated connections that it assumes. --- src/nm-manager.c | 4 ++- src/settings/nm-settings-connection.c | 43 +++++++++++++++++++++++++++ src/settings/nm-settings-connection.h | 3 ++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 0f2556487b..92ea164e92 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1572,7 +1572,9 @@ get_existing_connection (NMManager *manager, NMDevice *device) nm_connection_get_id (connection)); added = nm_settings_add_connection (priv->settings, connection, FALSE, &error); - if (!added) { + if (added) + nm_settings_connection_set_nm_generated (added); + else { nm_log_warn (LOGD_SETTINGS, "(%s) Couldn't save generated connection '%s': %s", nm_device_get_iface (device), nm_connection_get_id (connection), diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 6598990862..63b6a09b19 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -100,6 +100,11 @@ typedef struct { */ gboolean unsaved; + /* TRUE if the connection was generated by NetworkManager and has + * not been saved or modified by the user. + */ + gboolean nm_generated; + guint updated_idle_id; GSList *pending_auths; /* List of pending authentication requests */ @@ -402,6 +407,9 @@ set_unsaved (NMSettingsConnection *self, gboolean now_unsaved) if (priv->unsaved != now_unsaved) { priv->unsaved = now_unsaved; + if (!priv->unsaved) + priv->nm_generated = FALSE; + g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_UNSAVED); } } @@ -456,6 +464,8 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, if (nm_connection_replace_settings_from_connection (NM_CONNECTION (self), new_connection, error)) { + priv->nm_generated = FALSE; + /* Cache the just-updated system secrets in case something calls * nm_connection_clear_secrets() and clears them. */ @@ -1976,6 +1986,39 @@ nm_settings_connection_can_autoconnect (NMSettingsConnection *connection) return TRUE; } +/** + * nm_settings_connection_get_nm_generated: + * @connection: an #NMSettingsConnection + * + * Gets the "nm-generated" flag on @connection. + * + * A connection is "nm-generated" if it was generated by + * nm_device_generate_connection() and then assumed by #NMManager, and + * it has not been modified or saved by the user since then. In other + * words, an "nm-generated" connection reflects state that is entirely + * external to NetworkManager. + */ +gboolean +nm_settings_connection_get_nm_generated (NMSettingsConnection *connection) +{ + return NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->nm_generated; +} + +/** + * nm_settings_connection_set_nm_generated: + * @connection: an #NMSettingsConnection + * + * Sets the "nm-generated" flag on @connection; see + * nm_settings_connection_get_nm_generated(). + */ +void +nm_settings_connection_set_nm_generated (NMSettingsConnection *connection) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection); + + priv->nm_generated = TRUE; +} + /**************************************************************/ static void diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index 5a84349746..0c2ca849b4 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -162,6 +162,9 @@ void nm_settings_connection_set_autoconnect_blocked_reason (NMSettingsConnection gboolean nm_settings_connection_can_autoconnect (NMSettingsConnection *connection); +void nm_settings_connection_set_nm_generated (NMSettingsConnection *connection); +gboolean nm_settings_connection_get_nm_generated (NMSettingsConnection *connection); + G_END_DECLS #endif /* NM_SETTINGS_CONNECTION_H */ From a9a25973ccca48480d2c37b7f33833283840f27f Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 27 May 2014 16:42:19 -0400 Subject: [PATCH 3/7] devices: update generated connections when the underlying IP config changes If the IP config changes on a device that has assumed a generated connection, then update the connection's NMSettingIP4Config / NMSettingIP6Config, under the assumption that the configuration of that device was in progress but incomplete when NM first observed it. --- src/devices/nm-device.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index acdd834f0c..f916675193 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -855,6 +855,17 @@ nm_device_get_type_desc (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->type_desc; } +static gboolean +nm_device_uses_generated_connection (NMDevice *self) +{ + NMConnection *connection; + + connection = nm_device_get_connection (self); + if (!connection) + return FALSE; + return nm_settings_connection_get_nm_generated (NM_SETTINGS_CONNECTION (connection)); +} + static SlaveInfo * find_slave_info (NMDevice *self, NMDevice *slave) { @@ -5221,6 +5232,17 @@ nm_device_set_ip4_config (NMDevice *self, if (old_config != priv->ip4_config && old_config) g_object_unref (old_config); + + if (nm_device_uses_generated_connection (self)) { + NMConnection *connection = nm_device_get_connection (self); + NMSetting *s_ip4; + + g_object_freeze_notify (G_OBJECT (connection)); + nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); + nm_connection_add_setting (connection, s_ip4); + g_object_thaw_notify (G_OBJECT (connection)); + } } if (reason) @@ -5312,6 +5334,17 @@ nm_device_set_ip6_config (NMDevice *self, if (old_config != priv->ip6_config && old_config) g_object_unref (old_config); + + if (nm_device_uses_generated_connection (self)) { + NMConnection *connection = nm_device_get_connection (self); + NMSetting *s_ip6; + + g_object_freeze_notify (G_OBJECT (connection)); + nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); + s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); + nm_connection_add_setting (connection, s_ip6); + g_object_thaw_notify (G_OBJECT (connection)); + } } if (reason) From f229f4e201c9b6aefddafcee362b99d2ef6ab40c Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 28 May 2014 10:18:34 -0400 Subject: [PATCH 4/7] core: re-attempt connection assumption when the device state changes If the initial attempt to assume a connection on a device fails, and the device remains un-activated, but then something changes its configuration externally, try to generate a new connection and assume that. --- src/devices/nm-device-private.h | 1 + src/devices/nm-device.c | 38 ++++++++++ src/devices/nm-device.h | 1 + src/nm-manager.c | 127 +++++++++++++++++++++++--------- 4 files changed, 131 insertions(+), 36 deletions(-) diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 8dae02e0bd..24bb0b3362 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -97,5 +97,6 @@ void nm_device_master_check_slave_physical_port (NMDevice *dev, NMDevice *slave, void nm_device_set_carrier (NMDevice *device, gboolean carrier); void nm_device_emit_recheck_auto_activate (NMDevice *device); +void nm_device_queue_recheck_assume (NMDevice *device); #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f916675193..5dea3971e1 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, + RECHECK_ASSUME, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -237,6 +238,7 @@ typedef struct { gpointer act_source_func; guint act_source6_id; gpointer act_source6_func; + guint recheck_assume_id; /* Link stuff */ guint link_connected_id; @@ -2016,6 +2018,26 @@ nm_device_can_assume_connections (NMDevice *device) return !!NM_DEVICE_GET_CLASS (device)->update_connection; } +static gboolean +nm_device_emit_recheck_assume (gpointer self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + priv->recheck_assume_id = 0; + if (!nm_device_get_act_request (self) && (priv->ip4_config || priv->ip6_config)) + g_signal_emit (self, signals[RECHECK_ASSUME], 0); + return G_SOURCE_REMOVE; +} + +void +nm_device_queue_recheck_assume (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (nm_device_can_assume_connections (self) && !priv->recheck_assume_id) + priv->recheck_assume_id = g_idle_add (nm_device_emit_recheck_assume, self); +} + void nm_device_emit_recheck_auto_activate (NMDevice *self) { @@ -5243,6 +5265,8 @@ nm_device_set_ip4_config (NMDevice *self, nm_connection_add_setting (connection, s_ip4); g_object_thaw_notify (G_OBJECT (connection)); } + + nm_device_queue_recheck_assume (self); } if (reason) @@ -5345,6 +5369,8 @@ nm_device_set_ip6_config (NMDevice *self, nm_connection_add_setting (connection, s_ip6); g_object_thaw_notify (G_OBJECT (connection)); } + + nm_device_queue_recheck_assume (self); } if (reason) @@ -5789,6 +5815,11 @@ dispose (GObject *object) g_clear_pointer (&priv->ip6_saved_properties, g_hash_table_unref); + if (priv->recheck_assume_id) { + g_source_remove (priv->recheck_assume_id); + priv->recheck_assume_id = 0; + } + link_disconnect_action_cancel (self); if (priv->con_provider) { @@ -6437,6 +6468,13 @@ nm_device_class_init (NMDeviceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + signals[RECHECK_ASSUME] = + g_signal_new (NM_DEVICE_RECHECK_ASSUME, + 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); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 9193264c97..503837281c 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_RECHECK_ASSUME "recheck-assume" G_BEGIN_DECLS diff --git a/src/nm-manager.c b/src/nm-manager.c index 92ea164e92..681de94ac3 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1586,6 +1586,89 @@ get_existing_connection (NMManager *manager, NMDevice *device) return added ? NM_CONNECTION (added) : NULL; } +static gboolean +assume_connection (NMManager *self, NMDevice *device, NMConnection *connection) +{ + NMActiveConnection *active, *master_ac; + 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 */ + if (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE) { + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } + g_return_if_fail (nm_device_get_state (device) >= NM_DEVICE_STATE_DISCONNECTED); + + subject = nm_auth_subject_new_internal (); + active = _new_active_connection (self, connection, NULL, device, subject, &error); + g_object_unref (subject); + + if (!active) { + 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); + return FALSE; + } + + /* If the device is a slave or VLAN, find the master ActiveConnection */ + master_ac = NULL; + 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); + + return TRUE; +} + +static void +recheck_assume_connection (NMDevice *device, gpointer user_data) +{ + NMManager *self = user_data; + NMConnection *connection; + gboolean was_unmanaged = FALSE; + + if (manager_sleeping (self)) + return; + if (nm_device_get_unmanaged_flag (device, NM_UNMANAGED_USER)) + return; + + connection = get_existing_connection (self, device); + if (!connection) { + nm_log_dbg (LOGD_DEVICE, "(%s): can't assume; no connection", + nm_device_get_iface (device)); + return; + } + + if (nm_device_get_state (device) == NM_DEVICE_STATE_UNMANAGED) { + was_unmanaged = TRUE; + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } + + if (!assume_connection (self, device, connection)) { + if (was_unmanaged) { + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + nm_device_state_changed (device, + NM_DEVICE_STATE_UNMANAGED, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + } + } +} + /** * add_device: * @self: the #NMManager @@ -1708,42 +1791,14 @@ 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 the device has a connection it can assume, do that now. If it's a + * device that we might ever want to assume a connection on, then set that up. + */ + if (connection) + assume_connection (self, device, connection); + if (generate_con) { + g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME, + G_CALLBACK (recheck_assume_connection), self); } } From 950525f5c31aa454896cee9b4bb9de91cc2cbfc6 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 29 May 2014 13:54:50 -0400 Subject: [PATCH 5/7] devices: don't allow generated master connections to have no IP config nm_device_generate_connection() was allowing connections for master devices to have no IP config, but this didn't really make much sense, since they would just fail at stage3 in that case anyway. Now that we get multiple tries at generating a connection on a device, we can just ignore the device until it has a proper connection. --- src/devices/nm-device.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5dea3971e1..fb0c9a962e 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1875,9 +1875,8 @@ nm_device_generate_connection (NMDevice *device) ip6_method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); if ( g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0 && g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0 - && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con)) - && !nm_platform_link_supports_slaves (priv->ifindex)) { - nm_log_dbg (LOGD_DEVICE, "(%s): ignoring generated connection (no IP, not master, no slaves)", ifname); + && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con))) { + nm_log_dbg (LOGD_DEVICE, "(%s): ignoring generated connection (no IP and not slave)", ifname); g_object_unref (connection); connection = NULL; } From 1dbf69cd0ada64b3af472a9511406444273a7d37 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 5 Jun 2014 13:31:46 -0400 Subject: [PATCH 6/7] devices: don't allow assuming a slave before its master The process of activating a slave requires that its master have an NMActiveConnection. So don't allow generating a connection on a slave until we have generated the connection on the master. --- src/devices/nm-device.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index fb0c9a962e..10ebb7a92d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1799,6 +1799,19 @@ nm_device_generate_connection (NMDevice *device) return NULL; } + if (ifindex) + master_ifindex = nm_platform_link_get_master (ifindex); + if (master_ifindex) { + NMDevice *master; + + master = nm_manager_get_device_by_ifindex (nm_manager_get (), master_ifindex); + if (!master || !nm_device_get_act_request (master)) { + nm_log_dbg (LOGD_DEVICE, "(%s): cannot generate connection for slave before its master (%s)", + ifname, nm_platform_link_get_name (master_ifindex)); + return NULL; + } + } + connection = nm_connection_new (); s_con = nm_setting_connection_new (); uuid = nm_utils_uuid_generate (); @@ -1816,9 +1829,7 @@ nm_device_generate_connection (NMDevice *device) nm_connection_add_setting (connection, s_con); /* If the device is a slave, update various slave settings */ - if (ifindex) - master_ifindex = nm_platform_link_get_master (ifindex); - if (master_ifindex > 0) { + if (master_ifindex) { const char *master_iface = nm_platform_link_get_name (master_ifindex); const char *slave_type = NULL; gboolean success = FALSE; @@ -2317,9 +2328,13 @@ nm_device_activate_stage2_device_config (gpointer user_data) /* If we have slaves that aren't yet enslaved, do that now */ for (iter = priv->slaves; iter; iter = g_slist_next (iter)) { SlaveInfo *info = iter->data; + NMDeviceState slave_state = nm_device_get_state (info->slave); - if (nm_device_get_state (info->slave) == NM_DEVICE_STATE_IP_CONFIG) + if (slave_state == NM_DEVICE_STATE_IP_CONFIG) nm_device_enslave_slave (self, info->slave, nm_device_get_connection (info->slave)); + else if ( nm_device_uses_generated_connection (self) + && slave_state <= NM_DEVICE_STATE_DISCONNECTED) + nm_device_queue_recheck_assume (info->slave); } nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 2 of 5 (Device Configure) successful.", iface); From 08e0cfb484dfc6aa6342871158ffe752c7c50f03 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 25 Feb 2014 16:44:01 -0500 Subject: [PATCH 7/7] devices: observe externally-caused master/slave changes (rh #1066706) If a link's "master" property changes unexpectedly (ie, from outside NM), update the master and slave NMDevices to reflect it, without making any changes to them. --- src/devices/nm-device-bond.c | 58 ++++++++++------ src/devices/nm-device-bridge.c | 37 ++++++---- src/devices/nm-device-team.c | 59 ++++++++++------ src/devices/nm-device.c | 123 ++++++++++++++++++++++++--------- src/devices/nm-device.h | 3 +- 5 files changed, 189 insertions(+), 91 deletions(-) diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 2708dad89e..6f8caeb40b 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -421,42 +421,56 @@ enslave_slave (NMDevice *device, success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); nm_device_bring_up (slave, TRUE, &no_firmware); - } - if (success) { + if (!success) + return FALSE; + nm_log_info (LOGD_BOND, "(%s): enslaved bond slave %s", iface, slave_iface); - g_object_notify (G_OBJECT (device), "slaves"); - } + } else + nm_log_info (LOGD_BOND, "(%s): bond slave %s was enslaved", iface, slave_iface); - return success; + g_object_notify (G_OBJECT (device), NM_DEVICE_BOND_SLAVES); + return TRUE; } static gboolean -release_slave (NMDevice *device, NMDevice *slave) +release_slave (NMDevice *device, + NMDevice *slave, + gboolean configure) { - gboolean success, no_firmware = FALSE; + gboolean success = TRUE, no_firmware = FALSE; - success = nm_platform_link_release (nm_device_get_ip_ifindex (device), - nm_device_get_ip_ifindex (slave)); + if (configure) { + success = nm_platform_link_release (nm_device_get_ip_ifindex (device), + nm_device_get_ip_ifindex (slave)); - if (success) { - nm_log_info (LOGD_BOND, "(%s): released bond slave %s", - nm_device_get_ip_iface (device), - nm_device_get_ip_iface (slave)); + if (success) { + nm_log_info (LOGD_BOND, "(%s): released bond slave %s", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave)); + } else { + nm_log_warn (LOGD_BOND, "(%s): failed to release bond slave %s", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave)); + } } else { - nm_log_warn (LOGD_BOND, "(%s): failed to release bond slave %s", + nm_log_info (LOGD_BOND, "(%s): bond slave %s was released", nm_device_get_ip_iface (device), nm_device_get_ip_iface (slave)); } - g_object_notify (G_OBJECT (device), "slaves"); - /* Kernel bonding code "closes" the slave when releasing it, (which clears - * IFF_UP), so we must bring it back up here to ensure carrier changes and - * other state is noticed by the now-released slave. - */ - if (!nm_device_bring_up (slave, TRUE, &no_firmware)) { - nm_log_warn (LOGD_BOND, "(%s): released bond slave could not be brought up.", - nm_device_get_iface (slave)); + if (success) + g_object_notify (G_OBJECT (device), NM_DEVICE_BOND_SLAVES); + + if (configure) { + /* Kernel bonding code "closes" the slave when releasing it, (which clears + * IFF_UP), so we must bring it back up here to ensure carrier changes and + * other state is noticed by the now-released slave. + */ + if (!nm_device_bring_up (slave, TRUE, &no_firmware)) { + nm_log_warn (LOGD_BOND, "(%s): released bond slave could not be brought up.", + nm_device_get_iface (slave)); + } } return success; diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index ad2dc7c8bb..5c99c0e998 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -391,30 +391,43 @@ enslave_slave (NMDevice *device, return FALSE; commit_slave_options (slave, nm_connection_get_setting_bridge_port (connection)); + + nm_log_info (LOGD_BRIDGE, "(%s): attached bridge port %s", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave)); + } else { + nm_log_info (LOGD_BRIDGE, "(%s): bridge port %s was attached", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave)); } - nm_log_info (LOGD_BRIDGE, "(%s): attached bridge port %s", - nm_device_get_ip_iface (device), - nm_device_get_ip_iface (slave)); g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES); return TRUE; } static gboolean -release_slave (NMDevice *device, NMDevice *slave) +release_slave (NMDevice *device, + NMDevice *slave, + gboolean configure) { - gboolean success; + gboolean success = TRUE; - success = nm_platform_link_release (nm_device_get_ip_ifindex (device), - nm_device_get_ip_ifindex (slave)); + if (configure) { + success = nm_platform_link_release (nm_device_get_ip_ifindex (device), + nm_device_get_ip_ifindex (slave)); - if (success) { - nm_log_info (LOGD_BRIDGE, "(%s): detached bridge port %s", - nm_device_get_ip_iface (device), - nm_device_get_ip_iface (slave)); + if (success) { + nm_log_info (LOGD_BRIDGE, "(%s): detached bridge port %s", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave)); + } else { + nm_log_warn (LOGD_BRIDGE, "(%s): failed to detach bridge port %s", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave)); + } } else { - nm_log_warn (LOGD_BRIDGE, "(%s): failed to detach bridge port %s", + nm_log_info (LOGD_BRIDGE, "(%s): bridge port %s was detached", nm_device_get_ip_iface (device), nm_device_get_ip_iface (slave)); } diff --git a/src/devices/nm-device-team.c b/src/devices/nm-device-team.c index e672f6e1a3..63c2673fd9 100644 --- a/src/devices/nm-device-team.c +++ b/src/devices/nm-device-team.c @@ -691,42 +691,57 @@ enslave_slave (NMDevice *device, success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); nm_device_bring_up (slave, TRUE, &no_firmware); - } - if (success) { + if (!success) + return FALSE; + nm_log_info (LOGD_TEAM, "(%s): enslaved team port %s", iface, slave_iface); - g_object_notify (G_OBJECT (device), "slaves"); - } + } else + nm_log_info (LOGD_TEAM, "(%s): team port %s was enslaved", iface, slave_iface); - return success; + g_object_notify (G_OBJECT (device), NM_DEVICE_TEAM_SLAVES); + + return TRUE; } static gboolean -release_slave (NMDevice *device, NMDevice *slave) +release_slave (NMDevice *device, + NMDevice *slave, + gboolean configure) { - gboolean success, no_firmware = FALSE; + gboolean success = TRUE, no_firmware = FALSE; - success = nm_platform_link_release (nm_device_get_ip_ifindex (device), - nm_device_get_ip_ifindex (slave)); + if (configure) { + success = nm_platform_link_release (nm_device_get_ip_ifindex (device), + nm_device_get_ip_ifindex (slave)); - if (success) { - nm_log_info (LOGD_TEAM, "(%s): released team port %s", - nm_device_get_ip_iface (device), - nm_device_get_ip_iface (slave)); + if (success) { + nm_log_info (LOGD_TEAM, "(%s): released team port %s", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave)); + } else { + nm_log_warn (LOGD_TEAM, "(%s): failed to release team port %s", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave)); + } } else { - nm_log_warn (LOGD_TEAM, "(%s): failed to release team port %s", + nm_log_info (LOGD_TEAM, "(%s): team port %s was released", nm_device_get_ip_iface (device), nm_device_get_ip_iface (slave)); } - g_object_notify (G_OBJECT (device), "slaves"); - /* Kernel team code "closes" the port when releasing it, (which clears - * IFF_UP), so we must bring it back up here to ensure carrier changes and - * other state is noticed by the now-released port. - */ - if (!nm_device_bring_up (slave, TRUE, &no_firmware)) { - nm_log_warn (LOGD_TEAM, "(%s): released team port could not be brought up.", - nm_device_get_iface (slave)); + if (success) + g_object_notify (G_OBJECT (device), NM_DEVICE_TEAM_SLAVES); + + if (configure) { + /* Kernel team code "closes" the port when releasing it, (which clears + * IFF_UP), so we must bring it back up here to ensure carrier changes and + * other state is noticed by the now-released port. + */ + if (!nm_device_bring_up (slave, TRUE, &no_firmware)) { + nm_log_warn (LOGD_TEAM, "(%s): released team port could not be brought up.", + nm_device_get_iface (slave)); + } } return success; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 10ebb7a92d..2b576add4a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -896,7 +896,7 @@ free_slave_info (SlaveInfo *info) * nm_device_enslave_slave: * @dev: the master device * @slave: the slave device to enslave - * @connection: the slave device's connection + * @connection: (allow-none): the slave device's connection * * If @dev is capable of enslaving other devices (ie it's a bridge, bond, team, * etc) then this function enslaves @slave. @@ -909,20 +909,27 @@ nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connectio { SlaveInfo *info; gboolean success = FALSE; + gboolean configure; g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (slave != NULL, FALSE); - g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); g_return_val_if_fail (NM_DEVICE_GET_CLASS (dev)->enslave_slave != NULL, FALSE); info = find_slave_info (dev, slave); if (!info) return FALSE; - g_warn_if_fail (info->enslaved == FALSE); - success = NM_DEVICE_GET_CLASS (dev)->enslave_slave (dev, slave, connection, info->configure); + if (info->enslaved) + success = TRUE; + else { + configure = (info->configure && connection != NULL); + if (configure) + g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); + + success = NM_DEVICE_GET_CLASS (dev)->enslave_slave (dev, slave, connection, configure); + info->enslaved = success; + } - info->enslaved = success; nm_device_slave_notify_enslave (info->slave, success); /* Ensure the device's hardware address is up-to-date; it often changes @@ -949,15 +956,17 @@ nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connectio * nm_device_release_one_slave: * @dev: the master device * @slave: the slave device to release + * @configure: whether @dev needs to actually release @slave * * If @dev is capable of enslaving other devices (ie it's a bridge, bond, team, - * etc) then this function releases the previously enslaved @slave. + * etc) then this function releases the previously enslaved @slave and/or + * updates the state of @dev and @slave to reflect its release. * * Returns: %TRUE on success, %FALSE on failure, if this device cannot enslave * other devices, or if @slave was never enslaved. */ static gboolean -nm_device_release_one_slave (NMDevice *dev, NMDevice *slave) +nm_device_release_one_slave (NMDevice *dev, NMDevice *slave, gboolean configure) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); SlaveInfo *info; @@ -973,13 +982,15 @@ nm_device_release_one_slave (NMDevice *dev, NMDevice *slave) priv->slaves = g_slist_remove (priv->slaves, info); if (info->enslaved) { - success = NM_DEVICE_GET_CLASS (dev)->release_slave (dev, slave); + success = NM_DEVICE_GET_CLASS (dev)->release_slave (dev, slave, configure); /* The release_slave() implementation logs success/failure (in the * correct device-specific log domain), so we don't have to do anything. */ } - if (priv->state == NM_DEVICE_STATE_FAILED) + if (!configure) + reason = NM_DEVICE_STATE_REASON_NONE; + else if (priv->state == NM_DEVICE_STATE_FAILED) reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; else reason = priv->state_reason; @@ -1208,6 +1219,29 @@ device_link_changed (NMDevice *device, NMPlatformLink *info) nm_device_emit_recheck_auto_activate (device); } + /* Update slave status for external changes */ + if (info->master && !priv->enslaved) { + NMDevice *master; + + master = nm_manager_get_device_by_ifindex (nm_manager_get (), info->master); + if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) { + g_clear_object (&priv->master); + priv->master = g_object_ref (master); + nm_device_master_add_slave (master, device, FALSE); + nm_device_enslave_slave (master, device, NULL); + } else if (master) { + nm_log_info (LOGD_DEVICE, "(%s): enslaved to non-master-type device %s; ignoring", + nm_device_get_iface (device), + nm_device_get_iface (master)); + } else { + nm_log_warn (LOGD_DEVICE, "(%s): enslaved to unknown device %d %s", + nm_device_get_iface (device), + info->master, + nm_platform_link_get_name (info->master)); + } + } else if (priv->enslaved && !info->master) + nm_device_release_one_slave (priv->master, device, FALSE); + if (klass->link_changed) klass->link_changed (device, info); @@ -1330,8 +1364,6 @@ slave_state_changed (NMDevice *slave, slave_new_state, state_to_string (slave_new_state)); - g_assert (priv->state > NM_DEVICE_STATE_DISCONNECTED); - /* Don't try to enslave slaves until the master is ready */ if (priv->state < NM_DEVICE_STATE_CONFIG) return; @@ -1347,7 +1379,7 @@ slave_state_changed (NMDevice *slave, } if (release) { - nm_device_release_one_slave (self, slave); + nm_device_release_one_slave (self, slave, TRUE); /* Bridge/bond/team interfaces are left up until manually deactivated */ if (priv->slaves == NULL && priv->state == NM_DEVICE_STATE_ACTIVATED) { nm_log_dbg (LOGD_DEVICE, "(%s): last slave removed; remaining activated", @@ -1376,9 +1408,11 @@ nm_device_master_add_slave (NMDevice *dev, NMDevice *slave, gboolean configure) g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (slave != NULL, FALSE); - g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); g_return_val_if_fail (NM_DEVICE_GET_CLASS (dev)->enslave_slave != NULL, FALSE); + if (configure) + g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); + if (!find_slave_info (dev, slave)) { info = g_malloc0 (sizeof (SlaveInfo)); info->slave = g_object_ref (slave); @@ -1493,10 +1527,14 @@ nm_device_master_release_slaves (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + /* Don't release the slaves if this connection doesn't belong to NM. */ + if (nm_device_uses_generated_connection (self)) + return; + while (priv->slaves) { SlaveInfo *info = priv->slaves->data; - nm_device_release_one_slave (self, info->slave); + nm_device_release_one_slave (self, info->slave, TRUE); } } @@ -1535,31 +1573,42 @@ nm_device_slave_notify_enslave (NMDevice *dev, gboolean success) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); NMConnection *connection = nm_device_get_connection (dev); + gboolean activating = (priv->state == NM_DEVICE_STATE_IP_CONFIG); g_assert (priv->master); - g_warn_if_fail (priv->enslaved == FALSE); - g_warn_if_fail (priv->state == NM_DEVICE_STATE_IP_CONFIG); - if (success) { - nm_log_info (LOGD_DEVICE, - "Activation (%s) connection '%s' enslaved, continuing activation", - nm_device_get_iface (dev), - nm_connection_get_id (connection)); + if (!priv->enslaved) { + if (success) { + if (activating) { + nm_log_info (LOGD_DEVICE, + "Activation (%s) connection '%s' enslaved, continuing activation", + nm_device_get_iface (dev), + nm_connection_get_id (connection)); + } else { + nm_log_info (LOGD_DEVICE, + "(%s): enslaved to %s", + nm_device_get_iface (dev), + nm_device_get_iface (priv->master)); + } - priv->enslaved = TRUE; - g_object_notify (G_OBJECT (dev), NM_DEVICE_MASTER); - } else { - nm_log_warn (LOGD_DEVICE, - "Activation (%s) connection '%s' could not be enslaved", - nm_device_get_iface (dev), - nm_connection_get_id (connection)); + priv->enslaved = TRUE; + g_object_notify (G_OBJECT (dev), NM_DEVICE_MASTER); + } else if (activating) { + nm_log_warn (LOGD_DEVICE, + "Activation (%s) connection '%s' could not be enslaved", + nm_device_get_iface (dev), + nm_connection_get_id (connection)); + } } - priv->ip4_state = IP_DONE; - priv->ip6_state = IP_DONE; - nm_device_queue_state (dev, - success ? NM_DEVICE_STATE_SECONDARIES : NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NONE); + if (activating) { + priv->ip4_state = IP_DONE; + priv->ip6_state = IP_DONE; + nm_device_queue_state (dev, + success ? NM_DEVICE_STATE_SECONDARIES : NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NONE); + } else + nm_device_queue_recheck_assume (dev); } /** @@ -1577,7 +1626,8 @@ nm_device_slave_notify_release (NMDevice *dev, NMDeviceStateReason reason) NMDeviceState new_state; const char *master_status; - if ( priv->state > NM_DEVICE_STATE_DISCONNECTED + if ( reason != NM_DEVICE_STATE_REASON_NONE + && priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state <= NM_DEVICE_STATE_ACTIVATED) { if (reason == NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED) { new_state = NM_DEVICE_STATE_FAILED; @@ -1597,6 +1647,11 @@ nm_device_slave_notify_release (NMDevice *dev, NMDeviceStateReason reason) master_status); nm_device_queue_state (dev, new_state, reason); + } else { + nm_log_info (LOGD_DEVICE, + "(%s): released from master %s", + nm_device_get_iface (dev), + nm_device_get_iface (priv->master)); } if (priv->enslaved) { diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 503837281c..1e2f39a31e 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -198,7 +198,8 @@ typedef struct { gboolean configure); gboolean (* release_slave) (NMDevice *self, - NMDevice *slave); + NMDevice *slave, + gboolean configure); gboolean (* have_any_ready_slaves) (NMDevice *self, const GSList *slaves);