8e1ea856e8
Every SUPUSB/SUPUSBFLT CTL_CODE was computed with Access = 0 instead of FILE_WRITE_ACCESS (2 << 14), so the driver dispatch rejected each call with STATUS_INVALID_DEVICE_REQUEST and the export host could not even pass monitor GET_VERSION. Values now match usbipd-win's interop definitions (VBoxUsb.cs / VBoxUsbMon.cs).
131 lines
4.5 KiB
Go
131 lines
4.5 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`
|
|
)
|
|
|
|
// 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_981C // function 0x607
|
|
IOCTLUSBSelectInterface uint32 = 0x0022_9824 // function 0x609
|
|
IOCTLUSBSetConfig uint32 = 0x0022_9828 // function 0x60a
|
|
IOCTLUSBClaimDevice uint32 = 0x0022_982C // function 0x60b
|
|
IOCTLUSBClearEndpoint uint32 = 0x0022_9838 // function 0x60e
|
|
IOCTLGetVersion uint32 = 0x0022_983C // function 0x60f
|
|
IOCTLUSBAbortEndpoint uint32 = 0x0022_9840 // function 0x610
|
|
|
|
// VBoxUSBMon (\\.\VBoxUSBMon). Note GET_VERSION shares the numeric
|
|
// code with VBoxUSB's USB_ABORT_ENDPOINT — different handles.
|
|
IOCTLMonitorGetVersion uint32 = 0x0022_9840 // function 0x610
|
|
IOCTLMonitorAddFilter uint32 = 0x0022_9844 // function 0x611
|
|
IOCTLMonitorRemoveFilter uint32 = 0x0022_9848 // function 0x612
|
|
)
|
|
|
|
// 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
|
|
}
|