The Windows Bluetooth stack uses private IOCTLs in order to set the [discoverability](https://learn.microsoft.com/en-us/windows/win32/api/bluetoothapis/nf-bluetoo...) and [connectability](https://learn.microsoft.com/en-us/windows/win32/api/bluetoothapis/nf-bluetoo...) status of a local radio, and to start/stop the device inquiry procedure. This MR introduces 3 wine-specific IOCTL codes for the same purposes, as most applications seem to the Win32 API itself for these operations:
* IOCTL_WINBTH_RADIO_SET_FLAG * IOCTL_WINEBTH_RADIO_START_DISCOVERY * IOCTL_WINEBTH_RADIO_STOP_DISCOVERY
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 89 ++++++++++++++++++++++++++++++++ dlls/winebth.sys/dbus.h | 2 + dlls/winebth.sys/unixlib.c | 10 ++++ dlls/winebth.sys/unixlib.h | 10 ++++ dlls/winebth.sys/unixlib_priv.h | 3 ++ dlls/winebth.sys/winebluetooth.c | 29 +++++++++++ dlls/winebth.sys/winebth.c | 37 ++++++++++++- dlls/winebth.sys/winebth_priv.h | 16 ++++-- include/Makefile.in | 1 + include/wine/winebth.h | 42 +++++++++++++++ 10 files changed, 234 insertions(+), 5 deletions(-) create mode 100644 include/wine/winebth.h
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 38636db18a1..35ac0ff32fe 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -2,6 +2,7 @@ * Support for communicating with BlueZ over DBus. * * Copyright 2024 Vibhav Pant + * Copyright 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -264,6 +265,94 @@ static void parse_mac_address( const char *addr_str, BYTE dest[6] ) dest[i] = addr[i]; }
+NTSTATUS bluez_adapter_set_prop( void *connection, struct bluetooth_adapter_set_prop_params *params ) +{ + DBusMessage *request, *reply; + DBusMessageIter iter, sub_iter; + DBusError error; + DBusBasicValue val; + int val_type; + static const char *adapter_iface = BLUEZ_INTERFACE_ADAPTER; + const char *prop_name; + + TRACE( "(%p, %p)\n", connection, params ); + + switch (params->prop_flag) + { + case WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERABLE: + prop_name = "Discoverable"; + val.bool_val = params->prop->boolean; + val_type = DBUS_TYPE_BOOLEAN; + break; + case WINEBLUETOOTH_RADIO_PROPERTY_CONNECTABLE: + prop_name = "Connectable"; + val.bool_val = params->prop->boolean; + val_type = DBUS_TYPE_BOOLEAN; + break; + case WINEBLUETOOTH_RADIO_PROPERTY_PAIRABLE: + prop_name = "Pairable"; + val.bool_val = params->prop->boolean; + val_type = DBUS_TYPE_BOOLEAN; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + TRACE( "Setting property %s for adapter %s\n", debugstr_a( prop_name ), + debugstr_a( params->adapter->str ) ); + request = p_dbus_message_new_method_call( BLUEZ_DEST, params->adapter->str, + DBUS_INTERFACE_PROPERTIES, "Set" ); + if (!request) return STATUS_NO_MEMORY; + + p_dbus_message_iter_init_append( request, &iter ); + if (!p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &adapter_iface )) + { + p_dbus_message_unref( request ); + return STATUS_NO_MEMORY; + } + if (!p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &prop_name )) + { + p_dbus_message_unref( request ); + return STATUS_NO_MEMORY; + } + if (!p_dbus_message_iter_open_container( &iter, DBUS_TYPE_VARIANT, DBUS_TYPE_BOOLEAN_AS_STRING, + &sub_iter )) + { + p_dbus_message_unref( request ); + return STATUS_NO_MEMORY; + } + if (!p_dbus_message_iter_append_basic( &sub_iter, val_type, &val )) + { + p_dbus_message_iter_abandon_container( &iter, &sub_iter ); + p_dbus_message_unref( request ); + return STATUS_NO_MEMORY; + } + if (!p_dbus_message_iter_close_container( &iter, &sub_iter )) + { + p_dbus_message_unref( request ); + return STATUS_NO_MEMORY; + } + + p_dbus_error_init( &error ); + reply = + p_dbus_connection_send_with_reply_and_block( connection, request, bluez_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + NTSTATUS status; + ERR( "Failed to set property %s for adapter %s: %s: %s\n", debugstr_a( prop_name ), + debugstr_a( params->adapter->str ), debugstr_a( error.name ), + debugstr_a( error.message ) ); + status = bluez_dbus_error_to_ntstatus( &error ); + p_dbus_error_free( &error ); + return status; + } + p_dbus_error_free( &error ); + p_dbus_message_unref( reply ); + + return STATUS_SUCCESS; +} + static void bluez_radio_prop_from_dict_entry( const char *prop_name, DBusMessageIter *variant, struct winebluetooth_radio_properties *props, winebluetooth_radio_props_mask_t *props_mask, diff --git a/dlls/winebth.sys/dbus.h b/dlls/winebth.sys/dbus.h index 025d2c6fd2c..19b94776fd3 100644 --- a/dlls/winebth.sys/dbus.h +++ b/dlls/winebth.sys/dbus.h @@ -2,6 +2,7 @@ * DBus declarations. * * Copyright 2024 Vibhav Pant + * Copyright 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -79,6 +80,7 @@ DO_FUNC(dbus_message_is_method_call); \ DO_FUNC(dbus_message_is_signal); \ DO_FUNC(dbus_message_iter_append_basic); \ + DO_FUNC(dbus_message_iter_abandon_container); \ DO_FUNC(dbus_message_iter_close_container); \ DO_FUNC(dbus_message_iter_get_arg_type); \ DO_FUNC(dbus_message_iter_get_element_type); \ diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index 09641be6396..982652498e5 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -2,6 +2,7 @@ * winebluetooth Unix interface * * Copyright 2024 Vibhav Pant + * Copyright 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -154,6 +155,14 @@ static NTSTATUS bluetooth_adapter_free( void *args ) return STATUS_SUCCESS; }
+static NTSTATUS bluetooth_adapter_set_prop( void *arg ) +{ + struct bluetooth_adapter_set_prop_params *params = arg; + + if (!dbus_connection) return STATUS_NOT_SUPPORTED; + return bluez_adapter_set_prop( dbus_connection, params ); +} + static NTSTATUS bluetooth_get_event( void *args ) { struct bluetooth_get_event_params *params = args; @@ -167,6 +176,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { bluetooth_init, bluetooth_shutdown,
+ bluetooth_adapter_set_prop, bluetooth_adapter_get_unique_name, bluetooth_adapter_free,
diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h index 45a000a2e88..b16f873deef 100644 --- a/dlls/winebth.sys/unixlib.h +++ b/dlls/winebth.sys/unixlib.h @@ -2,6 +2,7 @@ * Unix interface definitions * * Copyright 2024 Vibhav Pant + * Copyright 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -56,6 +57,14 @@ struct bluetooth_adapter_get_unique_name_params SIZE_T buf_size; };
+struct bluetooth_adapter_set_prop_params +{ + unix_name_t adapter; + winebluetooth_radio_props_mask_t prop_flag; + + union winebluetooth_property *prop; +}; + struct bluetooth_get_event_params { struct winebluetooth_event result; @@ -66,6 +75,7 @@ enum bluetoothapis_funcs unix_bluetooth_init, unix_bluetooth_shutdown,
+ unix_bluetooth_adapter_set_prop, unix_bluetooth_adapter_get_unique_name, unix_bluetooth_adapter_free,
diff --git a/dlls/winebth.sys/unixlib_priv.h b/dlls/winebth.sys/unixlib_priv.h index 5ed5204e930..5146799e705 100644 --- a/dlls/winebth.sys/unixlib_priv.h +++ b/dlls/winebth.sys/unixlib_priv.h @@ -2,6 +2,7 @@ * Bluetoothapis Unix interface * * Copyright 2024 Vibhav Pant + * Copyright 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -47,6 +48,8 @@ extern void *bluez_dbus_init( void ); extern void bluez_dbus_close( void *connection ); extern void bluez_dbus_free( void *connection ); extern NTSTATUS bluez_dbus_loop( void *connection, void *watcher_ctx, struct winebluetooth_event *result ); +extern NTSTATUS bluez_adapter_set_prop( void *connection, + struct bluetooth_adapter_set_prop_params *params ); extern NTSTATUS bluez_watcher_init( void *connection, void **ctx ); extern void bluez_watcher_close( void *connection, void *ctx ); #endif /* __WINE_WINEBTH_UNIXLIB_PRIV_H */ diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c index 3d5aa77094d..faf3b387aef 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -2,6 +2,7 @@ * Wine bluetooth APIs * * Copyright 2024 Vibhav Pant + * Copyright 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -53,6 +54,34 @@ NTSTATUS winebluetooth_radio_get_unique_name( winebluetooth_radio_t radio, char return status; }
+NTSTATUS winebluetooth_radio_set_property( winebluetooth_radio_t radio, + winebluetooth_radio_props_mask_t prop, + union winebluetooth_property *property ) +{ + struct bluetooth_adapter_set_prop_params params = { 0 }; + NTSTATUS status; + + TRACE( "(%p, %#x, %p)\n", (void *)radio.handle, prop, property ); + + params.adapter = radio.handle; + + switch (prop) + { + case WINEBLUETOOTH_RADIO_PROPERTY_CONNECTABLE: + case WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERABLE: + case WINEBLUETOOTH_RADIO_PROPERTY_PAIRABLE: + break; + default: + return STATUS_INVALID_PARAMETER; + } + + status = UNIX_BLUETOOTH_CALL( bluetooth_adapter_set_prop, ¶ms ); + + if (status != STATUS_SUCCESS) return status; + + return STATUS_SUCCESS; +} + void winebluetooth_radio_free( winebluetooth_radio_t radio ) { struct bluetooth_adapter_free_params args = { 0 }; diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 5ba846e6459..e5ae08d4b32 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -1,7 +1,7 @@ /* * Bluetooth bus driver * - * Copyright 2024 Vibhav Pant + * Copyright 2024-2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -37,6 +37,7 @@ #include <bthioctl.h> #include <ddk/wdm.h>
+#include <wine/winebth.h> #include <wine/debug.h> #include <wine/list.h>
@@ -84,6 +85,7 @@ static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) struct bluetooth_radio *ext = (struct bluetooth_radio *)device->DeviceExtension; IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + ULONG insize = stack->Parameters.DeviceIoControl.InputBufferLength; ULONG outsize = stack->Parameters.DeviceIoControl.OutputBufferLength; NTSTATUS status = irp->IoStatus.Status;
@@ -133,6 +135,39 @@ static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) status = STATUS_SUCCESS; break; } + case IOCTL_WINEBTH_RADIO_SET_FLAG: + { + const struct winebth_radio_set_flag_params *params = irp->AssociatedIrp.SystemBuffer; + union winebluetooth_property prop_value = {0}; + + if (!params) + { + status = STATUS_INVALID_PARAMETER; + break; + } + if (insize < sizeof(UINT32)) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + prop_value.boolean = !!params->enable; + switch (params->flag) + { + case LOCAL_RADIO_CONNECTABLE: + status = + winebluetooth_radio_set_property( ext->radio, WINEBLUETOOTH_RADIO_PROPERTY_CONNECTABLE, &prop_value ); + + break; + case LOCAL_RADIO_DISCOVERABLE: + status = + winebluetooth_radio_set_property( ext->radio, WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERABLE, &prop_value ); + break; + default: + status = STATUS_INVALID_PARAMETER; + } + break; + } default: FIXME( "Unimplemented IOCTL code: %#lx\n", code ); break; diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 117b02f3294..06dc3a8b799 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -2,6 +2,7 @@ * Private winebth.sys defs * * Copyright 2024 Vibhav Pant + * Copyright 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -108,10 +109,6 @@ DEFINE_BTH_RADIO_DEVPROPKEY( HCIVendorFeatures, 8 ); /* DEVPROP_TY DEFINE_BTH_RADIO_DEVPROPKEY( MaximumAdvertisementDataLength, 17 ); /* DEVPROP_TYPE_UINT16 */ DEFINE_BTH_RADIO_DEVPROPKEY( LELocalSupportedFeatures, 22 ); /* DEVPROP_TYPE_UINT64 */
-/* Valid masks for the "flags" field in BTH_LOCAL_RADIO_INFO. */ -#define LOCAL_RADIO_DISCOVERABLE 0x0001 -#define LOCAL_RADIO_CONNECTABLE 0x0002 - typedef struct { UINT_PTR handle; @@ -136,6 +133,14 @@ typedef UINT16 winebluetooth_radio_props_mask_t; WINEBLUETOOTH_RADIO_PROPERTY_VERSION | WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERING | \ WINEBLUETOOTH_RADIO_PROPERTY_PAIRABLE)
+union winebluetooth_property +{ + BOOL boolean; + ULONG ulong; + BLUETOOTH_ADDRESS address; + WCHAR name[BLUETOOTH_MAX_NAME_SIZE]; +}; + struct winebluetooth_radio_properties { BOOL discoverable; @@ -156,6 +161,9 @@ static inline BOOL winebluetooth_radio_equal( winebluetooth_radio_t r1, wineblue { return r1.handle == r2.handle; } +NTSTATUS winebluetooth_radio_set_property( winebluetooth_radio_t radio, + winebluetooth_radio_props_mask_t prop, + union winebluetooth_property *property );
enum winebluetooth_watcher_event_type { diff --git a/include/Makefile.in b/include/Makefile.in index cb2b83b6d8c..1886c623466 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -957,6 +957,7 @@ SOURCES = \ wine/wgl_driver.h \ wine/winbase16.h \ wine/windef16.h \ + wine/winebth.h \ wine/wine_common_ver.rc \ wine/wined3d.h \ wine/winedmo.h \ diff --git a/include/wine/winebth.h b/include/wine/winebth.h new file mode 100644 index 00000000000..c26a2100fb9 --- /dev/null +++ b/include/wine/winebth.h @@ -0,0 +1,42 @@ +/* + * Wine-specific IOCTL definitions for interfacing with winebth.sys + * + * Copyright 2025 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#ifndef __WINEBTH_H__ +#define __WINEBTH_H__ + +/* Set the discoverability or connectable flag for a local radio. Enabling discoverability will also enable incoming + * connections, while disabling incoming connections disables discoverability as well. */ +#define IOCTL_WINEBTH_RADIO_SET_FLAG CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xa3, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#include <pshpack1.h> + +#define LOCAL_RADIO_DISCOVERABLE 0x0001 +#define LOCAL_RADIO_CONNECTABLE 0x0002 + +struct winebth_radio_set_flag_params +{ + unsigned int flag: 2; + unsigned int enable : 1; +}; + +#include <poppack.h> + +#endif /* __WINEBTH_H__ */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 155 +++++++++++++++++++++++++++++-- dlls/winebth.sys/unixlib.c | 11 +++ dlls/winebth.sys/unixlib.h | 8 ++ dlls/winebth.sys/unixlib_priv.h | 2 + dlls/winebth.sys/winebluetooth.c | 12 +++ dlls/winebth.sys/winebth.c | 28 ++++++ dlls/winebth.sys/winebth_priv.h | 10 ++ include/wine/winebth.h | 8 ++ 8 files changed, 225 insertions(+), 9 deletions(-)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 35ac0ff32fe..19f25e517d9 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -178,6 +178,22 @@ static const char *bluez_next_dict_entry( DBusMessageIter *iter, DBusMessageIter return name; }
+/* Adds an entry to a dict iterator of type {sv} */ +static void bluez_variant_dict_add_entry( DBusMessageIter *dict, const char *key, int value_type, + const char *value_type_str, const void *value ) +{ + DBusMessageIter entry, variant; + + p_dbus_message_iter_open_container( dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry ); + p_dbus_message_iter_append_basic( &entry, DBUS_TYPE_STRING, &key ); + + p_dbus_message_iter_open_container( &entry, DBUS_TYPE_VARIANT, value_type_str, &variant ); + p_dbus_message_iter_append_basic( &variant, value_type, value ); + p_dbus_message_iter_close_container( &entry, &variant ); + + p_dbus_message_iter_close_container( dict, &entry ); +} + static const char *dbgstr_dbus_message( DBusMessage *message ) { const char *interface; @@ -265,6 +281,103 @@ static void parse_mac_address( const char *addr_str, BYTE dest[6] ) dest[i] = addr[i]; }
+static NTSTATUS bluez_adapter_set_discovery_filter( void *connection, const char *adapter_path, + const char *transport_str ) +{ + DBusMessage *request, *reply; + DBusMessageIter iter, dict_iter; + DBusError error; + + TRACE( "(%p, %s, %s)\n", connection, debugstr_a( adapter_path ), debugstr_a( transport_str ) ); + + request = p_dbus_message_new_method_call( BLUEZ_DEST, adapter_path, BLUEZ_INTERFACE_ADAPTER, + "SetDiscoveryFilter" ); + if (!request) return STATUS_NO_MEMORY; + + p_dbus_message_iter_init_append( request, &iter ); + p_dbus_message_iter_open_container( &iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter ); + bluez_variant_dict_add_entry( &dict_iter, "Transport", DBUS_TYPE_STRING, + DBUS_TYPE_STRING_AS_STRING, &transport_str ); + p_dbus_message_iter_close_container( &iter, &dict_iter ); + + p_dbus_error_init ( &error ); + + TRACE( "Setting discovery filter on %s to use transport %s\n", debugstr_a( adapter_path ), + debugstr_a( transport_str ) ); + reply = + p_dbus_connection_send_with_reply_and_block( connection, request, bluez_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + NTSTATUS status; + WARN( "Failed to set discovery filter: %s: %s\n", debugstr_a( error.name ), + debugstr_a( error.message ) ); + status = bluez_dbus_error_to_ntstatus( &error ); + p_dbus_error_free( &error ); + return status; + } + p_dbus_message_unref( reply ); + p_dbus_error_free( &error ); + + return STATUS_SUCCESS; + +} + +NTSTATUS bluez_adapter_start_discovery( void *connection, const char *adapter_path, + enum winebluetooth_discovery_transport transport ) +{ + DBusMessage *request, *reply; + DBusError error; + + TRACE( "(%p, %s, %d)\n", connection, debugstr_a( adapter_path ), transport ); + + if (transport != WINEBLUETOOTH_DISCOVERY_TRANSPORT_DEFAULT) + { + const char *transport_str; + NTSTATUS status; + + switch ( transport ) + { + case WINEBLUETOOTH_DISCOVERY_TRANSPORT_AUTO: + transport_str = "auto"; + break; + case WINEBLUETOOTH_DISCOVERY_TRANSPORT_BR_EDR: + transport_str = "bredr"; + break; + case WINEBLUETOOTH_DISCOVERY_TRANSPORT_LE: + transport_str = "le"; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + status = bluez_adapter_set_discovery_filter( connection, adapter_path, transport_str ); + if (status != STATUS_SUCCESS) return status; + } + + request = p_dbus_message_new_method_call( BLUEZ_DEST, adapter_path, BLUEZ_INTERFACE_ADAPTER, + "StartDiscovery" ); + if (!request) return STATUS_NO_MEMORY; + + TRACE( "Starting discovery on %s\n", debugstr_a( adapter_path ) ); + p_dbus_error_init( &error ); + reply = + p_dbus_connection_send_with_reply_and_block( connection, request, bluez_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + NTSTATUS status; + ERR( "Failed to start discovery on adapter %s: %s: %s", debugstr_a( adapter_path ), + debugstr_a( error.message ), debugstr_a( error.name ) ); + status = bluez_dbus_error_to_ntstatus( &error ); + p_dbus_error_free( &error ); + return status; + } + p_dbus_error_free( &error ); + p_dbus_message_unref( reply ); + return STATUS_SUCCESS; +} + NTSTATUS bluez_adapter_set_prop( void *connection, struct bluetooth_adapter_set_prop_params *params ) { DBusMessage *request, *reply; @@ -460,6 +573,10 @@ struct bluez_watcher_ctx { void *init_device_list_call;
+ /* Calling dbus_connection_send_to_reply_and_block from other threads will run the DBus dispatch + * loop, which calls bluez_filter. Therefore, we need to protect access to the event list(s) + * with a lock. */ + pthread_mutex_t event_lists_lock; /* struct bluez_init_entry */ struct list initial_radio_list;
@@ -614,13 +731,11 @@ static UINT16 bluez_dbus_get_invalidated_properties_from_iter(
static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, void *user_data ) { - struct list *event_list; + struct bluez_watcher_ctx *ctx = user_data;
if (TRACE_ON( dbus )) TRACE_( dbus )( "(%s, %s, %p)\n", dbgstr_dbus_connection( conn ), dbgstr_dbus_message( msg ), user_data );
- event_list = &((struct bluez_watcher_ctx *)user_data)->event_list; - if (p_dbus_message_is_signal( msg, DBUS_INTERFACE_OBJECTMANAGER, DBUS_OBJECTMANAGER_SIGNAL_INTERFACESADDED ) && p_dbus_message_has_signature( msg, DBUS_INTERFACES_ADDED_SIGNATURE )) { @@ -667,9 +782,11 @@ static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, v union winebluetooth_watcher_event_data event = { .radio_added = radio_added }; TRACE( "New BlueZ org.bluez.Adapter1 object added at %s: %p\n", debugstr_a( object_path ), radio ); + pthread_mutex_lock( &ctx->event_lists_lock ); if (!bluez_event_list_queue_new_event( - event_list, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED, event )) + &ctx->event_list, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED, event )) unix_name_free( radio ); + pthread_mutex_unlock( &ctx->event_lists_lock ); } } p_dbus_message_iter_next( &ifaces_iter ); @@ -713,9 +830,11 @@ static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, v } radio.handle = (UINT_PTR)radio_name; event.radio_removed = radio; + pthread_mutex_lock( &ctx->event_lists_lock ); if (!bluez_event_list_queue_new_event( - event_list, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_REMOVED, event )) + &ctx->event_list, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_REMOVED, event )) unix_name_free( radio_name ); + pthread_mutex_unlock( &ctx->event_lists_lock ); } } p_dbus_free_string_array( interfaces ); @@ -791,27 +910,33 @@ static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, v return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
- if (!bluez_event_list_queue_new_event_with_call( event_list, + pthread_mutex_lock( &ctx->event_lists_lock ); + if (!bluez_event_list_queue_new_event_with_call( &ctx->event_list, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED, event, pending_call, bluez_filter_radio_props_changed_callback )) { + pthread_mutex_unlock( &ctx->event_lists_lock ); unix_name_free( radio ); p_dbus_pending_call_cancel( pending_call ); p_dbus_pending_call_unref( pending_call ); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } + pthread_mutex_unlock( &ctx->event_lists_lock ); } else { union winebluetooth_watcher_event_data event = { .radio_props_changed = props_changed }; - if (!bluez_event_list_queue_new_event( event_list, + pthread_mutex_lock( &ctx->event_lists_lock ); + if (!bluez_event_list_queue_new_event( &ctx->event_list, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED, event )) { + pthread_mutex_unlock( &ctx->event_lists_lock ); unix_name_free( radio ); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } + pthread_mutex_unlock( &ctx->event_lists_lock ); } } } @@ -848,6 +973,7 @@ NTSTATUS bluez_watcher_init( void *connection, void **ctx ) return status; } watcher_ctx->init_device_list_call = call; + pthread_mutex_init( &watcher_ctx->event_lists_lock, NULL ); list_init( &watcher_ctx->initial_radio_list );
list_init( &watcher_ctx->event_list ); @@ -971,14 +1097,17 @@ static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct lis
static BOOL bluez_watcher_event_queue_ready( struct bluez_watcher_ctx *ctx, struct winebluetooth_watcher_event *event ) { + pthread_mutex_lock( &ctx->event_lists_lock ); if (!list_empty( &ctx->initial_radio_list )) { struct bluez_init_entry *radio;
radio = LIST_ENTRY( list_head( &ctx->initial_radio_list ), struct bluez_init_entry, entry ); + list_remove( &radio->entry ); + pthread_mutex_unlock( &ctx->event_lists_lock ); + event->event_type = BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED; event->event_data.radio_added = radio->object.radio; - list_remove( &radio->entry ); free( radio ); return TRUE; } @@ -988,16 +1117,22 @@ static BOOL bluez_watcher_event_queue_ready( struct bluez_watcher_ctx *ctx, stru LIST_ENTRY( list_head( &ctx->event_list ), struct bluez_watcher_event, entry );
if (watcher_event->pending_call && !p_dbus_pending_call_get_completed( watcher_event->pending_call )) + { + pthread_mutex_unlock( &ctx->event_lists_lock); return FALSE; + } + + list_remove( &watcher_event->entry ); + pthread_mutex_unlock( &ctx->event_lists_lock );
event->event_type = watcher_event->event_type; event->event_data = watcher_event->event; - list_remove( &watcher_event->entry ); if (watcher_event->pending_call) p_dbus_pending_call_unref( watcher_event->pending_call ); free( watcher_event ); return TRUE; } + pthread_mutex_unlock( &ctx->event_lists_lock ); return FALSE; }
@@ -1045,7 +1180,9 @@ NTSTATUS bluez_dbus_loop( void *c, void *watcher, p_dbus_connection_unref( connection ); return STATUS_NO_MEMORY; } + pthread_mutex_lock( &watcher_ctx->event_lists_lock ); status = bluez_build_initial_device_lists( reply, &watcher_ctx->initial_radio_list ); + pthread_mutex_unlock( &watcher_ctx->event_lists_lock ); p_dbus_message_unref( reply ); if (status != STATUS_SUCCESS) { diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index 982652498e5..6009f7f3af1 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -163,6 +163,15 @@ static NTSTATUS bluetooth_adapter_set_prop( void *arg ) return bluez_adapter_set_prop( dbus_connection, params ); }
+static NTSTATUS bluetooth_adapter_start_discovery( void *args ) +{ + struct bluetooth_adapter_start_discovery_params *params = args; + + if (!dbus_connection) return STATUS_NOT_SUPPORTED; + return bluez_adapter_start_discovery( dbus_connection, params->adapter->str, + params->transport ); +} + static NTSTATUS bluetooth_get_event( void *args ) { struct bluetooth_get_event_params *params = args; @@ -180,6 +189,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { bluetooth_adapter_get_unique_name, bluetooth_adapter_free,
+ bluetooth_adapter_start_discovery, + bluetooth_get_event, };
diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h index b16f873deef..8d10f1d8adb 100644 --- a/dlls/winebth.sys/unixlib.h +++ b/dlls/winebth.sys/unixlib.h @@ -65,6 +65,12 @@ struct bluetooth_adapter_set_prop_params union winebluetooth_property *prop; };
+struct bluetooth_adapter_start_discovery_params +{ + unix_name_t adapter; + enum winebluetooth_discovery_transport transport; +}; + struct bluetooth_get_event_params { struct winebluetooth_event result; @@ -79,6 +85,8 @@ enum bluetoothapis_funcs unix_bluetooth_adapter_get_unique_name, unix_bluetooth_adapter_free,
+ unix_bluetooth_adapter_start_discovery, + unix_bluetooth_get_event,
unix_funcs_count diff --git a/dlls/winebth.sys/unixlib_priv.h b/dlls/winebth.sys/unixlib_priv.h index 5146799e705..7683af6ef2d 100644 --- a/dlls/winebth.sys/unixlib_priv.h +++ b/dlls/winebth.sys/unixlib_priv.h @@ -50,6 +50,8 @@ extern void bluez_dbus_free( void *connection ); extern NTSTATUS bluez_dbus_loop( void *connection, void *watcher_ctx, struct winebluetooth_event *result ); extern NTSTATUS bluez_adapter_set_prop( void *connection, struct bluetooth_adapter_set_prop_params *params ); +extern NTSTATUS bluez_adapter_start_discovery( void *connection, const char *adapter_path, + enum winebluetooth_discovery_transport transport ); extern NTSTATUS bluez_watcher_init( void *connection, void **ctx ); extern void bluez_watcher_close( void *connection, void *ctx ); #endif /* __WINE_WINEBTH_UNIXLIB_PRIV_H */ diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c index faf3b387aef..7f321c8348e 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -82,6 +82,18 @@ NTSTATUS winebluetooth_radio_set_property( winebluetooth_radio_t radio, return STATUS_SUCCESS; }
+NTSTATUS winebluetooth_radio_start_discovery( winebluetooth_radio_t radio, + enum winebluetooth_discovery_transport transport ) +{ + struct bluetooth_adapter_start_discovery_params params = {0}; + + TRACE( "(%p, %d)\n", (void *)radio.handle, transport ); + + params.adapter = radio.handle; + params.transport = transport; + return UNIX_BLUETOOTH_CALL( bluetooth_adapter_start_discovery, ¶ms ); +} + void winebluetooth_radio_free( winebluetooth_radio_t radio ) { struct bluetooth_adapter_free_params args = { 0 }; diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index e5ae08d4b32..71bcc7b3ca9 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <assert.h>
+#define WINE_BTH_EXTENSIONS #include <ntstatus.h> #define WIN32_NO_STATUS #include <windef.h> @@ -168,6 +169,33 @@ static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) } break; } + case IOCTL_WINEBTH_RADIO_START_DISCOVERY: + { + struct winebth_radio_start_discovery_params *filter = irp->AssociatedIrp.SystemBuffer; + enum winebluetooth_discovery_transport transport; + + if (!filter) + { + status = STATUS_INVALID_PARAMETER; + break; + } + if (insize < sizeof(*filter)) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + if (filter->le && filter->bredr) + transport = WINEBLUETOOTH_DISCOVERY_TRANSPORT_AUTO; + else if (filter->le) + transport = WINEBLUETOOTH_DISCOVERY_TRANSPORT_LE; + else if (filter->bredr) + transport = WINEBLUETOOTH_DISCOVERY_TRANSPORT_BR_EDR; + else + transport = WINEBLUETOOTH_DISCOVERY_TRANSPORT_DEFAULT; + status = winebluetooth_radio_start_discovery( ext->radio, transport ); + break; + } default: FIXME( "Unimplemented IOCTL code: %#lx\n", code ); break; diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 06dc3a8b799..1f9f74bf5a7 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -154,6 +154,14 @@ struct winebluetooth_radio_properties BYTE version; };
+enum winebluetooth_discovery_transport +{ + WINEBLUETOOTH_DISCOVERY_TRANSPORT_DEFAULT, + WINEBLUETOOTH_DISCOVERY_TRANSPORT_AUTO, + WINEBLUETOOTH_DISCOVERY_TRANSPORT_BR_EDR, + WINEBLUETOOTH_DISCOVERY_TRANSPORT_LE +}; + NTSTATUS winebluetooth_radio_get_unique_name( winebluetooth_radio_t radio, char *name, SIZE_T *size ); void winebluetooth_radio_free( winebluetooth_radio_t radio ); @@ -164,6 +172,8 @@ static inline BOOL winebluetooth_radio_equal( winebluetooth_radio_t r1, wineblue NTSTATUS winebluetooth_radio_set_property( winebluetooth_radio_t radio, winebluetooth_radio_props_mask_t prop, union winebluetooth_property *property ); +NTSTATUS winebluetooth_radio_start_discovery( winebluetooth_radio_t radio, + enum winebluetooth_discovery_transport transport );
enum winebluetooth_watcher_event_type { diff --git a/include/wine/winebth.h b/include/wine/winebth.h index c26a2100fb9..94812a345a2 100644 --- a/include/wine/winebth.h +++ b/include/wine/winebth.h @@ -25,6 +25,8 @@ /* Set the discoverability or connectable flag for a local radio. Enabling discoverability will also enable incoming * connections, while disabling incoming connections disables discoverability as well. */ #define IOCTL_WINEBTH_RADIO_SET_FLAG CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xa3, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* Start and stop the device inquiry procedure for a local radio. */ +#define IOCTL_WINEBTH_RADIO_START_DISCOVERY CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xa6, METHOD_BUFFERED, FILE_ANY_ACCESS)
#include <pshpack1.h>
@@ -37,6 +39,12 @@ struct winebth_radio_set_flag_params unsigned int enable : 1; };
+struct winebth_radio_start_discovery_params +{ + unsigned int bredr : 1; + unsigned int le : 1; +}; + #include <poppack.h>
#endif /* __WINEBTH_H__ */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 29 +++++++++++++++++++++++++++++ dlls/winebth.sys/unixlib.c | 9 +++++++++ dlls/winebth.sys/unixlib.h | 6 ++++++ dlls/winebth.sys/unixlib_priv.h | 1 + dlls/winebth.sys/winebluetooth.c | 9 +++++++++ dlls/winebth.sys/winebth.c | 3 +++ dlls/winebth.sys/winebth_priv.h | 1 + include/wine/winebth.h | 1 + 8 files changed, 59 insertions(+)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 19f25e517d9..c911e26550b 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -378,6 +378,35 @@ NTSTATUS bluez_adapter_start_discovery( void *connection, const char *adapter_pa return STATUS_SUCCESS; }
+NTSTATUS bluez_adapter_stop_discovery( void *connection, const char *adapter_path ) +{ + DBusMessage *request, *reply; + DBusError error; + + TRACE( "(%p, %s)\n", connection, debugstr_a( adapter_path ) ); + + request = p_dbus_message_new_method_call( BLUEZ_DEST, adapter_path, BLUEZ_INTERFACE_ADAPTER, + "StopDiscovery" ); + if (!request) return STATUS_NO_MEMORY; + + p_dbus_error_init( &error ); + reply = + p_dbus_connection_send_with_reply_and_block( connection, request, bluez_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + NTSTATUS status; + ERR( "Failed to stop discovery on adapter %s: %s: %s", debugstr_a( adapter_path ), + debugstr_a( error.message ), debugstr_a( error.name ) ); + status = bluez_dbus_error_to_ntstatus( &error ); + p_dbus_error_free( &error ); + return status; + } + p_dbus_error_free( &error ); + p_dbus_message_unref( reply ); + return STATUS_SUCCESS; +} + NTSTATUS bluez_adapter_set_prop( void *connection, struct bluetooth_adapter_set_prop_params *params ) { DBusMessage *request, *reply; diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index 6009f7f3af1..e42707ce3ba 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -172,6 +172,14 @@ static NTSTATUS bluetooth_adapter_start_discovery( void *args ) params->transport ); }
+static NTSTATUS bluetooth_adapter_stop_discovery( void *args ) +{ + struct bluetooth_adapter_stop_discovery_params *params = args; + + if (!dbus_connection) return STATUS_NOT_SUPPORTED; + return bluez_adapter_stop_discovery( dbus_connection, params->adapter->str ); +} + static NTSTATUS bluetooth_get_event( void *args ) { struct bluetooth_get_event_params *params = args; @@ -190,6 +198,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { bluetooth_adapter_free,
bluetooth_adapter_start_discovery, + bluetooth_adapter_stop_discovery,
bluetooth_get_event, }; diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h index 8d10f1d8adb..5393989df4f 100644 --- a/dlls/winebth.sys/unixlib.h +++ b/dlls/winebth.sys/unixlib.h @@ -71,6 +71,11 @@ struct bluetooth_adapter_start_discovery_params enum winebluetooth_discovery_transport transport; };
+struct bluetooth_adapter_stop_discovery_params +{ + unix_name_t adapter; +}; + struct bluetooth_get_event_params { struct winebluetooth_event result; @@ -86,6 +91,7 @@ enum bluetoothapis_funcs unix_bluetooth_adapter_free,
unix_bluetooth_adapter_start_discovery, + unix_bluetooth_adapter_stop_discovery,
unix_bluetooth_get_event,
diff --git a/dlls/winebth.sys/unixlib_priv.h b/dlls/winebth.sys/unixlib_priv.h index 7683af6ef2d..5a5212ed8c1 100644 --- a/dlls/winebth.sys/unixlib_priv.h +++ b/dlls/winebth.sys/unixlib_priv.h @@ -52,6 +52,7 @@ extern NTSTATUS bluez_adapter_set_prop( void *connection, struct bluetooth_adapter_set_prop_params *params ); extern NTSTATUS bluez_adapter_start_discovery( void *connection, const char *adapter_path, enum winebluetooth_discovery_transport transport ); +extern NTSTATUS bluez_adapter_stop_discovery( void *connection, const char *adapter_path ); extern NTSTATUS bluez_watcher_init( void *connection, void **ctx ); extern void bluez_watcher_close( void *connection, void *ctx ); #endif /* __WINE_WINEBTH_UNIXLIB_PRIV_H */ diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c index 7f321c8348e..1e93d95ac72 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -94,6 +94,15 @@ NTSTATUS winebluetooth_radio_start_discovery( winebluetooth_radio_t radio, return UNIX_BLUETOOTH_CALL( bluetooth_adapter_start_discovery, ¶ms ); }
+NTSTATUS winebluetooth_radio_stop_discovery( winebluetooth_radio_t radio ) +{ + struct bluetooth_adapter_stop_discovery_params params = {0}; + + TRACE( "(%p)\n", (void *)radio.handle ); + params.adapter = radio.handle; + return UNIX_BLUETOOTH_CALL(bluetooth_adapter_stop_discovery, ¶ms); +} + void winebluetooth_radio_free( winebluetooth_radio_t radio ) { struct bluetooth_adapter_free_params args = { 0 }; diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 71bcc7b3ca9..4513f85ed67 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -196,6 +196,9 @@ static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) status = winebluetooth_radio_start_discovery( ext->radio, transport ); break; } + case IOCTL_WINEBTH_RADIO_STOP_DISCOVERY: + status = winebluetooth_radio_stop_discovery( ext->radio ); + break; default: FIXME( "Unimplemented IOCTL code: %#lx\n", code ); break; diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 1f9f74bf5a7..20b54e23dea 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -174,6 +174,7 @@ NTSTATUS winebluetooth_radio_set_property( winebluetooth_radio_t radio, union winebluetooth_property *property ); NTSTATUS winebluetooth_radio_start_discovery( winebluetooth_radio_t radio, enum winebluetooth_discovery_transport transport ); +NTSTATUS winebluetooth_radio_stop_discovery( winebluetooth_radio_t radio );
enum winebluetooth_watcher_event_type { diff --git a/include/wine/winebth.h b/include/wine/winebth.h index 94812a345a2..f04587e8f4b 100644 --- a/include/wine/winebth.h +++ b/include/wine/winebth.h @@ -27,6 +27,7 @@ #define IOCTL_WINEBTH_RADIO_SET_FLAG CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xa3, METHOD_BUFFERED, FILE_ANY_ACCESS) /* Start and stop the device inquiry procedure for a local radio. */ #define IOCTL_WINEBTH_RADIO_START_DISCOVERY CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xa6, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINEBTH_RADIO_STOP_DISCOVERY CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xa7, METHOD_BUFFERED, FILE_ANY_ACCESS)
#include <pshpack1.h>
From: Vibhav Pant vibhavp@gmail.com
This frees all associated resources with the watcher, including events and initial devices that were not consumed by the PE driver. --- dlls/winebth.sys/dbus.c | 59 ++++++++++++++++++++++++++++++++------ dlls/winebth.sys/unixlib.c | 1 + 2 files changed, 51 insertions(+), 9 deletions(-)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index c911e26550b..f9754309ee5 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -613,6 +613,14 @@ struct bluez_watcher_ctx struct list event_list; };
+struct bluez_init_entry +{ + union { + struct winebluetooth_watcher_event_radio_added radio; + } object; + struct list entry; +}; + void *bluez_dbus_init( void ) { DBusError error; @@ -984,6 +992,47 @@ static const char BLUEZ_MATCH_PROPERTIES[] = "type='signal',"
static const char *BLUEZ_MATCH_RULES[] = { BLUEZ_MATCH_OBJECTMANAGER, BLUEZ_MATCH_PROPERTIES };
+static void bluez_watcher_free( void *data ) +{ + struct bluez_watcher_ctx *watcher = data; + struct bluez_watcher_event *event1, *event2; + struct bluez_init_entry *entry1, *entry2; + + if (watcher->init_device_list_call) + { + p_dbus_pending_call_cancel( watcher->init_device_list_call ); + p_dbus_pending_call_unref( watcher->init_device_list_call ); + } + + LIST_FOR_EACH_ENTRY_SAFE( entry1, entry2, &watcher->initial_radio_list, struct bluez_init_entry, entry ) + { + list_remove( &entry1->entry ); + unix_name_free( (struct unix_name *)entry1->object.radio.radio.handle ); + free( entry1 ); + } + + LIST_FOR_EACH_ENTRY_SAFE( event1, event2, &watcher->event_list, struct bluez_watcher_event, entry ) + { + list_remove( &event1->entry ); + switch (event1->event_type) + { + case BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED: + unix_name_free( (struct unix_name *)event1->event.radio_added.radio.handle ); + break; + case BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_REMOVED: + unix_name_free( (struct unix_name *)event1->event.radio_removed.handle ); + break; + case BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED: + unix_name_free( (struct unix_name *)event1->event.radio_props_changed.radio.handle ); + break; + } + free( event1 ); + } + + pthread_mutex_destroy( &watcher->event_lists_lock ); + free( watcher ); +} + NTSTATUS bluez_watcher_init( void *connection, void **ctx ) { DBusError err; @@ -1007,7 +1056,7 @@ NTSTATUS bluez_watcher_init( void *connection, void **ctx )
list_init( &watcher_ctx->event_list );
- if (!p_dbus_connection_add_filter( connection, bluez_filter, watcher_ctx, free )) + if (!p_dbus_connection_add_filter( connection, bluez_filter, watcher_ctx, bluez_watcher_free )) { p_dbus_pending_call_cancel( call ); p_dbus_pending_call_unref( call ); @@ -1056,14 +1105,6 @@ void bluez_watcher_close( void *connection, void *ctx ) p_dbus_connection_remove_filter( connection, bluez_filter, ctx ); }
-struct bluez_init_entry -{ - union { - struct winebluetooth_watcher_event_radio_added radio; - } object; - struct list entry; -}; - static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct list *adapter_list ) { DBusMessageIter dict, paths_iter, iface_iter, prop_iter; diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index e42707ce3ba..28d12f1e2e0 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -114,6 +114,7 @@ static NTSTATUS bluetooth_shutdown( void *params ) { if (!dbus_connection) return STATUS_NOT_SUPPORTED;
+ bluez_watcher_close( dbus_connection, bluetooth_watcher ); bluez_dbus_close( dbus_connection ); bluez_dbus_free( dbus_connection ); return STATUS_SUCCESS;