summaryrefslogtreecommitdiff
path: root/src/devices/bluetooth/nm-bluez-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bluetooth/nm-bluez-device.c')
-rw-r--r--src/devices/bluetooth/nm-bluez-device.c1207
1 files changed, 0 insertions, 1207 deletions
diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c
deleted file mode 100644
index 072582ed87..0000000000
--- a/src/devices/bluetooth/nm-bluez-device.c
+++ /dev/null
@@ -1,1207 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/* NetworkManager -- Network link manager
- *
- * Copyright (C) 2009 - 2012 Red Hat, Inc.
- * Copyright (C) 2013 Intel Corporation.
- */
-
-#include "nm-default.h"
-
-#include "nm-bluez-device.h"
-
-#include "nm-core-internal.h"
-#include "nm-bt-error.h"
-#include "nm-bluez-common.h"
-#include "settings/nm-settings.h"
-#include "settings/nm-settings-connection.h"
-#include "NetworkManagerUtils.h"
-
-#if WITH_BLUEZ5_DUN
-#include "nm-bluez5-dun.h"
-#endif
-
-/*****************************************************************************/
-
-#define VARIANT_IS_OF_TYPE_BOOLEAN(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_BOOLEAN) ))
-#define VARIANT_IS_OF_TYPE_STRING(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_STRING) ))
-#define VARIANT_IS_OF_TYPE_OBJECT_PATH(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_OBJECT_PATH) ))
-#define VARIANT_IS_OF_TYPE_STRING_ARRAY(v) ((v) != NULL && ( g_variant_is_of_type ((v), G_VARIANT_TYPE_STRING_ARRAY) ))
-
-/*****************************************************************************/
-
-NM_GOBJECT_PROPERTIES_DEFINE (NMBluezDevice,
- PROP_PATH,
- PROP_ADDRESS,
- PROP_NAME,
- PROP_CAPABILITIES,
- PROP_USABLE,
- PROP_CONNECTED,
-);
-
-enum {
- INITIALIZED,
- REMOVED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-typedef struct {
- char *path;
-
- GDBusConnection *dbus_connection;
-
- GDBusProxy *proxy;
-
- GDBusProxy *adapter5;
- gboolean adapter_powered;
-
- gboolean initialized;
- gboolean usable;
- NMBluetoothCapabilities connection_bt_type;
-
- guint check_emit_usable_id;
-
- char *adapter_address;
- char *address;
- char *name;
- guint32 capabilities;
- gboolean connected;
- gboolean paired;
-
- char *b4_iface;
-#if WITH_BLUEZ5_DUN
- NMBluez5DunContext *b5_dun_context;
-#endif
-
- NMSettings *settings;
- GSList *connections;
-
- NMSettingsConnection *pan_connection;
- gboolean pan_connection_no_autocreate;
-} NMBluezDevicePrivate;
-
-struct _NMBluezDevice {
- GObject parent;
- NMBluezDevicePrivate _priv;
-};
-
-struct _NMBluezDeviceClass {
- GObjectClass parent;
-};
-
-G_DEFINE_TYPE (NMBluezDevice, nm_bluez_device, G_TYPE_OBJECT)
-
-#define NM_BLUEZ_DEVICE_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMBluezDevice, NM_IS_BLUEZ_DEVICE)
-
-/*****************************************************************************/
-
-#define _NMLOG_PREFIX_NAME "bluez"
-#define _NMLOG_DOMAIN LOGD_BT
-#define _NMLOG(level, ...) \
- G_STMT_START { \
- if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \
- const char *_path = (self) ? NM_BLUEZ_DEVICE_GET_PRIVATE (self)->path : NULL; \
- \
- _nm_log ((level), \
- (_NMLOG_DOMAIN), \
- 0, \
- NULL, \
- NULL, \
- "%s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- NM_PRINT_FMT_QUOTED (_path, _NMLOG_PREFIX_NAME"[", _path, "]: ", _NMLOG_PREFIX_NAME": ") \
- _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- } G_STMT_END
-
-/*****************************************************************************/
-
-static void cp_connection_added (NMSettings *settings,
- NMSettingsConnection *sett_conn,
- NMBluezDevice *self);
-static gboolean connection_compatible (NMBluezDevice *self, NMSettingsConnection *sett_conn);
-
-/*****************************************************************************/
-
-const char *
-nm_bluez_device_get_path (NMBluezDevice *self)
-{
- g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL);
-
- return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->path;
-}
-
-const char *
-nm_bluez_device_get_address (NMBluezDevice *self)
-{
- g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL);
-
- return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->address;
-}
-
-gboolean
-nm_bluez_device_get_initialized (NMBluezDevice *self)
-{
- g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE);
-
- return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->initialized;
-}
-
-gboolean
-nm_bluez_device_get_usable (NMBluezDevice *self)
-{
- g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE);
-
- return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->usable;
-}
-
-const char *
-nm_bluez_device_get_name (NMBluezDevice *self)
-{
- g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), NULL);
-
- return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->name;
-}
-
-guint32
-nm_bluez_device_get_capabilities (NMBluezDevice *self)
-{
- g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), 0);
-
- return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->capabilities;
-}
-
-gboolean
-nm_bluez_device_get_connected (NMBluezDevice *self)
-{
- NMBluezDevicePrivate *priv;
-
- g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE);
-
- priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- return priv->connected;
-}
-
-static void
-pan_connection_check_create (NMBluezDevice *self)
-{
- gs_unref_object NMConnection *connection = NULL;
- NMSettingsConnection *added;
- NMSetting *setting;
- gs_free char *id = NULL;
- char uuid[37];
- GError *error = NULL;
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- g_return_if_fail (priv->capabilities & NM_BT_CAPABILITY_NAP);
- g_return_if_fail (priv->connections == NULL);
- g_return_if_fail (priv->name);
-
- if (priv->pan_connection || priv->pan_connection_no_autocreate) {
- /* already have a connection or we don't want to create one, nothing to do. */
- return;
- }
-
- /* Only try once to create a connection. If it does not succeed, we do not try again. Also,
- * if the connection gets deleted later, do not create another one for this device. */
- priv->pan_connection_no_autocreate = TRUE;
-
- /* create a new connection */
-
- connection = nm_simple_connection_new ();
-
- /* Setting: Connection */
- nm_utils_uuid_generate_buf (uuid);
- id = g_strdup_printf (_("%s Network"), priv->name);
- setting = nm_setting_connection_new ();
- g_object_set (setting,
- NM_SETTING_CONNECTION_ID, id,
- NM_SETTING_CONNECTION_UUID, uuid,
- NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
- NM_SETTING_CONNECTION_TYPE, NM_SETTING_BLUETOOTH_SETTING_NAME,
- NULL);
- nm_connection_add_setting (connection, setting);
-
- /* Setting: Bluetooth */
- setting = nm_setting_bluetooth_new ();
- g_object_set (G_OBJECT (setting),
- NM_SETTING_BLUETOOTH_BDADDR, priv->address,
- NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU,
- NULL);
- nm_connection_add_setting (connection, setting);
-
- if (!nm_connection_normalize (connection, NULL, NULL, &error)) {
- _LOGE ("couldn't generate a connection for NAP device: %s",
- error->message);
- g_error_free (error);
- g_return_if_reached ();
- }
-
- /* Adding a new connection raises a signal which eventually calls check_emit_usable (again)
- * which then already finds the suitable connection in priv->connections. This is confusing,
- * so block the signal. check_emit_usable will succeed after this function call returns. */
- g_signal_handlers_block_by_func (priv->settings, cp_connection_added, self);
- nm_settings_add_connection (priv->settings,
- connection,
- NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
- NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
- NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED,
- &added,
- &error);
- g_signal_handlers_unblock_by_func (priv->settings, cp_connection_added, self);
-
- if (added) {
- nm_assert (!g_slist_find (priv->connections, added));
- nm_assert (connection_compatible (self, added));
- priv->connections = g_slist_prepend (priv->connections, g_object_ref (added));
- priv->pan_connection = added;
- _LOGD ("added new Bluetooth connection for NAP device: '%s' (%s)",
- id, uuid);
- } else {
- _LOGW ("couldn't add new Bluetooth connection for NAP device: '%s' (%s): %s",
- id, uuid, error->message);
- g_clear_error (&error);
- }
-}
-
-static gboolean
-check_emit_usable (NMBluezDevice *self)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- gboolean new_usable;
-
- /* only expect the supported capabilities set. */
- nm_assert ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP | NM_BT_CAPABILITY_DUN)) == NM_BT_CAPABILITY_NONE );
-
- new_usable = ( priv->initialized
- && priv->capabilities
- && priv->name
- && priv->paired
- && priv->adapter5
- && priv->adapter_powered
- && priv->dbus_connection
- && priv->address
- && priv->adapter_address);
-
- if (!new_usable)
- goto END;
-
- if (priv->connections)
- goto END;
-
- if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) {
- /* non NAP devices are only usable, if they already have a connection. */
- new_usable = FALSE;
- goto END;
- }
-
- pan_connection_check_create (self);
- new_usable = !!priv->pan_connection;
-
-END:
- if (new_usable != priv->usable) {
- priv->usable = new_usable;
- _notify (self, PROP_USABLE);
- }
-
- return G_SOURCE_REMOVE;
-}
-
-static void
-check_emit_usable_schedule (NMBluezDevice *self)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- if (priv->check_emit_usable_id == 0)
- priv->check_emit_usable_id = g_idle_add ((GSourceFunc) check_emit_usable, self);
-}
-
-/*****************************************************************************/
-
-static gboolean
-connection_compatible (NMBluezDevice *self, NMSettingsConnection *sett_conn)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- NMConnection *connection = nm_settings_connection_get_connection (sett_conn);
- NMSettingBluetooth *s_bt;
- const char *bt_type;
- const char *bdaddr;
-
- if (!nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME))
- return FALSE;
-
- s_bt = nm_connection_get_setting_bluetooth (connection);
- if (!s_bt)
- return FALSE;
-
- if (!priv->address)
- return FALSE;
-
- bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt);
- if (!bdaddr)
- return FALSE;
- if (!nm_utils_hwaddr_matches (bdaddr, -1, priv->address, -1))
- return FALSE;
-
- bt_type = nm_setting_bluetooth_get_connection_type (s_bt);
-
- if (nm_streq (bt_type, NM_SETTING_BLUETOOTH_TYPE_NAP))
- return FALSE;
-
- if ( g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)
- && !(priv->capabilities & NM_BT_CAPABILITY_DUN))
- return FALSE;
-
- if ( g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)
- && !(priv->capabilities & NM_BT_CAPABILITY_NAP))
- return FALSE;
-
- return TRUE;
-}
-
-static gboolean
-_internal_track_connection (NMBluezDevice *self,
- NMSettingsConnection *sett_conn,
- gboolean tracked)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- gboolean was_tracked;
-
- was_tracked = !!g_slist_find (priv->connections, sett_conn);
- if (was_tracked == !!tracked)
- return FALSE;
-
- if (tracked)
- priv->connections = g_slist_prepend (priv->connections, g_object_ref (sett_conn));
- else {
- priv->connections = g_slist_remove (priv->connections, sett_conn);
- if (priv->pan_connection == sett_conn)
- priv->pan_connection = NULL;
- g_object_unref (sett_conn);
- }
-
- return TRUE;
-}
-
-static void
-cp_connection_added (NMSettings *settings,
- NMSettingsConnection *sett_conn,
- NMBluezDevice *self)
-{
- if (connection_compatible (self, sett_conn)) {
- if (_internal_track_connection (self, sett_conn, TRUE))
- check_emit_usable (self);
- }
-}
-
-static void
-cp_connection_removed (NMSettings *settings,
- NMSettingsConnection *sett_conn,
- NMBluezDevice *self)
-{
- if (_internal_track_connection (self, sett_conn, FALSE))
- check_emit_usable (self);
-}
-
-static void
-cp_connection_updated (NMSettings *settings,
- NMSettingsConnection *sett_conn,
- guint update_reason_u,
- NMBluezDevice *self)
-{
- if (_internal_track_connection (self, sett_conn,
- connection_compatible (self, sett_conn)))
- check_emit_usable_schedule (self);
-}
-
-static void
-load_connections (NMBluezDevice *self)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- NMSettingsConnection *const*connections;
- guint i;
- gboolean changed = FALSE;
-
- connections = nm_settings_get_connections (priv->settings, NULL);
- for (i = 0; connections[i]; i++) {
- if (connection_compatible (self, connections[i]))
- changed |= _internal_track_connection (self, connections[i], TRUE);
- }
- if (changed)
- check_emit_usable (self);
-}
-
-/*****************************************************************************/
-
-static void
-bluez_disconnect_cb (GDBusConnection *dbus_connection,
- GAsyncResult *res,
- gpointer user_data)
-{
- gs_unref_object NMBluezDevice *self = user_data;
- gs_free_error GError *error = NULL;
- gs_unref_variant GVariant *variant = NULL;
-
- variant = g_dbus_connection_call_finish (dbus_connection, res, &error);
- if (!variant) {
- if (!strstr (error->message, "org.bluez.Error.NotConnected"))
- _LOGW ("failed to disconnect: %s", error->message);
- }
-}
-
-void
-nm_bluez_device_disconnect (NMBluezDevice *self)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- GVariant *args = NULL;
- const char *dbus_iface = NULL;
-
- g_return_if_fail (priv->dbus_connection);
-
- /* FIXME: if we are in the process of connecting and cancel the
- * connection attempt, we must complete the pending connect request.
- * However, we must also ensure that we don't leave a connected device. */
- if (priv->connection_bt_type == NM_BT_CAPABILITY_DUN) {
-#if WITH_BLUEZ5_DUN
- nm_bluez5_dun_cleanup (priv->b5_dun_context);
-#endif
- priv->connected = FALSE;
- goto out;
- } else if (priv->connection_bt_type == NM_BT_CAPABILITY_NAP) {
- dbus_iface = NM_BLUEZ5_NETWORK_INTERFACE;
- } else
- nm_assert_not_reached ();
-
- g_dbus_connection_call (priv->dbus_connection,
- NM_BLUEZ_SERVICE,
- priv->path,
- dbus_iface,
- "Disconnect",
- args ?: g_variant_new("()"),
- NULL,
- G_DBUS_CALL_FLAGS_NONE,
- 10000,
- NULL,
- (GAsyncReadyCallback) bluez_disconnect_cb,
- g_object_ref (self));
-
-out:
- g_clear_pointer (&priv->b4_iface, g_free);
- priv->connection_bt_type = NM_BT_CAPABILITY_NONE;
-}
-
-static void
-_connect_complete (NMBluezDevice *self,
- const char *device,
- NMBluezDeviceConnectCallback callback,
- gpointer callback_user_data,
- GError *error)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- nm_assert ((device || error) && !(device && error));
-
- if (device) {
- priv->connected = TRUE;
- _notify (self, PROP_CONNECTED);
- }
-
- if (callback)
- callback (self, device, error, callback_user_data);
-}
-
-static void
-_connect_cb (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
-{
- gs_unref_object NMBluezDevice *self = NULL;
- NMBluezDevicePrivate *priv;
- NMBluezDeviceConnectCallback callback;
- gpointer callback_user_data;
- gs_free_error GError *error = NULL;
- char *device = NULL;
- gs_unref_variant GVariant *variant = NULL;
-
- nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data);
-
- priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- variant = _nm_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, G_VARIANT_TYPE ("(s)"), &error);
- if (variant) {
- g_variant_get (variant, "(s)", &device);
- priv->b4_iface = device;
- }
-
- _connect_complete (self, device, callback, callback_user_data, error);
-}
-
-#if WITH_BLUEZ5_DUN
-static void
-_connect_cb_bluez5_dun (NMBluez5DunContext *context,
- const char *device,
- GError *error,
- gpointer user_data)
-{
- gs_unref_object NMBluezDevice *self = NULL;
- gs_unref_object GCancellable *cancellable = NULL;
- NMBluezDeviceConnectCallback callback;
- gpointer callback_user_data;
- gs_free_error GError *cancelled_error = NULL;
-
- nm_utils_user_data_unpack (user_data, &self, &cancellable, &callback, &callback_user_data);
-
- /* FIXME(shutdown): the async operation nm_bluez5_dun_connect() should be cancellable.
- * Fake it here. */
- if (g_cancellable_set_error_if_cancelled (cancellable, &cancelled_error))
- error = cancelled_error;
-
- _connect_complete (self, device, callback, callback_user_data, error);
-}
-#else /* WITH_BLUEZ5_DUN */
-static void
-_connect_cb_bluez5_dun_idle_no_b5 (gpointer user_data,
- GCancellable *cancellable)
-{
- gs_unref_object NMBluezDevice *self = NULL;
- NMBluezDeviceConnectCallback callback;
- gpointer callback_user_data;
- gs_free_error GError *error = NULL;
-
- nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data);
-
- if (!g_cancellable_set_error_if_cancelled (cancellable, &error)) {
- g_set_error (&error,
- NM_BT_ERROR,
- NM_BT_ERROR_DUN_CONNECT_FAILED,
- "NetworkManager built without support for Bluez 5");
- }
- callback (self, NULL, error, callback_user_data);
-}
-#endif /* WITH_BLUEZ5_DUN */
-
-void
-nm_bluez_device_connect_async (NMBluezDevice *self,
- NMBluetoothCapabilities connection_bt_type,
- GCancellable *cancellable,
- NMBluezDeviceConnectCallback callback,
- gpointer callback_user_data)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- const char *dbus_iface = NULL;
- const char *connect_type = NULL;
-
- g_return_if_fail (priv->capabilities & connection_bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP));
-
- priv->connection_bt_type = connection_bt_type;
-
- if (connection_bt_type == NM_BT_CAPABILITY_NAP) {
- connect_type = BLUETOOTH_CONNECT_NAP;
- dbus_iface = NM_BLUEZ5_NETWORK_INTERFACE;
- } else if (connection_bt_type == NM_BT_CAPABILITY_DUN) {
- connect_type = BLUETOOTH_CONNECT_DUN;
-#if WITH_BLUEZ5_DUN
- if (priv->b5_dun_context == NULL)
- priv->b5_dun_context = nm_bluez5_dun_new (priv->adapter_address, priv->address);
- nm_bluez5_dun_connect (priv->b5_dun_context,
- _connect_cb_bluez5_dun,
- nm_utils_user_data_pack (g_object_ref (self),
- nm_g_object_ref (cancellable),
- callback,
- callback_user_data));
-#else
- if (callback) {
- nm_utils_invoke_on_idle (_connect_cb_bluez5_dun_idle_no_b5,
- nm_utils_user_data_pack (g_object_ref (self),
- callback,
- callback_user_data),
- cancellable);
- }
-#endif
- return;
- } else
- g_return_if_reached ();
-
- /* FIXME: we need to remember that a connect is in progress.
- * So, if the request gets cancelled, that we disconnect the
- * connection that was established in the meantime. */
- g_dbus_connection_call (priv->dbus_connection,
- NM_BLUEZ_SERVICE,
- priv->path,
- dbus_iface,
- "Connect",
- g_variant_new ("(s)", connect_type),
- NULL,
- G_DBUS_CALL_FLAGS_NONE,
- 20000,
- cancellable,
- _connect_cb,
- nm_utils_user_data_pack (g_object_ref (self),
- callback,
- callback_user_data));
-}
-
-/*****************************************************************************/
-
-static void
-set_adapter_address (NMBluezDevice *self, const char *address)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- g_return_if_fail (address);
-
- if (priv->adapter_address)
- g_free (priv->adapter_address);
- priv->adapter_address = g_strdup (address);
-}
-
-static guint32
-convert_uuids_to_capabilities (const char **strings)
-{
- const char **iter;
- guint32 capabilities = 0;
-
- for (iter = strings; iter && *iter; iter++) {
- char **parts;
-
- parts = g_strsplit (*iter, "-", -1);
- if (parts && parts[0]) {
- switch (g_ascii_strtoull (parts[0], NULL, 16)) {
- case 0x1103:
- capabilities |= NM_BT_CAPABILITY_DUN;
- break;
- case 0x1116:
- capabilities |= NM_BT_CAPABILITY_NAP;
- break;
- default:
- break;
- }
- }
- g_strfreev (parts);
- }
-
- return capabilities;
-}
-
-static void
-_set_property_capabilities (NMBluezDevice *self, const char **uuids)
-{
- guint32 uint_val;
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- uint_val = convert_uuids_to_capabilities (uuids);
- if (priv->capabilities != uint_val) {
- if (priv->capabilities) {
- /* changing (relevant) capabilities is not supported and ignored -- except setting initially */
- _LOGW ("ignore change of capabilities for Bluetooth device from %u to %u",
- priv->capabilities, uint_val);
- return;
- }
- _LOGD ("set capabilities for Bluetooth device: %s%s%s",
- uint_val & NM_BT_CAPABILITY_NAP ? "NAP" : "",
- ((uint_val & NM_BT_CAPABILITY_DUN) && (uint_val &NM_BT_CAPABILITY_NAP)) ? " | " : "",
- uint_val & NM_BT_CAPABILITY_DUN ? "DUN" : "");
- priv->capabilities = uint_val;
- _notify (self, PROP_CAPABILITIES);
- }
-}
-
-/**
- * priv->address can only be set one to a certain (non NULL) value. Every later attempt
- * to reset it to another value will be ignored and a warning will be logged.
- **/
-static void
-_set_property_address (NMBluezDevice *self, const char *addr)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- if (g_strcmp0 (priv->address, addr) == 0)
- return;
-
- if (!addr) {
- _LOGW ("cannot reset address from '%s' to NULL", priv->address);
- return;
- }
-
- if (priv->address != NULL) {
- _LOGW ("cannot reset address from '%s' to '%s'", priv->address, addr);
- return;
- }
-
- if (!nm_utils_hwaddr_valid (addr, ETH_ALEN)) {
- _LOGW ("cannot set address to '%s' (invalid value)", addr);
- return;
- }
-
- priv->address = g_strdup (addr);
- _notify (self, PROP_ADDRESS);
-}
-
-static void
-_take_variant_property_address (NMBluezDevice *self, GVariant *v)
-{
- _set_property_address (self, VARIANT_IS_OF_TYPE_STRING (v) ? g_variant_get_string (v, NULL) : NULL);
- if (v)
- g_variant_unref (v);
-}
-
-static void
-_take_variant_property_name (NMBluezDevice *self, GVariant *v)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- const char *str;
-
- if (VARIANT_IS_OF_TYPE_STRING (v)) {
- str = g_variant_get_string (v, NULL);
- if (g_strcmp0 (priv->name, str)) {
- g_free (priv->name);
- priv->name = g_strdup (str);
- _notify (self, PROP_NAME);
- }
- }
- if (v)
- g_variant_unref (v);
-}
-
-static void
-_take_variant_property_uuids (NMBluezDevice *self, GVariant *v)
-{
- if (VARIANT_IS_OF_TYPE_STRING_ARRAY (v)) {
- const char **uuids = g_variant_get_strv (v, NULL);
-
- _set_property_capabilities (self, uuids);
- g_free (uuids);
- }
- if (v)
- g_variant_unref (v);
-}
-
-static void
-_take_variant_property_connected (NMBluezDevice *self, GVariant *v)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- if (VARIANT_IS_OF_TYPE_BOOLEAN (v)) {
- gboolean connected = g_variant_get_boolean (v);
-
- if (priv->connected != connected) {
- priv->connected = connected;
- _notify (self, PROP_CONNECTED);
- }
- }
- if (v)
- g_variant_unref (v);
-}
-
-static void
-_take_variant_property_paired (NMBluezDevice *self, GVariant *v)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- if (VARIANT_IS_OF_TYPE_BOOLEAN (v))
- priv->paired = g_variant_get_boolean (v);
-
- if (v)
- g_variant_unref (v);
-}
-
-static void
-adapter5_on_properties_changed (GDBusProxy *proxy,
- GVariant *changed_properties,
- GStrv invalidated_properties,
- gpointer user_data)
-{
- NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data);
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- GVariantIter i;
- const char *property;
- GVariant *v;
-
- g_variant_iter_init (&i, changed_properties);
- while (g_variant_iter_next (&i, "{&sv}", &property, &v)) {
- if (!strcmp (property, "Powered") && VARIANT_IS_OF_TYPE_BOOLEAN (v)) {
- gboolean powered = g_variant_get_boolean (v);
- if (priv->adapter_powered != powered)
- priv->adapter_powered = powered;
- }
- g_variant_unref (v);
- }
-
- check_emit_usable (self);
-}
-
-static void
-adapter5_on_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- GError *error = NULL;
- GVariant *v;
-
- priv->adapter5 = g_dbus_proxy_new_for_bus_finish (res, &error);
- if (!priv->adapter5) {
- _LOGW ("failed to acquire adapter proxy: %s", error->message);
- g_clear_error (&error);
- g_signal_emit (self, signals[INITIALIZED], 0, FALSE);
- } else {
- g_signal_connect (priv->adapter5, "g-properties-changed",
- G_CALLBACK (adapter5_on_properties_changed), self);
-
- /* Check adapter's powered state */
- v = g_dbus_proxy_get_cached_property (priv->adapter5, "Powered");
- priv->adapter_powered = VARIANT_IS_OF_TYPE_BOOLEAN (v) ? g_variant_get_boolean (v) : FALSE;
- if (v)
- g_variant_unref (v);
-
- v = g_dbus_proxy_get_cached_property (priv->adapter5, "Address");
- if (VARIANT_IS_OF_TYPE_STRING (v))
- set_adapter_address (self, g_variant_get_string (v, NULL));
-
- priv->initialized = TRUE;
- g_signal_emit (self, signals[INITIALIZED], 0, TRUE);
-
- check_emit_usable (self);
- }
-
- g_object_unref (self);
-}
-
-static void
-_take_one_variant_property (NMBluezDevice *self, const char *property, GVariant *v)
-{
- if (v) {
- if (!g_strcmp0 (property, "Address"))
- _take_variant_property_address (self, v);
- else if (!g_strcmp0 (property, "Connected"))
- _take_variant_property_connected (self, v);
- else if (!g_strcmp0 (property, "Paired"))
- _take_variant_property_paired (self, v);
- else if (!g_strcmp0 (property, "Name"))
- _take_variant_property_name (self, v);
- else if (!g_strcmp0 (property, "UUIDs"))
- _take_variant_property_uuids (self, v);
- else
- g_variant_unref (v);
- }
-}
-
-static void
-_set_properties (NMBluezDevice *self, GVariant *properties)
-{
- GVariantIter i;
- const char *property;
- GVariant *v;
-
- g_object_freeze_notify (G_OBJECT (self));
- g_variant_iter_init (&i, properties);
- while (g_variant_iter_next (&i, "{&sv}", &property, &v))
- _take_one_variant_property (self, property, v);
- g_object_thaw_notify (G_OBJECT (self));
-}
-
-static void
-properties_changed (GDBusProxy *proxy,
- GVariant *changed_properties,
- GStrv invalidated_properties,
- gpointer user_data)
-{
- NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data);
-
- _set_properties (self, changed_properties);
- check_emit_usable (self);
-}
-
-static void
-query_properties (NMBluezDevice *self)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- GVariant *v;
-
- g_object_freeze_notify (G_OBJECT (self));
- _take_variant_property_address (self, g_dbus_proxy_get_cached_property (priv->proxy, "Address"));
- _take_variant_property_connected (self, g_dbus_proxy_get_cached_property (priv->proxy, "Connected"));
- _take_variant_property_paired (self, g_dbus_proxy_get_cached_property (priv->proxy, "Paired"));
- _take_variant_property_name (self, g_dbus_proxy_get_cached_property (priv->proxy, "Name"));
- _take_variant_property_uuids (self, g_dbus_proxy_get_cached_property (priv->proxy, "UUIDs"));
- g_object_thaw_notify (G_OBJECT (self));
-
- v = g_dbus_proxy_get_cached_property (priv->proxy, "Adapter");
- if (VARIANT_IS_OF_TYPE_OBJECT_PATH (v)) {
- g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL,
- NM_BLUEZ_SERVICE,
- g_variant_get_string (v, NULL),
- NM_BLUEZ5_ADAPTER_INTERFACE,
- NULL,
- (GAsyncReadyCallback) adapter5_on_acquired,
- g_object_ref (self));
- g_variant_unref (v);
- } else {
- /* If the Adapter property is unset at this point, we won't try to acquire the adapter later on
- * and the device stays unusable. This should not happen, but if it does, log a debug message. */
- _LOGD ("device has no adapter property and cannot be used");
- }
-
- /* Check if any connections match this device */
- load_connections (self);
-}
-
-static void
-on_proxy_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- GError *error = NULL;
-
- priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
-
- if (!priv->proxy) {
- _LOGW ("failed to acquire device proxy: %s", error->message);
- g_clear_error (&error);
- g_signal_emit (self, signals[INITIALIZED], 0, FALSE);
- } else {
- g_signal_connect (priv->proxy, "g-properties-changed",
- G_CALLBACK (properties_changed), self);
- query_properties (self);
- }
- g_object_unref (self);
-}
-
-/*****************************************************************************/
-
-static void
-get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *pspec)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE ((NMBluezDevice *) object);
-
- switch (prop_id) {
- case PROP_PATH:
- g_value_set_string (value, priv->path);
- break;
- case PROP_ADDRESS:
- g_value_set_string (value, priv->address);
- break;
- case PROP_NAME:
- g_value_set_string (value, priv->name);
- break;
- case PROP_CAPABILITIES:
- g_value_set_uint (value, priv->capabilities);
- break;
- case PROP_USABLE:
- g_value_set_boolean (value, priv->usable);
- break;
- case PROP_CONNECTED:
- g_value_set_boolean (value, priv->connected);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec)
-{
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE ((NMBluezDevice *) object);
-
- switch (prop_id) {
- case PROP_PATH:
- /* construct-only */
- priv->path = g_value_dup_string (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/*****************************************************************************/
-
-static void
-nm_bluez_device_init (NMBluezDevice *self)
-{
-}
-
-NMBluezDevice *
-nm_bluez_device_new (GDBusConnection *dbus_connection,
- const char *path,
- NMSettings *settings)
-{
- NMBluezDevice *self;
- NMBluezDevicePrivate *priv;
-
- g_return_val_if_fail (path != NULL, NULL);
- g_return_val_if_fail (NM_IS_SETTINGS (settings), NULL);
- g_return_val_if_fail (G_IS_DBUS_CONNECTION (dbus_connection), NULL);
-
- self = (NMBluezDevice *) g_object_new (NM_TYPE_BLUEZ_DEVICE,
- NM_BLUEZ_DEVICE_PATH, path,
- NULL);
- if (!self)
- return NULL;
-
- _LOGD ("create NMBluezDevice");
-
- priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- priv->settings = g_object_ref (settings);
-
- g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, G_CALLBACK (cp_connection_added), self);
- g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, G_CALLBACK (cp_connection_removed), self);
- g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, G_CALLBACK (cp_connection_updated), self);
-
- priv->dbus_connection = g_object_ref (dbus_connection);
-
- g_dbus_proxy_new (priv->dbus_connection,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL,
- NM_BLUEZ_SERVICE,
- priv->path,
- NM_BLUEZ5_DEVICE_INTERFACE,
- NULL,
- (GAsyncReadyCallback) on_proxy_acquired,
- g_object_ref (self));
-
- return self;
-}
-
-static void
-dispose (GObject *object)
-{
- NMBluezDevice *self = NM_BLUEZ_DEVICE (object);
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
- NMSettingsConnection *to_delete = NULL;
-
- nm_clear_g_source (&priv->check_emit_usable_id);
-
- if (priv->pan_connection) {
- /* Check whether we want to remove the created connection. If so, we take a reference
- * and delete it at the end of dispose(). */
- if (NM_FLAGS_HAS (nm_settings_connection_get_flags (priv->pan_connection),
- NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED))
- to_delete = g_object_ref (priv->pan_connection);
-
- priv->pan_connection = NULL;
- }
-
-#if WITH_BLUEZ5_DUN
- if (priv->b5_dun_context) {
- nm_bluez5_dun_free (priv->b5_dun_context);
- priv->b5_dun_context = NULL;
- }
-#endif
-
- if (priv->settings) {
- g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_added, self);
- g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_removed, self);
- g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_updated, self);
- }
-
- g_slist_free_full (priv->connections, g_object_unref);
- priv->connections = NULL;
-
- if (priv->adapter5) {
- g_signal_handlers_disconnect_by_func (priv->adapter5, adapter5_on_properties_changed, self);
- g_clear_object (&priv->adapter5);
- }
-
- g_clear_object (&priv->dbus_connection);
-
- G_OBJECT_CLASS (nm_bluez_device_parent_class)->dispose (object);
-
- if (to_delete) {
- _LOGD ("removing Bluetooth connection for NAP device: '%s' (%s)",
- nm_settings_connection_get_id (to_delete),
- nm_settings_connection_get_uuid (to_delete));
- nm_settings_connection_delete (to_delete, FALSE);
- g_object_unref (to_delete);
- }
-
- g_clear_object (&priv->settings);
-}
-
-static void
-finalize (GObject *object)
-{
- NMBluezDevice *self = NM_BLUEZ_DEVICE (object);
- NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
- _LOGD ("finalize NMBluezDevice");
-
- g_free (priv->path);
- g_free (priv->adapter_address);
- g_free (priv->address);
- g_free (priv->name);
- g_free (priv->b4_iface);
-
- if (priv->proxy)
- g_signal_handlers_disconnect_by_data (priv->proxy, object);
- g_clear_object (&priv->proxy);
-
- G_OBJECT_CLASS (nm_bluez_device_parent_class)->finalize (object);
-}
-
-static void
-nm_bluez_device_class_init (NMBluezDeviceClass *config_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (config_class);
-
- object_class->get_property = get_property;
- object_class->set_property = set_property;
- object_class->dispose = dispose;
- object_class->finalize = finalize;
-
- obj_properties[PROP_PATH] =
- g_param_spec_string (NM_BLUEZ_DEVICE_PATH, "", "",
- NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_ADDRESS] =
- g_param_spec_string (NM_BLUEZ_DEVICE_ADDRESS, "", "",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_NAME] =
- g_param_spec_string (NM_BLUEZ_DEVICE_NAME, "", "",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_CAPABILITIES] =
- g_param_spec_uint (NM_BLUEZ_DEVICE_CAPABILITIES, "", "",
- 0, G_MAXUINT, 0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_USABLE] =
- g_param_spec_boolean (NM_BLUEZ_DEVICE_USABLE, "", "",
- FALSE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_CONNECTED] =
- g_param_spec_boolean (NM_BLUEZ_DEVICE_CONNECTED, "", "",
- FALSE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
-
- signals[INITIALIZED] = g_signal_new (NM_BLUEZ_DEVICE_INITIALIZED,
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL, NULL,
- G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
- signals[REMOVED] = g_signal_new (NM_BLUEZ_DEVICE_REMOVED,
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL, NULL,
- G_TYPE_NONE, 0);
-}
-