Skip to the content.

USB/IP protocol

1. Architecture

USB/IP 协议遵循服务器/客户端架构。 服务器导出 USB 设备,客户端导入它们。 导出的 USB 设备的设备驱动程序在客户端计算机上运行。

客户端可能会询问导出的 USB 设备的列表。 为了获取该列表,客户端打开到服务器的 TCP/IP 连接,并在 TCP/IP 连接之上发送 OP_REQ_DEVLIST 数据包(因此实际的 OP_REQ_DEVLIST 可能会在低层传输层以一个或多个块的形式发送)。 服务器发回 OP_REP_DEVLIST 数据包,其中列出了导出的 USB 设备。 最后,TCP/IP 连接关闭。

virtual host controller                                 usb host
     "client"                                           "server"
 (imports USB devices)                             (exports USB devices)
         |                                                 |
         |                  OP_REQ_DEVLIST                 |
         | ----------------------------------------------> |
         |                                                 |
         |                  OP_REP_DEVLIST                 |
         | <---------------------------------------------- |
         |                                                 |

一旦客户端知道导出的 USB 设备列表,它可能会决定使用其中之一。 首先,客户端打开到服务器的 TCP/IP 连接并发送 OP_REQ_IMPORT 数据包。 服务器回复 OP_REP_IMPORT。 如果导入成功,TCP/IP 连接将保持打开状态,并将用于在客户端和服务器之间传输 URB 流量。 客户端可以发送两种类型的数据包:用于提交 URB 的 USBIP_CMD_SUBMIT 和用于取消链接先前提交的 URB 的 USBIP_CMD_UNLINK。 服务器的回答可以分别是USBIP_RET_SUBMIT和USBIP_RET_UNLINK。

virtual host controller                                 usb host
     "client"                                           "server"
 (imports USB devices)                             (exports USB devices)
         |                                                 |
         |                  OP_REQ_IMPORT                  |
         | ----------------------------------------------> |
         |                                                 |
         |                  OP_REP_IMPORT                  |
         | <---------------------------------------------- |
         |                                                 |
         |                                                 |
         |            USBIP_CMD_SUBMIT(seqnum = n)         |
         | ----------------------------------------------> |
         |                                                 |
         |            USBIP_RET_SUBMIT(seqnum = n)         |
         | <---------------------------------------------- |
         |                        .                        |
         |                        :                        |
         |                                                 |
         |            USBIP_CMD_SUBMIT(seqnum = m)         |
         | ----------------------------------------------> |
         |                                                 |
         |            USBIP_CMD_SUBMIT(seqnum = m+1)       |
         | ----------------------------------------------> |
         |                                                 |
         |            USBIP_CMD_SUBMIT(seqnum = m+2)       |
         | ----------------------------------------------> |
         |                                                 |
         |            USBIP_RET_SUBMIT(seqnum = m)         |
         | <---------------------------------------------- |
         |                                                 |
         |            USBIP_CMD_SUBMIT(seqnum = m+3)       |
         | ----------------------------------------------> |
         |                                                 |
         |            USBIP_RET_SUBMIT(seqnum = m+1)       |
         | <---------------------------------------------- |
         |                                                 |
         |            USBIP_CMD_SUBMIT(seqnum = m+4)       |
         | ----------------------------------------------> |
         |                                                 |
         |            USBIP_RET_SUBMIT(seqnum = m+2)       |
         | <---------------------------------------------- |
         |                        .                        |
         |                        :                        |

对于UNLINK,请注意,成功USBIP_RET_UNLINK后,未链接的URB提交将不会有相应的USBIP_RET_SUBMIT(这在drivers/usb/usbip/stub_rx.c的函数stub_recv_cmd_unlink中进行了解释)。

virtual host controller                                 usb host
     "client"                                           "server"
 (imports USB devices)                             (exports USB devices)
         |                                                 |
         |            USBIP_CMD_SUBMIT(seqnum = p)         |
         | ----------------------------------------------> |
         |                                                 |
         |               USBIP_CMD_UNLINK                  |
         |         (seqnum = p+1, unlink_seqnum = p)       |
         | ----------------------------------------------> |
         |                                                 |
         |               USBIP_RET_UNLINK                  |
         |        (seqnum = p+1, status = -ECONNRESET)     |
         | <---------------------------------------------- |
         |                                                 |
         |         Note: No USBIP_RET_SUBMIT(seqnum = p)   |
         | <--X---X---X---X---X---X---X---X---X---X---X--- |
         |                        .                        |
         |                        :                        |
         |                                                 |
         |            USBIP_CMD_SUBMIT(seqnum = q)         |
         | ----------------------------------------------> |
         |                                                 |
         |            USBIP_RET_SUBMIT(seqnum = q)         |
         | <---------------------------------------------- |
         |                                                 |
         |               USBIP_CMD_UNLINK                  |
         |         (seqnum = q+1, unlink_seqnum = q)       |
         | ----------------------------------------------> |
         |                                                 |
         |               USBIP_RET_UNLINK                  |
         |           (seqnum = q+1, status = 0)            |
         | <---------------------------------------------- |
         |                                                 |

这些字段采用网络(大端)字节顺序,这意味着最高有效字节 (MSB) 存储在最低地址。

2. Protocol Version

记录的 USBIP 版本是 v1.1.1。 消息标头中此版本的二进制表示形式是 0x0111。

这是在tools/usb/usbip/configure.ac中定义的。

3. Message Format

OP_REQ_DEVLIST:

检索导出的 USB 设备列表。

Offset Length Value Description
0 2   USBIP 版本
2 2 0x8005 命令码:获取导出的USB设备列表
4 4 0x00000000 状态:未使用,应设置为0

OP_REP_DEVLIST:

回复导出的 USB 设备列表。

Offset Length Value Description
0 2   USBIP 版本
2 2 0x0005 回复码:导出的USB设备列表
4 4 0x00000000 状态:0 表示正常
8 4 n 导出设备数量:0表示无导出设备
0x0C     从现在开始,将描述导出的 n 个设备(如果有)。 如果没有导出任何设备,则消息将以之前的“导出设备数量”字段结束
  256   path:导出 USB 设备的主机上的设备路径,以零字节结束的字符串,例如 “/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2” 未使用的字节应用零字节填充
0x10C 32   busid:导出设备的总线ID,以零字节结束的字符串,例如 “3-2”。 未使用的字节应用零字节填充s
0x12C 4   busnum
0x130 4   devnum
0x134 4   speed
0x138 2   idVendor
0x13A 2   idProduct
0x13C 2   bcdDevice
0x13E 1   bDeviceClass
0x13F 1   bDeviceSubClass
0x140 1   bDeviceProtocol
0x141 1   bConfigurationValue
0x142 1   bNumConfigurations
0x143 1   bNumInterfaces
0x144 m_0   从现在开始,对每个接口进行描述,总共 bNumInterfaces 次,具有以下 4 个字段
  1   bInterfaceClass
0x145 1   bInterfaceSubClass
0x146 1   bInterfaceProtocol
0x147 1   用于对齐的填充字节,应设置为零
0xC + i0x138 + m_(i-1)4     第二个导出的 USB 设备从 i=1 开始,路径字段为

OP_REQ_IMPORT:

请求导入(连接)远程 USB 设备。

Offset Length Value Description
0 2   USBIP 版本
2 2 0x8003 命令码:导入远程USB设备
4 4 0x00000000 状态:未使用,应设置为0
8 32   busid:远程主机上导出设备的busid。 可能的值取自消息字段 OP_REP_DEVLIST.busid。 以零结束的字符串,未使用的字节应用零填充

OP_REP_IMPORT:

回复导入(连接)远程 USB 设备。

Offset Length Value Description
0 2   USBIP 版本
2 2 0x0003 回复码:回复导入
4 4 0x00000000 状态:0 表示正常,1 表示错误
8     从现在开始,如果之前的状态字段为 OK (0),则显示导入设备的详细信息,否则回复以状态字段结束
  256   path:导出 USB 设备的主机上的设备路径,以零字节结束的字符串,例如 “/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2” 未使用的字节应用零字节填充
0x108 32   busid:导出设备的总线ID,以零字节结束的字符串,例如 “3-2”。 未使用的字节应用零字节填充
0x128 4   busnum
0x12C 4   devnum
0x130 4   speed
0x134 2   idVendor
0x136 2   idProduct
0x138 2   bcdDevice
0x139 1   bDeviceClass
0x13A 1   bDeviceSubClass
0x13B 1   bDeviceProtocol
0x13C 1   bConfigurationValue
0x13D 1   bNumConfigurations
0x13E 1   bNumInterfaces

以下四个命令有一个称为“usbip_header_basic”的通用基本标头,并且它们的标头(称为“usbip_header”)(在transfer_buffer有效负载之前)具有相同的长度,因此需要填充。

usbip_header_basic:

Offset Length Description  
0 4 命令  
4 4 seqnum:标识请求和相应响应的序列号; 每个连接递增  
8 4 devid:唯一指定一个远程USB设备,而不是busnum和devnum; 对于客户端(请求),该值为 ((busnum « 16) devnum); 对于服务器(响应),应设置为 0
0xC 4 方向:0:USBIP_DIR_OUT,1:USBIP_DIR_IN,仅由客户端使用,对于服务器应为0  
0x10 4 ep:仅由客户端使用的端点号,对于服务器来说应为0; 对于 UNLINK,该值为 0  

USBIP_CMD_SUBMIT:

Submit an URB

Offset Length Description
0 20 usbip_header_basic,“命令”应为 0x00000001
0x14 4 Transfer_flags:可能的值取决于 USBIP_URB Transfer_flags。 请参阅 include/uapi/linux/usbip.h 和 USB 请求块 (URB)。 参考drivers/usb/usbip/usbip_common.c中的usbip_pack_cmd_submit()和tweak_transfer_flags()
0x18 4 Transfer_buffer_length:使用URB Transfer_buffer_length
0x1C 4 start_frame: 使用URB start_frame; ISO 传输的初始帧; 如果不是 ISO 传输则应设置为 0
0x20 4 number_of_packets: ISO 数据包数量; 如果不是 ISO 传输,则应设置为 0xffffffff
0x24 4 interval: 服务器端主机控制器上请求的最长时间
0x28 8 setup: USB 设置的数据字节,如果不使用则用零填充
0x30 n 传输缓冲区。 如果方向是USBIP_DIR_OUT,则n等于transfer_buffer_length; 否则 n 等于 0。对于 ISO 传输,不传输每个 ISO 数据包之间的填充
0x30+n m iso_packet_descriptor

USBIP_RET_SUBMIT:

回复提交 URB。

Offset Length Description
0 20 usbip_header_basic, “命令”应为 0x00000003
0x14 4 status: 成功的 URB 交易为零,否则发生某种错误
0x18 4 actual_length: URB 数据字节数; 使用URB实际长度
0x1C 4 start_frame: 使用URB start_frame; ISO 传输的初始帧; 如果不是 ISO 传输则应设置为 0
0x20 4 number_of_packets: ISO 数据包数量; 如果不是 ISO 传输,则应设置为 0xffffffff
0x24 4 error_count
0x28 8 填充,应设置为 0
0x30 n 传输缓冲区。 如果方向为 USBIP_DIR_IN,则 n 等于实际长度; 否则 n 等于 0。对于 ISO 传输,不传输每个 ISO 数据包之间的填充
0x30+n m iso_packet_descriptor

USBIP_CMD_UNLINK:

Unlink an URB

Offset Length Description
0 20 usbip_header_basic, “命令”应为 0x00000002
0x14 4 unlink_seqnum, 取消链接的 SUBMIT 请求
0x18 24 填充,应设置为 0

USBIP_RET_UNLINK:

回复 URB 取消链接。

Offset Length Description
0 20 usbip_header_basic, “命令”应为 0x00000004
0x14 4 status: 这与USBIP_RET_SUBMIT的状态类似(共享相同的内存偏移量)。 UNLINK成功时,状态为-ECONNRESET; 当USBIP_CMD_UNLINK在USBIP_RET_SUBMIT之后状态为0时
0x18 24 填充,应设置为 0

4. EXAMPLE

以下数据是通过人机接口设备 (HID) 有效负载从线路捕获的:

CmdIntrIN:  00000001 00000d05 0001000f 00000001 00000001 00000200 00000040 ffffffff 00000000 00000004 00000000 00000000
CmdIntrOUT: 00000001 00000d06 0001000f 00000000 00000001 00000000 00000040 ffffffff 00000000 00000004 00000000 00000000
            ffffffff860008a784ce5ae212376300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
RetIntrOut: 00000003 00000d06 00000000 00000000 00000000 00000000 00000040 ffffffff 00000000 00000000 00000000 00000000
RetIntrIn:  00000003 00000d05 00000000 00000000 00000000 00000000 00000040 ffffffff 00000000 00000000 00000000 00000000
            ffffffff860011a784ce5ae2123763612891b1020100000400000000000000000000000000000000000000000000000000000000000000000000000000000000