Skip to content

Core types & errors

Role-neutral USB building blocks shared by the device and host sides. If any of the USB terms below are unfamiliar, the USB concepts primer explains them in plain language; this page is the reference for the actual types.

Most names are re-exported from the top-level usbip package (e.g. usbip.Setup, usbip.Stall).

What's here

Setup - the control-request packet. Every control transfer starts with an 8-byte SETUP packet. Setup holds its fields: bmRequestType (a bitmask: direction · type · recipient - decoded here), bRequest (the request code), wValue / wIndex (parameters), and wLength (bytes of data to follow). Your on_control callback receives a Setup and decides how to respond.

Descriptors - the typed structs the library serialises to describe the device to the host: DeviceDescriptor (VID/PID, class, …), ConfigurationDescriptor, InterfaceDescriptor, EndpointDescriptor. A device class fills these in for you; you only touch them for a hand-built Interface.

Exceptions - all USB failures are USBError subclasses:

  • Stall - the device rejected the request or halted the endpoint (USB's "no"). Raise it from a control handler to STALL a request; catch it on the host side when a request is refused. See STALL.
  • Timeout - no response within the timeout.
  • NotFound - no matching device or endpoint.

Constants (from usbip): directions IN / OUT, and link speeds SPEED_LOW · SPEED_FULL · SPEED_HIGH · SPEED_SUPER.

Reference

core

USB-level types shared by host and device sides.

Nothing in here knows about USB/IP, sockets, or transports - it is pure USB: the SETUP packet, descriptors, transfer enums, errors, and the URB that the transport layer ferries around.

USBError

Bases: Exception

Base for all usbip errors.

Stall

Bases: USBError

Raised by a device control/endpoint handler to STALL the request.

Timeout

Bases: USBError

NotFound

Bases: USBError

Setup dataclass

Setup(bmRequestType, bRequest, wValue, wIndex, wLength)

bmRequestType instance-attribute

bmRequestType

bRequest instance-attribute

bRequest

wValue instance-attribute

wValue

wIndex instance-attribute

wIndex

wLength instance-attribute

wLength

direction property

direction

type property

type

recipient property

recipient

parse classmethod

parse(raw)
Source code in usbip/core.py
@classmethod
def parse(cls, raw: bytes) -> Setup:
    return cls(*struct.unpack("<BBHHH", bytes(raw[:8])))

pack

pack()
Source code in usbip/core.py
def pack(self) -> bytes:
    return struct.pack(
        "<BBHHH", self.bmRequestType, self.bRequest, self.wValue, self.wIndex, self.wLength
    )

DeviceDescriptor dataclass

DeviceDescriptor(bcdUSB=512, bDeviceClass=0, bDeviceSubClass=0, bDeviceProtocol=0, bMaxPacketSize0=64, idVendor=0, idProduct=0, bcdDevice=256, iManufacturer=0, iProduct=0, iSerialNumber=0, bNumConfigurations=1)

bcdUSB class-attribute instance-attribute

bcdUSB = 512

bDeviceClass class-attribute instance-attribute

bDeviceClass = 0

bDeviceSubClass class-attribute instance-attribute

bDeviceSubClass = 0

bDeviceProtocol class-attribute instance-attribute

bDeviceProtocol = 0

bMaxPacketSize0 class-attribute instance-attribute

bMaxPacketSize0 = 64

idVendor class-attribute instance-attribute

idVendor = 0

idProduct class-attribute instance-attribute

idProduct = 0

bcdDevice class-attribute instance-attribute

bcdDevice = 256

iManufacturer class-attribute instance-attribute

iManufacturer = 0

iProduct class-attribute instance-attribute

iProduct = 0

iSerialNumber class-attribute instance-attribute

iSerialNumber = 0

bNumConfigurations class-attribute instance-attribute

bNumConfigurations = 1

pack

pack()
Source code in usbip/core.py
def pack(self) -> bytes:
    return struct.pack(
        "<BBHBBBBHHHBBBB",
        18,
        DT_DEVICE,
        self.bcdUSB,
        self.bDeviceClass,
        self.bDeviceSubClass,
        self.bDeviceProtocol,
        self.bMaxPacketSize0,
        self.idVendor,
        self.idProduct,
        self.bcdDevice,
        self.iManufacturer,
        self.iProduct,
        self.iSerialNumber,
        self.bNumConfigurations,
    )

parse classmethod

parse(raw)
Source code in usbip/core.py
@classmethod
def parse(cls, raw: bytes) -> DeviceDescriptor:
    (_, _, bcdUSB, dc, sc, pr, mps, vid, pid, bcdDev, im, ip, iser, nc) = struct.unpack(
        "<BBHBBBBHHHBBBB", bytes(raw[:18])
    )
    return cls(bcdUSB, dc, sc, pr, mps, vid, pid, bcdDev, im, ip, iser, nc)

ConfigurationDescriptor dataclass

ConfigurationDescriptor(wTotalLength, bNumInterfaces, bConfigurationValue=1, iConfiguration=0, bmAttributes=128, bMaxPower=50)

Standard Configuration descriptor (USB 2.0 Sec.9.6.3). wTotalLength spans this descriptor plus every interface/endpoint/class descriptor that follows it.

wTotalLength instance-attribute

wTotalLength

bNumInterfaces instance-attribute

bNumInterfaces

bConfigurationValue class-attribute instance-attribute

bConfigurationValue = 1

iConfiguration class-attribute instance-attribute

iConfiguration = 0

bmAttributes class-attribute instance-attribute

bmAttributes = 128

bMaxPower class-attribute instance-attribute

bMaxPower = 50

pack

pack()
Source code in usbip/core.py
def pack(self) -> bytes:
    return struct.pack(
        "<BBHBBBBB",
        9,
        DT_CONFIG,
        self.wTotalLength,
        self.bNumInterfaces,
        self.bConfigurationValue,
        self.iConfiguration,
        self.bmAttributes,
        self.bMaxPower,
    )

parse classmethod

parse(raw)
Source code in usbip/core.py
@classmethod
def parse(cls, raw: bytes) -> ConfigurationDescriptor:
    (_, _, total, n_ifaces, val, icfg, attrs, power) = struct.unpack("<BBHBBBBB", bytes(raw[:9]))
    return cls(total, n_ifaces, val, icfg, attrs, power)

InterfaceDescriptor dataclass

InterfaceDescriptor(bInterfaceNumber, bAlternateSetting, bNumEndpoints, bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, iInterface=0)

Standard Interface descriptor (USB 2.0 Sec.9.6.5).

bInterfaceNumber instance-attribute

bInterfaceNumber

bAlternateSetting instance-attribute

bAlternateSetting

bNumEndpoints instance-attribute

bNumEndpoints

bInterfaceClass instance-attribute

bInterfaceClass

bInterfaceSubClass instance-attribute

bInterfaceSubClass

bInterfaceProtocol instance-attribute

bInterfaceProtocol

iInterface class-attribute instance-attribute

iInterface = 0

pack

pack()
Source code in usbip/core.py
def pack(self) -> bytes:
    return struct.pack(
        "<BBBBBBBBB",
        9,
        DT_INTERFACE,
        self.bInterfaceNumber,
        self.bAlternateSetting,
        self.bNumEndpoints,
        self.bInterfaceClass,
        self.bInterfaceSubClass,
        self.bInterfaceProtocol,
        self.iInterface,
    )

parse classmethod

parse(raw)
Source code in usbip/core.py
@classmethod
def parse(cls, raw: bytes) -> InterfaceDescriptor:
    (_, _, num, alt, neps, iclass, isub, iproto, i_if) = struct.unpack("<BBBBBBBBB", bytes(raw[:9]))
    return cls(num, alt, neps, iclass, isub, iproto, i_if)

EndpointDescriptor dataclass

EndpointDescriptor(bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval)

Standard Endpoint descriptor (USB 2.0 Sec.9.6.6). bmAttributes' low two bits select the transfer type (CONTROL/ISO/BULK/INTERRUPT).

bEndpointAddress instance-attribute

bEndpointAddress

bmAttributes instance-attribute

bmAttributes

wMaxPacketSize instance-attribute

wMaxPacketSize

bInterval instance-attribute

bInterval

pack

pack()
Source code in usbip/core.py
def pack(self) -> bytes:
    return struct.pack(
        "<BBBBHB",
        7,
        DT_ENDPOINT,
        self.bEndpointAddress,
        self.bmAttributes,
        self.wMaxPacketSize,
        self.bInterval,
    )

parse classmethod

parse(raw)
Source code in usbip/core.py
@classmethod
def parse(cls, raw: bytes) -> EndpointDescriptor:
    (_, _, addr, attrs, mps, ivl) = struct.unpack("<BBBBHB", bytes(raw[:7]))
    return cls(addr, attrs, mps, ivl)