USB/IP 协议¶
架构¶
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 流量。客户端可能会发送两种类型的数据包:USBIP_CMD_SUBMIT 来提交 URB,以及 USBIP_CMD_UNLINK 来取消链接先前提交的 URB。服务器的答案可能是 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) 存储在最低地址。
协议版本¶
记录的 USBIP 版本是 v1.1.1。消息头中此版本的二进制表示形式是 0x0111。
这在 tools/usb/usbip/configure.ac 中定义
消息格式¶
- OP_REQ_DEVLIST
检索导出的 USB 设备列表。
偏移量 |
长度 |
值 |
描述 |
---|---|---|---|
0 |
2 |
USBIP 版本 |
|
2 |
2 |
0x0111 |
0x8005 |
4 |
4 |
命令代码:检索导出的 USB 设备列表。 |
0x00000000 |
- 状态:未使用,应设置为 0
OP_REP_DEVLIST
偏移量 |
长度 |
值 |
描述 |
---|---|---|---|
0 |
2 |
USBIP 版本 |
|
2 |
2 |
回复导出的 USB 设备列表。 |
0x0111 |
4 |
4 |
命令代码:检索导出的 USB 设备列表。 |
0x0005 |
8 |
4 |
回复代码:导出的 USB 设备列表。 |
状态:0 表示 OK |
n |
导出的设备数量:0 表示没有导出的设备。 |
||
256 |
0x0C |
||
从现在开始,描述导出的 n 个设备(如果有)。如果没有导出设备,则消息在之前的“导出的设备数量”字段处结束。 |
32 |
路径:主机上导出 USB 设备的设备的路径,以零字节结尾的字符串,例如“/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2”。未使用的字节应填充为零字节。 |
|
0x10C |
4 |
busid:导出的设备的 Bus ID,以零字节结尾的字符串,例如“3-2”。未使用的字节应填充为零字节。 |
|
0x12C |
4 |
busnum |
|
0x130 |
4 |
devnum |
|
0x134 |
2 |
速度 |
|
0x138 |
2 |
idVendor |
|
0x13A |
2 |
idProduct |
|
0x13C |
1 |
bcdDevice |
|
0x13E |
1 |
bDeviceClass |
|
0x13F |
1 |
bDeviceSubClass |
|
0x140 |
1 |
bDeviceProtocol |
|
0x141 |
1 |
bConfigurationValue |
|
0x142 |
1 |
bNumConfigurations |
|
0x143 |
bNumInterfaces |
0x144 |
|
1 |
m_0 |
||
从现在开始,每个接口都将描述 bNumInterfaces 次,总共包含以下 4 个字段 |
1 |
bInterfaceClass |
|
0x145 |
1 |
bInterfaceSubClass |
|
0x146 |
1 |
bInterfaceProtocol |
|
0x147 |
用于对齐的填充字节,应设置为零 |
- 0xC + i*0x138 + m_(i-1)*4
第二个导出的 USB 设备从 i=1 开始,带有路径字段。
偏移量 |
长度 |
值 |
描述 |
---|---|---|---|
0 |
2 |
USBIP 版本 |
|
2 |
2 |
OP_REQ_IMPORT |
请求导入(附加)远程 USB 设备。 |
4 |
4 |
命令代码:检索导出的 USB 设备列表。 |
0x00000000 |
8 |
32 |
0x8003 |
- 命令代码:导入远程 USB 设备。
busid:远程主机上导出的设备的 busid。可能的值取自消息字段 OP_REP_DEVLIST.busid。以零结尾的字符串,未使用的字节应填充为零。
偏移量 |
长度 |
值 |
描述 |
---|---|---|---|
0 |
2 |
USBIP 版本 |
|
2 |
2 |
OP_REP_IMPORT |
回复导入(附加)远程 USB 设备。 |
4 |
4 |
命令代码:检索导出的 USB 设备列表。 |
0x0003
|
8 |
0 表示 OK |
||
256 |
0x0C |
||
1 表示错误 |
32 |
路径:主机上导出 USB 设备的设备的路径,以零字节结尾的字符串,例如“/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2”。未使用的字节应填充为零字节。 |
|
从现在开始,如果之前的状态字段为 OK (0),则会显示导入设备的详细信息,否则回复将以状态字段结束。 |
4 |
busid:导出的设备的 Bus ID,以零字节结尾的字符串,例如“3-2”。未使用的字节应填充为零字节。 |
|
0x10C |
4 |
busnum |
|
0x12C |
4 |
devnum |
|
0x130 |
2 |
速度 |
|
0x108 |
2 |
idVendor |
|
0x134 |
2 |
idProduct |
|
0x128 |
1 |
bcdDevice |
|
0x138 |
1 |
bDeviceClass |
|
0x136 |
1 |
bDeviceSubClass |
|
0x13A |
1 |
bDeviceProtocol |
|
0x139 |
1 |
bConfigurationValue |
|
0x13C |
1 |
bNumConfigurations |
0x13B
0x13D
偏移量 |
长度 |
描述 |
---|---|---|
0 |
4 |
以下四个命令具有一个公共的基本头,称为 ‘usbip_header_basic’,它们的头,称为 ‘usbip_header’(在 transfer_buffer 有效负载之前),具有相同的长度,因此需要填充。 |
4 |
4 |
usbip_header_basic |
8 |
4 |
command |
seqnum:标识请求和相应响应的顺序号;每次连接递增 |
4 |
devid:唯一指定远程 USB 设备,而不是 busnum 和 devnum;对于客户端(请求),此值为 ((busnum << 16) | devnum);对于服务器(响应),应设置为 0
0:USBIP_DIR_OUT |
1:USBIP_DIR_IN |
4 |
仅由客户端使用,对于服务器,应为 0 |
- 0x10
ep:仅由客户端使用的端点号,对于服务器,应为 0;对于 UNLINK,应为 0
偏移量 |
长度 |
描述 |
---|---|---|
0 |
20 |
USBIP_CMD_SUBMIT |
提交 URB |
4 |
usbip_header_basic,‘command’ 应为 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 |
8 |
interval:服务器端主机控制器上请求的最长时间 |
0x28 |
回复代码:导出的 USB 设备列表。 |
setup:USB 设置的数据字节,如果未使用,则填充为零。 |
0x30 |
transfer_buffer。如果方向为 USBIP_DIR_OUT,则 n 等于 transfer_buffer_length;否则 n 等于 0。对于 ISO 传输,每个 ISO 数据包之间的填充不会传输。 |
0x30+n |
- m
iso_packet_descriptor
偏移量 |
长度 |
描述 |
---|---|---|
0 |
20 |
USBIP_RET_SUBMIT |
提交 URB |
4 |
提交 URB 的回复 |
0x14 |
4 |
usbip_header_basic,‘command’ 应为 0x00000003 |
0x18 |
4 |
transfer_buffer_length:使用 URB transfer_buffer_length |
0x1C |
4 |
start_frame:使用 URB start_frame;ISO 传输的初始帧;如果不是 ISO 传输,则应设置为 0 |
0x20 |
4 |
状态:零表示 URB 事务成功,否则发生了某种错误。 |
0x24 |
8 |
actual_length:URB 数据字节数;使用 URB actual_length |
0x28 |
回复代码:导出的 USB 设备列表。 |
error_count |
0x30 |
transfer_buffer。如果方向为 USBIP_DIR_OUT,则 n 等于 transfer_buffer_length;否则 n 等于 0。对于 ISO 传输,每个 ISO 数据包之间的填充不会传输。 |
0x30+n |
- 填充,应设置为 0
transfer_buffer。如果方向为 USBIP_DIR_IN,则 n 等于 actual_length;否则 n 等于 0。对于 ISO 传输,每个 ISO 数据包之间的填充不会传输。
偏移量 |
长度 |
描述 |
---|---|---|
0 |
20 |
USBIP_CMD_UNLINK |
提交 URB |
4 |
取消链接 URB |
0x14 |
24 |
actual_length:URB 数据字节数;使用 URB actual_length |
- usbip_header_basic,‘command’ 应为 0x00000002
unlink_seqnum,要取消链接的 SUBMIT 请求的序号
偏移量 |
长度 |
描述 |
---|---|---|
0 |
20 |
USBIP_RET_UNLINK |
提交 URB |
4 |
URB 取消链接的回复 |
0x14 |
24 |
actual_length:URB 数据字节数;使用 URB actual_length |
usbip_header_basic,‘command’ 应为 0x00000004
状态:这类似于 USBIP_RET_SUBMIT 的状态(共享相同的内存偏移量)。当 UNLINK 成功时,状态为 -ECONNRESET;当 USBIP_CMD_UNLINK 在 USBIP_RET_SUBMIT 之后时,状态为 0
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