From 723f9d59d8830cf5a73ceacded5229a2faa93c90 Mon Sep 17 00:00:00 2001
From: vadimgrn <67631045+vadimgrn@users.noreply.github.com>
Date: Wed, 14 Jul 2021 09:41:24 +0300
Subject: [PATCH] Fix vhci wdm driver installation failure
Signed-off-by: vadimgrn <67631045+vadimgrn@users.noreply.github.com>
---
driver/vhci/usbip_root.inf | 2 +-
driver/vhci/usbip_vhci.inf | 8 +-
driver/vhci/usbip_vhci.vcxproj | 8 +-
driver/vhci/vhci_dev.h | 8 +-
driver/vhci/vhci_plugin.c | 55 +++---
driver/vhci/vhci_pnp.h | 14 ++
driver/vhci/vhci_pnp_id.c | 334 +++++++++++++++++++++++----------
7 files changed, 290 insertions(+), 139 deletions(-)
diff --git a/driver/vhci/usbip_root.inf b/driver/vhci/usbip_root.inf
index cd2c6042..b274de71 100644
--- a/driver/vhci/usbip_root.inf
+++ b/driver/vhci/usbip_root.inf
@@ -48,7 +48,7 @@ AddService = usbip_vhci,%SPSVCINST_ASSOCSERVICE%, usbip_vhci_Service_Inst
[usbip_vhci_Service_Inst]
DisplayName = %ServiceDesc%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
-StartType = 3 ; SERVICE_DEMAND_START
+StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\usbip_vhci.sys
LoadOrderGroup = Extended Base
diff --git a/driver/vhci/usbip_vhci.inf b/driver/vhci/usbip_vhci.inf
index 38b52138..7c27f9c0 100644
--- a/driver/vhci/usbip_vhci.inf
+++ b/driver/vhci/usbip_vhci.inf
@@ -18,7 +18,7 @@ PnpLockDown=1
[Standard.NT$ARCH$]
%DeviceDesc%=usbip_vhci_Device, USBIPWIN\vhci
-%vhub_DeviceDesc%=usbip_vhci_Device, USB\ROOT_HUB&VID1209&PID8250&REV0000
+%vhub_DeviceDesc%=usbip_vhci_Device, USB\ROOT_HUB&VID_1209&PID_8250&REV_0000
[DestinationDirs]
DefaultDestDir = 12
@@ -38,7 +38,7 @@ CopyFiles=Drivers_Dir
[usbip_vhci_Device.NT$ARCH$.HW]
AddReg=usbip_vhci_Device_AddReg
-[usbip_vhci_Device_AddReg]
+[usbip_vhci_Device_AddReg]
HKR,,DeviceCharacteristics,0x10001,0x0100 ; Use same security checks on relative opens
;-------------- Service installation
@@ -49,7 +49,7 @@ AddService = usbip_vhci,%SPSVCINST_ASSOCSERVICE%, usbip_vhci_Service_Inst
[usbip_vhci_Service_Inst]
DisplayName = %ServiceDesc%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
-StartType = 3 ; SERVICE_DEMAND_START
+StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\usbip_vhci.sys
LoadOrderGroup = Extended Base
@@ -62,4 +62,4 @@ DiskId1 = "usbip-win VHCI Disk"
DeviceDesc = "usbip-win VHCI"
vhub_DeviceDesc = "usbip-win VHUB"
ServiceDesc = "usbip-win VHCI Service"
-DisplayClassName = "usbip-win"
\ No newline at end of file
+DisplayClassName = "usbip-win"
diff --git a/driver/vhci/usbip_vhci.vcxproj b/driver/vhci/usbip_vhci.vcxproj
index efdff777..b8a0f446 100644
--- a/driver/vhci/usbip_vhci.vcxproj
+++ b/driver/vhci/usbip_vhci.vcxproj
@@ -215,9 +215,7 @@
0.3.4.0
-
- sha256
-
+
gencat.bat $(OutDir) 10_$(DDKPlatform) $(SolutionDir)/driver/usbip_test.pfx
@@ -240,9 +238,7 @@
0.3.4.0
-
- sha256
-
+
gencat.bat $(OutDir) 10_$(DDKPlatform) $(SolutionDir)/driver/usbip_test.pfx
diff --git a/driver/vhci/vhci_dev.h b/driver/vhci/vhci_dev.h
index eb63968b..415f622c 100644
--- a/driver/vhci/vhci_dev.h
+++ b/driver/vhci/vhci_dev.h
@@ -23,10 +23,6 @@
#define IS_FDO(type) ((type) == VDEV_ROOT || (type) == VDEV_VHCI || (type) == VDEV_VHUB)
-#define HWID_ROOT L"USBIPWIN\\root"
-#define HWID_VHCI L"USBIPWIN\\vhci"
-#define HWID_VHUB L"USB\\ROOT_HUB&VID1209&PID8250&REV0000"
-
extern LPCWSTR devcodes[];
// These are the states a vpdo or vhub transition upon
@@ -65,7 +61,7 @@ typedef struct _vdev {
PDEVICE_OBJECT Self;
vdev_type_t type;
- // reference count for maintaining vdev validity
+ // reference count for maintaining vdev validity
LONG n_refs;
// We track the state of the device with every PnP Irp
@@ -174,7 +170,7 @@ typedef struct
BOOLEAN plugged;
UCHAR speed;
- UCHAR unused; /* 4 bytes alignment */
+ UCHAR num_configurations; // Number of Possible Configurations
// a pending irp when no urb is requested
PIRP pending_read_irp;
diff --git a/driver/vhci/vhci_plugin.c b/driver/vhci/vhci_plugin.c
index 0876016d..4987f9b0 100644
--- a/driver/vhci/vhci_plugin.c
+++ b/driver/vhci/vhci_plugin.c
@@ -58,8 +58,8 @@ setup_vpdo_with_dsc_dev(pvpdo_dev_t vpdo, PUSB_DEVICE_DESCRIPTOR dsc_dev)
vpdo->subclass = dsc_dev->bDeviceSubClass;
vpdo->protocol = dsc_dev->bDeviceProtocol;
vpdo->speed = (UCHAR)get_usb_speed(dsc_dev->bcdUSB);
- }
- else {
+ vpdo->num_configurations = dsc_dev->bNumConfigurations;
+ } else {
vpdo->vendor = 0;
vpdo->product = 0;
vpdo->revision = 0;
@@ -67,37 +67,40 @@ setup_vpdo_with_dsc_dev(pvpdo_dev_t vpdo, PUSB_DEVICE_DESCRIPTOR dsc_dev)
vpdo->subclass = 0;
vpdo->protocol = 0;
vpdo->speed = USB_SPEED_LOW;
+ vpdo->num_configurations = 0;
}
}
static void
setup_vpdo_with_dsc_conf(pvpdo_dev_t vpdo, PUSB_CONFIGURATION_DESCRIPTOR dsc_conf)
{
- if (dsc_conf) {
- vpdo->inum = dsc_conf->bNumInterfaces;
-
- /* Many devices have 0 usb class number in a device descriptor.
- * 0 value means that class number is determined at interface level.
- * USB class, subclass and protocol numbers should be setup before importing.
- * Because windows vhci driver builds a device compatible id with those numbers.
- */
- if (vpdo->usbclass == 0 && vpdo->subclass == 0 && vpdo->protocol == 0) {
- /* buf[4] holds the number of interfaces in USB configuration.
- * Supplement class/subclass/protocol only if there exists only single interface.
- * A device with multiple interfaces will be detected as a composite by vhci.
- */
- if (vpdo->inum == 1) {
- PUSB_INTERFACE_DESCRIPTOR dsc_intf = dsc_find_first_intf(dsc_conf);
- if (dsc_intf) {
- vpdo->usbclass = dsc_intf->bInterfaceClass;
- vpdo->subclass = dsc_intf->bInterfaceSubClass;
- vpdo->protocol = dsc_intf->bInterfaceProtocol;
- }
- }
- }
- }
- else {
+ if (!dsc_conf) {
vpdo->inum = 0;
+ return;
+ }
+
+ vpdo->inum = dsc_conf->bNumInterfaces;
+
+ /* Many devices have 0 usb class number in a device descriptor.
+ * 0 value means that class number is determined at interface level.
+ * USB class, subclass and protocol numbers should be setup before importing.
+ * Because windows vhci driver builds a device compatible id with those numbers.
+ */
+ if (vpdo->usbclass || vpdo->subclass || vpdo->protocol) {
+ return;
+ }
+
+ /* buf[4] holds the number of interfaces in USB configuration.
+ * Supplement class/subclass/protocol only if there exists only single interface.
+ * A device with multiple interfaces will be detected as a composite by vhci.
+ */
+ if (vpdo->inum == 1) {
+ PUSB_INTERFACE_DESCRIPTOR dsc_intf = dsc_find_first_intf(dsc_conf);
+ if (dsc_intf) {
+ vpdo->usbclass = dsc_intf->bInterfaceClass;
+ vpdo->subclass = dsc_intf->bInterfaceSubClass;
+ vpdo->protocol = dsc_intf->bInterfaceProtocol;
+ }
}
}
diff --git a/driver/vhci/vhci_pnp.h b/driver/vhci/vhci_pnp.h
index cb70ff28..b1fd05a9 100644
--- a/driver/vhci/vhci_pnp.h
+++ b/driver/vhci/vhci_pnp.h
@@ -3,6 +3,20 @@
#include "basetype.h"
#include "vhci_dev.h"
+#define HWID_ROOT L"USBIPWIN\\root"
+#define HWID_VHCI L"USBIPWIN\\vhci"
+
+#define VHUB_PREFIX L"USB\\ROOT_HUB"
+#define VHUB_VID L"1209"
+#define VHUB_PID L"8250"
+#define VHUB_REV L"0000"
+
+#define HWID_VHUB \
+ VHUB_PREFIX \
+ L"&VID_" VHUB_VID \
+ L"&PID_" VHUB_PID \
+ L"&REV_" VHUB_REV
+
#define INITIALIZE_PNP_STATE(_Data_) \
(_Data_)->common.DevicePnPState = NotStarted;\
(_Data_)->common.PreviousPnPState = NotStarted;
diff --git a/driver/vhci/vhci_pnp_id.c b/driver/vhci/vhci_pnp_id.c
index b1eba7e5..33c700cb 100644
--- a/driver/vhci/vhci_pnp_id.c
+++ b/driver/vhci/vhci_pnp_id.c
@@ -1,183 +1,325 @@
#include "vhci.h"
-
-#include "vhci_dev.h"
+#include "vhci_pnp.h"
#include "usbip_vhci_api.h"
#include "vhci_irp.h"
-#define DEVID_VHCI HWID_VHCI
-#define DEVID_VHUB L"USB\\ROOT_HUB"
-
-#define HWIDS_VHCI HWID_VHCI L"\0"
-#define HWIDS_VHUB HWID_VHUB L"\0USB\\ROOT_HUB&VID1209&PID8250\0USB\\ROOT_HUB\0"
+#include
-/* Device with zero class/subclass/protocol */
-#define IS_ZERO_CLASS(vpdo) ((vpdo)->usbclass == 0x00 && (vpdo)->subclass == 0x00 && (vpdo)->protocol == 0x00 && (vpdo)->inum > 1)
-/* Device with IAD(Interface Association Descriptor) */
-#define IS_IAD_DEVICE(vpdo) ((vpdo)->usbclass == 0xef && (vpdo)->subclass == 0x02 && (vpdo)->protocol == 0x01)
-
-static LPCWSTR vdev_devids[] = {
- NULL, DEVID_VHCI, NULL, DEVID_VHUB, NULL, (LPCWSTR)TRUE
+#define DEVID_VHCI HWID_VHCI
+#define DEVID_VHUB HWID_VHUB
+
+/*
+ * The first hardware ID in the list should be the device ID, and
+ * the remaining IDs should be listed in order of decreasing suitability.
+ */
+#define HWIDS_VHCI DEVID_VHCI L"\0"
+
+#define HWIDS_VHUB \
+ DEVID_VHUB L"\0" \
+ VHUB_PREFIX L"&VID_" VHUB_VID L"&PID_" VHUB_PID L"\0"
+
+// vdev_type_t is an index
+static const LPCWSTR vdev_devids[] = {
+ NULL, DEVID_VHCI,
+ NULL, DEVID_VHUB,
+ NULL, L"USB\\VID_%04hx&PID_%04hx" // 21 chars after formatting
};
-static ULONG vdev_devid_lens[] = {
- 0, sizeof(DEVID_VHCI), 0, sizeof(DEVID_VHUB), 0, 22 * sizeof(wchar_t)
+static const size_t vdev_devid_size[] = {
+ 0, sizeof(DEVID_VHCI),
+ 0, sizeof(DEVID_VHUB),
+ 0, (21 + 1)*sizeof(WCHAR)
};
-static LPCWSTR vdev_hwids[] = {
- NULL, HWIDS_VHCI, NULL, HWIDS_VHUB, NULL, (LPCWSTR)TRUE
+static const LPCWSTR vdev_hwids[] = {
+ NULL, HWIDS_VHCI,
+ NULL, HWIDS_VHUB,
+ NULL, L"USB\\VID_%04hx&PID_%04hx&REV_%04hx;" // 31 chars after formatting
+ L"USB\\VID_%04hx&PID_%04hx;" // 22 chars after formatting
};
-static ULONG vdev_hwids_lens[] = {
- 0, sizeof(HWIDS_VHCI), 0, sizeof(HWIDS_VHUB), 0, 54 * sizeof(wchar_t)
+static const size_t vdev_hwids_size[] = {
+ 0, sizeof(HWIDS_VHCI),
+ 0, sizeof(HWIDS_VHUB),
+ 0, (31 + 22 + 1)*sizeof(WCHAR)
};
+void subst_char(wchar_t *s, wchar_t ch, wchar_t rep)
+{
+ for ( ; *s; ++s) {
+ if (*s == ch) {
+ *s = rep;
+ }
+ }
+}
+
+/*
+ Enumeration of USB Composite Devices.
+
+ The bus driver also reports a compatible identifier (ID) of USB\COMPOSITE,
+ if the device meets the following requirements:
+ * The device class field of the device descriptor (bDeviceClass) must contain a value of zero,
+ or the class (bDeviceClass), subclass (bDeviceSubClass), and protocol (bDeviceProtocol) fields
+ of the device descriptor must have the values 0xEF, 0x02 and 0x01 respectively, as explained
+ in USB Interface Association Descriptor.
+ * The device must have multiple interfaces.
+ * The device must have a single configuration.
+
+ The bus driver also checks the device class (bDeviceClass), subclass (bDeviceSubClass),
+ and protocol (bDeviceProtocol) fields of the device descriptor. If these fields are zero,
+ the device is a composite device, and the bus driver reports an extra compatible
+ identifier (ID) of USB\COMPOSITE for the PDO.
+*/
+static bool is_composite(vpdo_dev_t *vpdo)
+{
+ bool ok = !vpdo->usbclass || // generic composite device
+ (vpdo->usbclass == 0xEF &&
+ vpdo->subclass == 0x02 &&
+ vpdo->protocol == 0x01); // IAD composite device
+
+ if (ok && vpdo->inum > 1 && vpdo->num_configurations == 1) {
+ return true;
+ }
+
+ return vpdo->num_configurations && // zero if the device descriptor wasn't read yet
+ !(vpdo->usbclass || vpdo->subclass || vpdo->protocol);
+}
+
+/*
+ * For all USB devices, the USB bus driver reports a device ID with the following format:
+ * USB\VID_xxxx&PID_yyyy
+ */
static NTSTATUS
-setup_device_id(pvdev_t vdev, PIRP irp)
+setup_device_id(PWCHAR *result, bool *subst_result, pvdev_t vdev, PIRP irp)
{
- PWCHAR id_dev;
+ UNREFERENCED_PARAMETER(subst_result);
+ UNREFERENCED_PARAMETER(irp);
+
+ NTSTATUS status = STATUS_SUCCESS;
- if (vdev_devids[vdev->type] == NULL) {
- DBGI(DBG_PNP, "%s: query device id: NOT SUPPORTED\n", dbg_vdev_type(vdev->type));
+ LPCWSTR str = vdev_devids[vdev->type];
+ if (!str) {
return STATUS_NOT_SUPPORTED;
}
- id_dev = ExAllocatePoolWithTag(PagedPool, vdev_devid_lens[vdev->type], USBIP_VHCI_POOL_TAG);
- if (id_dev == NULL) {
+
+ size_t str_sz = vdev_devid_size[vdev->type];
+
+ PWCHAR id_dev = ExAllocatePoolWithTag(PagedPool, str_sz, USBIP_VHCI_POOL_TAG);
+ if (!id_dev) {
DBGE(DBG_PNP, "%s: query device id: out of memory\n", dbg_vdev_type(vdev->type));
return STATUS_INSUFFICIENT_RESOURCES;
}
+
if (vdev->type == VDEV_VPDO) {
- pvpdo_dev_t vpdo = (pvpdo_dev_t)vdev;
- RtlStringCchPrintfW(id_dev, 22, L"USB\\VID_%04hx&PID_%04hx", vpdo->vendor, vpdo->product);
+ pvpdo_dev_t vpdo = (pvpdo_dev_t)vdev;
+ status = RtlStringCbPrintfW(id_dev, str_sz, str, vpdo->vendor, vpdo->product);
+ } else {
+ RtlCopyMemory(id_dev, str, str_sz);
}
- else
- RtlStringCchCopyW(id_dev, vdev_devid_lens[vdev->type], vdev_devids[vdev->type]);
-
- irp->IoStatus.Information = (ULONG_PTR)id_dev;
- DBGI(DBG_PNP, "%s: device id: %S\n", dbg_vdev_type(vdev->type), id_dev);
+ if (status == STATUS_SUCCESS) {
+ *result = id_dev;
+ }
- return STATUS_SUCCESS;
+ return status;
}
static NTSTATUS
-setup_hw_ids(pvdev_t vdev, PIRP irp)
+setup_hw_ids(PWCHAR *result, bool *subst_result, pvdev_t vdev, PIRP irp)
{
- PWCHAR ids_hw;
+ UNREFERENCED_PARAMETER(irp);
+
+ NTSTATUS status = STATUS_SUCCESS;
- if (vdev_hwids[vdev->type] == NULL) {
- DBGI(DBG_PNP, "%s: query hw ids: NOT SUPPORTED%s\n", dbg_vdev_type(vdev->type));
+ LPCWSTR str = vdev_hwids[vdev->type];
+ if (!str) {
return STATUS_NOT_SUPPORTED;
}
- ids_hw = ExAllocatePoolWithTag(PagedPool, vdev_hwids_lens[vdev->type], USBIP_VHCI_POOL_TAG);
- if (ids_hw == NULL) {
+
+ size_t str_sz = vdev_hwids_size[vdev->type];
+
+ PWCHAR ids_hw = ExAllocatePoolWithTag(PagedPool, str_sz, USBIP_VHCI_POOL_TAG);
+ if (!ids_hw) {
DBGE(DBG_PNP, "%s: query hw ids: out of memory\n", dbg_vdev_type(vdev->type));
return STATUS_INSUFFICIENT_RESOURCES;
}
- if (vdev->type == VDEV_VPDO) {
- pvpdo_dev_t vpdo = (pvpdo_dev_t)vdev;
- RtlStringCchPrintfW(ids_hw, 31, L"USB\\VID_%04hx&PID_%04hx&REV_%04hx", vpdo->vendor, vpdo->product, vpdo->revision);
- RtlStringCchPrintfW(ids_hw + 31, 22, L"USB\\VID_%04hx&PID_%04hx", vpdo->vendor, vpdo->product);
- ids_hw[53] = L'\0';
- }
- else {
- RtlCopyMemory(ids_hw, vdev_hwids[vdev->type], vdev_hwids_lens[vdev->type]);
- }
- irp->IoStatus.Information = (ULONG_PTR)ids_hw;
+ *subst_result = vdev->type == VDEV_VPDO;
- DBGI(DBG_PNP, "%s: hw id: %S\n", dbg_vdev_type(vdev->type), ids_hw);
+ if (*subst_result) {
+ pvpdo_dev_t vpdo = (pvpdo_dev_t)vdev;
+ status = RtlStringCbPrintfW(ids_hw, str_sz, str,
+ vpdo->vendor, vpdo->product, vpdo->revision,
+ vpdo->vendor, vpdo->product);
+ } else {
+ RtlCopyMemory(ids_hw, str, str_sz);
+ }
- return STATUS_SUCCESS;
+ if (status == STATUS_SUCCESS) {
+ *result = ids_hw;
+ }
+
+ return status;
}
+/*
+Instance ID
+
+An instance ID is a device identification string that distinguishes a device
+from other devices of the same type on a computer. An instance ID contains
+serial number information, if supported by the underlying bus, or some kind
+of location information. The string cannot contain any "\" characters;
+otherwise, the generic format of the string is bus-specific.
+
+The number of characters of an instance ID, excluding a NULL-terminator, must be
+less than MAX_DEVICE_ID_LEN. In addition, when an instance ID is concatenated
+to a device ID to create a device instance ID, the lengths of the device ID
+and the instance ID are further constrained by the maximum possible length
+of a device instance ID.
+
+The UniqueID member of the DEVICE_CAPABILITIES structure for a device indicates
+if a bus-supplied instance ID is unique across the system, as follows:
+ * If UniqueID is FALSE, the bus-supplied instance ID for a device is unique
+ only to the device's bus. The Plug and Play (PnP) manager modifies
+ the bus-supplied instance ID, and combines it with the corresponding device ID,
+ to create a device instance ID that is unique in the system.
+ * If UniqueID is TRUE, the device instance ID, formed from the bus-supplied
+ device ID and instance ID, uniquely identifies a device in the system.
+
+An instance ID is persistent across system restarts.
+*/
static NTSTATUS
-setup_inst_id(pvdev_t vdev, PIRP irp)
+setup_inst_id_or_serial(PWCHAR *result, bool *subst_result, pvdev_t vdev, PIRP irp, bool serial)
{
- pvpdo_dev_t vpdo;
- PWCHAR id_inst;
+ UNREFERENCED_PARAMETER(subst_result);
+ UNREFERENCED_PARAMETER(irp);
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ const size_t max_wchars = MAX_VHCI_SERIAL_ID + 1;
+ // static_assert(MAX_VHCI_SERIAL_ID <= MAX_DEVICE_ID_LEN, "assert");
if (vdev->type != VDEV_VPDO) {
- DBGI(DBG_PNP, "%s: query instance id: NOT SUPPORTED\n", dbg_vdev_type(vdev->type));
return STATUS_NOT_SUPPORTED;
}
- vpdo = (pvpdo_dev_t)vdev;
+ pvpdo_dev_t vpdo = (pvpdo_dev_t)vdev;
- id_inst = ExAllocatePoolWithTag(PagedPool, (MAX_VHCI_SERIAL_ID + 1) * sizeof(wchar_t), USBIP_VHCI_POOL_TAG);
- if (id_inst == NULL) {
- DBGE(DBG_PNP, "vpdo: query instance id: out of memory\n");
+ PWCHAR id_inst = ExAllocatePoolWithTag(PagedPool, max_wchars*sizeof(wchar_t), USBIP_VHCI_POOL_TAG);
+ if (!id_inst) {
+ DBGE(DBG_PNP, "vpdo: %s(%s): out of memory\n", __func__,
+ serial ? "DeviceSerialNumber" : "InstanceID");
return STATUS_INSUFFICIENT_RESOURCES;
}
- if (vpdo->winstid != NULL)
- RtlStringCchCopyW(id_inst, MAX_VHCI_SERIAL_ID + 1, vpdo->winstid);
- else
- RtlStringCchPrintfW(id_inst, 5, L"%04hx", vpdo->port);
-
- irp->IoStatus.Information = (ULONG_PTR)id_inst;
+ status = vpdo->winstid ? RtlStringCchCopyW(id_inst, max_wchars, vpdo->winstid) : // is a serial
+ serial ? RtlStringCchPrintfW(id_inst, max_wchars, L"") : // has no serial
+ RtlStringCchPrintfW(id_inst, max_wchars, L"%04hx", vpdo->port); // instance id
- DBGI(DBG_PNP, "vpdo: instance id: %S\n", id_inst);
+ if (status == STATUS_SUCCESS) {
+ *result = id_inst;
+ }
- return STATUS_SUCCESS;
+ return status;
}
static NTSTATUS
-setup_compat_ids(pvdev_t vdev, PIRP irp)
+setup_compat_ids(PWCHAR *result, bool *subst_result, pvdev_t vdev, PIRP irp)
{
- pvpdo_dev_t vpdo;
- PWCHAR ids_compat;
+ UNREFERENCED_PARAMETER(irp);
+
+ const wchar_t fmt[] =
+ L"USB\\Class_%02hhx&SubClass_%02hhx&Prot_%02hhx;" // 33 chars after formatting
+ L"USB\\Class_%02hhx&SubClass_%02hhx;" // 25 chars after formatting
+ L"USB\\Class_%02hhx;"; // 13 chars after formatting
+
+ const wchar_t comp[] = L"USB\\COMPOSITE\0";
+ const size_t max_wchars = 33 + 25 + 13 + sizeof(comp)/sizeof(*comp);
if (vdev->type != VDEV_VPDO) {
- DBGI(DBG_PNP, "%s: query compatible id: NOT SUPPORTED\n", dbg_vdev_type(vdev->type));
return STATUS_NOT_SUPPORTED;
}
- vpdo = (pvpdo_dev_t)vdev;
+ pvpdo_dev_t vpdo = (pvpdo_dev_t)vdev;
- ids_compat = ExAllocatePoolWithTag(PagedPool, 86 * sizeof(wchar_t), USBIP_VHCI_POOL_TAG);
- if (ids_compat == NULL) {
+ PWCHAR ids_compat = ExAllocatePoolWithTag(PagedPool, max_wchars * sizeof(wchar_t), USBIP_VHCI_POOL_TAG);
+ if (!ids_compat) {
DBGE(DBG_PNP, "vpdo: query compatible id: out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
- RtlStringCchPrintfW(ids_compat, 33, L"USB\\Class_%02hhx&SubClass_%02hhx&Prot_%02hhx", vpdo->usbclass, vpdo->subclass, vpdo->protocol);
- RtlStringCchPrintfW(ids_compat + 33, 25, L"USB\\Class_%02hhx&SubClass_%02hhx", vpdo->usbclass, vpdo->subclass);
- RtlStringCchPrintfW(ids_compat + 58, 13, L"USB\\Class_%02hhx", vpdo->usbclass);
- if (IS_ZERO_CLASS(vpdo) || IS_IAD_DEVICE(vpdo)) {
- RtlStringCchCopyW(ids_compat + 71, 14, L"USB\\COMPOSITE");
- ids_compat[85] = L'\0';
- }
- else
- ids_compat[71] = L'\0';
- irp->IoStatus.Information = (ULONG_PTR)ids_compat;
- return STATUS_SUCCESS;
+
+ NTSTRSAFE_PWSTR dest_end = NULL;
+ size_t remaining = 0;
+
+ NTSTATUS status = RtlStringCchPrintfExW(ids_compat, max_wchars, &dest_end, &remaining, 0, fmt,
+ vpdo->usbclass, vpdo->subclass, vpdo->protocol,
+ vpdo->usbclass, vpdo->subclass,
+ vpdo->usbclass);
+
+ if (status == STATUS_SUCCESS) {
+ *result = ids_compat;
+ *subst_result = true;
+ if (is_composite(vpdo)) {
+ NT_ASSERT(remaining == sizeof(comp)/sizeof(*comp));
+ RtlCopyMemory(dest_end, comp, sizeof(comp));
+ }
+ }
+
+ return status;
}
+/*
+ * On success, a driver sets Irp->IoStatus.Information to a WCHAR pointer
+ * that points to the requested information. On error, a driver sets
+ * Irp->IoStatus.Information to zero.
+ */
PAGEABLE NTSTATUS
pnp_query_id(pvdev_t vdev, PIRP irp, PIO_STACK_LOCATION irpstack)
{
- NTSTATUS status = STATUS_NOT_SUPPORTED;
+ NTSTATUS status = STATUS_NOT_SUPPORTED;
- DBGI(DBG_PNP, "%s: query id: %s\n", dbg_vdev_type(vdev->type), dbg_bus_query_id_type(irpstack->Parameters.QueryId.IdType));
+ PWCHAR result = NULL;
+ bool subst_result = false;
+
+ BUS_QUERY_ID_TYPE type = irpstack->Parameters.QueryId.IdType;
PAGED_CODE();
- switch (irpstack->Parameters.QueryId.IdType) {
+ switch (type) {
case BusQueryDeviceID:
- status = setup_device_id(vdev, irp);
+ status = setup_device_id(&result, &subst_result, vdev, irp);
break;
case BusQueryInstanceID:
- status = setup_inst_id(vdev, irp);
+ status = setup_inst_id_or_serial(&result, &subst_result, vdev, irp, false);
break;
case BusQueryHardwareIDs:
- status = setup_hw_ids(vdev, irp);
+ status = setup_hw_ids(&result, &subst_result, vdev, irp);
break;
case BusQueryCompatibleIDs:
- status = setup_compat_ids(vdev, irp);
+ status = setup_compat_ids(&result, &subst_result, vdev, irp);
+ break;
+ case BusQueryDeviceSerialNumber:
+ status = setup_inst_id_or_serial(&result, &subst_result, vdev, irp, true);
break;
- default:
- DBGI(DBG_PNP, "%s: unhandled query id: %s\n", dbg_vdev_type(vdev->type), dbg_bus_query_id_type(irpstack->Parameters.QueryId.IdType));
+ case BusQueryContainerID:
break;
}
+ if (status == STATUS_SUCCESS) {
+ DBGI(DBG_PNP, "%s: %s: %S\n", dbg_vdev_type(vdev->type), dbg_bus_query_id_type(type), result);
+ if (subst_result) {
+ subst_char(result, L';', L'\0');
+ }
+ } else {
+ DBGW(DBG_PNP, "%s: %s: %s\n", dbg_vdev_type(vdev->type), dbg_bus_query_id_type(type),
+ status == STATUS_NOT_SUPPORTED ? "not supported" : "failed");
+
+ if (result) {
+ ExFreePoolWithTag(result, USBIP_VHCI_POOL_TAG);
+ result = NULL;
+ }
+ }
+
+ irp->IoStatus.Information = (ULONG_PTR)result;
return irp_done(irp, status);
-}
\ No newline at end of file
+}