整理一下在USB通信时所作的相关工作,因为是对USBMS进行相关操作,涉及到了USBMS的传输格式(CBWCSW),不太熟悉导致前期回补了一下USB的相关知识。

因为在搜索资料的时候,发现市面上貌似这方面编程相关资料比较少,这里我直接写出来记录一下,也是帮助自己记忆。

传输数据上的简单概念

usb在普通通信过程中,使用端点进行通信,USBMS(USB Mass Storage)设备则在传输过程中遵守一套传输格式。

  • CBW->DATA->CSW

  • CBW:是一个数据块,携带主机发给设备的SCSI命令。接收了CBW后,设备就可以从中知道在接下来的DATA阶段中该干什么。

  • DATA:阶段有三种情况:无数据需要传输,IN传输(设备到主机)或OUT传输(主机到设备)。

  • CSW:阶段反馈这次传输的结果给主机。

发送数据时,host需要按照这个格式与device进行通信,也只有这样的通信,设备才会与host进行正常的交互。

数据详解

USB抓包

CBW

1
2
3
4
5
6
7
8
9
10
// Section 5.1: Command Block Wrapper (CBW)
struct command_block_wrapper {
uint8_t dCBWSignature[4];
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
uint8_t bCBWLUN;
uint8_t bCBWCBLength;
uint8_t CBWCB[16];
};

Command Block Wrapper

注意:发送时指定发送字节为31个字节,发送错误会导致无法识别包为CBW包。

command_block_wrapper,该数据结构长度为32字节,调用write函数时需注意。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
dCBWSignature: CBW的标识,固定值:43425355h(little endian)。
dCBWSignature[0] = 'U'
dCBWSignature[1] = 'S'
dCBWSignature[2] = 'B'
dCBWSignature[3] = 'C'

dCBWTag: 主机发送的一个命令块标识,设备需要原样作为dCSWTag(CSW中的一部分)再发送给Host; 通信配对。

dCBWDataTransferLength: 本次CBW命令要求在命令与回应之间传输的字节数(接下要写或读的数据量)。如果为0,则不传输数据。

bmCBWFlags: 反映数据传输的方向,0x00 表示来自Host,0x80 表示发至Host;

bCBWLUN: 对于有多个LUN逻辑单元的设备,用来选择具体目标。如果没有多个LUN,则写0。

bCBWCBLength: 命令的长度,范围在0~16。

CBWCB: 传输的具体命令,符合bInterfaceSubClass.中定义的命令规范,此处是SCSI指令集。

DATA

这里就是真正的数据传输期了,可以没有数据,可以读数据,可以写数据。

数据的交互都是双方约定的过程,假设在host发送一个私有命令,设备有数据发上来,此时host调用read函数。

CSW

1
2
3
4
5
6
7
// Section 5.2: Command Status Wrapper (CSW)
struct command_status_wrapper {
uint8_t dCSWSignature[4];
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
uint8_t bCSWStatus;
};

CSW(Command Status Wrapper)状态格式

CSW的长度为13个字节,是对应CBW指令的状态返回,它指示了上一条指令执行是否成功。

1
2
3
4
5
6
7
dCSWSignature: CSW的标识,固定值:53425355h(little endian)。

dCSWTag: 设置这个标识和CBW中的dCBWTag一致,参照上面关于dCBWTag的解释。

dCSWDataResidue: 还需要传送的数据,此数据根据dCBWDataTransferLength-本次已经传送的数据得到。

bCSWStatus: 指示命令的执行状态。如果命令正确执行,bCSWStatus返回0 ,不正确返回1,phase错返回2(当HOST收到此错误时需要对Device复位)。

可以借鉴:GitHub

分析工具

linux和windows下都通用的是,使用wireshake,抓包工具抓取的包都是一样的,而且都比较好用,算是比较推荐的。推荐文章,linux下USB数据包分析(usbmon + wireshark)

另外windows下,有Bus Hound,也是非常好用,只是linux没有。