[PATCH 0/4] MR11084: winebth.sys: Expose GUID_BTH_DEVICE_INTERFACE for remote devices that support Bluetooth Classic
BlueZ exposes the `org.bluez.Bearer.LE1` and `org.bluez.Bearer.BREDR1` interfaces for devices that support Low Energy and Classic (BR/EDR) bearers respectively. This MR relays bearer information from unix to the PE driver, and enables `GUID_BTH_DEVICE_INTERFACE` for remote devices that support BR/EDR. Also, make the `GUID_BTH_DEVICE_INTERFACE`<span dir=""> and </span>`GUID_BLUETOOTHLE_DEVICE_INTERFACE`<span dir=""> interfaces expose </span>`BDIF_*`<span dir=""> flags through the property </span>`PKEY_DeviceInterface_Bluetooth_Flags`. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11084
From: Vibhav Pant <vibhavp@gmail.com> --- dlls/winebth.sys/dbus.c | 214 ++++++++++++++++++++++++++------ dlls/winebth.sys/winebth_priv.h | 14 +++ 2 files changed, 191 insertions(+), 37 deletions(-) diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index ba25d4ee988..e85ca5b7bf1 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -121,6 +121,8 @@ const int bluez_timeout = -1; #define BLUEZ_DEST "org.bluez" #define BLUEZ_INTERFACE_ADAPTER "org.bluez.Adapter1" #define BLUEZ_INTERFACE_DEVICE "org.bluez.Device1" +#define BLUEZ_INTERFACE_BEARER_BREDR "org.bluez.Bearer.BREDR1" +#define BLUEZ_INTERFACE_BEARER_LE "org.bluez.Bearer.LE1" #define BLUEZ_INTERFACE_AGENT_MANAGER "org.bluez.AgentManager1" #define BLUEZ_INTERFACE_AGENT "org.bluez.Agent1" #define BLUEZ_INTERFACE_GATT_SERVICE "org.bluez.GattService1" @@ -872,6 +874,37 @@ static void bluez_device_prop_from_dict_entry( const char *prop_name, DBusMessag } } +static void bluez_device_bearer_prop_from_dict_entry( const char *prop_name, DBusMessageIter *variant, + struct winebluetooth_device_bearer_properties *props ) +{ + const struct { + const char *name; + BOOL *val; + UINT8 flag; + } obj_props[] = { + { "Bonded", &props->bonded, WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_BONDED }, + { "Connected", &props->connected, WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_CONNECTED }, + { "Paired", &props->paired, WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_PAIRED }, + }; + int i; + + TRACE_( dbus )( "(%s, %s, %p)\n", debugstr_a( prop_name ), dbgstr_dbus_iter( variant ), props ); + + if (p_dbus_message_iter_get_arg_type( variant ) != DBUS_TYPE_BOOLEAN) return; + for (i = 0; i < ARRAY_SIZE( obj_props ); i++) + { + if (!strcmp( prop_name, obj_props[i].name )) + { + dbus_bool_t val; + + p_dbus_message_iter_get_basic( variant, &val ); + *(obj_props[i].val) = !!val; + props->props_mask |= obj_props[i].flag; + break; + } + } +} + static void bluez_gatt_service_props_from_dict_entry( const char *prop_name, DBusMessageIter *variant, struct winebluetooth_watcher_event_gatt_service_added *service ) { @@ -1958,6 +1991,96 @@ static void winebluetooth_watcher_event_free( enum winebluetooth_watcher_event_t } } +/* Populate winebluetooth_watcher_event_device_added for a newly discovered BlueZ remote device object. + * Return TRUE if a valid remote device was discovered. + * cur_iface should be one of "org.bluez.Device1", "org.bluez.Bearer.BREDR1", or "org.bluez.BearerLE1". + */ +static BOOL bluez_new_device_object_get_event( const char *path, const char *cur_iface, DBusMessageIter *iface_iter, + DBusMessageIter *props_iter, + struct winebluetooth_watcher_event_device_added *device_added, + BOOL *oom ) +{ + TRACE_( dbus )( "(%s, %s, %s, %s, %p, %p)\n", debugstr_a( path ), debugstr_a( cur_iface ), + dbgstr_dbus_iter( iface_iter ), dbgstr_dbus_iter( props_iter ), device_added, oom ); + + /* Objects for remote devices expose three interfaces that we're interested in: + * - org.bluez.Device1 + * - org.bluez.Bearer.BREDR1: Present if the device supports BREDR (Bluetooth Classic) + * - org.bluez.Bearer.LE1: Present if the device supports Low Energy + * The last two interfaces are only present in newer versions of BlueZ, so we cannot always rely + * on them to figure out BR/EDR and LE support. */ + do + { + if (!strcmp( cur_iface, BLUEZ_INTERFACE_DEVICE )) + { + DBusMessageIter variant; + const char *prop_name; + + if (!(device_added->device.handle = (UINT_PTR)unix_name_get_or_create( path ))) + { + *oom = TRUE; + return FALSE; + } + + while ((prop_name = bluez_next_dict_entry( props_iter, &variant ))) + { + if (!strcmp( prop_name, "Adapter" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_OBJECT_PATH) + { + const char *adapter_path; + + p_dbus_message_iter_get_basic( &variant, &adapter_path ); + if (!(device_added->radio.handle = (UINT_PTR)unix_name_get_or_create( adapter_path ))) + { + *oom = TRUE; + unix_name_free( (struct unix_name *)device_added->device.handle ); + return FALSE; + } + } + else + bluez_device_prop_from_dict_entry( prop_name, &variant, &device_added->props, + &device_added->known_props_mask, + WINEBLUETOOTH_DEVICE_ALL_PROPERTIES ); + } + + if (!device_added->radio.handle) + { + unix_name_free( (struct unix_name *)device_added->device.handle ); + ERR( "Could not find the associated adapter for device %s\n", debugstr_a( path ) ); + return FALSE; + } + } + else if (!strcmp( cur_iface, BLUEZ_INTERFACE_BEARER_BREDR ) || !strcmp( cur_iface, BLUEZ_INTERFACE_BEARER_LE )) + { + struct winebluetooth_device_bearer_properties *props; + DBusMessageIter variant; + const char *prop_name; + + if (!strcmp( cur_iface, BLUEZ_INTERFACE_BEARER_BREDR )) + { + device_added->known_props_mask |= WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_BREDR; + props = &device_added->props.bredr; + } + else + { + device_added->known_props_mask |= WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_LE; + props = &device_added->props.le; + } + + while ((prop_name = bluez_next_dict_entry( props_iter, &variant ))) + bluez_device_bearer_prop_from_dict_entry( prop_name, &variant, props ); + } + } while ((cur_iface = bluez_next_dict_entry( iface_iter, props_iter ))); + + if (!device_added->device.handle) + { + assert( !device_added->radio.handle ); /* This is only set when iterating org.bluez.Device1 properties. */ + ERR( "Object %s does not implement org.bluez.Device1, skipping.\n" ,debugstr_a( path ) ); + return FALSE; + } + return TRUE; +} + /* Examine a new BlueZ DBus object available at path and queue a BLUETOOTH_WATCHER_* event if it is an object we * are interested in. * ifaces_iter should point to the start of the interfaces + properties dict. @@ -1968,7 +2091,7 @@ static BOOL bluez_handle_new_object( DBusMessage *msg, const char *path, DBusMes struct list *event_list, BOOL *ret_oom ) { enum winebluetooth_watcher_event_type event_type = 0; - union winebluetooth_watcher_event_data event = {0}; + union winebluetooth_watcher_event_data event; BOOL new_object = FALSE, oom = FALSE; DBusMessageIter props_iter; const char *iface; @@ -1981,6 +2104,7 @@ static BOOL bluez_handle_new_object( DBusMessage *msg, const char *path, DBusMes DBusMessageIter variant; const char *prop_name; + memset( &event, 0, sizeof( event ) ); if (!strcmp( iface, BLUEZ_INTERFACE_ADAPTER )) { if (!(event.radio_added.radio.handle = (UINT_PTR)unix_name_get_or_create( path ))) @@ -1999,44 +2123,21 @@ static BOOL bluez_handle_new_object( DBusMessage *msg, const char *path, DBusMes TRACE( "New BlueZ org.bluez.Adapter1 object %s: %#" PRIxPTR "\n", debugstr_a( path ), event.radio_added.radio.handle ); } - else if (!strcmp( iface, BLUEZ_INTERFACE_DEVICE )) + else if (!strcmp( iface, BLUEZ_INTERFACE_DEVICE ) || !strcmp( iface, BLUEZ_INTERFACE_BEARER_BREDR ) || + !strcmp( iface, BLUEZ_INTERFACE_BEARER_LE )) { - if (!(event.device_added.device.handle = (UINT_PTR)unix_name_get_or_create( path ))) - { - oom = TRUE; - break; - } - event.device_added.init_entry = init_entry; + BOOL has_bredr_iface = FALSE, has_le_iface = FALSE; - while ((prop_name = bluez_next_dict_entry( &props_iter, &variant ))) - { - if (!strcmp( prop_name, "Adapter" ) && - p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_OBJECT_PATH) - { - const char *path; - p_dbus_message_iter_get_basic( &variant, &path ); - if (!(event.device_added.radio.handle = (UINT_PTR)unix_name_get_or_create( path ))) - { - oom = TRUE; - goto done; - } - } - else - bluez_device_prop_from_dict_entry( prop_name, &variant, &event.device_added.props, - &event.device_added.known_props_mask, - WINEBLUETOOTH_DEVICE_ALL_PROPERTIES ); - } - if (!event.device_added.radio.handle) - { - unix_name_free( (struct unix_name *)event.device_added.device.handle ); - ERR( "Could not find the associated adapter for device %s\n", debugstr_a( path ) ); - } - else + new_object = + bluez_new_device_object_get_event( path, iface, ifaces_iter, &props_iter, &event.device_added, &oom ); + if (oom) break; + if (new_object) { - TRACE( "New org.bluez.Device1 object %s: %#" PRIxPTR "\n", debugstr_a( path ), - event.device_added.device.handle ); event_type = BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED; - new_object = TRUE; + has_bredr_iface = !!(event.device_added.known_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_BREDR); + has_le_iface = !!(event.device_added.known_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_LE); + TRACE( "New org.bluez.Device1 object (has_bredr_iface: %d, has_le_iface: %d) %s: %#" PRIxPTR "\n", + has_bredr_iface, has_le_iface, debugstr_a( path ), event.device_added.device.handle ); } } else if (!strcmp( iface ,BLUEZ_INTERFACE_GATT_SERVICE )) @@ -2386,8 +2487,8 @@ static void bluez_signal_handler( DBusConnection *conn, DBusMessage *msg, const return; object_path = p_dbus_message_get_path( msg ); - TRACE( "Properties changed for device %s, changed %#x, invalidated %#x\n", debugstr_a( object_path ), - props_changed.changed_props_mask, props_changed.invalid_props_mask ); + TRACE( "Properties changed for device %s, interface org.bluez.Device1, changed %#x, invalidated %#x\n", + debugstr_a( object_path ), props_changed.changed_props_mask, props_changed.invalid_props_mask ); device = unix_name_get_or_create( object_path ); if (!device) @@ -2431,6 +2532,45 @@ static void bluez_signal_handler( DBusConnection *conn, DBusMessage *msg, const return; } } + else if (!strcmp( iface, BLUEZ_INTERFACE_BEARER_BREDR ) || !strcmp( iface, BLUEZ_INTERFACE_BEARER_LE )) + { + struct winebluetooth_device_bearer_properties *bearer_props; + union winebluetooth_watcher_event_data event = {0}; + DBusMessageIter changed_props_iter, variant; + const char *prop_name, *path; + + if (!strcmp( iface, BLUEZ_INTERFACE_BEARER_BREDR )) + { + event.device_props_changed.changed_props_mask = WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_BREDR; + bearer_props = &event.device_props_changed.props.bredr; + } + else + { + event.device_props_changed.changed_props_mask = WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_LE; + bearer_props = &event.device_props_changed.props.le; + } + + p_dbus_message_iter_next( &iter ); + p_dbus_message_iter_recurse( &iter, &changed_props_iter ); + while ((prop_name = bluez_next_dict_entry( &changed_props_iter, &variant ))) + bluez_device_bearer_prop_from_dict_entry( prop_name, &variant, bearer_props ); + if (!bearer_props->props_mask) return; + + path = p_dbus_message_get_path( msg ); + if (!(event.device_props_changed.device.handle = (UINT_PTR)unix_name_get_or_create( path ))) + { + ERR( "Failed to allocate memory for device path %s\n", path ); + return; + } + TRACE( "Properties changed for device %s, interface %s, changed %#x\n", debugstr_a( path ), + debugstr_a( iface ), bearer_props->props_mask ); + if (!bluez_event_list_queue_new_event( event_list, BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED, + event )) + { + unix_name_free( (struct unix_name *)event.device_props_changed.device.handle ); + return; + } + } else if (!strcmp( iface, BLUEZ_INTERFACE_GATT_CHARACTERISTICS )) { struct winebluetooth_watcher_event_gatt_characteristic_value_changed changed_event = {0}; diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index d2d8c4477e1..62cbed7326a 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -169,6 +169,8 @@ typedef UINT16 winebluetooth_device_props_mask_t; #define WINEBLUETOOTH_DEVICE_PROPERTY_LEGACY_PAIRING (1 << 4) #define WINEBLUETOOTH_DEVICE_PROPERTY_TRUSTED (1 << 5) #define WINEBLUETOOTH_DEVICE_PROPERTY_CLASS (1 << 6) +#define WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_BREDR (1 << 7) +#define WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_LE (1 << 8) #define WINEBLUETOOTH_DEVICE_ALL_PROPERTIES \ (WINEBLUETOOTH_DEVICE_PROPERTY_NAME | WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS | \ @@ -197,6 +199,16 @@ struct winebluetooth_radio_properties BYTE version; }; +#define WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_BONDED (1) +#define WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_CONNECTED (1 << 1) +#define WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_PAIRED (1 << 2) +struct winebluetooth_device_bearer_properties +{ + UINT8 props_mask; + BOOL bonded; + BOOL connected; + BOOL paired; +}; struct winebluetooth_device_properties { BLUETOOTH_ADDRESS address; @@ -206,6 +218,8 @@ struct winebluetooth_device_properties BOOL legacy_pairing; BOOL trusted; UINT32 class; + struct winebluetooth_device_bearer_properties bredr; + struct winebluetooth_device_bearer_properties le; }; typedef struct -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11084
From: Vibhav Pant <vibhavp@gmail.com> --- dlls/winebth.sys/winebth.c | 56 ++++++++++++++++++++++++++------------ include/ddk/bthguid.h | 5 ++++ 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index fccac50bdef..dea7af365c0 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -102,8 +102,12 @@ struct bluetooth_remote_device BOOL started; /* Whether the device has been started. Guarded by props_cs */ BOOL removed; - BOOL le; /* Guarded by props_cs */ + /* Whether the device supports LE. Set when support is either indicated by unix + * (WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_LE) or manually detected when a GATT service for this device is found. + * Guarded by props_cs */ + BOOL le; UNICODE_STRING bthle_symlink_name; /* Guarded by props_cs */ + UNICODE_STRING bredr_symlink_name; /* Guarded by props_cs */ struct list gatt_services; /* Guarded by props_cs */ }; @@ -334,6 +338,18 @@ static NTSTATUS bluetooth_gatt_service_dispatch( DEVICE_OBJECT *device, struct b return status; } +/* Returns whether the remote device supports BR/EDR. Caller should hold device->props_cs. */ +static BOOL bluetooth_remote_device_has_bredr( const struct bluetooth_remote_device *device ) +{ + return !!(device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_BREDR); +} + +/* Returns whether the remote device supports LE. Caller should hold device->props_cs. */ +static BOOL bluetooth_remote_device_has_le( const struct bluetooth_remote_device *device ) +{ + return device->le; +} + static NTSTATUS bluetooth_remote_device_dispatch( DEVICE_OBJECT *device, struct bluetooth_remote_device *ext, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); @@ -1044,7 +1060,7 @@ static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_even ext->remote_device.removed = FALSE; ext->remote_device.started = FALSE; - ext->remote_device.le = FALSE; + ext->remote_device.le = !!(event.known_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_LE); list_init( &ext->remote_device.gatt_services ); if (!event.init_entry) @@ -1297,17 +1313,15 @@ static void complete_irp( IRP *irp, NTSTATUS result ) /* Enables the low energy interface for this device if it hasn't been already. Caller should hold device->props_cs. */ static void bluetooth_device_enable_le_iface( struct bluetooth_remote_device *device ) { - /* The device hasn't been started by the PnP manager yet. Set le, and let remote_device_pdo_pnp enable the - * interface. */ - if (!device->started) - device->le = TRUE; - else if (!device->le) - { - device->le = TRUE; - if (!IoRegisterDeviceInterface( device->device_obj, &GUID_BLUETOOTHLE_DEVICE_INTERFACE, NULL, - &device->bthle_symlink_name )) + if (bluetooth_remote_device_has_le( device )) return; + + device->le = TRUE; + /* If the device hasn't been started by the PnP manager, do nothing as remote_device_pdo_pnp enables the interface. */ + if (!device->started) return; + /* Otherwise, do it manually. */ + if (!IoRegisterDeviceInterface( device->device_obj, &GUID_BLUETOOTHLE_DEVICE_INTERFACE, NULL, + &device->bthle_symlink_name )) IoSetDeviceInterfaceState( &device->bthle_symlink_name, TRUE ); - } } static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_event_gatt_service_added event ) @@ -1397,7 +1411,7 @@ static void bluetooth_gatt_service_remove( winebluetooth_gatt_service_t service struct bluetooth_gatt_service *svc; EnterCriticalSection( &device->props_cs ); - if (!device->le) + if (!bluetooth_remote_device_has_le( device )) { LeaveCriticalSection( &device->props_cs ); continue; @@ -1437,7 +1451,7 @@ bluetooth_gatt_service_add_characteristic( struct winebluetooth_watcher_event_ga struct bluetooth_gatt_service *svc; EnterCriticalSection( &device->props_cs ); - if (!device->le) + if (!bluetooth_remote_device_has_le( device )) { LeaveCriticalSection( &device->props_cs ); continue; @@ -1514,7 +1528,7 @@ static void bluetooth_gatt_characteristic_remove( winebluetooth_gatt_characteris struct bluetooth_gatt_service *svc; EnterCriticalSection( &device->props_cs ); - if (!device->le) + if (!bluetooth_remote_device_has_le( device )) { LeaveCriticalSection( &device->props_cs ); continue; @@ -1564,7 +1578,7 @@ static void bluetooth_gatt_characteristic_value_update( struct winebluetooth_wat struct bluetooth_gatt_service *svc; EnterCriticalSection( &device->props_cs ); - if (!device->le) + if (!bluetooth_remote_device_has_le( device )) { LeaveCriticalSection( &device->props_cs ); continue; @@ -2061,6 +2075,11 @@ static void remote_device_destroy( struct bluetooth_remote_device *ext ) IoSetDeviceInterfaceState( &ext->bthle_symlink_name, FALSE ); RtlFreeUnicodeString( &ext->bthle_symlink_name ); } + if (ext->bredr_symlink_name.Buffer) + { + IoSetDeviceInterfaceState( &ext->bredr_symlink_name, FALSE ); + RtlFreeUnicodeString( &ext->bredr_symlink_name ); + } ext->props_cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &ext->props_cs ); winebluetooth_device_free( ext->device ); @@ -2128,10 +2147,13 @@ static NTSTATUS WINAPI remote_device_pdo_pnp( DEVICE_OBJECT *device_obj, struct LeaveCriticalSection( &device_list_cs ); EnterCriticalSection( &ext->props_cs ); - if (ext->le && + if (bluetooth_remote_device_has_le( ext ) && !IoRegisterDeviceInterface( device_obj, &GUID_BLUETOOTHLE_DEVICE_INTERFACE, NULL, &ext->bthle_symlink_name )) IoSetDeviceInterfaceState( &ext->bthle_symlink_name, TRUE ); + if (bluetooth_remote_device_has_bredr( ext ) && + !IoRegisterDeviceInterface( device_obj, &GUID_BTH_DEVICE_INTERFACE, NULL, &ext->bredr_symlink_name )) + IoSetDeviceInterfaceState( &ext->bredr_symlink_name, TRUE ); ext->started = TRUE; bluetooth_device_set_properties( ext, adapter_addr.rgBytes, &ext->props, ext->props_mask ); LeaveCriticalSection( &ext->props_cs ); diff --git a/include/ddk/bthguid.h b/include/ddk/bthguid.h index 2b850969972..ca902dd94a6 100644 --- a/include/ddk/bthguid.h +++ b/include/ddk/bthguid.h @@ -19,9 +19,14 @@ #ifndef __DDK_BTHGUID_H__ #define __DDK_BTHGUID_H__ +/* Interface for BR/EDR (Bluetooth Classic) devices. */ +DEFINE_GUID( GUID_BTH_DEVICE_INTERFACE, 0x00f40965,0xe89d,0x4487,0x98,0x90,0x87,0xc3,0xab,0xb2,0x11,0xf4 ); + /* DEVPROP_TYPE_STRING */ DEFINE_DEVPROPKEY( DEVPKEY_Bluetooth_DeviceAddress, 0x2bd67d8b,0x8beb,0x48d5,0x87,0xe0,0x6c,0xda,0x34,0x28,0x04,0x0a,1 ); /* DEVPROP_TYPE_UINT32 */ +DEFINE_DEVPROPKEY( DEVPKEY_Bluetooth_DeviceFlags, 0x2bd67d8b,0x8beb,0x48d5,0x87,0xe0,0x6c,0xda,0x34,0x28,0x04,0x0a,3 ); +/* DEVPROP_TYPE_UINT32 */ DEFINE_DEVPROPKEY( DEVPKEY_Bluetooth_ClassOfDevice, 0x2bd67d8b,0x8beb,0x48d5,0x87,0xe0,0x6c,0xda,0x34,0x28,0x04,0x0a,10 ); /* DEVPROP_TYPE_FILETIME */ DEFINE_DEVPROPKEY( DEVPKEY_Bluetooth_LastConnectedTime, 0x2bd67d8b,0x8beb,0x48d5,0x87,0xe0,0x6c,0xda,0x34,0x28,0x04,0x0a,11 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11084
From: Vibhav Pant <vibhavp@gmail.com> --- dlls/winebth.sys/winebluetooth.c | 25 +++++++++++++++++++++++++ dlls/winebth.sys/winebth.c | 25 +++++++++++++++++++++++++ dlls/winebth.sys/winebth_priv.h | 3 +++ include/bthdef.h | 9 ++++++++- 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c index 5bab7230fa3..a95f12b1af4 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -29,6 +29,7 @@ #include <wine/debug.h> #include <wine/unixlib.h> +#include "bthdef.h" #include "winebth_priv.h" #include "unixlib.h" @@ -175,6 +176,20 @@ void winebluetooth_device_properties_to_info( winebluetooth_device_props_mask_t info->classOfDevice = props->class; info->flags |= BDIF_COD; } + if (props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_BREDR) + info->flags |= BDIF_BR; + if (props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_LE) + { + const struct winebluetooth_device_bearer_properties *le = &props->le; + + info->flags |= BDIF_LE; + if (le->props_mask & WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_BONDED && le->bonded) + info->flags |= (BDIF_LE_PERSONAL | BDIF_LE_PAIRED); + if (le->props_mask & WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_CONNECTED && le->connected) + info->flags |= BDIF_LE_CONNECTED; + if (le->props_mask & WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_PAIRED && le->paired) + info->flags |= BDIF_LE_PAIRED; + } } NTSTATUS winebluetooth_auth_send_response( winebluetooth_device_t device, BLUETOOTH_AUTHENTICATION_METHOD method, @@ -272,6 +287,16 @@ NTSTATUS winebluetooth_get_event( struct winebluetooth_event *result ) return status; } +void winebluetooth_device_bearer_properties_update( struct winebluetooth_device_bearer_properties *props, + const struct winebluetooth_device_bearer_properties *new_props ) +{ + props->props_mask |= new_props->props_mask; + + if (new_props->props_mask & WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_BONDED) props->bonded = new_props->bonded; + if (new_props->props_mask & WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_CONNECTED) props->connected = new_props->connected; + if (new_props->props_mask & WINEBLUETOOTH_DEVICE_BEARER_PROPERTY_PAIRED) props->paired = new_props->paired; +} + NTSTATUS winebluetooth_init( void ) { NTSTATUS status; diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index dea7af365c0..7eb915a016d 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -46,6 +46,7 @@ #include <wine/list.h> #include "winebth_priv.h" +#include "winnt.h" WINE_DEFAULT_DEBUG_CHANNEL( winebth ); @@ -1146,6 +1147,8 @@ static void bluetooth_device_set_properties( struct bluetooth_remote_device *dev const struct winebluetooth_device_properties *props, winebluetooth_device_props_mask_t mask ) { + BTH_DEVICE_INFO info = {0}; + if (mask & WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS) { WCHAR addr_str[18], aep_id[59]; @@ -1168,6 +1171,10 @@ static void bluetooth_device_set_properties( struct bluetooth_remote_device *dev IoSetDeviceInterfacePropertyData( &device->bthle_symlink_name, (DEVPROPKEY *)&PKEY_DeviceInterface_Bluetooth_DeviceAddress, LOCALE_NEUTRAL, 0, DEVPROP_TYPE_STRING, 26, addr_str ); + if (device->bredr_symlink_name.Buffer) + IoSetDeviceInterfacePropertyData( &device->bredr_symlink_name, + (DEVPROPKEY *)&PKEY_DeviceInterface_Bluetooth_DeviceAddress, + LOCALE_NEUTRAL, 0, DEVPROP_TYPE_STRING, 26, addr_str ); swprintf( addr_str, ARRAY_SIZE( addr_str ), L"%02x:%02x:%02x:%02x:%02x:%02x", device_addr[0], device_addr[1], device_addr[2], device_addr[3], device_addr[4], device_addr[5] ); @@ -1188,7 +1195,21 @@ static void bluetooth_device_set_properties( struct bluetooth_remote_device *dev IoSetDeviceInterfacePropertyData( &device->bthle_symlink_name, (DEVPROPKEY *)&PKEY_DeviceInterface_Bluetooth_LastConnectedTime, LOCALE_NEUTRAL, 0, DEVPROP_TYPE_FILETIME, sizeof( time ), (void *)&time ); + if (device->bredr_symlink_name.Buffer) + IoSetDeviceInterfacePropertyData( &device->bredr_symlink_name, + (DEVPROPKEY *)&PKEY_DeviceInterface_Bluetooth_LastConnectedTime, + LOCALE_NEUTRAL, 0, DEVPROP_TYPE_FILETIME, sizeof( time ), (void *)&time ); } + + winebluetooth_device_properties_to_info( mask, props, &info ); + if (device->bthle_symlink_name.Buffer) + IoSetDeviceInterfacePropertyData( &device->bthle_symlink_name, + (DEVPROPKEY *)&PKEY_DeviceInterface_Bluetooth_Flags, LOCALE_NEUTRAL, 0, + DEVPROP_TYPE_UINT32, sizeof( info.flags ), &info.flags ); + if (device->bredr_symlink_name.Buffer) + IoSetDeviceInterfacePropertyData( &device->bredr_symlink_name, + (DEVPROPKEY *)&PKEY_DeviceInterface_Bluetooth_Flags, LOCALE_NEUTRAL, 0, + DEVPROP_TYPE_UINT32, sizeof( info.flags ), &info.flags ); } static void bluetooth_radio_update_device_props( struct winebluetooth_watcher_event_device_props_changed event ) @@ -1232,6 +1253,10 @@ static void bluetooth_radio_update_device_props( struct winebluetooth_watcher_ev device->props.trusted = event.props.trusted; if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_CLASS) device->props.class = event.props.class; + if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_BREDR) + winebluetooth_device_bearer_properties_update( &device->props.bredr, &event.props.bredr ); + if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_BEARER_LE) + winebluetooth_device_bearer_properties_update( &device->props.le, &event.props.le ); 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 ); diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 62cbed7326a..726b6208878 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -209,6 +209,9 @@ struct winebluetooth_device_bearer_properties BOOL connected; BOOL paired; }; + +void winebluetooth_device_bearer_properties_update( struct winebluetooth_device_bearer_properties *props, + const struct winebluetooth_device_bearer_properties *new_props ); struct winebluetooth_device_properties { BLUETOOTH_ADDRESS address; diff --git a/include/bthdef.h b/include/bthdef.h index b61d5b033d3..346d0ba94a3 100644 --- a/include/bthdef.h +++ b/include/bthdef.h @@ -49,7 +49,14 @@ typedef ULONGLONG BTH_ADDR, *PBTH_ADDR; #define BDIF_SSP_SUPPORTED 0x00000100 #define BDIF_SSP_PAIRED 0x00000200 -#define BDIF_SSP_MITM_PROTECTED 0x00000200 +#define BDIF_SSP_MITM_PROTECTED 0x00000400 + +#define BDIF_BR 0x00004000 +#define BDIF_LE 0x00008000 +#define BDIF_LE_PAIRED 0x00010000 +#define BDIF_LE_PERSONAL 0x00020000 +#define BDIF_LE_NAME 0x00400000 +#define BDIF_LE_CONNECTED 0x01000000 typedef struct _BTH_DEVICE_INFO { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11084
From: Vibhav Pant <vibhavp@gmail.com> --- dlls/bluetoothapis/tests/device.c | 124 +++++++++++++++++++++++++++++- dlls/bluetoothapis/tests/gatt.c | 13 +++- 2 files changed, 134 insertions(+), 3 deletions(-) diff --git a/dlls/bluetoothapis/tests/device.c b/dlls/bluetoothapis/tests/device.c index 8753d675b46..d4d72e317c4 100644 --- a/dlls/bluetoothapis/tests/device.c +++ b/dlls/bluetoothapis/tests/device.c @@ -24,9 +24,14 @@ #include <winbase.h> #include <winnls.h> #include <winuser.h> +#include <winreg.h> +#include <wtypes.h> +#include <propkey.h> +#include <setupapi.h> #include <bthsdpdef.h> #include <bluetoothapis.h> +#include <ddk/bthguid.h> #include <wine/debug.h> #include <wine/test.h> @@ -60,6 +65,50 @@ static const char *debugstr_BLUETOOTH_DEVICE_INFO( const BLUETOOTH_DEVICE_INFO * debugstr_w( last_used ), debugstr_w( info->szName ) ); } +const char *debugstr_BDIF_flags( UINT32 flags ) +{ + + static const struct { + UINT32 flag; + const char *str; + } flag_str[] = { +#define XX(f) {(f), #f} + XX(BDIF_ADDRESS), + XX(BDIF_COD), + XX(BDIF_NAME), + XX(BDIF_PAIRED), + XX(BDIF_PERSONAL), + XX(BDIF_CONNECTED), + XX(BDIF_SSP_SUPPORTED), + XX(BDIF_SSP_PAIRED), + XX(BDIF_SSP_MITM_PROTECTED), + XX(BDIF_BR), + XX(BDIF_LE), + XX(BDIF_LE_PAIRED), + XX(BDIF_LE_PERSONAL), + XX(BDIF_LE_NAME), + XX(BDIF_LE_CONNECTED), +#undef XX + }; + char buf[350], *ptr = buf; + ULONG rem = sizeof( buf ), i; + + if (!flags) return "0x0"; + + for (i = 0; i < ARRAY_SIZE( flag_str ); i++) + { + if (flags & flag_str[i].flag) + { + ULONG n = snprintf( ptr, rem, buf == ptr ? "%s" : "|%s", flag_str[i].str ); + if (n >= rem) return wine_dbg_sprintf( "%#I32x\n", flags ); + rem -= n; + ptr += n; + } + } + + return wine_dbg_sprintf( "{%s}\n", buf ); +} + void test_radio_BluetoothFindFirstDevice( HANDLE radio, void *data ) { BLUETOOTH_DEVICE_SEARCH_PARAMS search_params; @@ -123,6 +172,63 @@ void test_BluetoothFindFirstDevice( void ) test_for_all_radios( __FILE__, __LINE__, test_radio_BluetoothFindFirstDevice, NULL ); } +/* Tests whether the associated interface for the remote device exists. */ +void test_device_iface( const BLUETOOTH_DEVICE_INFO *info, UINT32 *device_flags, UINT32 *cod ) +{ + char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof( WCHAR )]; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)buffer; + const BYTE *addr = info->Address.rgBytes; + SP_DEVICE_INTERFACE_DATA iface_data; + BOOL found = FALSE; + WCHAR addr_str[13]; + DWORD ret, idx = 0; + HDEVINFO devinfo; + + swprintf( addr_str, ARRAY_SIZE( addr_str ), L"%02X%02X%02X%02X%02X%02X", addr[5], addr[4], addr[3], addr[2], + addr[1], addr[0] ); + + devinfo = SetupDiGetClassDevsW( &GUID_BTH_DEVICE_INTERFACE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); + ret = GetLastError(); + ok( devinfo != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsW failed %lu\n", ret ); + + iface_detail->cbSize = sizeof( *iface_detail ); + iface_data.cbSize = sizeof( iface_data ); + while (SetupDiEnumDeviceInterfaces( devinfo, NULL, &GUID_BTH_DEVICE_INTERFACE, idx++, &iface_data )) + { + DEVPROPTYPE type = DEVPROP_TYPE_NULL; + WCHAR cur_addr_str[13]; + BOOL success; + DWORD size; + + cur_addr_str[0] = L'\0'; + success = SetupDiGetDeviceInterfacePropertyW( devinfo, &iface_data, + (DEVPROPKEY *)&PKEY_DeviceInterface_Bluetooth_DeviceAddress, + &type, (BYTE *)cur_addr_str, sizeof( cur_addr_str ), &size, 0 ); + ok( success, "SetupDiGetDeviceInterfacePropertyW failed: %lu\n", GetLastError() ); + ok( type == DEVPROP_TYPE_STRING, "Got type %#lx\n", type ); + ok( size == sizeof( cur_addr_str ), "got size %lu\n", size ); + if (!wcsicmp( addr_str, cur_addr_str )) + { + found = TRUE; + success = SetupDiGetDeviceInterfacePropertyW( devinfo, &iface_data, + (DEVPROPKEY *)&PKEY_DeviceInterface_Bluetooth_Flags, &type, + (BYTE *)device_flags, sizeof( *device_flags ), &size, 0 ); + ok( success, "SetupDiGetDeviceInterfacePropertyW failed: %lu\n", GetLastError() ); + ok( type == DEVPROP_TYPE_UINT32, "Got type %#lx\n", type ); + ok( size == sizeof( *device_flags ), "got size %lu\n", size ); + success = SetupDiGetDeviceInterfacePropertyW( devinfo, &iface_data, &DEVPKEY_Bluetooth_ClassOfDevice, &type, + (BYTE *)cod, sizeof( *cod ), &size, 0 ); + todo_wine ok( success, "SetupDiGetDeviceInterfacePropertyW failed: %lu\n", GetLastError() ); + todo_wine ok( type == DEVPROP_TYPE_UINT32, "Got type %#lx\n", type ); + todo_wine ok( size == sizeof( *cod ), "got size %lu\n", size ); + break; + } + } + + SetupDiDestroyDeviceInfoList( devinfo ); + ok( found, "Could not find associated device object.\n" ); +} + void test_radio_BluetoothFindNextDevice( HANDLE radio, void *data ) { BLUETOOTH_DEVICE_SEARCH_PARAMS search_params = *(BLUETOOTH_DEVICE_SEARCH_PARAMS *)data; @@ -149,12 +255,27 @@ void test_radio_BluetoothFindNextDevice( HANDLE radio, void *data ) BLUETOOTH_DEVICE_INFO info2 = {0}; BOOL matches; + winetest_push_context("device %lu", i++ ); matches = (info.fConnected && search_params.fReturnConnected) || (info.fAuthenticated && search_params.fReturnAuthenticated) || (info.fRemembered && search_params.fReturnRemembered) || (!info.fRemembered && search_params.fReturnUnknown); ok( matches, "Device does not match filter constraints\n" ); - trace( "device %lu: %s\n", i, debugstr_BLUETOOTH_DEVICE_INFO( &info ) ); + trace( "%s\n", debugstr_BLUETOOTH_DEVICE_INFO( &info ) ); + + if (info.fConnected) + { + UINT32 flags = 0, cod = 0, mask = BDIF_BR | BDIF_CONNECTED | BDIF_ADDRESS; + + if (info.szName[0]) + mask |= BDIF_NAME; + if (info.fAuthenticated) + mask |= (BDIF_PAIRED | BDIF_PERSONAL); + + test_device_iface( &info, &flags, &cod ); + ok( flags & mask, "Got flags %s\n", debugstr_BDIF_flags( flags ) ); + todo_wine ok( cod == info.ulClassofDevice, "Got cod %#I32x != %#lx\n", cod, info.ulClassofDevice ); + } info2.dwSize = sizeof( info2 ); info2.Address = info.Address; @@ -173,6 +294,7 @@ void test_radio_BluetoothFindNextDevice( HANDLE radio, void *data ) success = BluetoothFindNextDevice( hfind, &info ); err = GetLastError(); ok( success || err == ERROR_NO_MORE_ITEMS, "BluetoothFindNextDevice failed: %lu\n", err ); + winetest_pop_context(); if (!success) break; } diff --git a/dlls/bluetoothapis/tests/gatt.c b/dlls/bluetoothapis/tests/gatt.c index 58c0f426383..eeb89d7ed2b 100644 --- a/dlls/bluetoothapis/tests/gatt.c +++ b/dlls/bluetoothapis/tests/gatt.c @@ -27,9 +27,10 @@ #include <winreg.h> #include <setupapi.h> -#include <setupapi.h> - #include <initguid.h> +#include <wtypes.h> +#include <propkey.h> +#include <bthdef.h> #include <bthledef.h> #include <bluetoothleapis.h> #include <devpkey.h> @@ -37,6 +38,7 @@ #include <wine/test.h> +const char *debugstr_BDIF_flags( UINT32 flags ); static void le_to_uuid( const BTH_LE_UUID *le_uuid, GUID *uuid ) { if (le_uuid->IsShortUuid) @@ -72,6 +74,7 @@ static void test_for_all_le_devices( int line, void (*func)( HANDLE, const WCHAR DEVPROPTYPE type; WCHAR addr_str[13]; BOOL success; + UINT32 flags = 0; devinfo_data.cbSize = sizeof( devinfo_data ); success = SetupDiGetDeviceInterfaceDetailW( devinfo, &iface_data, iface_detail, sizeof( buffer ), NULL, @@ -82,6 +85,12 @@ static void test_for_all_le_devices( int line, void (*func)( HANDLE, const WCHAR (BYTE *)addr_str, sizeof( addr_str ), NULL, 0 ); ok( success, "SetupDiGetDevicePropertyW failed: %lu\n", GetLastError() ); ok( type == DEVPROP_TYPE_STRING, "got type %lu\n", type ); + success = SetupDiGetDeviceInterfacePropertyW( devinfo, &iface_data, + (DEVPROPKEY *)&PKEY_DeviceInterface_Bluetooth_Flags, &type, + (BYTE *)&flags, sizeof( flags ), NULL, 0 ); + ok( success, "SetupDiGetDeviceInterfacePropertyW failed: %lu\n", GetLastError() ); + ok( type == DEVPROP_TYPE_UINT32, "got type %lu\n", type ); + ok( flags & BDIF_LE, "Got flags %s\n", debugstr_BDIF_flags( flags ) ); device = CreateFileW( iface_detail->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); winetest_push_context( "device %lu", n++ ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11084
participants (2)
-
Vibhav Pant -
Vibhav Pant (@vibhavp)