From: Vibhav Pant <vibhavp@gmail.com> --- dlls/winebth.sys/dbus.c | 76 ++++++++++++++++++++++++++++++-- dlls/winebth.sys/unixlib.c | 17 +++++++ dlls/winebth.sys/unixlib.h | 13 ++++++ dlls/winebth.sys/unixlib_priv.h | 2 + dlls/winebth.sys/winebluetooth.c | 30 ++++++++++++- dlls/winebth.sys/winebth.c | 16 +++++++ dlls/winebth.sys/winebth_priv.h | 10 +++++ include/bthledef.h | 6 +++ 8 files changed, 164 insertions(+), 6 deletions(-) diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index a2b1e1020fb..6001e2a75b1 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -1,8 +1,7 @@ /* * Support for communicating with BlueZ over DBus. * - * Copyright 2024 Vibhav Pant - * Copyright 2025 Vibhav Pant + * Copyright 2024-2026 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -984,6 +983,50 @@ static NTSTATUS bluez_device_get_props_by_path_async( DBusConnection *connection return STATUS_SUCCESS; } +struct bluez_gatt_characteristic_value +{ + DBusMessage *message; + const BYTE *buf; /* Points into message */ +}; + +/* array_iter must point to the start of the byte array, message should be the DBus message that the iterator belongs + * to. */ +static BOOL bluez_gatt_characteristic_value_new_from_iter( DBusMessage *message, DBusMessageIter *array_iter, + struct winebluetooth_gatt_characteristic_value *value ) +{ + struct bluez_gatt_characteristic_value *val; + DBusMessageIter bytes_iter; + int size; + + TRACE_( dbus )( "(%s, %s, %p)\n", dbgstr_dbus_message( message ), dbgstr_dbus_iter( array_iter ), value ); + + if (!(val = calloc( 1, sizeof( *val ) ))) return FALSE; + val->message = p_dbus_message_ref( message ); + p_dbus_message_iter_recurse( array_iter, &bytes_iter ); + p_dbus_message_iter_get_fixed_array( &bytes_iter, &val->buf, &size ); + + value->size = size; + value->handle = (UINT_PTR)val; + + return TRUE; +} + +void bluez_gatt_characteristic_value_free( void *val ) +{ + struct bluez_gatt_characteristic_value *value = val; + + p_dbus_message_unref( value->message ); + free( value ); +} + +void bluez_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *value, BYTE *dest ) +{ + struct bluez_gatt_characteristic_value *val = (struct bluez_gatt_characteristic_value *)value->handle; + + memcpy( dest, val->buf, value->size ); + bluez_gatt_characteristic_value_free( val ); +} + struct bluez_watcher_ctx { char *bluez_dbus_unique_name; @@ -2247,6 +2290,8 @@ static void bluez_watcher_free( struct bluez_watcher_ctx *watcher ) case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_ADDED: unix_name_free( (struct unix_name *)event1->event.gatt_characteristic_added.characteristic.handle ); unix_name_free( (struct unix_name *)event1->event.gatt_characteristic_added.service.handle ); + bluez_gatt_characteristic_value_free( + (struct bluez_gatt_characteristic_value *)event1->event.gatt_characteristic_added.value.handle ); break; case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_REMOVED: unix_name_free( (struct unix_name *)event1->event.gatt_characterisic_removed.handle ); @@ -2510,10 +2555,28 @@ static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct lis init_entry->object.characteristic.characteristic.handle = (UINT_PTR)char_name; while ((prop_name = bluez_next_dict_entry( &prop_iter, &variant ))) - bluez_gatt_characteristic_props_from_dict_entry( prop_name, &variant, - &init_entry->object.characteristic ); + { + if (!strcmp( prop_name, "Value" ) + && p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_ARRAY + && p_dbus_message_iter_get_element_type( &variant ) == DBUS_TYPE_BYTE) + { + if (!bluez_gatt_characteristic_value_new_from_iter( reply, &variant, + &init_entry->object.characteristic.value )) + { + unix_name_free( char_name ); + free( init_entry ); + status = STATUS_NO_MEMORY; + goto done; + } + } + else + bluez_gatt_characteristic_props_from_dict_entry( prop_name, &variant, + &init_entry->object.characteristic ); + } if (!init_entry->object.characteristic.service.handle) { + bluez_gatt_characteristic_value_free( + (struct bluez_gatt_characteristic_value *)init_entry->object.characteristic.value.handle ); unix_name_free( char_name ); free( init_entry ); ERR( "Could not find the associated service for the GATT charcteristic %s\n", debugstr_a( path ) ); @@ -2732,5 +2795,10 @@ NTSTATUS bluez_device_start_pairing( void *connection, void *watcher_ctx, struct { return STATUS_NOT_SUPPORTED; } +void bluez_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *value, BYTE *buf ) +{ + return STATUS_NOT_SUPPORTED; +} +void bluez_gatt_characteristic_value_free( void *val ) { return STATUS_NOT_SUPPORTED; } #endif /* SONAME_LIBDBUS_1 */ diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index 530fe432413..4eee0bfa132 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -275,6 +275,21 @@ static NTSTATUS bluetooth_gatt_characteristic_free( void *args ) return STATUS_SUCCESS; } +static NTSTATUS bluetooth_gatt_characteristic_value_move( void *args ) +{ + struct bluetooth_gatt_characteristic_value_move_params *params = args; + if (!dbus_connection) return STATUS_NOT_SUPPORTED; + bluez_gatt_characteristic_value_move( params->val, params->buf ); + return STATUS_SUCCESS; +} + +static NTSTATUS bluetooth_gatt_characteristic_value_free( void *args ) +{ + struct bluetooth_gatt_characteristic_value_free_params *params = args; + if (!dbus_connection) return STATUS_NOT_SUPPORTED; + bluez_gatt_characteristic_value_free( (void *)params->handle ); + return STATUS_SUCCESS; +} static NTSTATUS bluetooth_get_event( void *args ) { @@ -308,6 +323,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { bluetooth_gatt_service_free, bluetooth_gatt_characteristic_free, + bluetooth_gatt_characteristic_value_move, + bluetooth_gatt_characteristic_value_free, bluetooth_get_event, }; diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h index 765003a5fc3..beaa6ae2825 100644 --- a/dlls/winebth.sys/unixlib.h +++ b/dlls/winebth.sys/unixlib.h @@ -74,6 +74,17 @@ struct bluetooth_gatt_characteristic_free_params unix_name_t characteristic; }; +struct bluetooth_gatt_characteristic_value_move_params +{ + struct winebluetooth_gatt_characteristic_value *val; + BYTE *buf; +}; + +struct bluetooth_gatt_characteristic_value_free_params +{ + UINT_PTR handle; +}; + struct bluetooth_device_disconnect_params { unix_name_t device; @@ -155,6 +166,8 @@ enum bluetoothapis_funcs unix_bluetooth_gatt_service_free, unix_bluetooth_gatt_characteristic_free, + unix_bluetooth_gatt_characteristic_value_move, + unix_bluetooth_gatt_characteristic_value_free, unix_bluetooth_get_event, diff --git a/dlls/winebth.sys/unixlib_priv.h b/dlls/winebth.sys/unixlib_priv.h index 4348aa6f5df..93e9ea35aa5 100644 --- a/dlls/winebth.sys/unixlib_priv.h +++ b/dlls/winebth.sys/unixlib_priv.h @@ -61,5 +61,7 @@ extern NTSTATUS bluez_auth_agent_send_response( void *auth_agent, struct unix_na extern NTSTATUS bluez_device_disconnect( void *connection, const char *device_path ); extern NTSTATUS bluez_device_start_pairing( void *dbus_connection, void *watcher_ctx, struct unix_name *device, IRP *irp ); extern NTSTATUS bluez_watcher_init( void *connection, void **ctx ); +extern void bluez_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *value, BYTE *buf ); +extern void bluez_gatt_characteristic_value_free( void *val ); 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 f91d2b9a440..98c716f98be 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -1,8 +1,7 @@ /* * Wine bluetooth APIs * - * Copyright 2024 Vibhav Pant - * Copyright 2025 Vibhav Pant + * Copyright 2024-2026 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -224,6 +223,33 @@ void winebluetooth_gatt_characteristic_free( winebluetooth_gatt_characteristic_t UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_free, &args ); } +static const char * +debugstr_winebluetooth_gatt_characteristic_value( const struct winebluetooth_gatt_characteristic_value *val ) +{ + return val ? wine_dbg_sprintf( "{ %I32u { %#Ix } }", val->size, val->handle ) : "(null)"; +} + +void winebluetooth_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *val, BYTE *dest ) +{ + struct bluetooth_gatt_characteristic_value_move_params args = {0}; + + TRACE( "(%s, %p)\n", debugstr_winebluetooth_gatt_characteristic_value( val ), dest ); + + args.val = val; + args.buf = dest; + UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_value_move, &args ); +} + +void winebluetooth_gatt_characteristic_value_free( struct winebluetooth_gatt_characteristic_value *val ) +{ + struct bluetooth_gatt_characteristic_value_free_params args = {0}; + + TRACE( "(%#Ix)\n", val->handle ); + + args.handle = val->handle; + UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_value_free, &args ); +} + NTSTATUS winebluetooth_get_event( struct winebluetooth_event *result ) { struct bluetooth_get_event_params params = {0}; diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 510d7fb72b7..ac33b16de71 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -130,6 +130,7 @@ struct bluetooth_gatt_characteristic winebluetooth_gatt_characteristic_t characteristic; BTH_LE_GATT_CHARACTERISTIC props; + BTH_LE_GATT_CHARACTERISTIC_VALUE *value; }; enum bluetooth_pdo_ext_type @@ -1333,6 +1334,18 @@ bluetooth_gatt_service_add_characteristic( struct winebluetooth_watcher_event_ga LeaveCriticalSection( &device->props_cs ); goto failed; } + if (characteristic.value.size) + { + entry->value = calloc( 1, offsetof( BTH_LE_GATT_CHARACTERISTIC_VALUE, Data[characteristic.value.size] ) ); + if (!entry->value) + { + LeaveCriticalSection( &device->props_cs ); + free( entry ); + goto failed; + } + entry->value->DataSize = characteristic.value.size; + winebluetooth_gatt_characteristic_value_move( &characteristic.value, entry->value->Data ); + } TRACE( "Adding GATT characteristic %#x under service %s for device %p\n", characteristic.props.AttributeHandle, debugstr_guid( &svc->uuid ), @@ -1352,6 +1365,7 @@ bluetooth_gatt_service_add_characteristic( struct winebluetooth_watcher_event_ga } failed: LeaveCriticalSection( &device_list_cs ); + winebluetooth_gatt_characteristic_value_free( &characteristic.value ); winebluetooth_gatt_characteristic_free( characteristic.characteristic ); winebluetooth_gatt_service_free( characteristic.service ); } @@ -1390,6 +1404,8 @@ static void bluetooth_gatt_characteristic_remove( winebluetooth_gatt_characteris winebluetooth_gatt_characteristic_free( chrc->characteristic ); winebluetooth_gatt_characteristic_free( handle ); + if (chrc->value) + free( chrc->value ); free( chrc ); return; } diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 765fe1d55f7..ff489097081 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -262,6 +262,15 @@ static inline BOOL winebluetooth_gatt_characteristic_equal( winebluetooth_gatt_c return c1.handle == c2.handle; } +struct winebluetooth_gatt_characteristic_value +{ + UINT32 size; + UINT_PTR handle; +}; + +void winebluetooth_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *val, BYTE *dest ); +void winebluetooth_gatt_characteristic_value_free( struct winebluetooth_gatt_characteristic_value *val ); + enum winebluetooth_watcher_event_type { BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED, @@ -346,6 +355,7 @@ struct winebluetooth_watcher_event_gatt_characteristic_added winebluetooth_gatt_characteristic_t characteristic; winebluetooth_gatt_service_t service; BTH_LE_GATT_CHARACTERISTIC props; + struct winebluetooth_gatt_characteristic_value value; }; union winebluetooth_watcher_event_data diff --git a/include/bthledef.h b/include/bthledef.h index 32585c06f8e..3cc9e01410a 100644 --- a/include/bthledef.h +++ b/include/bthledef.h @@ -54,6 +54,12 @@ typedef struct _BTH_LE_GATT_CHARACTERISTIC BOOLEAN HasExtendedProperties; } BTH_LE_GATT_CHARACTERISTIC, *PBTH_LE_GATT_CHARACTERISTIC; +typedef struct _BTH_LE_GATT_CHARACTERISTIC_VALUE +{ + ULONG DataSize; + UCHAR Data[1]; +} BTH_LE_GATT_CHARACTERISTIC_VALUE, *PBTH_LE_GATT_CHARACTERISTIC_VALUE; + DEFINE_GUID( GUID_BLUETOOTHLE_DEVICE_INTERFACE, 0x781aee18, 0x7733, 0x4ce4, 0xad, 0xd0, 0x91, 0xf4, 0x1c, 0x67, 0xb5, 0x92 ); DEFINE_GUID( GUID_BLUETOOTH_GATT_SERVICE_DEVICE_INTERFACE, 0x6e3bb679, 0x4372, 0x40c8, 0x9e, 0xaa, 0x45, 0x09, 0xdf, 0x26, 0x0c, 0xd8 ); DEFINE_GUID( BTH_LE_ATT_BLUETOOTH_BASE_GUID, 0, 0, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10208