Disconnecting and removing remote devices hold device_list_cs before blocking on the DBus event loop, which may cause a deadlock if we receive a message from BlueZ whose handler also attempts to enter device_list_cs (Like BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED). To fix this, the device/radio handle is duplicated once found, device_list_cs is released, and the DBus method call is made using the duplicate handle(s), which are then freed normally.
Also, replace the two locks in `bluetooth_radio` with `device_list_cs` instead.
-- v2: winebth.sys: Fix potential deadlocks while performing operations that block on the DBus event loop. winebth.sys: Unify critical sections used for bluetooth_radio.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/winebth.c | 87 ++++++++++++-------------------------- 1 file changed, 27 insertions(+), 60 deletions(-)
diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 32cc6300958..60e6d98dcaf 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -76,17 +76,15 @@ struct bluetooth_radio BOOL removed;
DEVICE_OBJECT *device_obj; - CRITICAL_SECTION props_cs; - winebluetooth_radio_props_mask_t props_mask; /* Guarded by props_cs */ - struct winebluetooth_radio_properties props; /* Guarded by props_cs */ - BOOL started; /* Guarded by props_cs */ + winebluetooth_radio_props_mask_t props_mask; /* Guarded by device_list_cs */ + struct winebluetooth_radio_properties props; /* Guarded by device_list_cs */ + BOOL started; /* Guarded by device_list_cs */ winebluetooth_radio_t radio; WCHAR *hw_name; UNICODE_STRING bthport_symlink_name; UNICODE_STRING bthradio_symlink_name;
- CRITICAL_SECTION remote_devices_cs; - struct list remote_devices; /* Guarded by remote_devices_cs */ + struct list remote_devices; /* Guarded by device_list_cs */
/* Guarded by device_list_cs */ LIST_ENTRY irp_list; @@ -323,7 +321,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot
memset( info, 0, sizeof( *info ) );
- EnterCriticalSection( &ext->props_cs ); + EnterCriticalSection( &device_list_cs ); if (ext->props_mask & WINEBLUETOOTH_RADIO_PROPERTY_ADDRESS) { info->localInfo.flags |= BDIF_ADDRESS; @@ -347,7 +345,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot info->flags |= LOCAL_RADIO_DISCOVERABLE; if (ext->props_mask & WINEBLUETOOTH_RADIO_PROPERTY_MANUFACTURER) info->radioInfo.mfg = ext->props.manufacturer; - LeaveCriticalSection( &ext->props_cs ); + LeaveCriticalSection( &device_list_cs );
irp->IoStatus.Information = sizeof( *info ); status = STATUS_SUCCESS; @@ -375,7 +373,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot irp->IoStatus.Information = 0; list->numOfDevices = 0;
- EnterCriticalSection( &ext->remote_devices_cs ); + EnterCriticalSection( &device_list_cs ); LIST_FOR_EACH_ENTRY( device, &ext->remote_devices, struct bluetooth_remote_device, entry ) { list->numOfDevices++; @@ -394,7 +392,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot rem_devices--; } } - LeaveCriticalSection( &ext->remote_devices_cs ); + LeaveCriticalSection( &device_list_cs );
irp->IoStatus.Information += sizeof( *list ); if (list->numOfDevices) @@ -420,7 +418,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot device_addr = RtlUlonglongByteSwap( *param ) >> 16; status = STATUS_DEVICE_NOT_CONNECTED;
- EnterCriticalSection( &ext->remote_devices_cs ); + EnterCriticalSection( &device_list_cs ); LIST_FOR_EACH_ENTRY( device, &ext->remote_devices, struct bluetooth_remote_device, entry ) { BOOL matches; @@ -435,7 +433,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot break; } } - LeaveCriticalSection( &ext->remote_devices_cs ); + LeaveCriticalSection( &device_list_cs ); break; } case IOCTL_WINEBTH_RADIO_SET_FLAG: @@ -486,7 +484,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot }
status = STATUS_DEVICE_NOT_CONNECTED; - EnterCriticalSection( &ext->remote_devices_cs ); + EnterCriticalSection( &device_list_cs ); LIST_FOR_EACH_ENTRY( device, &ext->remote_devices, struct bluetooth_remote_device, entry ) { BOOL matches; @@ -506,7 +504,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot } if (!status) irp->IoStatus.Information = sizeof( *params ); - LeaveCriticalSection( &ext->remote_devices_cs ); + LeaveCriticalSection( &device_list_cs ); break; } case IOCTL_WINEBTH_RADIO_START_AUTH: @@ -527,7 +525,6 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot
status = STATUS_DEVICE_DOES_NOT_EXIST; EnterCriticalSection( &device_list_cs ); - EnterCriticalSection( &ext->remote_devices_cs ); LIST_FOR_EACH_ENTRY( device, &ext->remote_devices, struct bluetooth_remote_device, entry ) { BOOL matches; @@ -546,7 +543,6 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot break; } } - LeaveCriticalSection( &ext->remote_devices_cs ); LeaveCriticalSection( &device_list_cs ); break; } @@ -567,7 +563,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot }
status = STATUS_NOT_FOUND; - EnterCriticalSection( &ext->remote_devices_cs ); + EnterCriticalSection( &device_list_cs ); LIST_FOR_EACH_ENTRY( device, &ext->remote_devices, struct bluetooth_remote_device, entry ) { BOOL matches; @@ -582,7 +578,7 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot break; } } - LeaveCriticalSection( &ext->remote_devices_cs ); + LeaveCriticalSection( &device_list_cs ); break; } default: @@ -725,8 +721,6 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added ext->radio.started = FALSE; list_init( &ext->radio.remote_devices );
- InitializeCriticalSection( &ext->radio.props_cs ); - InitializeCriticalSection( &ext->radio.remote_devices_cs ); InitializeListHead( &ext->radio.irp_list );
EnterCriticalSection( &device_list_cs ); @@ -772,7 +766,6 @@ static void update_bluetooth_radio_properties( struct winebluetooth_watcher_even { if (winebluetooth_radio_equal( radio, device->radio ) && !device->removed) { - EnterCriticalSection( &device->props_cs ); device->props_mask |= event.changed_props_mask; device->props_mask &= ~event.invalid_props_mask;
@@ -797,7 +790,6 @@ static void update_bluetooth_radio_properties( struct winebluetooth_watcher_even if (device->started) bluetooth_radio_set_properties( device->device_obj, device->props_mask, &device->props ); - LeaveCriticalSection( &device->props_cs ); break; } } @@ -861,7 +853,8 @@ static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_even ext->remote_device.radio = radio;
ext->remote_device.device_obj = device_obj; - InitializeCriticalSection( &ext->remote_device.props_cs ); + InitializeCriticalSectionEx( &ext->remote_device.props_cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); + ext->remote_device.props_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": bluetooth_pdo_ext.props_cs"); ext->remote_device.device = event.device; ext->remote_device.props_mask = event.known_props_mask; ext->remote_device.props = event.props; @@ -878,9 +871,7 @@ static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_even bluetooth_radio_report_radio_in_range_event( radio->device_obj, 0, &device_info ); }
- EnterCriticalSection( &radio->remote_devices_cs ); list_add_tail( &radio->remote_devices, &ext->remote_device.entry ); - LeaveCriticalSection( &radio->remote_devices_cs ); IoInvalidateDeviceRelations( radio->device_obj, BusRelations ); break; } @@ -899,7 +890,6 @@ static void bluetooth_radio_remove_remote_device( struct winebluetooth_watcher_e { struct bluetooth_remote_device *device, *next;
- EnterCriticalSection( &radio->remote_devices_cs ); LIST_FOR_EACH_ENTRY_SAFE( device, next, &radio->remote_devices, struct bluetooth_remote_device, entry ) { if (winebluetooth_device_equal( event.device, device->device )) @@ -939,14 +929,12 @@ static void bluetooth_radio_remove_remote_device( struct winebluetooth_watcher_e ExFreePool( notification ); } } - LeaveCriticalSection( &radio->remote_devices_cs ); LeaveCriticalSection( &device_list_cs ); IoInvalidateDeviceRelations( radio->device_obj, BusRelations ); winebluetooth_device_free( event.device ); return; } } - LeaveCriticalSection( &radio->remote_devices_cs ); } LeaveCriticalSection( &device_list_cs ); winebluetooth_device_free( event.device ); @@ -1015,7 +1003,6 @@ static void bluetooth_radio_update_device_props( struct winebluetooth_watcher_ev { struct bluetooth_remote_device *device;
- EnterCriticalSection( &radio->remote_devices_cs ); LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry ) { if (winebluetooth_device_equal( event.device, device->device )) @@ -1024,9 +1011,7 @@ static void bluetooth_radio_update_device_props( struct winebluetooth_watcher_ev BLUETOOTH_ADDRESS adapter_addr;
radio_obj = radio->device_obj; - EnterCriticalSection( &radio->props_cs ); adapter_addr = radio->props.address; - LeaveCriticalSection( &radio->props_cs );
EnterCriticalSection( &device->props_cs ); winebluetooth_device_properties_to_info( device->props_mask, &device->props, &old_info ); @@ -1050,13 +1035,11 @@ static void bluetooth_radio_update_device_props( struct winebluetooth_watcher_ev winebluetooth_device_properties_to_info( device->props_mask, &device->props, &device_new_info ); bluetooth_device_set_properties( device, adapter_addr.rgBytes, &device->props, device->props_mask ); LeaveCriticalSection( &device->props_cs ); - LeaveCriticalSection( &radio->remote_devices_cs );
device_old_flags = old_info.flags; goto done; } } - LeaveCriticalSection( &radio->remote_devices_cs ); } done: winebluetooth_device_free( event.device ); @@ -1094,7 +1077,6 @@ static void bluetooth_radio_report_auth_event( struct winebluetooth_auth_event e { struct bluetooth_remote_device *device;
- EnterCriticalSection( &radio->remote_devices_cs ); LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry ) { if (winebluetooth_device_equal( event.device, device->device )) @@ -1104,7 +1086,6 @@ static void bluetooth_radio_report_auth_event( struct winebluetooth_auth_event e EnterCriticalSection( &device->props_cs ); winebluetooth_device_properties_to_info( device->props_mask, &device->props, &request->device_info ); LeaveCriticalSection( &device->props_cs ); - LeaveCriticalSection( &radio->remote_devices_cs ); LeaveCriticalSection( &device_list_cs );
ret = IoReportTargetDeviceChange( device_auth, notification ); @@ -1115,7 +1096,6 @@ static void bluetooth_radio_report_auth_event( struct winebluetooth_auth_event e return; } } - LeaveCriticalSection( &radio->remote_devices_cs ); } LeaveCriticalSection( &device_list_cs );
@@ -1165,7 +1145,6 @@ static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_even { struct bluetooth_remote_device *device;
- EnterCriticalSection( &radio->remote_devices_cs ); LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry ) { if (winebluetooth_device_equal( event.device, device->device ) && !device->removed) @@ -1178,7 +1157,6 @@ static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_even service = calloc( 1, sizeof( *service ) ); if (!service) { - LeaveCriticalSection( &radio->remote_devices_cs ); LeaveCriticalSection( &device_list_cs ); return; } @@ -1190,18 +1168,16 @@ static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_even bluetooth_device_enable_le_iface( device ); list_init( &service->characteristics ); InitializeCriticalSectionEx( &service->chars_cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); - service->chars_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": bluetooth_gatt_service.chars_le"); + service->chars_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": bluetooth_gatt_service.chars_cs");
EnterCriticalSection( &device->props_cs ); list_add_tail( &device->gatt_services, &service->entry ); LeaveCriticalSection( &device->props_cs ); - LeaveCriticalSection( &radio->remote_devices_cs ); LeaveCriticalSection( &device_list_cs ); winebluetooth_device_free( event.device ); return; } } - LeaveCriticalSection( &radio->remote_devices_cs ); } LeaveCriticalSection( &device_list_cs );
@@ -1218,7 +1194,6 @@ static void bluetooth_gatt_service_remove( winebluetooth_gatt_service_t service { struct bluetooth_remote_device *device;
- EnterCriticalSection( &radio->remote_devices_cs ); LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry ) { struct bluetooth_gatt_service *svc; @@ -1237,7 +1212,6 @@ static void bluetooth_gatt_service_remove( winebluetooth_gatt_service_t service
list_remove( &svc->entry ); LeaveCriticalSection( &device->props_cs ); - LeaveCriticalSection( &radio->remote_devices_cs ); LeaveCriticalSection( &device_list_cs ); winebluetooth_gatt_service_free( svc->service ); svc->chars_cs.DebugInfo->Spare[0] = 0; @@ -1254,7 +1228,6 @@ static void bluetooth_gatt_service_remove( winebluetooth_gatt_service_t service } LeaveCriticalSection( &device->props_cs ); } - LeaveCriticalSection( &radio->remote_devices_cs ); } LeaveCriticalSection( &device_list_cs ); winebluetooth_gatt_service_free( service ); @@ -1270,7 +1243,6 @@ bluetooth_gatt_service_add_characteristic( struct winebluetooth_watcher_event_ga { struct bluetooth_remote_device *device;
- EnterCriticalSection( &radio->remote_devices_cs ); LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry ) { struct bluetooth_gatt_service *svc; @@ -1290,7 +1262,6 @@ bluetooth_gatt_service_add_characteristic( struct winebluetooth_watcher_event_ga if (!(entry = calloc( 1, sizeof( *entry ) ))) { LeaveCriticalSection( &device->props_cs ); - LeaveCriticalSection( &radio->remote_devices_cs ); goto failed; }
@@ -1302,7 +1273,6 @@ bluetooth_gatt_service_add_characteristic( struct winebluetooth_watcher_event_ga entry->props = characteristic.props; list_add_tail( &svc->characteristics, &entry->entry ); LeaveCriticalSection( &device->props_cs ); - LeaveCriticalSection( &radio->remote_devices_cs ); LeaveCriticalSection( &device_list_cs ); winebluetooth_gatt_service_free( characteristic.service ); return; @@ -1310,7 +1280,6 @@ bluetooth_gatt_service_add_characteristic( struct winebluetooth_watcher_event_ga } LeaveCriticalSection( &device->props_cs ); } - LeaveCriticalSection( &radio->remote_devices_cs ); } failed: LeaveCriticalSection( &device_list_cs ); @@ -1327,7 +1296,6 @@ static void bluetooth_gatt_characteristic_remove( winebluetooth_gatt_characteris { struct bluetooth_remote_device *device;
- EnterCriticalSection( &radio->remote_devices_cs ); LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry ) { struct bluetooth_gatt_service *svc; @@ -1349,7 +1317,6 @@ static void bluetooth_gatt_characteristic_remove( winebluetooth_gatt_characteris list_remove( &chrc->entry ); LeaveCriticalSection( &svc->chars_cs ); LeaveCriticalSection( &device->props_cs ); - LeaveCriticalSection( &radio->remote_devices_cs ); LeaveCriticalSection( &device_list_cs );
winebluetooth_gatt_characteristic_free( chrc->characteristic ); @@ -1362,7 +1329,6 @@ static void bluetooth_gatt_characteristic_remove( winebluetooth_gatt_characteris } LeaveCriticalSection( &device->props_cs ); } - LeaveCriticalSection( &radio->remote_devices_cs ); } LeaveCriticalSection( &device_list_cs ); winebluetooth_gatt_characteristic_free( handle ); @@ -1642,6 +1608,7 @@ static void remote_device_destroy( struct bluetooth_remote_device *ext ) IoSetDeviceInterfaceState( &ext->bthle_symlink_name, FALSE ); RtlFreeUnicodeString( &ext->bthle_symlink_name ); } + ext->props_cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &ext->props_cs ); winebluetooth_device_free( ext->device ); LIST_FOR_EACH_ENTRY_SAFE( svc, next, &ext->gatt_services, struct bluetooth_gatt_service, entry ) @@ -1679,9 +1646,9 @@ static NTSTATUS WINAPI remote_device_pdo_pnp( DEVICE_OBJECT *device_obj, struct { BLUETOOTH_ADDRESS adapter_addr;
- EnterCriticalSection( &ext->radio->props_cs ); + EnterCriticalSection( &device_list_cs ); adapter_addr = ext->radio->props.address; - LeaveCriticalSection( &ext->radio->props_cs ); + LeaveCriticalSection( &device_list_cs );
EnterCriticalSection( &ext->props_cs ); if (ext->le && @@ -1703,13 +1670,13 @@ static NTSTATUS WINAPI remote_device_pdo_pnp( DEVICE_OBJECT *device_obj, struct } case IRP_MN_SURPRISE_REMOVAL: { - EnterCriticalSection( &ext->radio->remote_devices_cs ); + EnterCriticalSection( &device_list_cs); if (!ext->removed) { ext->removed = TRUE; list_remove( &ext->entry ); } - LeaveCriticalSection( &ext->radio->remote_devices_cs ); + LeaveCriticalSection( &device_list_cs ); ret = STATUS_SUCCESS; break; } @@ -1747,12 +1714,12 @@ static NTSTATUS WINAPI radio_pdo_pnp( DEVICE_OBJECT *device_obj, struct bluetoot break; }
- EnterCriticalSection( &device->remote_devices_cs ); + EnterCriticalSection( &device_list_cs ); devices = ExAllocatePool( PagedPool, offsetof( DEVICE_RELATIONS, Objects[list_count( &device->remote_devices )] ) ); if (!devices) { - LeaveCriticalSection( &device->remote_devices_cs ); + LeaveCriticalSection( &device_list_cs ); irp->IoStatus.Status = STATUS_NO_MEMORY; break; } @@ -1761,7 +1728,7 @@ static NTSTATUS WINAPI radio_pdo_pnp( DEVICE_OBJECT *device_obj, struct bluetoot devices->Objects[i++] = remote_device->device_obj; call_fastcall_func1( ObfReferenceObject, remote_device->device_obj ); } - LeaveCriticalSection( &device->remote_devices_cs ); + LeaveCriticalSection( &device_list_cs );
devices->Count = i; irp->IoStatus.Information = (ULONG_PTR)devices; @@ -1781,10 +1748,10 @@ static NTSTATUS WINAPI radio_pdo_pnp( DEVICE_OBJECT *device_obj, struct bluetoot break; } case IRP_MN_START_DEVICE: - EnterCriticalSection( &device->props_cs ); + EnterCriticalSection( &device_list_cs ); bluetooth_radio_set_properties( device_obj, device->props_mask, &device->props ); device->started = TRUE; - LeaveCriticalSection( &device->props_cs ); + LeaveCriticalSection( &device_list_cs );
if (IoRegisterDeviceInterface( device_obj, &GUID_BTHPORT_DEVICE_INTERFACE, NULL, &device->bthport_symlink_name ) == STATUS_SUCCESS)
From: Vibhav Pant vibhavp@gmail.com
Disconnecting and removing remote devices hold device_list_cs before blocking on the DBus event loop, which may cause a deadlock if we receive a message from BlueZ whose handler also attempts to enter device_list_cs (Like BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED). To fix this, the device/radio handle is duplicated once found, device_list_cs is released, and the DBus method call is made using the duplicate handle(s), which are then freed normally. --- dlls/winebth.sys/unixlib.c | 16 ++++++++++++++ dlls/winebth.sys/unixlib.h | 12 ++++++++++ dlls/winebth.sys/winebluetooth.c | 18 +++++++++++++++ dlls/winebth.sys/winebth.c | 38 ++++++++++++++++++++++---------- dlls/winebth.sys/winebth_priv.h | 2 ++ 5 files changed, 74 insertions(+), 12 deletions(-)
diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index 763f2f32346..8db70b8f8a5 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -177,6 +177,13 @@ static NTSTATUS bluetooth_adapter_free( void *args ) return STATUS_SUCCESS; }
+static NTSTATUS bluetooth_adapter_dup( void *args ) +{ + struct bluetooth_adapter_dup_params *params = args; + unix_name_dup( params->adapter ); + return STATUS_SUCCESS; +} + static NTSTATUS bluetooth_adapter_set_prop( void *arg ) { struct bluetooth_adapter_set_prop_params *params = arg; @@ -192,6 +199,13 @@ static NTSTATUS bluetooth_device_free( void *args ) return STATUS_SUCCESS; }
+static NTSTATUS bluetooth_device_dup( void *args ) +{ + struct bluetooth_device_dup_params *params = args; + unix_name_dup( params->device ); + return STATUS_SUCCESS; +} + static NTSTATUS bluetooth_adapter_start_discovery( void *args ) { struct bluetooth_adapter_start_discovery_params *params = args; @@ -282,8 +296,10 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { bluetooth_adapter_stop_discovery, bluetooth_adapter_remove_device, bluetooth_adapter_free, + bluetooth_adapter_dup,
bluetooth_device_free, + bluetooth_device_dup, bluetooth_device_disconnect, bluetooth_device_start_pairing,
diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h index 4629a7191d4..765003a5fc3 100644 --- a/dlls/winebth.sys/unixlib.h +++ b/dlls/winebth.sys/unixlib.h @@ -49,11 +49,21 @@ struct bluetooth_adapter_free_params unix_name_t adapter; };
+struct bluetooth_adapter_dup_params +{ + unix_name_t adapter; +}; + struct bluetooth_device_free_params { unix_name_t device; };
+struct bluetooth_device_dup_params +{ + unix_name_t device; +}; + struct bluetooth_gatt_service_free_params { unix_name_t service; @@ -132,8 +142,10 @@ enum bluetoothapis_funcs unix_bluetooth_adapter_stop_discovery, unix_bluetooth_adapter_remove_device, unix_bluetooth_adapter_free, + unix_bluetooth_adapter_dup,
unix_bluetooth_device_free, + unix_bluetooth_device_dup, unix_bluetooth_device_disconnect, unix_bluetooth_device_start_pairing,
diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c index 7762b0f3fd1..ec81a64ec3b 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -111,6 +111,15 @@ void winebluetooth_radio_free( winebluetooth_radio_t radio ) UNIX_BLUETOOTH_CALL( bluetooth_adapter_free, &args ); }
+void winebluetooth_radio_dup( winebluetooth_radio_t radio ) +{ + struct bluetooth_adapter_dup_params args = {0}; + TRACE( "(%p)\n", (void *)radio.handle ); + + args.adapter = radio.handle; + UNIX_BLUETOOTH_CALL( bluetooth_adapter_dup, &args ); +} + void winebluetooth_device_free( winebluetooth_device_t device ) { struct bluetooth_device_free_params args = {0}; @@ -120,6 +129,15 @@ void winebluetooth_device_free( winebluetooth_device_t device ) UNIX_BLUETOOTH_CALL( bluetooth_device_free, &args ); }
+void winebluetooth_device_dup( winebluetooth_device_t device ) +{ + struct bluetooth_device_dup_params args = {0}; + TRACE( "(%p)\n", (void *)device.handle ); + + args.device = device.handle; + UNIX_BLUETOOTH_CALL( bluetooth_device_dup, &args ); +} + NTSTATUS winebluetooth_device_disconnect( winebluetooth_device_t device ) { struct bluetooth_device_disconnect_params args = {0}; diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 60e6d98dcaf..7ecb52d11cc 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -406,8 +406,10 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot case IOCTL_BTH_DISCONNECT_DEVICE: { const BTH_ADDR *param = irp->AssociatedIrp.SystemBuffer; - BTH_ADDR device_addr; struct bluetooth_remote_device *device; + winebluetooth_device_t device_handle; + BTH_ADDR device_addr; + BOOL found = FALSE;
if (!param || insize < sizeof( *param )) { @@ -421,19 +423,22 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot EnterCriticalSection( &device_list_cs ); LIST_FOR_EACH_ENTRY( device, &ext->remote_devices, struct bluetooth_remote_device, entry ) { - BOOL matches; - EnterCriticalSection( &device->props_cs ); - matches = device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS && - device_addr == device->props.address.ullLong; + found = device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS && + device_addr == device->props.address.ullLong; LeaveCriticalSection( &device->props_cs ); - if (matches) + if (found) { - status = winebluetooth_device_disconnect( device->device ); + winebluetooth_device_dup(( device_handle = device->device )); break; } } LeaveCriticalSection( &device_list_cs ); + if (found) + { + status = winebluetooth_device_disconnect( device_handle ); + winebluetooth_device_free( device_handle ); + } break; } case IOCTL_WINEBTH_RADIO_SET_FLAG: @@ -550,6 +555,9 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot { const BTH_ADDR *param = irp->AssociatedIrp.SystemBuffer; struct bluetooth_remote_device *device; + winebluetooth_device_t device_handle; + winebluetooth_radio_t radio_handle; + BOOL found = FALSE;
if (!param) { @@ -566,19 +574,25 @@ static NTSTATUS bluetooth_radio_dispatch( DEVICE_OBJECT *device, struct bluetoot EnterCriticalSection( &device_list_cs ); LIST_FOR_EACH_ENTRY( device, &ext->remote_devices, struct bluetooth_remote_device, entry ) { - BOOL matches; EnterCriticalSection( &device->props_cs ); - matches = device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS && - device->props.address.ullLong == *param && device->props.paired; + found = device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS && + device->props.address.ullLong == *param && device->props.paired; LeaveCriticalSection( &device->props_cs );
- if (matches) + if (found) { - status = winebluetooth_radio_remove_device( ext->radio, device->device ); + winebluetooth_device_dup(( device_handle = device->device )); + winebluetooth_radio_dup(( radio_handle = ext->radio )); break; } } LeaveCriticalSection( &device_list_cs ); + if (found) + { + status = winebluetooth_radio_remove_device( radio_handle, device_handle ); + winebluetooth_device_free( device_handle ); + winebluetooth_radio_free( radio_handle ); + } break; } default: diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 34582ed3759..765fe1d55f7 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -221,6 +221,7 @@ typedef struct NTSTATUS winebluetooth_radio_get_unique_name( winebluetooth_radio_t radio, char *name, SIZE_T *size ); void winebluetooth_radio_free( winebluetooth_radio_t radio ); +void winebluetooth_radio_dup( winebluetooth_radio_t radio ); static inline BOOL winebluetooth_radio_equal( winebluetooth_radio_t r1, winebluetooth_radio_t r2 ) { return r1.handle == r2.handle; @@ -234,6 +235,7 @@ NTSTATUS winebluetooth_radio_remove_device( winebluetooth_radio_t radio, wineblu NTSTATUS winebluetooth_auth_agent_enable_incoming( void );
void winebluetooth_device_free( winebluetooth_device_t device ); +void winebluetooth_device_dup( winebluetooth_device_t device ); static inline BOOL winebluetooth_device_equal( winebluetooth_device_t d1, winebluetooth_device_t d2 ) { return d1.handle == d2.handle;