def get_sense(handle, endpoint_in, endpoint_out): # Request Sense print("Request Sense:") sense = (ct.c_uint8 * 18)() cdb = (ct.c_uint8 * 16)() # SCSI Command Descriptor Block cdb[0] = 0x03 # Request Sense cdb[4] = REQUEST_SENSE_LENGTH expected_tag = ct.c_uint32() send_mass_storage_command(handle, endpoint_out, 0, cdb, usb.LIBUSB_ENDPOINT_IN, REQUEST_SENSE_LENGTH, ct.pointer(expected_tag)) size = ct.c_int() rc = usb.bulk_transfer(handle, endpoint_in, ct.cast(ct.pointer(sense), ct.POINTER(ct.c_ubyte)), REQUEST_SENSE_LENGTH, ct.byref(size), 1000) if rc < 0: print("usb.bulk_transfer failed: {}".format(usb.error_name(rc))) return size = size.value print(" received {} bytes".format(size)) if sense[0] != 0x70 and sense[0] != 0x71: perr(" ERROR No sense data\n") else: perr(" ERROR Sense: {:02X} {:02X} {:02X}\n", sense[2] & 0x0F, sense[12], sense[13]) # Strictly speaking, the get_mass_storage_status() call should come # before these perr() lines. If the status is nonzero then we must # assume there's no data in the buffer. For xusb it doesn't matter. get_mass_storage_status(handle, endpoint_in, expected_tag)
def send_mass_storage_command(handle, endpoint, lun, cdb, direction, data_length, ret_tag): global _tag #int i, r; cbw = command_block_wrapper() if not cdb: return -1 if endpoint & usb.LIBUSB_ENDPOINT_IN: perr("send_mass_storage_command: cannot send command on IN endpoint\n") return -1 #ct.c_uint8 cdb_len; cdb_len = cdb_length[cdb[0]] if cdb_len == 0 or cdb_len > ct.sizeof(cbw.CBWCB): perr( "send_mass_storage_command: don't know how to handle this command ({:02X}, length {})\n", cdb[0], cdb_len) return -1 cbw.dCBWSignature[0] = 'U' cbw.dCBWSignature[1] = 'S' cbw.dCBWSignature[2] = 'B' cbw.dCBWSignature[3] = 'C' ret_tag[0] = _tag cbw.dCBWTag = _tag cbw.dCBWDataTransferLength = data_length cbw.bmCBWFlags = direction cbw.bCBWLUN = lun _tag += 1 # Subclass is 1 or 6 => cdb_len cbw.bCBWCBLength = cdb_len memcpy(cbw.CBWCB, cdb, cdb_len) i = 0 while True: # The transfer length must always be exactly 31 bytes. size = ct.c_int() r = usb.bulk_transfer(handle, endpoint, ct.cast(ct.pointer(cbw), ct.POINTER(ct.c_ubyte)), 31, ct.byref(size), 1000) if r == usb.LIBUSB_ERROR_PIPE: usb.clear_halt(handle, endpoint) i += 1 if r != usb.LIBUSB_ERROR_PIPE or i >= RETRY_MAX: break if r != usb.LIBUSB_SUCCESS: perr(" send_mass_storage_command: {}\n", usb.strerror(usb.error(r))) return -1 print(" sent {} CDB bytes".format(cdb_len)) return 0
def get_mass_storage_status(handle, endpoint, expected_tag): #int r; csw = command_status_wrapper() # The device is allowed to STALL this transfer. If it does, you have to # clear the stall and try again. i = 0 while True: size = ct.c_int() r = usb.bulk_transfer(handle, endpoint, ct.cast(ct.pointer(csw), ct.POINTER(ct.c_ubyte)), 13, ct.byref(size), 1000) if r == usb.LIBUSB_ERROR_PIPE: usb.clear_halt(handle, endpoint) i += 1 if r != usb.LIBUSB_ERROR_PIPE or i >= RETRY_MAX: break if r != usb.LIBUSB_SUCCESS: perr(" get_mass_storage_status: {}\n", usb.strerror(usb.error(r))) return -1 size = size.value if size != 13: perr(" get_mass_storage_status: received {} bytes (expected 13)\n", size) return -1 if csw.dCSWTag != expected_tag: perr( " get_mass_storage_status: mismatched tags (expected {:08X}, received {:08X})\n", expected_tag, csw.dCSWTag) return -1 # For this test, we ignore the dCSWSignature check for validity... print(" Mass Storage Status: {:02X} ({})".format( csw.bCSWStatus, "FAILED" if csw.bCSWStatus else "Success")) if csw.dCSWTag != expected_tag: return -1 if csw.bCSWStatus: # REQUEST SENSE is appropriate only if bCSWStatus is 1, meaning that the # command failed somehow. Larger values (2 in particular) mean that # the command couldn't be understood. if csw.bCSWStatus == 1: return -2 # request Get Sense else: return -1 # In theory we also should check dCSWDataResidue. But lots of devices # set it wrongly. return 0
def test_mass_storage(handle, endpoint_in, endpoint_out): # Mass Storage device to test bulk transfers (non destructive test) global binary_dump global binary_name #int r; #ct.c_uint32 i print("Reading Max LUN:") lun = ct.c_uint8() r = usb.control_transfer(handle, usb.LIBUSB_ENDPOINT_IN | usb.LIBUSB_REQUEST_TYPE_CLASS | usb.LIBUSB_RECIPIENT_INTERFACE, BOMS_GET_MAX_LUN, 0, 0, ct.byref(lun), 1, 1000) lun = lun.value # Some devices send a STALL instead of the actual value. # In such cases we should set lun to 0. if r == 0: lun = 0 elif r < 0: perr(" Failed: {}".format(usb.strerror(usb.error(r)))) print(" Max LUN = {}".format(lun)) # Send Inquiry print("Sending Inquiry:") buffer = (ct.c_uint8 * 64)() cdb = (ct.c_uint8 * 16)() # SCSI Command Descriptor Block cdb[0] = 0x12 # Inquiry cdb[4] = INQUIRY_LENGTH expected_tag = ct.c_uint32() send_mass_storage_command(handle, endpoint_out, lun, cdb, usb.LIBUSB_ENDPOINT_IN, INQUIRY_LENGTH, ct.pointer(expected_tag)) size = ct.c_int() r = usb.bulk_transfer(handle, endpoint_in, ct.cast(ct.pointer(buffer), ct.POINTER(ct.c_ubyte)), INQUIRY_LENGTH, ct.byref(size), 1000) if r < 0: return err_exit(r) size = size.value print(" received {} bytes".format(size)) # The following strings are not zero terminated vid = (ct.c_char * 9)() pid = (ct.c_char * 9)() rev = (ct.c_char * 5)() for i in range(8): vid[i] = buffer[8 + i] pid[i] = buffer[16 + i] rev[i / 2] = buffer[32 + i / 2] # instead of another loop vid[8] = 0 pid[8] = 0 rev[4] = 0 print(" VID:PID:REV \"%8s\":\"%8s\":\"%4s\"".format(vid, pid, rev)) if get_mass_storage_status(handle, endpoint_in, expected_tag) == -2: get_sense(handle, endpoint_in, endpoint_out) # Read capacity print("Reading Capacity:") buffer = (ct.c_uint8 * 64)() cdb = (ct.c_uint8 * 16)() # SCSI Command Descriptor Block cdb[0] = 0x25 # Read Capacity expected_tag = ct.c_uint32() send_mass_storage_command(handle, endpoint_out, lun, cdb, usb.LIBUSB_ENDPOINT_IN, READ_CAPACITY_LENGTH, ct.pointer(expected_tag)) size = ct.c_int() r = usb.bulk_transfer(handle, endpoint_in, ct.cast(ct.pointer(buffer), ct.POINTER(ct.c_ubyte)), READ_CAPACITY_LENGTH, ct.byref(size), 1000) if r < 0: return err_exit(r) size = size.value print(" received {} bytes".format(size)) max_lba = be_to_int32(buffer[0:]) block_size = be_to_int32(buffer[4:]) device_size = (max_lba + 1.0) * block_size / (1024 * 1024 * 1024) print(" Max LBA: {:08X}, Block Size: {:08X} (%.2f GB)".format( max_lba, block_size, device_size)) if get_mass_storage_status(handle, endpoint_in, expected_tag) == -2: get_sense(handle, endpoint_in, endpoint_out) # coverity[tainted_data] try: data = ct.cast(calloc(1, block_size), ct.POINTER(ct.c_ubyte)) # unsigned char* except: perr(" unable to allocate data buffer\n") return -1 # Send Read print("Attempting to read %u bytes:".format(block_size)) cdb = (ct.c_uint8 * 16)() # SCSI Command Descriptor Block cdb[0] = 0x28 # Read(10) cdb[8] = 0x01 # 1 block expected_tag = ct.c_uint32() send_mass_storage_command(handle, endpoint_out, lun, cdb, usb.LIBUSB_ENDPOINT_IN, block_size, ct.pointer(expected_tag)) size = ct.c_int() usb.bulk_transfer(handle, endpoint_in, data, block_size, ct.byref(size), 5000) size = size.value print(" READ: received {} bytes".format(size)) if get_mass_storage_status(handle, endpoint_in, expected_tag) == -2: get_sense(handle, endpoint_in, endpoint_out) else: display_buffer_hex(data, size) if binary_dump: try: fd = open(binary_name, "w") except: pass else: with fd: if fd.fwrite(data, ct.c_size_t(size).value) != ct.c_uint(size).value: perr(" unable to write binary data\n") free(data) return 0