diff options
Diffstat (limited to 'src/devices/bluetooth/nm-bluez-manager.c')
| -rw-r--r-- | src/devices/bluetooth/nm-bluez-manager.c | 2895 |
1 files changed, 0 insertions, 2895 deletions
diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c deleted file mode 100644 index df0bcbbb..00000000 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ /dev/null @@ -1,2895 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 - 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-bluez-manager.h" - -#include <signal.h> -#include <stdlib.h> -#include <gmodule.h> - -#include "nm-glib-aux/nm-dbus-aux.h" -#include "nm-glib-aux/nm-c-list.h" -#include "nm-dbus-manager.h" -#include "devices/nm-device-factory.h" -#include "devices/nm-device-bridge.h" -#include "nm-setting-bluetooth.h" -#include "settings/nm-settings.h" -#include "nm-bluez-common.h" -#include "nm-device-bt.h" -#include "nm-manager.h" -#include "nm-bluez5-dun.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.h" -#include "nm-std-aux/nm-dbus-compat.h" - -/*****************************************************************************/ - -#if WITH_BLUEZ5_DUN - #define _NM_BT_CAPABILITY_SUPPORTED_DUN NM_BT_CAPABILITY_DUN -#else - #define _NM_BT_CAPABILITY_SUPPORTED_DUN NM_BT_CAPABILITY_NONE -#endif -#define _NM_BT_CAPABILITY_SUPPORTED (NM_BT_CAPABILITY_NAP | _NM_BT_CAPABILITY_SUPPORTED_DUN) - -typedef struct { - const char * bdaddr; - CList lst_head; - NMBluetoothCapabilities bt_type : 8; - char bdaddr_data[]; -} ConnDataHead; - -typedef struct { - NMSettingsConnection *sett_conn; - ConnDataHead * cdata_hd; - CList lst; -} ConnDataElem; - -typedef struct { - GCancellable * ext_cancellable; - GCancellable * int_cancellable; - NMBtVTableRegisterCallback callback; - gpointer callback_user_data; - gulong ext_cancelled_id; -} NetworkServerRegisterReqData; - -typedef struct { - GCancellable * ext_cancellable; - GCancellable * int_cancellable; - NMBluezManagerConnectCb callback; - gpointer callback_user_data; - char * device_name; - gulong ext_cancelled_id; - guint timeout_id; - guint timeout_wait_connect_id; -} DeviceConnectReqData; - -typedef struct { - const char *object_path; - - NMBluezManager *self; - - /* Fields name with "d_" prefix are purely cached values from BlueZ's - * ObjectManager D-Bus interface. There is no logic whatsoever about - * them. - */ - - CList process_change_lst; - - struct { - char *address; - } d_adapter; - - struct { - char *address; - char *name; - char *adapter; - } d_device; - - struct { - char *interface; - } d_network; - - struct { - CList lst; - char * adapter_address; - NMDevice * device_br; - NetworkServerRegisterReqData *r_req_data; - } x_network_server; - - struct { - NMSettingsConnection *panu_connection; - NMDeviceBt * device_bt; - DeviceConnectReqData *c_req_data; - NMBluez5DunContext * connect_dun_context; - gulong device_bt_signal_id; - } x_device; - - /* indicate whether the D-Bus object has the particular D-Bus interface. */ - bool d_has_adapter_iface : 1; - bool d_has_device_iface : 1; - bool d_has_network_iface : 1; - bool d_has_network_server_iface : 1; - - /* cached D-Bus properties for Device1 ("d_device*"). */ - NMBluetoothCapabilities d_device_capabilities : 6; - bool d_device_connected : 1; - bool d_device_paired : 1; - - /* cached D-Bus properties for Network1 ("d_network*"). */ - bool d_network_connected : 1; - - /* cached D-Bus properties for Adapter1 ("d_adapter*"). */ - bool d_adapter_powered : 1; - - /* properties related to device ("x_device*"). */ - NMBluetoothCapabilities x_device_connect_bt_type : 6; - bool x_device_is_usable : 1; - bool x_device_is_connected : 1; - - bool x_device_panu_connection_allow_create : 1; - - /* flag to remember last time when we checked wether the object - * was a suitable adapter that is usable to a device. */ - bool was_usable_adapter_for_device_before : 1; - - char _object_path_intern[]; -} BzDBusObj; - -typedef struct { - NMManager * manager; - NMSettings *settings; - - GDBusConnection *dbus_connection; - - NMBtVTableNetworkServer vtable_network_server; - - GCancellable *name_owner_get_cancellable; - GCancellable *get_managed_objects_cancellable; - - GHashTable *bzobjs; - - char *name_owner; - - GHashTable *conn_data_heads; - GHashTable *conn_data_elems; - - CList network_server_lst_head; - - CList process_change_lst_head; - - guint name_owner_changed_id; - - guint managed_objects_changed_id; - - guint properties_changed_id; - - guint process_change_idle_id; - - bool settings_registered : 1; -} NMBluezManagerPrivate; - -struct _NMBluezManager { - NMDeviceFactory parent; - NMBluezManagerPrivate _priv; -}; - -struct _NMBluezManagerClass { - NMDeviceFactoryClass parent; -}; - -G_DEFINE_TYPE(NMBluezManager, nm_bluez_manager, NM_TYPE_DEVICE_FACTORY); - -#define NM_BLUEZ_MANAGER_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMBluezManager, NM_IS_BLUEZ_MANAGER) - -/*****************************************************************************/ - -NM_DEVICE_FACTORY_DECLARE_TYPES(NM_DEVICE_FACTORY_DECLARE_LINK_TYPES( - NM_LINK_TYPE_BNEP) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_BLUETOOTH_SETTING_NAME)) - -G_MODULE_EXPORT NMDeviceFactory * - nm_device_factory_create(GError **error) -{ - return (NMDeviceFactory *) g_object_new(NM_TYPE_BLUEZ_MANAGER, NULL); -} - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_BT -#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "bluez", __VA_ARGS__) - -/*****************************************************************************/ - -static NMBluetoothCapabilities -convert_uuids_to_capabilities(const char *const *strv) -{ - NMBluetoothCapabilities capabilities = NM_BT_CAPABILITY_NONE; - - if (strv) { - for (; strv[0]; strv++) { - gs_free char *s_part1 = NULL; - const char * str = strv[0]; - const char * s; - - s = strchr(str, '-'); - if (!s) - continue; - - s_part1 = g_strndup(str, s - str); - switch (_nm_utils_ascii_str_to_int64(s_part1, 16, 0, G_MAXINT, -1)) { - case 0x1103: - capabilities |= NM_BT_CAPABILITY_DUN; - break; - case 0x1116: - capabilities |= NM_BT_CAPABILITY_NAP; - break; - default: - break; - } - } - } - - return capabilities; -} - -/*****************************************************************************/ - -static void _cleanup_for_name_owner(NMBluezManager *self); -static void _connect_disconnect(NMBluezManager *self, BzDBusObj *bzobj, const char *reason); -static gboolean _bzobjs_network_server_is_usable(const BzDBusObj *bzobj, gboolean require_powered); -static gboolean _bzobjs_is_dead(const BzDBusObj *bzobj); -static gboolean _bzobjs_device_is_usable(const BzDBusObj *bzobj, - BzDBusObj ** out_adapter_bzobj, - gboolean * out_create_panu_connection); -static gboolean _bzobjs_adapter_is_usable_for_device(const BzDBusObj *bzobj); -static ConnDataHead * -_conn_track_find_head(NMBluezManager *self, NMBluetoothCapabilities bt_type, const char *bdaddr); -static void _process_change_idle_schedule(NMBluezManager *self, BzDBusObj *bzobj); -static void -_network_server_unregister_bridge(NMBluezManager *self, BzDBusObj *bzobj, const char *reason); -static gboolean _connect_timeout_wait_connected_cb(gpointer user_data); - -/*****************************************************************************/ - -static void -_dbus_call_complete_cb_nop(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - /* we don't do anything at all. The only reason to register this - * callback is so that GDBusConnection keeps the cancellable alive - * long enough until the call completes. - * - * Note that this cancellable in turn is registered via - * nm_shutdown_wait_obj_register_*(), to block shutdown until - * we are done. */ -} - -/*****************************************************************************/ - -static void -_network_server_register_req_data_complete(NetworkServerRegisterReqData *r_req_data, GError *error) -{ - nm_clear_g_signal_handler(r_req_data->ext_cancellable, &r_req_data->ext_cancelled_id); - - nm_clear_g_cancellable(&r_req_data->int_cancellable); - - if (r_req_data->callback) { - gs_free_error GError *error_cancelled = NULL; - - if (g_cancellable_set_error_if_cancelled(r_req_data->ext_cancellable, &error_cancelled)) - error = error_cancelled; - - r_req_data->callback(error, r_req_data->callback_user_data); - } - - g_object_unref(r_req_data->ext_cancellable); - nm_g_slice_free(r_req_data); -} - -static void -_device_connect_req_data_complete(DeviceConnectReqData *c_req_data, - NMBluezManager * self, - const char * device_name, - GError * error) -{ - nm_assert((!!device_name) != (!!error)); - - nm_clear_g_signal_handler(c_req_data->ext_cancellable, &c_req_data->ext_cancelled_id); - - nm_clear_g_cancellable(&c_req_data->int_cancellable); - nm_clear_g_source(&c_req_data->timeout_id); - nm_clear_g_source(&c_req_data->timeout_wait_connect_id); - - if (c_req_data->callback) { - gs_free_error GError *error_cancelled = NULL; - - if (g_cancellable_set_error_if_cancelled(c_req_data->ext_cancellable, &error_cancelled)) { - error = error_cancelled; - device_name = NULL; - } - - c_req_data->callback(self, TRUE, device_name, error, c_req_data->callback_user_data); - } - - g_object_unref(c_req_data->ext_cancellable); - nm_clear_g_free(&c_req_data->device_name); - nm_g_slice_free(c_req_data); -} - -/*****************************************************************************/ - -static BzDBusObj * -_bz_dbus_obj_new(NMBluezManager *self, const char *object_path) -{ - BzDBusObj *bzobj; - gsize l; - - nm_assert(NM_IS_BLUEZ_MANAGER(self)); - - l = strlen(object_path) + 1; - - bzobj = g_malloc(sizeof(BzDBusObj) + l); - *bzobj = (BzDBusObj){ - .object_path = bzobj->_object_path_intern, - .self = self, - .x_network_server.lst = C_LIST_INIT(bzobj->x_network_server.lst), - .process_change_lst = C_LIST_INIT(bzobj->process_change_lst), - .x_device_panu_connection_allow_create = TRUE, - }; - memcpy(bzobj->_object_path_intern, object_path, l); - - return bzobj; -} - -static void -_bz_dbus_obj_free(BzDBusObj *bzobj) -{ - nm_assert(bzobj); - nm_assert(NM_IS_BLUEZ_MANAGER(bzobj->self)); - nm_assert(!bzobj->x_network_server.device_br); - nm_assert(!bzobj->x_network_server.r_req_data); - nm_assert(!bzobj->x_device.c_req_data); - - c_list_unlink_stale(&bzobj->process_change_lst); - c_list_unlink_stale(&bzobj->x_network_server.lst); - g_free(bzobj->x_network_server.adapter_address); - g_free(bzobj->d_adapter.address); - g_free(bzobj->d_network.interface); - g_free(bzobj->d_device.address); - g_free(bzobj->d_device.name); - g_free(bzobj->d_device.adapter); - g_free(bzobj); -} - -/*****************************************************************************/ - -static const char * -_bzobj_to_string(const BzDBusObj *bzobj, char *buf, gsize len) -{ - char * buf0 = buf; - const char *prefix = ""; - gboolean device_is_usable; - gboolean create_panu_connection = FALSE; - gboolean network_server_is_usable; - char sbuf_cap[100]; - - if (len > 0) - buf[0] = '\0'; - - if (bzobj->d_has_adapter_iface) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append_str(&buf, &len, "Adapter1 {"); - if (bzobj->d_adapter.address) { - nm_utils_strbuf_append(&buf, &len, " d.address: \"%s\"", bzobj->d_adapter.address); - if (bzobj->d_adapter_powered) - nm_utils_strbuf_append_str(&buf, &len, ","); - } - if (bzobj->d_adapter_powered) - nm_utils_strbuf_append(&buf, &len, " d.powered: 1"); - nm_utils_strbuf_append_str(&buf, &len, " }"); - } - - if (bzobj->d_has_device_iface) { - const char *prefix1 = ""; - - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append_str(&buf, &len, "Device1 {"); - if (bzobj->d_device.address) { - nm_utils_strbuf_append(&buf, - &len, - "%s d.address: \"%s\"", - prefix1, - bzobj->d_device.address); - prefix1 = ","; - } - if (bzobj->d_device.name) { - nm_utils_strbuf_append(&buf, &len, "%s d.name: \"%s\"", prefix1, bzobj->d_device.name); - prefix1 = ","; - } - if (bzobj->d_device.adapter) { - nm_utils_strbuf_append(&buf, - &len, - "%s d.adapter: \"%s\"", - prefix1, - bzobj->d_device.adapter); - prefix1 = ","; - } - if (bzobj->d_device_capabilities != NM_BT_CAPABILITY_NONE) { - nm_utils_strbuf_append(&buf, - &len, - "%s d.capabilities: \"%s\"", - prefix1, - nm_bluetooth_capability_to_string(bzobj->d_device_capabilities, - sbuf_cap, - sizeof(sbuf_cap))); - prefix1 = ","; - } - if (bzobj->d_device_connected) { - nm_utils_strbuf_append(&buf, &len, "%s d.connected: 1", prefix1); - prefix1 = ","; - } - if (bzobj->d_device_paired) { - nm_utils_strbuf_append(&buf, &len, "%s d.paired: 1", prefix1); - prefix1 = ","; - } - nm_utils_strbuf_append_str(&buf, &len, " }"); - } - - network_server_is_usable = _bzobjs_network_server_is_usable(bzobj, TRUE); - - if (bzobj->d_has_network_server_iface - || network_server_is_usable != (!c_list_is_empty(&bzobj->x_network_server.lst)) - || !c_list_is_empty(&bzobj->x_network_server.lst) - || !nm_streq0(bzobj->d_has_adapter_iface ? bzobj->d_adapter.address : NULL, - bzobj->x_network_server.adapter_address) - || bzobj->x_network_server.device_br || bzobj->x_network_server.r_req_data) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - - nm_utils_strbuf_append(&buf, &len, "NetworkServer1 { "); - - if (!bzobj->d_has_network_server_iface) - nm_utils_strbuf_append(&buf, &len, " has-d-iface: 0, "); - - if (network_server_is_usable != (!c_list_is_empty(&bzobj->x_network_server.lst))) - nm_utils_strbuf_append(&buf, - &len, - "usable: %d, used: %d", - !!network_server_is_usable, - !network_server_is_usable); - else if (network_server_is_usable) - nm_utils_strbuf_append(&buf, &len, "used: 1"); - else - nm_utils_strbuf_append(&buf, &len, "usable: 0"); - - if (!nm_streq0(bzobj->d_has_adapter_iface ? bzobj->d_adapter.address : NULL, - bzobj->x_network_server.adapter_address)) { - if (bzobj->x_network_server.adapter_address) - nm_utils_strbuf_append(&buf, - &len, - ", adapter-address: \"%s\"", - bzobj->x_network_server.adapter_address); - else - nm_utils_strbuf_append(&buf, &len, ", adapter-address: <NULL>"); - } - - if (bzobj->x_network_server.device_br) - nm_utils_strbuf_append(&buf, &len, ", bridge-device: 1"); - - if (bzobj->x_network_server.r_req_data) - nm_utils_strbuf_append(&buf, &len, ", register-in-progress: 1"); - - nm_utils_strbuf_append_str(&buf, &len, " }"); - } - - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, &create_panu_connection); - - if (bzobj->d_has_network_iface || bzobj->d_network.interface || bzobj->d_network_connected - || create_panu_connection || bzobj->x_device.panu_connection - || device_is_usable != bzobj->x_device_is_usable || bzobj->x_device.device_bt - || bzobj->x_device_connect_bt_type != NM_BT_CAPABILITY_NONE - || bzobj->x_device.connect_dun_context || bzobj->x_device.c_req_data - || bzobj->x_device_is_connected != bzobj->d_network_connected) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append_str(&buf, &len, "Network1 {"); - if (bzobj->d_network.interface) - nm_utils_strbuf_append(&buf, - &len, - " d.interface: \"%s\", ", - bzobj->d_network.interface); - if (bzobj->d_network_connected) - nm_utils_strbuf_append(&buf, &len, " d.connected: %d, ", !!bzobj->d_network_connected); - if (!bzobj->d_has_network_iface) - nm_utils_strbuf_append(&buf, &len, " has-d-iface: 0, "); - if (device_is_usable != bzobj->x_device_is_usable) - nm_utils_strbuf_append(&buf, - &len, - " usable: %d, used: %d", - !!device_is_usable, - !device_is_usable); - else if (device_is_usable) - nm_utils_strbuf_append(&buf, &len, " used: 1"); - else - nm_utils_strbuf_append(&buf, &len, " usable: 0"); - - if (create_panu_connection) - nm_utils_strbuf_append(&buf, &len, ", create-panu-connection: 1"); - - if (bzobj->x_device.panu_connection) - nm_utils_strbuf_append(&buf, &len, ", has-panu-connection: 1"); - - if (bzobj->x_device.device_bt) - nm_utils_strbuf_append(&buf, &len, ", has-device: 1"); - - if (bzobj->x_device_connect_bt_type != NM_BT_CAPABILITY_NONE - || bzobj->x_device.connect_dun_context) { - nm_utils_strbuf_append( - &buf, - &len, - ", connect: %s%s", - nm_bluetooth_capability_to_string(bzobj->x_device_connect_bt_type, - sbuf_cap, - sizeof(sbuf_cap)), - bzobj->x_device.connect_dun_context ? ",with-dun-context" : ""); - } - - if (bzobj->x_device.c_req_data) - nm_utils_strbuf_append(&buf, &len, ", connecting: 1"); - - if (bzobj->x_device_is_connected != bzobj->d_network_connected) - nm_utils_strbuf_append(&buf, &len, ", connected: %d", !!bzobj->x_device_is_connected); - - nm_utils_strbuf_append_str(&buf, &len, " }"); - } - - if (_bzobjs_is_dead(bzobj)) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append_str(&buf, &len, "dead: 1"); - } - - if (!c_list_is_empty(&bzobj->process_change_lst)) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append(&buf, &len, "change-pending-on-idle: 1"); - } - - if (_bzobjs_adapter_is_usable_for_device(bzobj) - != bzobj->was_usable_adapter_for_device_before) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append(&buf, &len, "change-usable-adapter-for-device: 1"); - } - - return buf0; -} - -#define _LOG_bzobj(bzobj, context) \ - G_STMT_START \ - { \ - const BzDBusObj *const _bzobj = (bzobj); \ - char _buf[500]; \ - \ - _LOGT("change %-21s %s : { %s }", \ - (context), \ - _bzobj->object_path, \ - _bzobj_to_string(_bzobj, _buf, sizeof(_buf))); \ - } \ - G_STMT_END - -static gboolean -_bzobjs_is_dead(const BzDBusObj *bzobj) -{ - return !bzobj->d_has_adapter_iface && !bzobj->d_has_device_iface && !bzobj->d_has_network_iface - && !bzobj->d_has_network_server_iface && c_list_is_empty(&bzobj->process_change_lst); -} - -static BzDBusObj * -_bzobjs_get(NMBluezManager *self, const char *object_path) -{ - return g_hash_table_lookup(NM_BLUEZ_MANAGER_GET_PRIVATE(self)->bzobjs, &object_path); -} - -static BzDBusObj * -_bzobjs_add(NMBluezManager *self, const char *object_path) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - BzDBusObj * bzobj; - - bzobj = _bz_dbus_obj_new(self, object_path); - if (!g_hash_table_add(priv->bzobjs, bzobj)) - nm_assert_not_reached(); - return bzobj; -} - -static void -_bzobjs_del(BzDBusObj *bzobj) -{ - nm_assert(bzobj); - nm_assert(bzobj == _bzobjs_get(bzobj->self, bzobj->object_path)); - - if (!g_hash_table_remove(NM_BLUEZ_MANAGER_GET_PRIVATE(bzobj->self)->bzobjs, bzobj)) - nm_assert_not_reached(); -} - -static void -_bzobjs_del_if_dead(BzDBusObj *bzobj) -{ - if (_bzobjs_is_dead(bzobj)) - _bzobjs_del(bzobj); -} - -static BzDBusObj * -_bzobjs_init(NMBluezManager *self, BzDBusObj **inout, const char *object_path) -{ - nm_assert(NM_IS_BLUEZ_MANAGER(self)); - nm_assert(object_path); - nm_assert(inout); - - if (!*inout) { - *inout = _bzobjs_get(self, object_path); - if (!*inout) - *inout = _bzobjs_add(self, object_path); - } - - nm_assert(nm_streq((*inout)->object_path, object_path)); - nm_assert(*inout == _bzobjs_get(self, object_path)); - return *inout; -} - -static gboolean -_bzobjs_adapter_is_usable_for_device(const BzDBusObj *bzobj) -{ - return bzobj->d_has_adapter_iface && bzobj->d_adapter.address && bzobj->d_adapter_powered; -} - -static gboolean -_bzobjs_device_is_usable(const BzDBusObj *bzobj, - BzDBusObj ** out_adapter_bzobj, - gboolean * out_create_panu_connection) -{ - NMBluezManager * self; - NMBluezManagerPrivate *priv; - gboolean usable_dun = FALSE; - gboolean usable_nap = FALSE; - BzDBusObj * bzobj_adapter; - gboolean create_panu_connection = FALSE; - - if (!bzobj->d_has_device_iface - || !NM_FLAGS_ANY((NMBluetoothCapabilities) bzobj->d_device_capabilities, - _NM_BT_CAPABILITY_SUPPORTED) - || !bzobj->d_device.name || !bzobj->d_device.address || !bzobj->d_device_paired - || !bzobj->d_device.adapter) - goto out_unusable; - - self = bzobj->self; - - priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - if (!priv->settings_registered) - goto out_unusable; - - bzobj_adapter = _bzobjs_get(self, bzobj->d_device.adapter); - if (!bzobj_adapter || !_bzobjs_adapter_is_usable_for_device(bzobj_adapter)) - goto out_unusable; - -#if WITH_BLUEZ5_DUN - if (NM_FLAGS_HAS(bzobj->d_device_capabilities, NM_BT_CAPABILITY_DUN)) { - if (_conn_track_find_head(self, NM_BT_CAPABILITY_DUN, bzobj->d_device.address)) - usable_dun = TRUE; - } -#endif - - if (NM_FLAGS_HAS(bzobj->d_device_capabilities, NM_BT_CAPABILITY_NAP)) { - if (!bzobj->d_has_network_iface) - usable_nap = FALSE; - else if (_conn_track_find_head(self, NM_BT_CAPABILITY_NAP, bzobj->d_device.address)) - usable_nap = TRUE; - else if (bzobj->x_device_panu_connection_allow_create) { - /* We didn't yet try to create a connection. Presume we are going to create - * it when the time comes... */ - usable_nap = TRUE; - create_panu_connection = TRUE; - } - } - - if (!usable_dun && !usable_nap) { - if (bzobj->x_device.device_bt - && nm_device_get_state(NM_DEVICE(bzobj->x_device.device_bt)) - > NM_DEVICE_STATE_DISCONNECTED) { - /* The device is still activated... the absence of a profile does not - * render it unusable (yet). But since there is no more profile, the - * device is probably about to disconnect. */ - } else - goto out_unusable; - } - - NM_SET_OUT(out_create_panu_connection, create_panu_connection); - NM_SET_OUT(out_adapter_bzobj, bzobj_adapter); - return TRUE; - -out_unusable: - NM_SET_OUT(out_create_panu_connection, FALSE); - NM_SET_OUT(out_adapter_bzobj, NULL); - return FALSE; -} - -static gboolean -_bzobjs_device_is_connected(const BzDBusObj *bzobj) -{ - nm_assert(_bzobjs_device_is_usable(bzobj, NULL, NULL)); - - if (!bzobj->d_has_device_iface || !bzobj->d_device_connected) - return FALSE; - - if (bzobj->d_has_network_iface && bzobj->d_network_connected) - return TRUE; - if (bzobj->x_device.connect_dun_context) { - /* As long as we have a dun-context, we consider it connected. - * - * We require NMDeviceBt to try to connect to the modem, and if that fails, - * it will disconnect. */ - return TRUE; - } - return FALSE; -} - -static gboolean -_bzobjs_network_server_is_usable(const BzDBusObj *bzobj, gboolean require_powered) -{ - return bzobj->d_has_network_server_iface && bzobj->d_has_adapter_iface - && bzobj->d_adapter.address && (!require_powered || bzobj->d_adapter_powered); -} - -/*****************************************************************************/ - -static ConnDataHead * -_conn_data_head_new(NMBluetoothCapabilities bt_type, const char *bdaddr) -{ - ConnDataHead *cdata_hd; - gsize l; - - nm_assert(NM_IN_SET(bt_type, NM_BT_CAPABILITY_DUN, NM_BT_CAPABILITY_NAP)); - nm_assert(bdaddr); - - l = strlen(bdaddr) + 1; - cdata_hd = g_malloc(sizeof(ConnDataHead) + l); - *cdata_hd = (ConnDataHead){ - .bdaddr = cdata_hd->bdaddr_data, - .lst_head = C_LIST_INIT(cdata_hd->lst_head), - .bt_type = bt_type, - }; - memcpy(cdata_hd->bdaddr_data, bdaddr, l); - - nm_assert(cdata_hd->bt_type == bt_type); - - return cdata_hd; -} - -static guint -_conn_data_head_hash(gconstpointer ptr) -{ - const ConnDataHead *cdata_hd = ptr; - NMHashState h; - - nm_hash_init(&h, 520317467u); - nm_hash_update_val(&h, (NMBluetoothCapabilities) cdata_hd->bt_type); - nm_hash_update_str(&h, cdata_hd->bdaddr); - return nm_hash_complete(&h); -} - -static gboolean -_conn_data_head_equal(gconstpointer a, gconstpointer b) -{ - const ConnDataHead *cdata_hd_a = a; - const ConnDataHead *cdata_hd_b = b; - - return cdata_hd_a->bt_type == cdata_hd_b->bt_type - && nm_streq(cdata_hd_a->bdaddr, cdata_hd_b->bdaddr); -} - -static ConnDataHead * -_conn_track_find_head(NMBluezManager *self, NMBluetoothCapabilities bt_type, const char *bdaddr) -{ - ConnDataHead cdata_hd = { - .bt_type = bt_type, - .bdaddr = bdaddr, - }; - - return g_hash_table_lookup(NM_BLUEZ_MANAGER_GET_PRIVATE(self)->conn_data_heads, &cdata_hd); -} - -static ConnDataElem * -_conn_track_find_elem(NMBluezManager *self, NMSettingsConnection *sett_conn) -{ - G_STATIC_ASSERT(G_STRUCT_OFFSET(ConnDataElem, sett_conn) == 0); - - return g_hash_table_lookup(NM_BLUEZ_MANAGER_GET_PRIVATE(self)->conn_data_elems, &sett_conn); -} - -static gboolean -_conn_track_is_relevant_connection(NMConnection * connection, - NMBluetoothCapabilities *out_bt_type, - const char ** out_bdaddr) -{ - NMSettingBluetooth * s_bt; - NMBluetoothCapabilities bt_type; - const char * bdaddr; - const char * b_type; - - s_bt = nm_connection_get_setting_bluetooth(connection); - if (!s_bt) - return FALSE; - - if (!nm_connection_is_type(connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) - return FALSE; - - bdaddr = nm_setting_bluetooth_get_bdaddr(s_bt); - if (!bdaddr) - return FALSE; - - b_type = nm_setting_bluetooth_get_connection_type(s_bt); - - if (nm_streq(b_type, NM_SETTING_BLUETOOTH_TYPE_DUN)) - bt_type = NM_BT_CAPABILITY_DUN; - else if (nm_streq(b_type, NM_SETTING_BLUETOOTH_TYPE_PANU)) - bt_type = NM_BT_CAPABILITY_NAP; - else - return FALSE; - - NM_SET_OUT(out_bt_type, bt_type); - NM_SET_OUT(out_bdaddr, bdaddr); - return TRUE; -} - -static gboolean -_conn_track_is_relevant_sett_conn(NMSettingsConnection * sett_conn, - NMBluetoothCapabilities *out_bt_type, - const char ** out_bdaddr) -{ - NMConnection *connection; - - connection = nm_settings_connection_get_connection(sett_conn); - if (!connection) - return FALSE; - - return _conn_track_is_relevant_connection(connection, out_bt_type, out_bdaddr); -} - -static gboolean -_conn_track_is_relevant_for_sett_conn(NMSettingsConnection * sett_conn, - NMBluetoothCapabilities bt_type, - const char * bdaddr) -{ - NMBluetoothCapabilities x_bt_type; - const char * x_bdaddr; - - return bdaddr && _conn_track_is_relevant_sett_conn(sett_conn, &x_bt_type, &x_bdaddr) - && x_bt_type == bt_type && nm_streq(x_bdaddr, bdaddr); -} - -static void -_conn_track_schedule_notify(NMBluezManager * self, - NMBluetoothCapabilities bt_type, - const char * bdaddr) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - GHashTableIter iter; - BzDBusObj * bzobj; - - g_hash_table_iter_init(&iter, priv->bzobjs); - while (g_hash_table_iter_next(&iter, (gpointer *) &bzobj, NULL)) { - gboolean device_is_usable; - - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, NULL); - if (bzobj->x_device_is_usable != device_is_usable) - _process_change_idle_schedule(self, bzobj); - } -} - -static void -_conn_track_update(NMBluezManager * self, - NMSettingsConnection *sett_conn, - gboolean track, - gboolean * out_changed, - gboolean * out_changed_usable, - ConnDataElem ** out_conn_data_elem) -{ - NMBluezManagerPrivate * priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - ConnDataHead * cdata_hd; - ConnDataElem * cdata_el; - ConnDataElem * cdata_el_remove = NULL; - NMBluetoothCapabilities bt_type; - const char * bdaddr; - gboolean changed = FALSE; - gboolean changed_usable = FALSE; - char sbuf_cap[100]; - - nm_assert(NM_IS_SETTINGS_CONNECTION(sett_conn)); - - cdata_el = _conn_track_find_elem(self, sett_conn); - - if (track) - track = _conn_track_is_relevant_sett_conn(sett_conn, &bt_type, &bdaddr); - - if (!track) { - cdata_el_remove = g_steal_pointer(&cdata_el); - goto out_remove; - } - - if (cdata_el) { - cdata_hd = cdata_el->cdata_hd; - if (cdata_hd->bt_type != bt_type || !nm_streq(cdata_hd->bdaddr, bdaddr)) - cdata_el_remove = g_steal_pointer(&cdata_el); - } - - if (!cdata_el) { - _LOGT("connection: track for %s, %s: %s (%s)", - nm_bluetooth_capability_to_string(bt_type, sbuf_cap, sizeof(sbuf_cap)), - bdaddr, - nm_settings_connection_get_uuid(sett_conn), - nm_settings_connection_get_id(sett_conn)); - changed = TRUE; - cdata_hd = _conn_track_find_head(self, bt_type, bdaddr); - if (!cdata_hd) { - changed_usable = TRUE; - cdata_hd = _conn_data_head_new(bt_type, bdaddr); - if (!g_hash_table_add(priv->conn_data_heads, cdata_hd)) - nm_assert_not_reached(); - _conn_track_schedule_notify(self, bt_type, bdaddr); - } - cdata_el = g_slice_new(ConnDataElem); - cdata_el->sett_conn = sett_conn; - cdata_el->cdata_hd = cdata_hd; - c_list_link_tail(&cdata_hd->lst_head, &cdata_el->lst); - if (!g_hash_table_add(priv->conn_data_elems, cdata_el)) - nm_assert_not_reached(); - } - -out_remove: - if (cdata_el_remove) { - GHashTableIter iter; - BzDBusObj * bzobj; - - _LOGT("connection: untrack for %s, %s: %s (%s)", - nm_bluetooth_capability_to_string(cdata_el_remove->cdata_hd->bt_type, - sbuf_cap, - sizeof(sbuf_cap)), - cdata_el_remove->cdata_hd->bdaddr, - nm_settings_connection_get_uuid(sett_conn), - nm_settings_connection_get_id(sett_conn)); - - g_hash_table_iter_init(&iter, priv->bzobjs); - while (g_hash_table_iter_next(&iter, (gpointer *) &bzobj, NULL)) { - if (bzobj->x_device.panu_connection == sett_conn) - bzobj->x_device.panu_connection = NULL; - } - - changed = TRUE; - cdata_hd = cdata_el_remove->cdata_hd; - c_list_unlink_stale(&cdata_el_remove->lst); - if (!g_hash_table_remove(priv->conn_data_elems, cdata_el_remove)) - nm_assert_not_reached(); - if (c_list_is_empty(&cdata_hd->lst_head)) { - changed_usable = TRUE; - _conn_track_schedule_notify(self, cdata_hd->bt_type, cdata_hd->bdaddr); - if (!g_hash_table_remove(priv->conn_data_heads, cdata_hd)) - nm_assert_not_reached(); - } - } - - NM_SET_OUT(out_changed, changed); - NM_SET_OUT(out_changed_usable, changed_usable); - NM_SET_OUT(out_conn_data_elem, cdata_el); -} - -/*****************************************************************************/ - -static void -cp_connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, NMBluezManager *self) -{ - _conn_track_update(self, sett_conn, TRUE, NULL, NULL, NULL); -} - -static void -cp_connection_updated(NMSettings * settings, - NMSettingsConnection *sett_conn, - guint update_reason_u, - NMBluezManager * self) -{ - _conn_track_update(self, sett_conn, TRUE, NULL, NULL, NULL); -} - -static void -cp_connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, NMBluezManager *self) -{ - _conn_track_update(self, sett_conn, FALSE, NULL, NULL, NULL); -} - -/*****************************************************************************/ - -static NMBluezManager * -_network_server_get_bluez_manager(const NMBtVTableNetworkServer *vtable_network_server) -{ - NMBluezManager *self; - - self = (NMBluezManager *) (((char *) vtable_network_server) - - G_STRUCT_OFFSET(NMBluezManager, _priv.vtable_network_server)); - - g_return_val_if_fail(NM_IS_BLUEZ_MANAGER(self), NULL); - - return self; -} - -static BzDBusObj * -_network_server_find_has_device(NMBluezManagerPrivate *priv, NMDevice *device) -{ - BzDBusObj *bzobj; - - c_list_for_each_entry (bzobj, &priv->network_server_lst_head, x_network_server.lst) { - if (bzobj->x_network_server.device_br == device) - return bzobj; - } - return NULL; -} - -static BzDBusObj * -_network_server_find_available(NMBluezManagerPrivate *priv, - const char * addr, - NMDevice * device_accept_busy) -{ - BzDBusObj *bzobj; - - c_list_for_each_entry (bzobj, &priv->network_server_lst_head, x_network_server.lst) { - if (bzobj->x_network_server.device_br) { - if (bzobj->x_network_server.device_br != device_accept_busy) - continue; - } - if (addr && !nm_streq(addr, bzobj->d_adapter.address)) - continue; - nm_assert(!bzobj->x_network_server.r_req_data); - return bzobj; - } - return NULL; -} - -static gboolean -_network_server_vt_is_available(const NMBtVTableNetworkServer *vtable, - const char * addr, - NMDevice * device_accept_busy) -{ - NMBluezManager * self = _network_server_get_bluez_manager(vtable); - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - return !!_network_server_find_available(priv, addr, device_accept_busy); -} - -static void -_network_server_register_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - BzDBusObj * bzobj; - - ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source_object), res, &error); - if (!ret && nm_utils_error_is_cancelled(error)) - return; - - bzobj = user_data; - - if (!ret) { - _LOGT("NAP: [%s]: registering failed: %s", bzobj->object_path, error->message); - } else - _LOGT("NAP: [%s]: registration successful", bzobj->object_path); - - g_clear_object(&bzobj->x_network_server.r_req_data->int_cancellable); - _network_server_register_req_data_complete(g_steal_pointer(&bzobj->x_network_server.r_req_data), - error); -} - -static void -_network_server_register_cancelled_cb(GCancellable *cancellable, BzDBusObj *bzobj) -{ - _network_server_unregister_bridge(bzobj->self, bzobj, "registration cancelled"); -} - -static gboolean -_network_server_vt_register_bridge(const NMBtVTableNetworkServer *vtable, - const char * addr, - NMDevice * device, - GCancellable * cancellable, - NMBtVTableRegisterCallback callback, - gpointer callback_user_data, - GError ** error) -{ - NMBluezManager * self = _network_server_get_bluez_manager(vtable); - NMBluezManagerPrivate * priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - NetworkServerRegisterReqData *r_req_data; - BzDBusObj * bzobj; - const char * ifname; - - g_return_val_if_fail(NM_IS_DEVICE(device), FALSE); - g_return_val_if_fail(G_IS_CANCELLABLE(cancellable), FALSE); - - nm_assert(!g_cancellable_is_cancelled(cancellable)); - nm_assert(!_network_server_find_has_device(priv, device)); - - ifname = nm_device_get_iface(device); - g_return_val_if_fail(ifname, FALSE); - - g_return_val_if_fail(ifname, FALSE); - - bzobj = _network_server_find_available(priv, addr, NULL); - if (!bzobj) { - /* The device checked that a network server is available, before - * starting the activation, but for some reason it no longer is. - * Indicate that the activation should not proceed. */ - if (addr) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "adapter %s is not available for %s", - addr, - ifname); - } else { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "no adapter available for %s", - ifname); - } - return FALSE; - } - - _LOGD("NAP: [%s]: registering \"%s\" on adapter %s", - bzobj->object_path, - ifname, - bzobj->d_adapter.address); - - r_req_data = g_slice_new(NetworkServerRegisterReqData); - *r_req_data = (NetworkServerRegisterReqData){ - .int_cancellable = g_cancellable_new(), - .ext_cancellable = g_object_ref(cancellable), - .callback = callback, - .callback_user_data = callback_user_data, - .ext_cancelled_id = g_signal_connect(cancellable, - "cancelled", - G_CALLBACK(_network_server_register_cancelled_cb), - bzobj), - }; - - bzobj->x_network_server.device_br = g_object_ref(device); - bzobj->x_network_server.r_req_data = r_req_data; - - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_NETWORK_SERVER_INTERFACE, - "Register", - g_variant_new("(ss)", BLUETOOTH_CONNECT_NAP, ifname), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - bzobj->x_network_server.r_req_data->int_cancellable, - _network_server_register_cb, - bzobj); - return TRUE; -} - -static void -_network_server_unregister_bridge_complete_on_idle_cb(gpointer user_data, GCancellable *cancellable) -{ - gs_free_error GError * error = NULL; - gs_free char * reason = NULL; - NetworkServerRegisterReqData *r_req_data; - - nm_utils_user_data_unpack(user_data, &r_req_data, &reason); - - nm_utils_error_set(&error, - NM_UTILS_ERROR_UNKNOWN, - "registration was aborted due to %s", - reason); - _network_server_register_req_data_complete(r_req_data, error); -} - -static void -_network_server_unregister_bridge(NMBluezManager *self, BzDBusObj *bzobj, const char *reason) -{ - NMBluezManagerPrivate * priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - _nm_unused gs_unref_object NMDevice *device = NULL; - NetworkServerRegisterReqData * r_req_data; - - nm_assert(NM_IS_DEVICE(bzobj->x_network_server.device_br)); - - _LOGD("NAP: [%s]: unregistering \"%s\" (%s)", - bzobj->object_path, - nm_device_get_iface(bzobj->x_network_server.device_br), - reason); - - device = g_steal_pointer(&bzobj->x_network_server.device_br); - - r_req_data = g_steal_pointer(&bzobj->x_network_server.r_req_data); - - if (priv->name_owner) { - gs_unref_object GCancellable *cancellable = NULL; - - cancellable = g_cancellable_new(); - - nm_shutdown_wait_obj_register_cancellable_full( - cancellable, - g_strdup_printf("bt-unregister-nap[%s]", bzobj->object_path), - TRUE); - - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_NETWORK_SERVER_INTERFACE, - "Unregister", - g_variant_new("(s)", BLUETOOTH_CONNECT_NAP), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - cancellable, - _dbus_call_complete_cb_nop, - NULL); - } - - if (r_req_data) { - nm_clear_g_cancellable(&r_req_data->int_cancellable); - nm_utils_invoke_on_idle(r_req_data->ext_cancellable, - _network_server_unregister_bridge_complete_on_idle_cb, - nm_utils_user_data_pack(r_req_data, g_strdup(reason))); - } - - _nm_device_bridge_notify_unregister_bt_nap(device, reason); -} - -static gboolean -_network_server_vt_unregister_bridge(const NMBtVTableNetworkServer *vtable, NMDevice *device) -{ - NMBluezManager * self = _network_server_get_bluez_manager(vtable); - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - BzDBusObj * bzobj; - - g_return_val_if_fail(NM_IS_DEVICE(device), FALSE); - - bzobj = _network_server_find_has_device(priv, device); - if (bzobj) - _network_server_unregister_bridge(self, bzobj, "disconnecting"); - - return TRUE; -} - -static void -_network_server_process_change(BzDBusObj *bzobj, gboolean *out_emit_device_availability_changed) -{ - NMBluezManager * self = bzobj->self; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gboolean network_server_is_usable; - gboolean emit_device_availability_changed = FALSE; - - network_server_is_usable = _bzobjs_network_server_is_usable(bzobj, TRUE); - - if (!network_server_is_usable) { - if (!c_list_is_empty(&bzobj->x_network_server.lst)) { - emit_device_availability_changed = TRUE; - c_list_unlink(&bzobj->x_network_server.lst); - } - - nm_clear_g_free(&bzobj->x_network_server.adapter_address); - - if (bzobj->x_network_server.device_br) { - _network_server_unregister_bridge(self, - bzobj, - _bzobjs_network_server_is_usable(bzobj, FALSE) - ? "adapter disabled" - : "adapter disappeared"); - } - - } else { - if (!nm_streq0(bzobj->x_network_server.adapter_address, bzobj->d_adapter.address)) { - emit_device_availability_changed = TRUE; - g_free(bzobj->x_network_server.adapter_address); - bzobj->x_network_server.adapter_address = g_strdup(bzobj->d_adapter.address); - } - - if (c_list_is_empty(&bzobj->x_network_server.lst)) { - emit_device_availability_changed = TRUE; - c_list_link_tail(&priv->network_server_lst_head, &bzobj->x_network_server.lst); - } - } - - if (emit_device_availability_changed) - NM_SET_OUT(out_emit_device_availability_changed, TRUE); -} - -/*****************************************************************************/ - -static void -_conn_create_panu_connection(NMBluezManager *self, BzDBusObj *bzobj) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gs_unref_object NMConnection *connection = NULL; - NMSettingsConnection * added; - NMSetting * setting; - gs_free char * id = NULL; - char uuid[37]; - gs_free_error GError *error = NULL; - - nm_utils_uuid_generate_buf(uuid); - id = g_strdup_printf(_("%s Network"), bzobj->d_device.name); - - connection = nm_simple_connection_new(); - - 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 = nm_setting_bluetooth_new(); - g_object_set(setting, - NM_SETTING_BLUETOOTH_BDADDR, - bzobj->d_device.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("connection: couldn't generate a connection for NAP device: %s", error->message); - g_return_if_reached(); - } - - nm_assert(_conn_track_is_relevant_connection(connection, NULL, NULL)); - - _LOGT("connection: create in-memory PANU connection %s (%s) for device \"%s\" (%s)", - uuid, - id, - bzobj->d_device.name, - bzobj->d_device.address); - - 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); - if (!added) { - _LOGW("connection: couldn't add new Bluetooth connection for NAP device: '%s' (%s): %s", - id, - uuid, - error->message); - return; - } - - if (!_conn_track_is_relevant_for_sett_conn(added, NM_BT_CAPABILITY_NAP, bzobj->d_device.address) - || !_conn_track_find_elem(self, added) || bzobj->x_device.panu_connection) { - _LOGE("connection: something went wrong creating PANU connection %s (%s) for device '%s'", - uuid, - id, - bzobj->d_device.address); - g_return_if_reached(); - } - - bzobj->x_device.panu_connection = added; -} - -/*****************************************************************************/ - -static void -_device_state_changed_cb(NMDevice *device, - guint new_state_u, - guint old_state_u, - guint reason_u, - gpointer user_data) -{ - BzDBusObj *bzobj = user_data; - - if (!_bzobjs_device_is_usable(bzobj, NULL, NULL)) { - /* the device got unusable? Need to revisit it... */ - _process_change_idle_schedule(bzobj->self, bzobj); - } -} - -static void -_device_process_change(BzDBusObj *bzobj) -{ - NMBluezManager *self = bzobj->self; - gs_unref_object NMDeviceBt *device_added = NULL; - gs_unref_object NMDeviceBt *device_deleted = NULL; - gboolean device_is_usable; - gboolean create_panu_connection = FALSE; - - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, &create_panu_connection); - - if (create_panu_connection) { - bzobj->x_device_panu_connection_allow_create = FALSE; - _conn_create_panu_connection(self, bzobj); - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, NULL); - } else { - if (device_is_usable && bzobj->x_device_panu_connection_allow_create - && NM_FLAGS_HAS(bzobj->d_device_capabilities, NM_BT_CAPABILITY_NAP) - && _conn_track_find_head(self, NM_BT_CAPABILITY_NAP, bzobj->d_device.address)) { - /* We have a useable device and also a panu-connection. We block future attemps - * to generate a connection. */ - bzobj->x_device_panu_connection_allow_create = FALSE; - } - if (bzobj->x_device.panu_connection) { - if (!NM_FLAGS_HAS(nm_settings_connection_get_flags(bzobj->x_device.panu_connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) { - /* the connection that we generated earlier still exists, but it's not longer the same - * as it was when we created it. Forget about it, so that we don't delete the profile later... */ - bzobj->x_device.panu_connection = NULL; - } else { - if (!device_is_usable - || !_conn_track_is_relevant_for_sett_conn(bzobj->x_device.panu_connection, - NM_BT_CAPABILITY_NAP, - bzobj->d_device.address)) { - _LOGT("connection: delete in-memory PANU connection %s (%s) as device %s", - nm_settings_connection_get_uuid(bzobj->x_device.panu_connection), - nm_settings_connection_get_id(bzobj->x_device.panu_connection), - !device_is_usable ? "is now unusable" : "no longer matches"); - bzobj->x_device_panu_connection_allow_create = TRUE; - nm_settings_connection_delete(g_steal_pointer(&bzobj->x_device.panu_connection), - FALSE); - } - } - } - } - - bzobj->x_device_is_connected = device_is_usable && _bzobjs_device_is_connected(bzobj); - - bzobj->x_device_is_usable = device_is_usable; - - if (bzobj->x_device.device_bt) { - const char *device_to_delete_msg; - - if (!device_is_usable) - device_to_delete_msg = "device became unusable"; - else if (!_nm_device_bt_for_same_device(bzobj->x_device.device_bt, - bzobj->object_path, - bzobj->d_device.address, - NULL, - bzobj->d_device_capabilities)) - device_to_delete_msg = "device is no longer compatible"; - else - device_to_delete_msg = NULL; - - if (device_to_delete_msg) { - nm_clear_g_signal_handler(bzobj->x_device.device_bt, - &bzobj->x_device.device_bt_signal_id); - - device_deleted = g_steal_pointer(&bzobj->x_device.device_bt); - - _LOGD("[%s]: drop device because %s", bzobj->object_path, device_to_delete_msg); - - _connect_disconnect(self, bzobj, device_to_delete_msg); - } - } - - if (device_is_usable) { - if (!bzobj->x_device.device_bt) { - bzobj->x_device.device_bt = nm_device_bt_new(self, - bzobj->object_path, - bzobj->d_device.address, - bzobj->d_device.name, - bzobj->d_device_capabilities); - device_added = g_object_ref(bzobj->x_device.device_bt); - bzobj->x_device.device_bt_signal_id = - g_signal_connect(device_added, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(_device_state_changed_cb), - bzobj); - } else - _nm_device_bt_notify_set_name(bzobj->x_device.device_bt, bzobj->d_device.name); - - _nm_device_bt_notify_set_connected(bzobj->x_device.device_bt, bzobj->x_device_is_connected); - } - - if (bzobj->x_device.c_req_data && !bzobj->x_device.c_req_data->int_cancellable - && bzobj->x_device_is_connected) { - gs_free char *device_name = g_steal_pointer(&bzobj->x_device.c_req_data->device_name); - - _device_connect_req_data_complete(g_steal_pointer(&bzobj->x_device.c_req_data), - self, - device_name, - NULL); - } - - if (device_added) - g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, device_added); - - if (device_deleted) - _nm_device_bt_notify_removed(device_deleted); -} - -/*****************************************************************************/ - -static void -_process_change_idle_all(NMBluezManager *self, gboolean *out_emit_device_availability_changed) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - BzDBusObj * bzobj; - - while ( - (bzobj = - c_list_first_entry(&priv->process_change_lst_head, BzDBusObj, process_change_lst))) { - c_list_unlink(&bzobj->process_change_lst); - - _LOG_bzobj(bzobj, "before-processing"); - - _device_process_change(bzobj); - - _network_server_process_change(bzobj, out_emit_device_availability_changed); - - _LOG_bzobj(bzobj, "after-processing"); - - _bzobjs_del_if_dead(bzobj); - } - - nm_clear_g_source(&priv->process_change_idle_id); -} - -static gboolean -_process_change_idle_cb(gpointer user_data) -{ - NMBluezManager * self = user_data; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gboolean emit_device_availability_changed = FALSE; - - _process_change_idle_all(self, &emit_device_availability_changed); - - if (emit_device_availability_changed) - nm_manager_notify_device_availability_maybe_changed(priv->manager); - - return G_SOURCE_CONTINUE; -} - -static void -_process_change_idle_schedule(NMBluezManager *self, BzDBusObj *bzobj) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - nm_c_list_move_tail(&priv->process_change_lst_head, &bzobj->process_change_lst); - if (priv->process_change_idle_id == 0) - priv->process_change_idle_id = - g_idle_add_full(G_PRIORITY_DEFAULT_IDLE + 1, _process_change_idle_cb, self, NULL); -} - -static void -_dbus_process_changes(NMBluezManager *self, BzDBusObj *bzobj, const char *log_reason) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gboolean network_server_is_usable; - gboolean adapter_is_usable_for_device; - gboolean device_is_usable; - gboolean changes = FALSE; - gboolean recheck_devices_for_adapter = FALSE; - - nm_assert(bzobj); - - _LOG_bzobj(bzobj, log_reason); - - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, NULL); - - if (bzobj->x_device_is_usable != device_is_usable) - changes = TRUE; - else if (bzobj->x_device.device_bt) { - if (!device_is_usable) - changes = TRUE; - else { - if (bzobj->x_device_is_connected != _bzobjs_device_is_connected(bzobj) - || !_nm_device_bt_for_same_device(bzobj->x_device.device_bt, - bzobj->object_path, - bzobj->d_device.address, - bzobj->d_device.name, - bzobj->d_device_capabilities)) - changes = TRUE; - } - } - - adapter_is_usable_for_device = _bzobjs_adapter_is_usable_for_device(bzobj); - if (adapter_is_usable_for_device != bzobj->was_usable_adapter_for_device_before) { - /* this function does not modify bzobj in any other cases except here. - * Usually changes are processed delayed, in the idle handler. - * - * But the bzobj->was_usable_adapter_for_device_before only exists to know whether - * we need to re-check device availability. It is correct to set the flag - * here, right before we checked. */ - bzobj->was_usable_adapter_for_device_before = adapter_is_usable_for_device; - recheck_devices_for_adapter = TRUE; - changes = TRUE; - } - - if (!changes) { - network_server_is_usable = _bzobjs_network_server_is_usable(bzobj, TRUE); - - if (network_server_is_usable != (!c_list_is_empty(&bzobj->x_network_server.lst))) - changes = TRUE; - else if (bzobj->x_network_server.device_br && !network_server_is_usable) - changes = TRUE; - else if (!nm_streq0(bzobj->d_has_adapter_iface ? bzobj->d_adapter.address : NULL, - bzobj->x_network_server.adapter_address)) - changes = TRUE; - } - - if (changes) - _process_change_idle_schedule(self, bzobj); - - if (recheck_devices_for_adapter) { - GHashTableIter iter; - BzDBusObj * bzobj2; - - /* we got a change to the availability of an adapter. We might need to recheck - * all devices that use this adapter... */ - g_hash_table_iter_init(&iter, priv->bzobjs); - while (g_hash_table_iter_next(&iter, (gpointer *) &bzobj2, NULL)) { - if (bzobj2 == bzobj) - continue; - if (!nm_streq0(bzobj2->d_device.adapter, bzobj->object_path)) - continue; - if (c_list_is_empty(&bzobj2->process_change_lst)) - _dbus_process_changes(self, bzobj2, "adapter-changed"); - else - nm_c_list_move_tail(&priv->process_change_lst_head, &bzobj2->process_change_lst); - } - } - - _bzobjs_del_if_dead(bzobj); -} - -/*****************************************************************************/ - -#define ALL_RELEVANT_INTERFACE_NAMES \ - NM_MAKE_STRV(NM_BLUEZ5_ADAPTER_INTERFACE, \ - NM_BLUEZ5_DEVICE_INTERFACE, \ - NM_BLUEZ5_NETWORK_INTERFACE, \ - NM_BLUEZ5_NETWORK_SERVER_INTERFACE) - -static gboolean -_dbus_handle_properties_changed(NMBluezManager * self, - const char * object_path, - const char * interface_name, - GVariant * changed_properties, - const char *const *invalidated_properties, - BzDBusObj ** inout_bzobj) -{ - BzDBusObj * bzobj = NULL; - gboolean changed = FALSE; - const char * property_name; - GVariant * property_value; - GVariantIter iter_prop; - gsize i; - - if (!invalidated_properties) - invalidated_properties = NM_PTRARRAY_EMPTY(const char *); - - nm_assert(g_variant_is_of_type(changed_properties, G_VARIANT_TYPE("a{sv}"))); - - if (inout_bzobj) { - bzobj = *inout_bzobj; - nm_assert(!bzobj || nm_streq(object_path, bzobj->object_path)); - } - - if (changed_properties) - g_variant_iter_init(&iter_prop, changed_properties); - - if (nm_streq(interface_name, NM_BLUEZ5_ADAPTER_INTERFACE)) { - _bzobjs_init(self, &bzobj, object_path); - if (!bzobj->d_has_adapter_iface) { - changed = TRUE; - bzobj->d_has_adapter_iface = TRUE; - } - - while (changed_properties - && g_variant_iter_next(&iter_prop, "{&sv}", &property_name, &property_value)) { - _nm_unused gs_unref_variant GVariant *property_value_free = property_value; - - if (nm_streq(property_name, "Address")) { - gs_free char *s = - g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING) - ? nm_utils_hwaddr_canonical(g_variant_get_string(property_value, NULL), - ETH_ALEN) - : NULL; - - if (!nm_streq0(bzobj->d_adapter.address, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_adapter.address); - bzobj->d_adapter.address = g_steal_pointer(&s); - } - continue; - } - if (nm_streq(property_name, "Powered")) { - bool v = g_variant_is_of_type(property_value, G_VARIANT_TYPE_BOOLEAN) - && g_variant_get_boolean(property_value); - - if (bzobj->d_adapter_powered != v) { - changed = TRUE; - bzobj->d_adapter_powered = v; - } - continue; - } - } - - for (i = 0; (property_name = invalidated_properties[i]); i++) { - if (nm_streq(property_name, "Address")) { - if (bzobj->d_adapter.address) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_adapter.address); - } - continue; - } - if (nm_streq(property_name, "Powered")) { - if (bzobj->d_adapter_powered) { - changed = TRUE; - bzobj->d_adapter_powered = FALSE; - } - continue; - } - } - - } else if (nm_streq(interface_name, NM_BLUEZ5_DEVICE_INTERFACE)) { - _bzobjs_init(self, &bzobj, object_path); - if (!bzobj->d_has_device_iface) { - changed = TRUE; - bzobj->d_has_device_iface = TRUE; - } - - while (changed_properties - && g_variant_iter_next(&iter_prop, "{&sv}", &property_name, &property_value)) { - _nm_unused gs_unref_variant GVariant *property_value_free = property_value; - - if (nm_streq(property_name, "Address")) { - gs_free char *s = - g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING) - ? nm_utils_hwaddr_canonical(g_variant_get_string(property_value, NULL), - ETH_ALEN) - : NULL; - - if (!nm_streq0(bzobj->d_device.address, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.address); - bzobj->d_device.address = g_steal_pointer(&s); - } - continue; - } - if (nm_streq(property_name, "Name")) { - const char *s = g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING) - ? g_variant_get_string(property_value, NULL) - : NULL; - - if (!nm_streq0(bzobj->d_device.name, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.name); - bzobj->d_device.name = g_strdup(s); - } - continue; - } - if (nm_streq(property_name, "Adapter")) { - const char *s = g_variant_is_of_type(property_value, G_VARIANT_TYPE_OBJECT_PATH) - ? g_variant_get_string(property_value, NULL) - : NULL; - - if (!nm_streq0(bzobj->d_device.adapter, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.adapter); - bzobj->d_device.adapter = g_strdup(s); - } - continue; - } - if (nm_streq(property_name, "UUIDs")) { - NMBluetoothCapabilities capabilities = NM_BT_CAPABILITY_NONE; - - if (g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING_ARRAY)) { - gs_free const char **s = g_variant_get_strv(property_value, NULL); - - capabilities = convert_uuids_to_capabilities(s); - } - if (bzobj->d_device_capabilities != capabilities) { - changed = TRUE; - bzobj->d_device_capabilities = capabilities; - nm_assert(bzobj->d_device_capabilities == capabilities); - } - continue; - } - if (nm_streq(property_name, "Connected")) { - bool v = g_variant_is_of_type(property_value, G_VARIANT_TYPE_BOOLEAN) - && g_variant_get_boolean(property_value); - - if (bzobj->d_device_connected != v) { - changed = TRUE; - bzobj->d_device_connected = v; - } - continue; - } - if (nm_streq(property_name, "Paired")) { - bool v = g_variant_is_of_type(property_value, G_VARIANT_TYPE_BOOLEAN) - && g_variant_get_boolean(property_value); - - if (bzobj->d_device_paired != v) { - changed = TRUE; - bzobj->d_device_paired = v; - } - continue; - } - } - - for (i = 0; (property_name = invalidated_properties[i]); i++) { - if (nm_streq(property_name, "Address")) { - if (bzobj->d_device.address) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.address); - } - continue; - } - if (nm_streq(property_name, "Name")) { - if (bzobj->d_device.name) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.name); - } - continue; - } - if (nm_streq(property_name, "Adapter")) { - if (bzobj->d_device.adapter) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.adapter); - } - continue; - } - if (nm_streq(property_name, "UUIDs")) { - if (bzobj->d_device_capabilities != NM_BT_CAPABILITY_NONE) { - changed = TRUE; - bzobj->d_device_capabilities = NM_BT_CAPABILITY_NONE; - } - continue; - } - if (nm_streq(property_name, "Connected")) { - if (bzobj->d_device_connected) { - changed = TRUE; - bzobj->d_device_connected = FALSE; - } - continue; - } - if (nm_streq(property_name, "Paired")) { - if (bzobj->d_device_paired) { - changed = TRUE; - bzobj->d_device_paired = FALSE; - } - continue; - } - } - - } else if (nm_streq(interface_name, NM_BLUEZ5_NETWORK_INTERFACE)) { - _bzobjs_init(self, &bzobj, object_path); - if (!bzobj->d_has_network_iface) { - changed = TRUE; - bzobj->d_has_network_iface = TRUE; - } - - while (changed_properties - && g_variant_iter_next(&iter_prop, "{&sv}", &property_name, &property_value)) { - _nm_unused gs_unref_variant GVariant *property_value_free = property_value; - - if (nm_streq(property_name, "Interface")) { - const char *s = g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING) - ? g_variant_get_string(property_value, NULL) - : NULL; - - if (!nm_streq0(bzobj->d_network.interface, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_network.interface); - bzobj->d_network.interface = g_strdup(s); - } - continue; - } - if (nm_streq(property_name, "Connected")) { - bool v = g_variant_is_of_type(property_value, G_VARIANT_TYPE_BOOLEAN) - && g_variant_get_boolean(property_value); - - if (bzobj->d_network_connected != v) { - changed = TRUE; - bzobj->d_network_connected = v; - } - continue; - } - } - - for (i = 0; (property_name = invalidated_properties[i]); i++) { - if (nm_streq(property_name, "Interface")) { - if (bzobj->d_network.interface) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_network.interface); - } - continue; - } - if (nm_streq(property_name, "Connected")) { - if (bzobj->d_network_connected) { - changed = TRUE; - bzobj->d_network_connected = FALSE; - } - continue; - } - } - - } else if (nm_streq(interface_name, NM_BLUEZ5_NETWORK_SERVER_INTERFACE)) { - _bzobjs_init(self, &bzobj, object_path); - if (!bzobj->d_has_network_server_iface) { - changed = TRUE; - bzobj->d_has_network_server_iface = TRUE; - } - } - - nm_assert(!changed || bzobj); - - if (inout_bzobj) - *inout_bzobj = bzobj; - - return changed; -} - -static void -_dbus_handle_interface_added(NMBluezManager *self, - const char * object_path, - GVariant * ifaces, - gboolean initial_get_managed_objects) -{ - BzDBusObj * bzobj = NULL; - gboolean changed = FALSE; - const char * interface_name; - GVariant * changed_properties; - GVariantIter iter_ifaces; - - nm_assert(g_variant_is_of_type(ifaces, G_VARIANT_TYPE("a{sa{sv}}"))); - - g_variant_iter_init(&iter_ifaces, ifaces); - while (g_variant_iter_next(&iter_ifaces, "{&s@a{sv}}", &interface_name, &changed_properties)) { - _nm_unused gs_unref_variant GVariant *changed_properties_free = changed_properties; - - if (_dbus_handle_properties_changed(self, - object_path, - interface_name, - changed_properties, - NULL, - &bzobj)) - changed = TRUE; - } - - if (changed) { - _dbus_process_changes(self, - bzobj, - initial_get_managed_objects ? "dbus-init" : "dbus-iface-added"); - } -} - -static gboolean -_dbus_handle_interface_removed(NMBluezManager * self, - const char * object_path, - BzDBusObj ** inout_bzobj, - const char *const *removed_interfaces) -{ - gboolean changed = FALSE; - BzDBusObj *bzobj; - gsize i; - - if (inout_bzobj && *inout_bzobj) { - bzobj = *inout_bzobj; - nm_assert(bzobj == _bzobjs_get(self, object_path)); - } else { - bzobj = _bzobjs_get(self, object_path); - if (!bzobj) - return FALSE; - NM_SET_OUT(inout_bzobj, bzobj); - } - - for (i = 0; removed_interfaces[i]; i++) { - const char *interface_name = removed_interfaces[i]; - - if (nm_streq(interface_name, NM_BLUEZ5_ADAPTER_INTERFACE)) { - if (bzobj->d_has_adapter_iface) { - changed = TRUE; - bzobj->d_has_adapter_iface = FALSE; - } - if (bzobj->d_adapter.address) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_adapter.address); - } - if (bzobj->d_adapter_powered) { - changed = TRUE; - bzobj->d_adapter_powered = FALSE; - } - } else if (nm_streq(interface_name, NM_BLUEZ5_DEVICE_INTERFACE)) { - if (bzobj->d_has_device_iface) { - changed = TRUE; - bzobj->d_has_device_iface = FALSE; - } - if (bzobj->d_device.address) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.address); - } - if (bzobj->d_device.name) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.name); - } - if (bzobj->d_device.adapter) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.adapter); - } - if (bzobj->d_device_capabilities != NM_BT_CAPABILITY_NONE) { - changed = TRUE; - bzobj->d_device_capabilities = NM_BT_CAPABILITY_NONE; - } - if (bzobj->d_device_connected) { - changed = TRUE; - bzobj->d_device_connected = FALSE; - } - if (bzobj->d_device_paired) { - changed = TRUE; - bzobj->d_device_paired = FALSE; - } - } else if (nm_streq(interface_name, NM_BLUEZ5_NETWORK_INTERFACE)) { - if (bzobj->d_has_network_iface) { - changed = TRUE; - bzobj->d_has_network_iface = FALSE; - } - if (bzobj->d_network.interface) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_network.interface); - } - if (bzobj->d_network_connected) { - changed = TRUE; - bzobj->d_network_connected = FALSE; - } - } else if (nm_streq(interface_name, NM_BLUEZ5_NETWORK_SERVER_INTERFACE)) { - if (bzobj->d_has_network_server_iface) { - changed = TRUE; - bzobj->d_has_network_server_iface = FALSE; - } - } - } - - return changed; -} - -static void -_dbus_managed_objects_changed_cb(GDBusConnection *connection, - const char * sender_name, - const char * arg_object_path, - const char * interface_name, - const char * signal_name, - GVariant * parameters, - gpointer user_data) -{ - NMBluezManager * self = user_data; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - BzDBusObj * bzobj = NULL; - gboolean changed; - - nm_assert(nm_streq0(interface_name, DBUS_INTERFACE_OBJECT_MANAGER)); - - if (priv->get_managed_objects_cancellable) { - /* we still wait for the initial GetManagedObjects(). Ignore the event. */ - return; - } - - if (nm_streq(signal_name, "InterfacesAdded")) { - gs_unref_variant GVariant *interfaces_and_properties = NULL; - const char * object_path; - - if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(oa{sa{sv}})"))) - return; - - g_variant_get(parameters, "(&o@a{sa{sv}})", &object_path, &interfaces_and_properties); - - _dbus_handle_interface_added(self, object_path, interfaces_and_properties, FALSE); - return; - } - - if (nm_streq(signal_name, "InterfacesRemoved")) { - gs_free const char **interfaces = NULL; - const char * object_path; - - if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(oas)"))) - return; - - g_variant_get(parameters, "(&o^a&s)", &object_path, &interfaces); - - changed = _dbus_handle_interface_removed(self, object_path, &bzobj, interfaces); - if (changed) - _dbus_process_changes(self, bzobj, "dbus-iface-removed"); - return; - } -} - -static void -_dbus_properties_changed_cb(GDBusConnection *connection, - const char * sender_name, - const char * object_path, - const char * signal_interface_name, - const char * signal_name, - GVariant * parameters, - gpointer user_data) -{ - NMBluezManager * self = user_data; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - const char * interface_name; - gs_unref_variant GVariant *changed_properties = NULL; - gs_free const char ** invalidated_properties = NULL; - BzDBusObj * bzobj = NULL; - - if (priv->get_managed_objects_cancellable) { - /* we still wait for the initial GetManagedObjects(). Ignore the event. */ - return; - } - - if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sa{sv}as)"))) - return; - - g_variant_get(parameters, - "(&s@a{sv}^a&s)", - &interface_name, - &changed_properties, - &invalidated_properties); - - if (_dbus_handle_properties_changed(self, - object_path, - interface_name, - changed_properties, - invalidated_properties, - &bzobj)) - _dbus_process_changes(self, bzobj, "dbus-property-changed"); -} - -static void -_dbus_get_managed_objects_cb(GVariant *result, GError *error, gpointer user_data) -{ - NMBluezManager * self; - NMBluezManagerPrivate *priv; - GVariantIter iter; - const char * object_path; - GVariant * ifaces; - - if (!result && nm_utils_error_is_cancelled(error)) - return; - - self = user_data; - priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->get_managed_objects_cancellable); - - if (!result) { - _LOGT("initial GetManagedObjects() call failed: %s", error->message); - _cleanup_for_name_owner(self); - return; - } - - _LOGT("initial GetManagedObjects call succeeded"); - - g_variant_iter_init(&iter, result); - while (g_variant_iter_next(&iter, "{&o@a{sa{sv}}}", &object_path, &ifaces)) { - _nm_unused gs_unref_variant GVariant *ifaces_free = ifaces; - - _dbus_handle_interface_added(self, object_path, ifaces, TRUE); - } -} - -/*****************************************************************************/ - -static void -_cleanup_for_name_owner(NMBluezManager *self) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gboolean emit_device_availability_changed = FALSE; - GHashTableIter iter; - BzDBusObj * bzobj; - gboolean first = TRUE; - - nm_clear_g_cancellable(&priv->get_managed_objects_cancellable); - - nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->managed_objects_changed_id); - nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->properties_changed_id); - - nm_clear_g_free(&priv->name_owner); - - g_hash_table_iter_init(&iter, priv->bzobjs); - while (g_hash_table_iter_next(&iter, (gpointer *) &bzobj, NULL)) { - if (first) { - first = FALSE; - _LOGT("drop all objects form D-Bus cache..."); - } - _dbus_handle_interface_removed(self, - bzobj->object_path, - &bzobj, - ALL_RELEVANT_INTERFACE_NAMES); - nm_c_list_move_tail(&priv->process_change_lst_head, &bzobj->process_change_lst); - } - _process_change_idle_all(self, &emit_device_availability_changed); - nm_assert(g_hash_table_size(priv->bzobjs) == 0); - - if (emit_device_availability_changed) - nm_manager_notify_device_availability_maybe_changed(priv->manager); -} - -static void -name_owner_changed(NMBluezManager *self, const char *owner) -{ - _nm_unused gs_unref_object NMBluezManager *self_keep_alive = g_object_ref(self); - NMBluezManagerPrivate * priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - owner = nm_str_not_empty(owner); - - if (!owner) - _LOGT("D-Bus name for bluez has no owner"); - else - _LOGT("D-Bus name for bluez has owner %s", owner); - - nm_clear_g_cancellable(&priv->name_owner_get_cancellable); - - if (nm_streq0(priv->name_owner, owner)) - return; - - _cleanup_for_name_owner(self); - - if (!owner) - return; - - priv->name_owner = g_strdup(owner); - - priv->get_managed_objects_cancellable = g_cancellable_new(); - - priv->managed_objects_changed_id = - nm_dbus_connection_signal_subscribe_object_manager(priv->dbus_connection, - priv->name_owner, - NM_BLUEZ_MANAGER_PATH, - NULL, - _dbus_managed_objects_changed_cb, - self, - NULL); - - priv->properties_changed_id = - nm_dbus_connection_signal_subscribe_properties_changed(priv->dbus_connection, - priv->name_owner, - NULL, - NULL, - _dbus_properties_changed_cb, - self, - NULL); - - nm_dbus_connection_call_get_managed_objects(priv->dbus_connection, - priv->name_owner, - NM_BLUEZ_MANAGER_PATH, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - 20000, - priv->get_managed_objects_cancellable, - _dbus_get_managed_objects_cb, - self); -} - -static void -name_owner_changed_cb(GDBusConnection *connection, - const char * sender_name, - const char * object_path, - const char * interface_name, - const char * signal_name, - GVariant * parameters, - gpointer user_data) -{ - NMBluezManager *self = user_data; - const char * new_owner; - - if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) - return; - - g_variant_get(parameters, "(&s&s&s)", NULL, NULL, &new_owner); - - name_owner_changed(self, new_owner); -} - -static void -name_owner_get_cb(const char *name_owner, GError *error, gpointer user_data) -{ - if (name_owner || !g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - name_owner_changed(user_data, name_owner); -} - -/*****************************************************************************/ - -static void -_cleanup_all(NMBluezManager *self) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - priv->settings_registered = FALSE; - - g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_added, self); - g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_updated, self); - g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_removed, self); - - g_hash_table_remove_all(priv->conn_data_elems); - g_hash_table_remove_all(priv->conn_data_heads); - - _cleanup_for_name_owner(self); - - nm_clear_g_cancellable(&priv->name_owner_get_cancellable); - - nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id); -} - -static void -start(NMDeviceFactory *factory) -{ - NMBluezManager * self; - NMBluezManagerPrivate * priv; - NMSettingsConnection *const *sett_conns; - guint n_sett_conns; - guint i; - - g_return_if_fail(NM_IS_BLUEZ_MANAGER(factory)); - - self = NM_BLUEZ_MANAGER(factory); - priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - _cleanup_all(self); - - if (!priv->dbus_connection) { - _LOGI("no D-Bus connection available"); - return; - } - - 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_UPDATED, - G_CALLBACK(cp_connection_updated), - self); - g_signal_connect(priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, - G_CALLBACK(cp_connection_removed), - self); - - priv->settings_registered = TRUE; - - sett_conns = nm_settings_get_connections(priv->settings, &n_sett_conns); - for (i = 0; i < n_sett_conns; i++) - _conn_track_update(self, sett_conns[i], TRUE, NULL, NULL, NULL); - - priv->name_owner_changed_id = - nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection, - NM_BLUEZ_SERVICE, - name_owner_changed_cb, - self, - NULL); - - priv->name_owner_get_cancellable = g_cancellable_new(); - - nm_dbus_connection_call_get_name_owner(priv->dbus_connection, - NM_BLUEZ_SERVICE, - 10000, - priv->name_owner_get_cancellable, - name_owner_get_cb, - self); -} - -/*****************************************************************************/ - -static void -_connect_returned(NMBluezManager * self, - BzDBusObj * bzobj, - NMBluetoothCapabilities bt_type, - const char * device_name, - NMBluez5DunContext * dun_context, - GError * error) -{ - char sbuf_cap[100]; - - if (error) { - nm_assert(!device_name); - nm_assert(!dun_context); - - _LOGI("%s [%s]: connect failed: %s", - nm_bluetooth_capability_to_string(bzobj->x_device_connect_bt_type, - sbuf_cap, - sizeof(sbuf_cap)), - bzobj->object_path, - error->message); - - _device_connect_req_data_complete(g_steal_pointer(&bzobj->x_device.c_req_data), - self, - NULL, - error); - _connect_disconnect(self, bzobj, "cleanup after connect failure"); - return; - } - - nm_assert(bzobj->x_device_connect_bt_type == bt_type); - nm_assert(device_name); - nm_assert((bt_type == NM_BT_CAPABILITY_DUN) == (!!dun_context)); - nm_assert(bzobj->x_device.c_req_data); - - g_clear_object(&bzobj->x_device.c_req_data->int_cancellable); - - bzobj->x_device.connect_dun_context = dun_context; - - _LOGD("%s [%s]: connect successful to device %s", - nm_bluetooth_capability_to_string(bzobj->x_device_connect_bt_type, - sbuf_cap, - sizeof(sbuf_cap)), - bzobj->object_path, - device_name); - - /* we already have another over-all timer running. But after we connected the device, - * we still need to wait for bluez to acknowledge the connected state (via D-Bus, for NAP). - * For DUN profiles we likely are already fully connected by now. - * - * Anyway, schedule another timeout that is possibly shorter than the overall, original - * timeout. Now this should go down fast. */ - bzobj->x_device.c_req_data->timeout_wait_connect_id = - g_timeout_add(5000, _connect_timeout_wait_connected_cb, bzobj), - bzobj->x_device.c_req_data->device_name = g_strdup(device_name); - - if (_bzobjs_device_is_usable(bzobj, NULL, NULL) && _bzobjs_device_is_connected(bzobj)) { - /* We are now connected. Schedule the task that completes the state. */ - _process_change_idle_schedule(self, bzobj); - } -} - -#if WITH_BLUEZ5_DUN -static void -_connect_dun_notify_tty_hangup_cb(NMBluez5DunContext *context, gpointer user_data) -{ - BzDBusObj *bzobj = user_data; - - _connect_disconnect(bzobj->self, bzobj, "DUN connection hung up"); -} - -static void -_connect_dun_step2_cb(NMBluez5DunContext *context, - const char * rfcomm_dev, - GError * error, - gpointer user_data) -{ - BzDBusObj *bzobj; - - if (nm_utils_error_is_cancelled(error)) - return; - - bzobj = user_data; - - if (rfcomm_dev) { - /* We want to early notify about the rfcomm path. That is because we might still delay - * to signal full activation longer (asynchronously). But the earliest time the callback - * is invoked with the rfcomm path, we just created the device synchronously. - * - * By already notifying the caller about the path early, it avoids a race where ModemManager - * would find the modem before the bluetooth code considers the profile fully activated. */ - - nm_assert(!error); - nm_assert(bzobj->x_device.c_req_data); - - if (!g_cancellable_is_cancelled(bzobj->x_device.c_req_data->ext_cancellable)) - bzobj->x_device.c_req_data->callback(bzobj->self, - FALSE, - rfcomm_dev, - NULL, - bzobj->x_device.c_req_data->callback_user_data); - - if (!context) { - /* No context set. This means, we just got notified about the rfcomm path and need to wait - * longer, for the next callback. */ - return; - } - } - - _connect_returned(bzobj->self, bzobj, NM_BT_CAPABILITY_DUN, rfcomm_dev, context, error); -} - -static void -_connect_dun_step1_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - BzDBusObj * bzobj_adapter; - BzDBusObj * bzobj; - - ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source_object), res, &error); - - if (!ret && nm_utils_error_is_cancelled(error)) - return; - - bzobj = user_data; - - if (error) { - _LOGT("DUN: [%s]: bluetooth device connect failed: %s", bzobj->object_path, error->message); - /* we actually ignore this error. Let's try, maybe we still can connect via DUN. */ - g_clear_error(&error); - } else - _LOGT("DUN: [%s]: bluetooth device connected successfully", bzobj->object_path); - - if (!_bzobjs_device_is_usable(bzobj, &bzobj_adapter, NULL)) { - nm_utils_error_set(&error, - NM_UTILS_ERROR_UNKNOWN, - "device %s is not usable for DUN after connect", - bzobj->object_path); - _connect_returned(bzobj->self, bzobj, NM_BT_CAPABILITY_DUN, NULL, NULL, error); - return; - } - - if (!nm_bluez5_dun_connect(bzobj_adapter->d_adapter.address, - bzobj->d_device.address, - bzobj->x_device.c_req_data->int_cancellable, - _connect_dun_step2_cb, - bzobj, - _connect_dun_notify_tty_hangup_cb, - bzobj, - &error)) { - _connect_returned(bzobj->self, bzobj, NM_BT_CAPABILITY_DUN, NULL, NULL, error); - return; - } -} -#endif - -static void -_connect_nap_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - gs_unref_variant GVariant *ret = NULL; - const char * network_iface_name = NULL; - gs_free_error GError *error = NULL; - BzDBusObj * bzobj; - - ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source_object), res, &error); - - if (!ret && nm_utils_error_is_cancelled(error)) - return; - - if (ret) - g_variant_get(ret, "(&s)", &network_iface_name); - - bzobj = user_data; - - _connect_returned(bzobj->self, bzobj, NM_BT_CAPABILITY_NAP, network_iface_name, NULL, error); -} - -static void -_connect_cancelled_cb(GCancellable *cancellable, BzDBusObj *bzobj) -{ - _connect_disconnect(bzobj->self, bzobj, "connect cancelled"); -} - -static gboolean -_connect_timeout_wait_connected_cb(gpointer user_data) -{ - BzDBusObj *bzobj = user_data; - - bzobj->x_device.c_req_data->timeout_wait_connect_id = 0; - _connect_disconnect(bzobj->self, bzobj, "timeout waiting for connected"); - return G_SOURCE_REMOVE; -} - -static gboolean -_connect_timeout_cb(gpointer user_data) -{ - BzDBusObj *bzobj = user_data; - - bzobj->x_device.c_req_data->timeout_id = 0; - _connect_disconnect(bzobj->self, bzobj, "timeout connecting"); - return G_SOURCE_REMOVE; -} - -static void -_connect_disconnect(NMBluezManager *self, BzDBusObj *bzobj, const char *reason) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - DeviceConnectReqData * c_req_data; - char sbuf_cap[100]; - gboolean bt_type; - - if (bzobj->x_device_connect_bt_type == NM_BT_CAPABILITY_NONE) { - nm_assert(!bzobj->x_device.c_req_data); - return; - } - - bt_type = bzobj->x_device_connect_bt_type; - nm_assert(NM_IN_SET(bt_type, NM_BT_CAPABILITY_DUN, NM_BT_CAPABILITY_NAP)); - bzobj->x_device_connect_bt_type = NM_BT_CAPABILITY_NONE; - - c_req_data = g_steal_pointer(&bzobj->x_device.c_req_data); - - _LOGD("%s [%s]: disconnect due to %s", - nm_bluetooth_capability_to_string(bt_type, sbuf_cap, sizeof(sbuf_cap)), - bzobj->object_path, - reason); - - if (c_req_data) - nm_clear_g_cancellable(&c_req_data->int_cancellable); - - if (bt_type == NM_BT_CAPABILITY_DUN) { - /* For DUN devices, we also called org.bluez.Device1.Connect() (because in order - * for nm_bluez5_dun_connect() to succeed, we need to be already connected *why??). - * - * But upon disconnect we don't call Disconnect() because we don't know whether somebody - * else also uses the bluetooth device for other purposes. During disconnect we only - * terminate the DUN connection, but don't disconnect entirely. I think that's the - * best we can do. */ -#if WITH_BLUEZ5_DUN - nm_clear_pointer(&bzobj->x_device.connect_dun_context, nm_bluez5_dun_disconnect); -#else - nm_assert_not_reached(); -#endif - } else { - if (priv->name_owner) { - gs_unref_object GCancellable *cancellable = NULL; - - cancellable = g_cancellable_new(); - - nm_shutdown_wait_obj_register_cancellable_full( - cancellable, - g_strdup_printf("bt-disconnect-nap[%s]", bzobj->object_path), - TRUE); - - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_NETWORK_INTERFACE, - "Disconnect", - g_variant_new("()"), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - cancellable, - _dbus_call_complete_cb_nop, - NULL); - } - } - - if (c_req_data) { - gs_free_error GError *error = NULL; - - nm_utils_error_set(&error, NM_UTILS_ERROR_UNKNOWN, "connect aborted due to %s", reason); - _device_connect_req_data_complete(c_req_data, self, NULL, error); - } -} - -gboolean -nm_bluez_manager_connect(NMBluezManager * self, - const char * object_path, - NMBluetoothCapabilities connection_bt_type, - int timeout_msec, - GCancellable * cancellable, - NMBluezManagerConnectCb callback, - gpointer callback_user_data, - GError ** error) -{ - gs_unref_object GCancellable *int_cancellable = NULL; - DeviceConnectReqData * c_req_data; - NMBluezManagerPrivate * priv; - BzDBusObj * bzobj; - char sbuf_cap[100]; - - g_return_val_if_fail(NM_IS_BLUEZ_MANAGER(self), FALSE); - g_return_val_if_fail(NM_IN_SET(connection_bt_type, NM_BT_CAPABILITY_DUN, NM_BT_CAPABILITY_NAP), - FALSE); - g_return_val_if_fail(callback, FALSE); - - nm_assert(timeout_msec > 0); - - priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - bzobj = _bzobjs_get(self, object_path); - - if (!bzobj) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "device %s does not exist", object_path); - return FALSE; - } - - if (!_bzobjs_device_is_usable(bzobj, NULL, NULL)) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "device %s is not usable", object_path); - return FALSE; - } - - if (!NM_FLAGS_ALL(bzobj->d_device_capabilities, connection_bt_type)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "device %s has not the required capabilities", - object_path); - return FALSE; - } - -#if !WITH_BLUEZ5_DUN - if (connection_bt_type == NM_BT_CAPABILITY_DUN) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "DUN is not supported"); - return FALSE; - } -#endif - - _connect_disconnect(self, bzobj, "new activation"); - - _LOGD("%s [%s]: connecting...", - nm_bluetooth_capability_to_string(connection_bt_type, sbuf_cap, sizeof(sbuf_cap)), - bzobj->object_path); - - int_cancellable = g_cancellable_new(); - -#if WITH_BLUEZ5_DUN - if (connection_bt_type == NM_BT_CAPABILITY_DUN) { - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_DEVICE_INTERFACE, - "Connect", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - timeout_msec, - int_cancellable, - _connect_dun_step1_cb, - bzobj); - } else -#endif - { - nm_assert(connection_bt_type == NM_BT_CAPABILITY_NAP); - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_NETWORK_INTERFACE, - "Connect", - g_variant_new("(s)", BLUETOOTH_CONNECT_NAP), - G_VARIANT_TYPE("(s)"), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - timeout_msec, - int_cancellable, - _connect_nap_cb, - bzobj); - } - - c_req_data = g_slice_new(DeviceConnectReqData); - *c_req_data = (DeviceConnectReqData){ - .int_cancellable = g_steal_pointer(&int_cancellable), - .ext_cancellable = g_object_ref(cancellable), - .callback = callback, - .callback_user_data = callback_user_data, - .ext_cancelled_id = - g_signal_connect(cancellable, "cancelled", G_CALLBACK(_connect_cancelled_cb), bzobj), - .timeout_id = g_timeout_add(timeout_msec, _connect_timeout_cb, bzobj), - }; - - bzobj->x_device_connect_bt_type = connection_bt_type; - bzobj->x_device.c_req_data = c_req_data; - - return TRUE; -} - -void -nm_bluez_manager_disconnect(NMBluezManager *self, const char *object_path) -{ - BzDBusObj *bzobj; - - g_return_if_fail(NM_IS_BLUEZ_MANAGER(self)); - g_return_if_fail(object_path); - - bzobj = _bzobjs_get(self, object_path); - if (!bzobj) - return; - - _connect_disconnect(self, bzobj, "disconnected by user"); -} - -/*****************************************************************************/ - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - *out_ignore = TRUE; - g_return_val_if_fail(plink->type == NM_LINK_TYPE_BNEP, NULL); - return NULL; -} - -static gboolean -match_connection(NMDeviceFactory *factory, NMConnection *connection) -{ - const char *type = nm_connection_get_connection_type(connection); - - nm_assert(nm_streq(type, NM_SETTING_BLUETOOTH_SETTING_NAME)); - - if (_nm_connection_get_setting_bluetooth_for_nap(connection)) - return FALSE; /* handled by the bridge factory */ - - return TRUE; -} - -/*****************************************************************************/ - -static void -nm_bluez_manager_init(NMBluezManager *self) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - priv->vtable_network_server = (NMBtVTableNetworkServer){ - .is_available = _network_server_vt_is_available, - .register_bridge = _network_server_vt_register_bridge, - .unregister_bridge = _network_server_vt_unregister_bridge, - }; - - c_list_init(&priv->network_server_lst_head); - c_list_init(&priv->process_change_lst_head); - - priv->conn_data_heads = - g_hash_table_new_full(_conn_data_head_hash, _conn_data_head_equal, g_free, NULL); - priv->conn_data_elems = g_hash_table_new_full(nm_pdirect_hash, - nm_pdirect_equal, - nm_g_slice_free_fcn(ConnDataElem), - NULL); - - priv->bzobjs = g_hash_table_new_full(nm_pstr_hash, - nm_pstr_equal, - (GDestroyNotify) _bz_dbus_obj_free, - NULL); - - priv->manager = g_object_ref(NM_MANAGER_GET); - priv->settings = g_object_ref(NM_SETTINGS_GET); - priv->dbus_connection = nm_g_object_ref(NM_MAIN_DBUS_CONNECTION_GET); - - g_atomic_pointer_compare_and_exchange(&nm_bt_vtable_network_server, - NULL, - &priv->vtable_network_server); -} - -static void -dispose(GObject *object) -{ - NMBluezManager * self = NM_BLUEZ_MANAGER(object); - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - /* FIXME(shutdown): we need a nm_device_factory_stop() hook to first unregister all - * BzDBusObj instances and do necessary cleanup actions (like disconnecting devices - * or deleting panu_connection). */ - - nm_assert(c_list_is_empty(&priv->network_server_lst_head)); - nm_assert(c_list_is_empty(&priv->process_change_lst_head)); - nm_assert(priv->process_change_idle_id == 0); - - g_atomic_pointer_compare_and_exchange(&nm_bt_vtable_network_server, - &priv->vtable_network_server, - NULL); - - _cleanup_all(self); - - G_OBJECT_CLASS(nm_bluez_manager_parent_class)->dispose(object); - - g_clear_object(&priv->settings); - g_clear_object(&priv->manager); - g_clear_object(&priv->dbus_connection); - - nm_clear_pointer(&priv->bzobjs, g_hash_table_destroy); -} - -static void -nm_bluez_manager_class_init(NMBluezManagerClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); - - object_class->dispose = dispose; - - factory_class->get_supported_types = get_supported_types; - factory_class->create_device = create_device; - factory_class->match_connection = match_connection; - factory_class->start = start; -} |