File 0001-Partial-implementation-for-BusQueryContainerId.patch of Package wine

From 4ebba13fe53a9732dea2b0fb6ddb832196953861 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
Date: Tue, 7 Jan 2025 19:42:27 +0100
Subject: [PATCH 1/7] Partial implementation for BusQueryContainerId

For devices implementing the ContainerID BOS the returned value will
be correct, and matching the Windows implementation.

The remaining cases have some implementation issues:
- Non-removable devices (e.g. laptop internal or multifunction devices)
  report distinct IDs instead of the ID of the containing parent
- Serial number based IDs are not hashed correctly, missing both the
  actual hashing and the (unknown) USB namespace
- Random IDs are not random but deterministic, although they are likely
  at least unique
---
 dlls/wineusb.sys/unixlib.c | 35 +++++++++++++++++++++++++
 dlls/wineusb.sys/unixlib.h |  2 ++
 dlls/wineusb.sys/wineusb.c | 53 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+)

diff --git a/dlls/wineusb.sys/unixlib.c b/dlls/wineusb.sys/unixlib.c
index a42482657b2..4c4e072c189 100644
--- a/dlls/wineusb.sys/unixlib.c
+++ b/dlls/wineusb.sys/unixlib.c
@@ -148,6 +148,41 @@ static void add_usb_device(libusb_device *libusb_device)
     usb_event.u.added_device.interface = false;
     usb_event.u.added_device.interface_index = -1;
 
+    memset(usb_event.u.added_device.container_id, 0, sizeof(usb_event.u.added_device.container_id));
+    if (device_desc.bcdUSB >= 0x201) {
+        struct libusb_bos_descriptor *bos_desc;
+        struct libusb_bos_dev_capability_descriptor *cid_cap = NULL;
+
+        if (libusb_get_bos_descriptor(unix_device->handle, &bos_desc) == LIBUSB_SUCCESS)
+        {
+            for (int i = 0; i < bos_desc->bNumDeviceCaps; i++)
+            {
+                if (bos_desc->dev_capability[i]->bDevCapabilityType == LIBUSB_BT_CONTAINER_ID)
+                {
+                    cid_cap = bos_desc->dev_capability[i];
+                }
+            }
+        }
+
+        if (cid_cap)
+        {
+            struct libusb_container_id_descriptor *container_id = NULL;
+            libusb_get_container_id_descriptor(NULL, cid_cap, &container_id);
+            if (container_id)
+            {
+                memcpy(usb_event.u.added_device.container_id, container_id->ContainerID, sizeof(usb_event.u.added_device.container_id));
+            }
+            libusb_free_container_id_descriptor(container_id);
+        }
+        libusb_free_bos_descriptor(bos_desc);
+    }
+
+    usb_event.u.added_device.serial[0] = '\0';
+    if (device_desc.iSerialNumber > 0) {
+        libusb_get_string_descriptor_ascii(unix_device->handle, device_desc.iSerialNumber,
+                usb_event.u.added_device.serial, sizeof(usb_event.u.added_device.serial));
+    }
+
     if (!(ret = libusb_get_active_config_descriptor(libusb_device, &config_desc)))
     {
         const struct libusb_interface *interface;
diff --git a/dlls/wineusb.sys/unixlib.h b/dlls/wineusb.sys/unixlib.h
index 33469f5a2b5..4b72c7afb94 100644
--- a/dlls/wineusb.sys/unixlib.h
+++ b/dlls/wineusb.sys/unixlib.h
@@ -46,6 +46,8 @@ struct usb_event
             UINT8 class, subclass, protocol, busnum, portnum;
             bool interface;
             INT16 interface_index;
+            unsigned char serial[33];
+            unsigned char container_id[16];
         } added_device;
         struct unix_device *removed_device;
         IRP *completed_irp;
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c
index 05603de1377..e2b0f65da8a 100644
--- a/dlls/wineusb.sys/wineusb.c
+++ b/dlls/wineusb.sys/wineusb.c
@@ -84,6 +84,10 @@ struct usb_device
 
     struct unix_device *unix_device;
 
+    unsigned char serial[33];
+
+    unsigned char container_id[16];
+
     LIST_ENTRY irp_list;
 };
 
@@ -141,6 +145,9 @@ static void add_unix_device(const struct usb_add_device_event *event)
     device->revision = event->revision;
     device->usbver = event->usbver;
 
+    memcpy(device->serial, event->serial, sizeof(device->serial));
+    memcpy(device->container_id, event->container_id, sizeof(device->container_id));
+
     EnterCriticalSection(&wineusb_cs);
     list_add_tail(&device_list, &device->entry);
     LeaveCriticalSection(&wineusb_cs);
@@ -403,6 +410,48 @@ static void get_compatible_ids(const struct usb_device *device, struct string_bu
     append_id(buffer, L"");
 }
 
+static void get_serial_number(const struct usb_device *device, struct string_buffer *buffer)
+{
+    if (device->serial[0] != '\0') {
+        append_id(buffer, L"%s", device->serial);
+    }
+}
+
+static void get_container_id(const struct usb_device *device, struct string_buffer *buffer, IRP *irp)
+{
+    GUID guid;
+
+    memset(&guid, 0, sizeof(guid));
+
+    if (memcmp(device->container_id, &guid, sizeof(guid)) != 0)
+    {
+        memcpy(&guid, device->container_id, sizeof(guid));
+    }
+    /* FIXME if the device is not removable, use the ContainerId of its parent */
+    else if (device->serial[0] != '\0')
+    {
+        /* Create temporary, unique string */
+        char s[45];
+        int len = snprintf(s, sizeof(s), "%0.32s%04%04X%04X", device->serial, device->vendor,
+            device->product, device->revision);
+        /* FIXME Should be UUIDv5 (SHA-1) hash, using a USB specific namespace */
+        memcpy(&guid, s, len > sizeof(guid) ? sizeof(guid) : len);
+    }
+    else
+    {
+        /* FIXME Should create a random ContainerId */
+        guid.Data1 = (device->vendor << 16) + device->product;
+        guid.Data2 = device->revision;
+        guid.Data4[0] = device->busnum;
+        guid.Data4[1] = device->portnum;
+    }
+
+    append_id(buffer, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+              (unsigned int)guid.Data1, guid.Data2, guid.Data3,
+              guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
+              guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] );
+}
+
 static NTSTATUS query_id(struct usb_device *device, IRP *irp, BUS_QUERY_ID_TYPE type)
 {
     struct string_buffer buffer = {0};
@@ -427,6 +476,10 @@ static NTSTATUS query_id(struct usb_device *device, IRP *irp, BUS_QUERY_ID_TYPE
             get_compatible_ids(device, &buffer);
             break;
 
+        case BusQueryContainerID:
+            get_container_id(device, &buffer, irp);
+            break;
+
         default:
             FIXME("Unhandled ID query type %#x.\n", type);
             return irp->IoStatus.Status;
-- 
2.49.0

openSUSE Build Service is sponsored by