From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/winebth.c | 85 +++++++++++++++++++++++++++++++++++++- include/wine/winebth.h | 9 ++++ 2 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 3b6bb293ac3..685e70aedc1 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -116,7 +116,8 @@ struct bluetooth_gatt_service unsigned int primary : 1; UINT16 handle;
- struct list characteristics; + CRITICAL_SECTION chars_cs; + struct list characteristics; /* Guarded by chars_cs */ };
struct bluetooth_gatt_characteristic @@ -180,10 +181,34 @@ static void uuid_to_le( const GUID *uuid, BTH_LE_UUID *le_uuid ) } }
+static void le_to_uuid( const BTH_LE_UUID *le_uuid, GUID *uuid ) +{ + if (le_uuid->IsShortUuid) + { + *uuid = BTH_LE_ATT_BLUETOOTH_BASE_GUID; + uuid->Data1 = le_uuid->Value.ShortUuid; + } + else + *uuid = le_uuid->Value.LongUuid; +} + +/* Caller should hold props_cs */ +static struct bluetooth_gatt_service *find_gatt_service( struct list *services, const GUID *uuid, UINT16 handle ) +{ + struct bluetooth_gatt_service *service; + LIST_FOR_EACH_ENTRY( service, services, struct bluetooth_gatt_service, entry ) + { + if (IsEqualGUID( &service->uuid, uuid ) && service->handle == handle) + return service; + } + return NULL; +} + static NTSTATUS bluetooth_remote_device_dispatch( DEVICE_OBJECT *device, struct bluetooth_remote_device *ext, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); ULONG outsize = stack->Parameters.DeviceIoControl.OutputBufferLength; + ULONG insize = stack->Parameters.DeviceIoControl.InputBufferLength; ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; NTSTATUS status = irp->IoStatus.Status;
@@ -232,6 +257,53 @@ static NTSTATUS bluetooth_remote_device_dispatch( DEVICE_OBJECT *device, struct status = STATUS_MORE_ENTRIES; break; } + case IOCTL_WINEBTH_LE_DEVICE_GET_GATT_CHARACTERISTICS: + { + const SIZE_T min_size = offsetof( struct winebth_le_device_get_gatt_characteristics_params, characteristics[0] ); + struct winebth_le_device_get_gatt_characteristics_params *chars = irp->AssociatedIrp.SystemBuffer; + struct bluetooth_gatt_characteristic *chrc; + struct bluetooth_gatt_service *service; + SIZE_T rem; + GUID uuid; + + if (!chars || insize < sizeof ( chars->service ) || outsize < sizeof( *chars )) + { + status = STATUS_INVALID_USER_BUFFER; + break; + } + + rem = (outsize - min_size)/sizeof( *chars->characteristics ); + status = STATUS_SUCCESS; + chars->count = 0; + le_to_uuid( &chars->service.ServiceUuid, &uuid ); + + EnterCriticalSection( &ext->props_cs ); + service = find_gatt_service( &ext->gatt_services, &uuid, chars->service.AttributeHandle ); + if (!service) + { + status = STATUS_INVALID_PARAMETER; + LeaveCriticalSection( &ext->props_cs ); + break; + } + + EnterCriticalSection( &service->chars_cs ); + LIST_FOR_EACH_ENTRY( chrc, &service->characteristics, struct bluetooth_gatt_characteristic, entry ) + { + chars->count++; + if (rem) + { + chars->characteristics[chars->count - 1] = chrc->props; + rem--; + } + } + LeaveCriticalSection( &service->chars_cs ); + LeaveCriticalSection( &ext->props_cs ); + + irp->IoStatus.Information = offsetof( struct winebth_le_device_get_gatt_characteristics_params, characteristics[chars->count] ); + if (chars->count > rem) + status = STATUS_MORE_ENTRIES; + break; + } default: FIXME( "Unimplemented IOCTL code: %#lx\n", code ); } @@ -1073,6 +1145,8 @@ static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_even service->handle = event.attr_handle; 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");
EnterCriticalSection( &device->props_cs ); list_add_tail( &device->gatt_services, &service->entry ); @@ -1115,11 +1189,20 @@ static void bluetooth_gatt_service_remove( winebluetooth_gatt_service_t service { if (winebluetooth_gatt_service_equal( svc->service, service )) { + struct bluetooth_gatt_characteristic *cur, *next; + 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; + DeleteCriticalSection( &svc->chars_cs ); + LIST_FOR_EACH_ENTRY_SAFE( cur, next, &svc->characteristics, struct bluetooth_gatt_characteristic, entry ) + { + winebluetooth_gatt_characteristic_free( cur->characteristic ); + free( cur ); + } free( svc ); winebluetooth_gatt_service_free( service ); return; diff --git a/include/wine/winebth.h b/include/wine/winebth.h index 6a2893d6474..572be91bb45 100644 --- a/include/wine/winebth.h +++ b/include/wine/winebth.h @@ -38,6 +38,8 @@
/* Get all primary GATT services for the LE device. */ #define IOCTL_WINEBTH_LE_DEVICE_GET_GATT_SERVICES CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xc0, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* Get all characteristics for a GATT service */ +#define IOCTL_WINEBTH_LE_DEVICE_GET_GATT_CHARACTERISTICS CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xc1, METHOD_BUFFERED, FILE_ANY_ACCESS)
DEFINE_GUID( GUID_WINEBTH_AUTHENTICATION_REQUEST, 0xca67235f, 0xf621, 0x4c27, 0x85, 0x65, 0xa4, 0xd5, 0x5e, 0xa1, 0x26, 0xe8 ); @@ -84,6 +86,13 @@ struct winebth_le_device_get_gatt_services_params BTH_LE_GATT_SERVICE services[0]; };
+struct winebth_le_device_get_gatt_characteristics_params +{ + BTH_LE_GATT_SERVICE service; + ULONG count; + BTH_LE_GATT_CHARACTERISTIC characteristics[0]; +}; + #pragma pack(pop)
#endif /* __WINEBTH_H__ */