Files
sing-box/option/usbip.go
T
2026-06-09 10:42:19 +08:00

85 lines
2.5 KiB
Go

package option
import (
"fmt"
"strconv"
"strings"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json"
)
// USBIPHexUint16 is a uint16 that accepts either a JSON integer or a hex
// string ("0x1d6b", "1d6b", "0X1D6B") on unmarshal, and emits a hex string
// on marshal. Zero means "unset".
type USBIPHexUint16 uint16
func (h USBIPHexUint16) MarshalJSON() ([]byte, error) {
if h == 0 {
return []byte(`""`), nil
}
return json.Marshal(fmt.Sprintf("0x%04x", uint16(h)))
}
func (h *USBIPHexUint16) UnmarshalJSON(data []byte) error {
var asNumber uint64
if err := json.Unmarshal(data, &asNumber); err == nil {
if asNumber > 0xffff {
return E.New("usb id out of uint16 range: ", asNumber)
}
*h = USBIPHexUint16(asNumber)
return nil
}
var asString string
if err := json.Unmarshal(data, &asString); err != nil {
return E.Cause(err, "parse usb id")
}
asString = strings.TrimSpace(asString)
if asString == "" {
*h = 0
return nil
}
parsed, err := strconv.ParseUint(asString, 0, 16)
if err != nil {
// Allow bare hex without 0x prefix.
if parsed2, err2 := strconv.ParseUint(asString, 16, 16); err2 == nil {
*h = USBIPHexUint16(parsed2)
return nil
}
return E.Cause(err, "parse usb id ", asString)
}
*h = USBIPHexUint16(parsed)
return nil
}
// USBIPDeviceMatch selects a USB device. Non-zero fields AND together.
// An all-zero match is rejected at service construction time.
type USBIPDeviceMatch struct {
BusID string `json:"busid,omitempty"`
VendorID USBIPHexUint16 `json:"vendor_id,omitempty"`
ProductID USBIPHexUint16 `json:"product_id,omitempty"`
Serial string `json:"serial,omitempty"`
}
func (m USBIPDeviceMatch) IsZero() bool {
return m.BusID == "" && m.VendorID == 0 && m.ProductID == 0 && m.Serial == ""
}
// USBIPServerServiceOptions configures a usbip-server service. It listens on
// TCP (default :3240) and binds matching local USB devices to the usbip-host
// kernel driver for export. Empty Devices means export nothing.
type USBIPServerServiceOptions struct {
ListenOptions
Devices []USBIPDeviceMatch `json:"devices,omitempty"`
}
// USBIPClientServiceOptions configures a usbip-client service. It connects to
// one remote usbip server and attaches matching remote USB devices to the
// local kernel via vhci_hcd. Empty Devices means import every device the
// remote currently exports.
type USBIPClientServiceOptions struct {
ServerOptions
DialerOptions
Devices []USBIPDeviceMatch `json:"devices,omitempty"`
}