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;