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
-- v6: winebth.sys: Call bluez_watcher_close as part of bluetooth_shutdown. winebth.sys: Implement IOCTL_WINEBTH_RADIO_STOP_DISCOVERY. winebth.sys: Implement IOCTL_WINEBTH_RADIO_START_DISCOVERY. winebth.sys: Implement IOCTL_WINEBTH_RADIO_SET_FLAG.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 93 ++++++++++++++++++++++++++++++++ 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, 238 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..999fc98076b 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, @@ -977,5 +1066,9 @@ NTSTATUS bluez_dbus_loop( void *c, void *watcher, struct winebluetooth_event *re { return STATUS_NOT_SUPPORTED; } +NTSTATUS bluez_adapter_set_prop( void *connection, struct bluetooth_adapter_set_prop_params *params ) +{ + return STATUS_NOT_SUPPORTED; +}
#endif /* SONAME_LIBDBUS_1 */ 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 | 160 +++++++++++++++++++++++++++++-- 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 | 27 ++++++ dlls/winebth.sys/winebth_priv.h | 10 ++ include/wine/winebth.h | 8 ++ 8 files changed, 229 insertions(+), 9 deletions(-)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 999fc98076b..51223267ea4 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) { @@ -1070,5 +1207,10 @@ NTSTATUS bluez_adapter_set_prop( void *connection, struct bluetooth_adapter_set_ { return STATUS_NOT_SUPPORTED; } +NTSTATUS bluez_adapter_start_discovery( void *connection, const char *adapter_path, + enum winebluetooth_discovery_transport transport ) +{ + return STATUS_NOT_SUPPORTED; +}
#endif /* SONAME_LIBDBUS_1 */ 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..245268e8a8f 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -168,6 +168,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 | 33 ++++++++++++++++++++++++++++++++ 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, 63 insertions(+)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 51223267ea4..176b6115bb4 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; @@ -1212,5 +1241,9 @@ NTSTATUS bluez_adapter_start_discovery( void *connection, const char *adapter_pa { return STATUS_NOT_SUPPORTED; } +NTSTATUS bluez_adapter_stop_discovery( void *connection, const char *adapter_path ) +{ + return STATUS_NOT_SUPPORTED; +}
#endif /* SONAME_LIBDBUS_1 */ 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 245268e8a8f..b1c2c770189 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -195,6 +195,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 | 64 ++++++++++++++++++++++++++++++++------ dlls/winebth.sys/unixlib.c | 1 + 2 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 176b6115bb4..180d73ed825 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 };
+/* Free up the watcher alongside any remaining events and initial devices and other associated resources. */ +static void bluez_watcher_free( struct bluez_watcher_ctx *watcher ) +{ + 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,10 @@ 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 )) + /* The bluez_dbus_loop thread will free up the watcher when the disconnect message is processed (i.e, + * dbus_connection_read_write_dispatch returns false). Using a free-function with dbus_connection_add_filter + * is racy as the filter is removed from a different thread. */ + if (!p_dbus_connection_add_filter( connection, bluez_filter, watcher_ctx, NULL )) { p_dbus_pending_call_cancel( call ); p_dbus_pending_call_unref( call ); @@ -1056,14 +1108,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; @@ -1184,6 +1228,7 @@ NTSTATUS bluez_dbus_loop( void *c, void *watcher, } else if (!p_dbus_connection_read_write_dispatch( connection, 100 )) { + bluez_watcher_free( watcher_ctx ); p_dbus_connection_unref( connection ); TRACE( "Disconnected from DBus\n" ); return STATUS_SUCCESS; @@ -1228,6 +1273,7 @@ void *bluez_dbus_init( void ) { return NULL; } void bluez_dbus_close( void *connection ) {} void bluez_dbus_free( void *connection ) {} NTSTATUS bluez_watcher_init( void *connection, void **ctx ) { return STATUS_NOT_SUPPORTED; } +void bluez_watcher_close( void *connection, void *ctx ) {} NTSTATUS bluez_dbus_loop( void *c, void *watcher, struct winebluetooth_event *result ) { return STATUS_NOT_SUPPORTED; diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index e42707ce3ba..0282fe8c956 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -115,6 +115,7 @@ static NTSTATUS bluetooth_shutdown( void *params ) if (!dbus_connection) return STATUS_NOT_SUPPORTED;
bluez_dbus_close( dbus_connection ); + bluez_watcher_close( dbus_connection, bluetooth_watcher ); bluez_dbus_free( dbus_connection ); return STATUS_SUCCESS; }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=151138
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: input.c:4306: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 00000000011900EE, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
Entirely cosmetic detail: in some files you're updating the copyright by appending a line for 2025, others changing 2024 to "2024-2025".
On Thu Jan 30 13:05:39 2025 +0000, William Horvath wrote:
Entirely cosmetic detail: in some files you're updating the copyright by appending a line for 2025, others changing 2024 to "2024-2025".
Fixed it, thanks!