From 4e9eedc1e8aae9ba9ce7dbbe3d15fbd6f0ec1a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 10 Jun 2026 09:24:18 +0800 Subject: [PATCH] usbip: upgrade outdated usbip-win2 drivers via capability probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The install fast path treated an openable VHCI interface as 'driver present', but the interface GUID is identical across all usbip-win2 releases while PLUGIN_HARDWARE_ONCE and STOP_ATTACH_ATTEMPTS only exist since 0.9.7.5 — a machine with an older community release passed the check and then failed every Plugin forever. The fast path now probes STOP_ATTACH_ATTEMPTS and falls through to the (in-place, FORCE) install when the driver lacks it. The probe's empty location doubles as cleanup, discarding ghost reattach attempts left by a previous process. --- common/usbipvhci/driver_windows.go | 31 ++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/common/usbipvhci/driver_windows.go b/common/usbipvhci/driver_windows.go index 61d828f05..865d4b9a9 100644 --- a/common/usbipvhci/driver_windows.go +++ b/common/usbipvhci/driver_windows.go @@ -45,9 +45,8 @@ var ( ) func installDriver() error { - controller, err := Open() + err := probeDriver() if err == nil { - _ = controller.Close() return nil } @@ -69,9 +68,8 @@ func installDriver() error { defer windows.ReleaseMutex(mutex) // Another process may have completed the install while we waited. - controller, err = Open() + err = probeDriver() if err == nil { - _ = controller.Close() return nil } @@ -88,6 +86,28 @@ func installDriver() error { return waitForInterface(20 * time.Second) } +// probeDriver verifies not just that the VHCI interface exists but that +// the bound driver speaks the bundled ABI. The interface GUID is +// identical across all usbip-win2 releases, while PLUGIN_HARDWARE_ONCE +// and STOP_ATTACH_ATTEMPTS only exist since 0.9.7.5 — an installed +// community release older than that opens fine and then fails every +// Plugin, so interface presence alone must not short-circuit the +// install. The probe doubles as cleanup: the empty location means +// "cancel all scheduled attach attempts", discarding ghost reconnects +// left over from a previous process toward dead loopback ports. +func probeDriver() error { + controller, err := Open() + if err != nil { + return err + } + defer controller.Close() + _, err = controller.StopAttachAttempts("", "", "") + if err != nil { + return E.Cause(err, "usbipvhci: installed driver lacks STOP_ATTACH_ATTEMPTS (older than 0.9.7.5); upgrading") + } + return nil +} + // addToDriverStore imports an INF (and its catalog-verified payload) into // the Windows driver store. SetupCopyOEMInfW rejects unsigned or tampered // packages; ERROR_FILE_EXISTS means the package is already present. @@ -179,9 +199,8 @@ func updateDriverForPlugAndPlayDevices(hardwareID, infPath string) error { func waitForInterface(timeout time.Duration) error { deadline := time.Now().Add(timeout) for { - controller, err := Open() + err := probeDriver() if err == nil { - _ = controller.Close() return nil } if time.Now().After(deadline) {