diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml
index a8362acba5..c23b596c4b 100644
--- a/introspection/nm-device.xml
+++ b/introspection/nm-device.xml
@@ -58,6 +58,12 @@
+
+
+ Disconnects a device and prevents the device from automatically activating further connections without user intervention.
+
+
+
diff --git a/libnm-glib/Makefile.am b/libnm-glib/Makefile.am
index 8d659ea0b7..f91623e1b9 100644
--- a/libnm-glib/Makefile.am
+++ b/libnm-glib/Makefile.am
@@ -105,7 +105,7 @@ libnm_glib_la_LIBADD = \
$(GUDEV_LIBS)
libnm_glib_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib.ver \
- -version-info "2:0:0"
+ -version-info "3:0:1"
noinst_PROGRAMS = libnm-glib-test
diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver
index 342f713dcc..25556391dd 100644
--- a/libnm-glib/libnm-glib.ver
+++ b/libnm-glib/libnm-glib.ver
@@ -48,6 +48,7 @@ global:
nm_dbus_settings_system_get_type;
nm_dbus_settings_system_get_unmanaged_devices;
nm_dbus_settings_system_new;
+ nm_device_disconnect;
nm_device_bt_new;
nm_device_bt_get_capabilities;
nm_device_bt_get_hw_address;
diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
index 6cc38a8f51..226b30587c 100644
--- a/libnm-glib/nm-device.c
+++ b/libnm-glib/nm-device.c
@@ -1065,3 +1065,60 @@ nm_device_get_vendor (NMDevice *device)
return priv->vendor;
}
+typedef struct {
+ NMDevice *device;
+ NMDeviceDeactivateFn fn;
+ gpointer user_data;
+} DeactivateInfo;
+
+static void
+deactivate_cb (DBusGProxy *proxy,
+ GError *error,
+ gpointer user_data)
+{
+ DeactivateInfo *info = user_data;
+
+ if (info->fn)
+ info->fn (info->device, error, info->user_data);
+ else if (error) {
+ g_warning ("%s: device %s deactivation failed: (%d) %s",
+ __func__,
+ nm_object_get_path (NM_OBJECT (info->device)),
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ }
+
+ g_object_unref (info->device);
+ g_slice_free (DeactivateInfo, info);
+}
+
+/**
+ * nm_device_disconnect:
+ * @device: a #NMDevice
+ * @error: a location to store an error on failure
+ *
+ * Disconnects the device if currently connected, and prevents the device from
+ * automatically connecting to networks until the next manual network connection
+ * request.
+ *
+ * Returns: TRUE on success, FALSE if an error occurred.
+ **/
+void
+nm_device_disconnect (NMDevice *device,
+ NMDeviceDeactivateFn callback,
+ gpointer user_data)
+{
+ DeactivateInfo *info;
+
+ g_return_if_fail (NM_IS_DEVICE (device));
+
+ info = g_slice_new (DeactivateInfo);
+ info->fn = callback;
+ info->user_data = user_data;
+ info->device = g_object_ref (device);
+
+ org_freedesktop_NetworkManager_Device_disconnect_async (NM_DEVICE_GET_PRIVATE (device)->proxy,
+ deactivate_cb,
+ info);
+}
+
diff --git a/libnm-glib/nm-device.h b/libnm-glib/nm-device.h
index 442643214d..7e016f4598 100644
--- a/libnm-glib/nm-device.h
+++ b/libnm-glib/nm-device.h
@@ -85,6 +85,12 @@ NMDeviceState nm_device_get_state (NMDevice *device);
const char * nm_device_get_product (NMDevice *device);
const char * nm_device_get_vendor (NMDevice *device);
+typedef void (*NMDeviceDeactivateFn) (NMDevice *device, GError *error, gpointer user_data);
+
+void nm_device_disconnect (NMDevice *device,
+ NMDeviceDeactivateFn callback,
+ gpointer user_data);
+
G_END_DECLS
#endif /* NM_DEVICE_H */
diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c
index 5e72afab9d..c8475df4ca 100644
--- a/src/nm-device-interface.c
+++ b/src/nm-device-interface.c
@@ -25,6 +25,9 @@
#include "nm-utils.h"
#include "nm-properties-changed-signal.h"
+static gboolean impl_device_disconnect (NMDeviceInterface *device,
+ GError **error);
+
#include "nm-device-interface-glue.h"
GQuark
@@ -50,6 +53,8 @@ nm_device_interface_error_get_type (void)
ENUM_ENTRY (NM_DEVICE_INTERFACE_ERROR_CONNECTION_ACTIVATING, "ConnectionActivating"),
/* Connection is invalid for this device. */
ENUM_ENTRY (NM_DEVICE_INTERFACE_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
+ /* Operation could not be performed because the device is not active. */
+ ENUM_ENTRY (NM_DEVICE_INTERFACE_ERROR_NOT_ACTIVE, "NotActive"),
{ 0, 0, 0 }
};
etype = g_enum_register_static ("NMDeviceInterfaceError", values);
@@ -270,6 +275,39 @@ nm_device_interface_activate (NMDeviceInterface *device,
return success;
}
+gboolean
+nm_device_interface_disconnect (NMDeviceInterface *device,
+ GError **error)
+{
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
+
+ switch (nm_device_interface_get_state (device)) {
+ case NM_DEVICE_STATE_UNKNOWN:
+ case NM_DEVICE_STATE_UNMANAGED:
+ case NM_DEVICE_STATE_UNAVAILABLE:
+ case NM_DEVICE_STATE_DISCONNECTED:
+ g_set_error_literal (error,
+ NM_DEVICE_INTERFACE_ERROR,
+ NM_DEVICE_INTERFACE_ERROR_NOT_ACTIVE,
+ "Cannot disconnect an inactive device.");
+ break;
+ default:
+ success = NM_DEVICE_INTERFACE_GET_INTERFACE (device)->disconnect (device, error);
+ break;
+ }
+
+ return success;
+}
+
+static gboolean
+impl_device_disconnect (NMDeviceInterface *device,
+ GError **error)
+{
+ return nm_device_interface_disconnect (device, error);
+}
+
void
nm_device_interface_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
{
diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h
index 0273c750d2..0867bc2923 100644
--- a/src/nm-device-interface.h
+++ b/src/nm-device-interface.h
@@ -36,6 +36,7 @@ typedef enum
{
NM_DEVICE_INTERFACE_ERROR_CONNECTION_ACTIVATING = 0,
NM_DEVICE_INTERFACE_ERROR_CONNECTION_INVALID,
+ NM_DEVICE_INTERFACE_ERROR_NOT_ACTIVE,
} NMDeviceInterfaceError;
#define NM_DEVICE_INTERFACE_ERROR (nm_device_interface_error_quark ())
@@ -68,7 +69,7 @@ typedef enum {
NM_DEVICE_INTERFACE_PROP_STATE,
NM_DEVICE_INTERFACE_PROP_DEVICE_TYPE,
NM_DEVICE_INTERFACE_PROP_MANAGED,
- NM_DEVICE_INTERFACE_PROP_TYPE_DESC
+ NM_DEVICE_INTERFACE_PROP_TYPE_DESC,
} NMDeviceInterfaceProp;
@@ -87,6 +88,7 @@ struct _NMDeviceInterface {
GError **error);
void (*deactivate) (NMDeviceInterface *device, NMDeviceStateReason reason);
+ gboolean (*disconnect) (NMDeviceInterface *device, GError **error);
gboolean (*spec_match_list) (NMDeviceInterface *device, const GSList *specs);
@@ -102,6 +104,8 @@ struct _NMDeviceInterface {
GQuark nm_device_interface_error_quark (void);
GType nm_device_interface_error_get_type (void);
+gboolean nm_device_interface_disconnect (NMDeviceInterface *device, GError **error);
+
GType nm_device_interface_get_type (void);
gboolean nm_device_interface_check_connection_compatible (NMDeviceInterface *device,
diff --git a/src/nm-device.c b/src/nm-device.c
index ec08f58106..d7e6e256c6 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -127,6 +127,9 @@ typedef struct {
gulong ip6_addrconf_sigid;
gulong ip6_config_changed_sigid;
gboolean ip6_waiting_for_config;
+
+ /* inhibit autoconnect feature */
+ gboolean autoconnect_inhibit;
} NMDevicePrivate;
static gboolean check_connection_compatible (NMDeviceInterface *device,
@@ -136,6 +139,7 @@ static gboolean nm_device_activate (NMDeviceInterface *device,
NMActRequest *req,
GError **error);
static void nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason);
+static gboolean device_disconnect (NMDeviceInterface *device, GError **error);
static gboolean spec_match_list (NMDeviceInterface *device, const GSList *specs);
static NMConnection *connection_match_config (NMDeviceInterface *device, const GSList *connections);
@@ -162,6 +166,7 @@ device_interface_init (NMDeviceInterface *device_interface_class)
device_interface_class->check_connection_compatible = check_connection_compatible;
device_interface_class->activate = nm_device_activate;
device_interface_class->deactivate = nm_device_deactivate;
+ device_interface_class->disconnect = device_disconnect;
device_interface_class->spec_match_list = spec_match_list;
device_interface_class->connection_match_config = connection_match_config;
}
@@ -410,6 +415,7 @@ autoconnect_allowed_accumulator (GSignalInvocationHint *ihint,
gboolean
nm_device_autoconnect_allowed (NMDevice *self)
{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
GValue instance = { 0, };
GValue retval = { 0, };
@@ -417,7 +423,10 @@ nm_device_autoconnect_allowed (NMDevice *self)
g_value_take_object (&instance, self);
g_value_init (&retval, G_TYPE_BOOLEAN);
- g_value_set_boolean (&retval, TRUE);
+ if (priv->autoconnect_inhibit)
+ g_value_set_boolean (&retval, FALSE);
+ else
+ g_value_set_boolean (&retval, TRUE);
/* Use g_signal_emitv() rather than g_signal_emit() to avoid the return
* value being changed if no handlers are connected */
@@ -2066,6 +2075,17 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
NM_DEVICE_GET_CLASS (self)->deactivate (self);
}
+static gboolean
+device_disconnect (NMDeviceInterface *device,
+ GError **error)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (NM_DEVICE (device));
+
+ priv->autoconnect_inhibit = TRUE;
+ nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_USER_REQUESTED);
+ return TRUE;
+}
+
static gboolean
check_connection_compatible (NMDeviceInterface *dev_iface,
NMConnection *connection,
@@ -3061,6 +3081,7 @@ nm_device_state_changed (NMDevice *device,
nm_device_interface_deactivate (NM_DEVICE_INTERFACE (device), reason);
break;
default:
+ priv->autoconnect_inhibit = FALSE;
break;
}
@@ -3198,3 +3219,11 @@ nm_device_set_dhcp_anycast_address (NMDevice *device, guint8 *addr)
}
+void
+nm_device_clear_autoconnect_inhibit (NMDevice *device)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+ g_return_if_fail (priv);
+ priv->autoconnect_inhibit = FALSE;
+}
+
diff --git a/src/nm-device.h b/src/nm-device.h
index c8f67dcc76..b81c460d6e 100644
--- a/src/nm-device.h
+++ b/src/nm-device.h
@@ -179,6 +179,8 @@ void nm_device_set_managed (NMDevice *device,
void nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout);
void nm_device_set_dhcp_anycast_address (NMDevice *device, guint8 *addr);
+void nm_device_clear_autoconnect_inhibit (NMDevice *device);
+
G_END_DECLS
#endif /* NM_DEVICE_H */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 2fd1cbd2d9..72a01345c5 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -2393,6 +2393,7 @@ impl_manager_sleep (NMManager *self, gboolean sleep, GError **error)
for (iter = priv->devices; iter; iter = iter->next) {
NMDevice *device = NM_DEVICE (iter->data);
+ nm_device_clear_autoconnect_inhibit (device);
if (nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs))
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
else
diff --git a/test/nm-tool.c b/test/nm-tool.c
index d9874bc2df..9d1a245718 100644
--- a/test/nm-tool.c
+++ b/test/nm-tool.c
@@ -43,7 +43,12 @@
#include
#include
-#include "nm-dbus-glib-types.h"
+/* Don't use nm-dbus-glib-types.h so that we can keep nm-tool
+ * building standalone outside of the NM tree.
+ */
+#define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
+#define DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT))
+#define DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH))
static GHashTable *user_connections = NULL;
static GHashTable *system_connections = NULL;