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

0x8005

命令程式碼:檢索匯出 USB 裝置的列表。

4

4

0x00000000

狀態:未使用,應設定為 0

OP_REP_DEVLIST

回覆匯出 USB 裝置的列表。

偏移量

長度

描述

0

2

USBIP 版本

2

2

0x0005

回覆程式碼:匯出 USB 裝置的列表。

4

4

0x00000000

狀態:0 表示 OK

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”。未使用的位元組應填充零位元組。

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 + i*0x138 + m_(i-1)*4

第二個匯出的 USB 裝置從 i=1 開始,包含 path 欄位。

OP_REQ_IMPORT

請求匯入(連線)遠端 USB 裝置。

偏移量

長度

描述

0

2

USBIP 版本

2

2

0x8003

命令程式碼:匯入遠端 USB 裝置。

4

4

0x00000000

狀態:未使用,應設定為 0

8

32

busid:遠端主機上匯出裝置的 busid。可能的值取自訊息欄位 OP_REP_DEVLIST.busid。以零結尾的字串,未使用的位元組應填充零。

OP_REP_IMPORT

回覆匯入(連線)遠端 USB 裝置。

偏移量

長度

描述

0

2

USBIP 版本

2

2

0x0003

回覆程式碼:回覆匯入。

4

4

0x00000000

狀態

  • 0 表示 OK

  • 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

0x13A

1

bDeviceClass

0x13B

1

bDeviceSubClass

0x13C

1

bDeviceProtocol

0x13D

1

bConfigurationValue

0x13E

1

bNumConfigurations

0x13F

1

bNumInterfaces

以下四個命令有一個通用的基本標頭,稱為“usbip_header_basic”,並且它們的標頭,稱為“usbip_header”(在 transfer_buffer 有效負載之前),具有相同的長度,因此需要填充。

usbip_header_basic

偏移量

長度

描述

0

4

command

4

4

seqnum:標識請求和相應響應的序列號;每次連線遞增

8

4

devid:唯一指定遠端 USB 裝置,而不是 busnum 和 devnum;對於客戶端(請求),此值為 ((busnum << 16) | devnum);對於伺服器(響應),應設定為 0

0xC

4

direction

  • 0: USBIP_DIR_OUT

  • 1: USBIP_DIR_IN

僅由客戶端使用,對於伺服器,此值應為 0

0x10

4

ep:端點號僅由客戶端使用,對於伺服器,此值應為 0;對於 UNLINK,此值應為 0

USBIP_CMD_SUBMIT

提交 URB

偏移量

長度

描述

0

20

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

4

interval:伺服器端主機控制器上請求的最大時間

0x28

8

setup:USB 設定的資料位元組,如果未使用,則填充零。

0x30

n

transfer_buffer。如果 direction 為 USBIP_DIR_OUT,則 n 等於 transfer_buffer_length;否則 n 等於 0。對於 ISO 傳輸,每個 ISO 資料包之間的填充不會傳輸。

0x30+n

m

iso_packet_descriptor

USBIP_RET_SUBMIT

提交 URB 的回覆

偏移量

長度

描述

0

20

usbip_header_basic,“command”應為 0x00000003

0x14

4

status:零表示成功的 URB 事務,否則會發生某種錯誤。

0x18

4

actual_length:URB 資料位元組數;使用 URB actual_length

0x1C

4

start_frame:使用 URB start_frame;ISO 傳輸的初始幀;如果不是 ISO 傳輸,則應設定為 0

0x20

4

number_of_packets:ISO 資料包的數量;如果不是 ISO 傳輸,則應設定為 0xffffffff

0x24

4

error_count

0x28

8

padding,應設定為 0

0x30

n

transfer_buffer。如果 direction 為 USBIP_DIR_IN,則 n 等於 actual_length;否則 n 等於 0。對於 ISO 傳輸,每個 ISO 資料包之間的填充不會傳輸。

0x30+n

m

iso_packet_descriptor

USBIP_CMD_UNLINK

取消連結 URB

偏移量

長度

描述

0

20

usbip_header_basic,“command”應為 0x00000002

0x14

4

unlink_seqnum,要取消連結的 SUBMIT 請求的序列號

0x18

24

padding,應設定為 0

USBIP_RET_UNLINK

URB 取消連結的回覆

偏移量

長度

描述

0

20

usbip_header_basic,“command”應為 0x00000004

0x14

4

status:這與 USBIP_RET_SUBMIT 的狀態類似(共享相同的記憶體偏移量)。當 UNLINK 成功時,status 為 -ECONNRESET;當 USBIP_CMD_UNLINK 在 USBIP_RET_SUBMIT 之後時,status 為 0

0x18

24

padding,應設定為 0

示例

以下資料是從 Human Interface Devices (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