diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 7dc536ce9a..294aa9918f 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -42,6 +42,7 @@ #include "nm-device.h" #include "nm-device-private.h" #include "NetworkManagerUtils.h" +#include "nm-manager.h" #include "nm-platform.h" #include "nm-rdisc.h" #include "nm-lndp-rdisc.h" @@ -4339,6 +4340,14 @@ disconnect_cb (NMDevice *device, g_error_free (local); } else { priv->autoconnect = FALSE; + + /* Software devices are removed when manually disconnected and thus + * we need to track the autoconnect flag outside the device. + */ + nm_manager_prevent_device_auto_connect (nm_manager_get (), + nm_device_get_ip_iface (device), + TRUE); + nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_USER_REQUESTED); diff --git a/src/nm-manager.c b/src/nm-manager.c index 073783473d..4f0d0073d9 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -263,6 +263,9 @@ typedef struct { GHashTable *nm_bridges; + /* Track auto-activation for software devices */ + GHashTable *noauto_sw_devices; + gboolean startup; gboolean disposed; } NMManagerPrivate; @@ -3096,13 +3099,29 @@ nm_manager_activate_connection (NMManager *manager, } device = find_device_by_ip_iface (manager, iface); - g_free (iface); if (!device) { - /* Create it */ + /* Create the software device. Only exception is when: + * - this is an auto-activation *and* the device denies auto-activation + * at this time (the device was manually disconnected/deleted before) + */ + if (!nm_manager_can_device_auto_connect (manager, iface)) { + if (dbus_sender) { + /* Manual activation - allow device auto-activation again */ + nm_manager_prevent_device_auto_connect (manager, iface, FALSE); + } else { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED, + "'%s' does not allow automatic connections at this time => software device '%s' not created for '%s'", + iface, nm_connection_get_id (connection), iface); + g_free (iface); + return NULL; + } + } + device = system_create_virtual_device (manager, connection); if (!device) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Failed to create virtual interface"); + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Failed to create virtual interface '%s'", iface); + g_free (iface); return NULL; } @@ -3118,6 +3137,7 @@ nm_manager_activate_connection (NMManager *manager, NM_DEVICE_STATE_REASON_NONE); } } + g_free (iface); } if (!nm_device_can_activate (device, connection)) { @@ -3498,6 +3518,30 @@ impl_manager_deactivate_connection (NMManager *self, } } +/* + * Track (software) devices that cannot auto activate. + * It is needed especially for software devices, that can be removed and added + * again. So we can't simply use a flag inside the device. + */ +void +nm_manager_prevent_device_auto_connect (NMManager *manager, const char *ifname, gboolean prevent) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + + if (prevent) + g_hash_table_add (priv->noauto_sw_devices, g_strdup (ifname)); + else + g_hash_table_remove (priv->noauto_sw_devices, ifname); +} + +gboolean +nm_manager_can_device_auto_connect (NMManager *manager, const char *ifname) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + + return !g_hash_table_contains (priv->noauto_sw_devices, ifname); +} + static void do_sleep_wake (NMManager *self) { @@ -4575,6 +4619,8 @@ dispose (GObject *object) g_object_unref (priv->fw_monitor); } + g_hash_table_unref (priv->noauto_sw_devices); + g_slist_free (priv->factories); if (priv->timestamp_update_id) { @@ -4938,6 +4984,9 @@ nm_manager_init (NMManager *manager) KERNEL_FIRMWARE_DIR); } + /* Hash table storing software devices that should not auto activate */ + priv->noauto_sw_devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + load_device_factories (manager); /* Update timestamps in active connections */ diff --git a/src/nm-manager.h b/src/nm-manager.h index e972644e6d..fd6fa0aeee 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -125,6 +125,12 @@ gboolean nm_manager_deactivate_connection (NMManager *manager, NMDeviceStateReason reason, GError **error); +void nm_manager_prevent_device_auto_connect (NMManager *manager, + const char *ifname, + gboolean prevent); +gboolean nm_manager_can_device_auto_connect (NMManager *manager, + const char *ifname); + /* State handling */ NMState nm_manager_get_state (NMManager *manager);