前提
使用的是qemu+spice_gtk+virt_viewer来做这个事情的,不过走了一些弯路,之前由于拿到这一块是用的是spicec的代码,在其上加入usb重定向的东西,不过这个spicec目前是不推荐使用的,官方早就推荐了用remote-viewer,故走了两个版本,一个版本是使用spicec加上重定向代码,还有一个是用spice-gtk上用其代码,但是要加入管控,两个版本都做了,觉得spice-gtk加上禁止,只读控制还是好一点。最后发现坐在qemu上最好
Mass Storage协议
U盘是属于大容量存取介质,USB一般是使用Mass Storage协议来进行通信的。使用Mass Storage协议通信之前主机需先获取设备的相关信息,并进行设置。 首先是control协议,然后是bulk的批量协议。 qemu对usb存储使用大容量存储传输协议,这种传输方式是大部分usb设备所使用的,官方原话:
qemu ${other_vm_args}QEMU has two emulations for usb storage devices.Number one emulates the classic bulk-only transport protocol which is used by 99% of the usb sticks on the marked today and is called “usb-storage”. Usage (hooking up to xhci, other host controllers work too):
-drive if=none,id=stick,file=/path/to/file.img \
-device nec-usb-xhci,id=xhci \
-device usb-storage,bus=xhci.0,drive=stick
检查了下启动参数,确实有点问题,这一块还有很多不是很明白。官方还有一种支持多分区的办法。
抓包Bulk Only传输协议
用抓包去分析这个问题,将usb通信协议都抓出来了,发现usb协议属于对话协议,即一问一答协议,先control后批量传输,前面一直觉得握手协议中控制协议一定标记了设备的属性等,最后发现不是这里,具体在bulk里面。 type 0x80 req 0x6 这里应该是标记usb协议的大容量协议吧,具体没去查文档。 传输方向是:CBW(Command Block Wrapper)->[DATA]->CSW(Command Status Wrapper)
CBW是以0x55534243(Little Endian)开始
CBW是以0x55534253(Little Endian)开始
dCBWSignature:
CBW的标识,固定值:43425355h (little endian)。
dCBWTag:
主机发送的一个命令块标识,设备需要原样作为dCSWTag(CSW中的一部分)再发送给Host;主要用于关联CSW到对应的CBW。 dCBWDataTransferLength:
本次CBW命令要求在命令与回应之间传输的字节数。如果为0,则不传输数据。 bmCBWFlags:
反映数据传输的方向,0 表示来自Host,1 表示发至Host; bCBWLUN:
对于有多个LUN逻辑单元的设备,用来选择具体目标。如果没有多个LUN,则写0。 bCBWCBLength:
命令的长度,范围在0~16. CBWCB:
传输的具体命令,符合bInterfaceSubClass.中定义的命令规范,此处是SCSI
下面是协议:
out: 55 53 42 43 60 6C 0E 02]out: 24 00 00 00 80 00 06 12]
out: 00 00 00 24 00 00 00 00]
out: 00 00 00 00 00 00 00]
log end
log start len = 36
in: 00 80 04 02 1F 00 00 00]
in: 4E 65 74 61 63 20 20 20]
in: 4F 6E 6C 79 44 69 73 6B]
in: 20 20 20 20 20 20 20 20]
in: 50 4D 41 50]
log start
in: 55 53 42 53 60 6C 0E 02]in: 00 00 00 00 00]
60 6C 0E 02是校验码,00 00 00 00 00是表示执行正常。中间的是数据块,这里表示什么要根据这个:
SCSI命令http://en.wikipedia.org/wiki/SCSI_command 这里0x1E是写保护,qemu也有这个代码 Prevent/Allow Medium Removal 。根据SCSI命令就完成了功能。
实现功能如下:
这里可以看到右键没有新建等选项