Beispiel #1
0
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)
Beispiel #2
0
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
Beispiel #3
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
Beispiel #4
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