Files
sing-box/common/vboxusb/vboxusb.go
T
世界 6a4ae5263e usbip: extract URBEngine + userspaceURBSession from darwin backend
Both the existing darwin backend and the upcoming windows backend
drive USB devices from user space (IOUSBHost CGO calls vs. VBoxUSB
IOCTLs). Refactor the per-attachment URB loop out of host_darwin.go
into a platform-agnostic userspaceURBSession that talks to a URBEngine
interface; the darwin-specific dispatch becomes a 30-line
darwinIOUSBHostEngine. Linux's kernelHandoffSession is untouched.

Move hex8 into shared.go and add usbipStatusEIO so the shared session
does not depend on golang.org/x/sys/unix (Windows has no equivalent).
2026-06-09 10:42:35 +08:00

176 lines
5.9 KiB
Go

// Package vboxusb provides a Go binding for Oracle's VBoxUSB +
// VBoxUSBMon kernel drivers on Windows (amd64 and arm64), packaged
// for embedding in sing-box.
//
// The driver pair is shipped verbatim from dorssel/usbipd-win, which
// in turn carries the binaries unchanged from upstream VirtualBox.
// VBoxUSB.sys provides per-device user-space URB submission via
// SUPUSB_IOCTL_* IOCTLs; VBoxUSBMon.sys is the system-wide monitor
// that arranges for VBoxUSB to bind matching devices on PnP arrival.
//
// Administrator is required for the first Open in a process so SCM
// can load VBoxUSBMon. The drivers are Microsoft-signed via Oracle's
// VirtualBox publishing chain; we never re-sign or modify them.
//
// Upstream:
// - https://github.com/dorssel/usbipd-win (driver packaging)
// - https://github.com/VirtualBox/VirtualBox (driver source)
//
// License: GPLv2-or-later (drivers) and GPLv3 (this binding); see
// assets/*.license files for the per-asset SPDX records.
package vboxusb
// AssetVersion identifies the bundled VBoxUSB driver release. Bumped
// in lock-step with the .sys files copied from
// /tmp/usbipd-win/Drivers/{x64,arm64}/. The on-disk extraction path
// (and SCM service version reuse) is keyed on this string, so a
// version bump triggers re-extraction.
const AssetVersion = "7.2.8.23730"
// DriverVersion enforces the minimum acceptable VBoxUSB/VBoxUSBMon
// driver major version reported via GET_VERSION. Mirrors usbipd-win's
// USBDRV_MAJOR_VERSION / USBMON_MAJOR_VERSION (both 5).
const (
DriverMajorVersion = 5
DriverMinorVersion = 0
)
// Driver and device names. The Windows side opens the monitor via
// CreateFile(MonitorDevicePath); per-device VBoxUSB handles are opened
// via SetupDi-resolved interface paths under the GUID below.
const (
MonitorServiceName = "VBoxUSBMon"
MonitorDevicePath = `\\.\VBoxUSBMon`
)
// MonitorAccessGUID is GUID_CLASS_VBOXUSB from VirtualBox usblib-win.h.
// Used with SetupDiEnumDeviceInterfaces to find the per-device file
// path after VBoxUSB binds.
var MonitorAccessGUID = GUID{
Data1: 0x00873fdf,
Data2: 0xCAFE,
Data3: 0x80EE,
Data4: [8]byte{0xaa, 0x5e, 0x00, 0xc0, 0x4f, 0xb1, 0x72, 0x0b},
}
// USBDeviceInterfaceGUID is GUID_DEVINTERFACE_USB_DEVICE
// ({a5dcbf10-6530-11d2-901f-00c04fb951ed}). Used to enumerate plugged
// USB devices regardless of which function driver currently owns them.
var USBDeviceInterfaceGUID = GUID{
Data1: 0xa5dcbf10,
Data2: 0x6530,
Data3: 0x11d2,
Data4: [8]byte{0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed},
}
// USBHubInterfaceGUID is GUID_DEVINTERFACE_USB_HUB
// ({f18a0e88-c30c-11d0-8815-00a0c906bed8}). The parent hub of a target
// device is opened with this GUID to issue IOCTL_USB_HUB_CYCLE_PORT.
var USBHubInterfaceGUID = GUID{
Data1: 0xf18a0e88,
Data2: 0xc30c,
Data3: 0x11d0,
Data4: [8]byte{0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8},
}
// GUID matches the Windows GUID layout exactly. We carry our own copy
// so the (cross-platform) package-level vars above can be declared
// without depending on golang.org/x/sys/windows.
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
// IOCTL codes from VirtualBox usblib-win.h, identical to those used by
// usbipd-win (Usbipd/Interop/VBoxUsb.cs:26-39 and VBoxUsbMon.cs:122-129).
// Encoding is the standard CTL_CODE shape:
//
// (DeviceType << 16) | (Access << 14) | (Function << 2) | Method
//
// DeviceType = FILE_DEVICE_UNKNOWN (0x22), Access = FILE_WRITE_ACCESS (2),
// Method = METHOD_BUFFERED (0).
const (
// Per-device VBoxUSB.sys (\\?\<setupapi-resolved path>).
IOCTLSendURB uint32 = 0x0022_181C // function 0x607
IOCTLUSBSelectInterface uint32 = 0x0022_1824 // function 0x609
IOCTLUSBSetConfig uint32 = 0x0022_1828 // function 0x60a
IOCTLUSBClaimDevice uint32 = 0x0022_182C // function 0x60b
IOCTLUSBClearEndpoint uint32 = 0x0022_1838 // function 0x60e
IOCTLGetVersion uint32 = 0x0022_183C // function 0x60f
IOCTLUSBAbortEndpoint uint32 = 0x0022_1840 // function 0x610
// VBoxUSBMon (\\.\VBoxUSBMon). Note GET_VERSION shares the numeric
// code with VBoxUSB's USB_ABORT_ENDPOINT — different handles.
IOCTLMonitorGetVersion uint32 = 0x0022_1840
IOCTLMonitorAddFilter uint32 = 0x0022_1844
IOCTLMonitorRemoveFilter uint32 = 0x0022_1848
)
// IOCTLHubCyclePort = IOCTL_USB_HUB_CYCLE_PORT from usbioctl.h
// (FILE_DEVICE_USB=0x22, FILE_ANY_ACCESS=0, function=0x111,
// METHOD_BUFFERED=0).
const IOCTLHubCyclePort uint32 = 0x0022_0444
// USB/IP-style transfer type enum, matching VirtualBox USBSUP_TRANSFER_TYPE.
type TransferType uint32
const (
TransferTypeControl TransferType = iota
TransferTypeIso
TransferTypeBulk
TransferTypeInterrupt
TransferTypeMessage // control with setup packet inline
)
// Direction matches USBSUP_DIRECTION.
type Direction uint32
const (
DirectionSetup Direction = iota
DirectionIn
DirectionOut
)
// TransferFlags matches USBSUP_XFER_FLAG. ShortOK is required for IN
// transfers unless the USB/IP request flags include URB_SHORT_NOT_OK.
type TransferFlags uint32
const (
TransferFlagNone TransferFlags = 0
TransferFlagShortOK TransferFlags = 1 << 0
)
// URBError mirrors USBSUP_ERROR. The session layer maps these into
// USBIP-wire-format status (negated Linux errno).
type URBError uint32
const (
URBOK URBError = iota
URBStall
URBDeviceNotResponding
URBCRCError
URBNACError
URBUnderrun
URBOverrun
)
// MaxIsoPacketsPerURB is the hard VBoxUSB limit (USBSUP_URB.aIsoPkts
// is sized for 8 entries). Callers with more iso packets must split
// into multiple URBs sharing one pinned buffer; offsets must stay
// within ushort range.
const MaxIsoPacketsPerURB = 8
// Filter is a logical builder for VBoxUSBMon ADD_FILTER. The Go side
// owns the byte layout (in monitor_windows.go) so callers see a clean
// API even though the on-the-wire struct is fixed-size packed.
type Filter struct {
VendorID *uint16
ProductID *uint16
DeviceRev *uint16
Bus *uint16
Port *uint16
DeviceClass *uint16
}