From 186eecd2417b6937341e6c07b446f991142207d1 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 30 Oct 2025 23:31:23 +0100 Subject: [SERVER] iscsi: Unify usage of length and position variables There were a lot of similarly named and redundant variables in various structs named pos, len, xfer_len, des_xfer_pos, etc. It could be very challenging to keep track of what information is stored where when working with the code. Attempt to minimize this by relying only on a single "len" variable in the scsi_task struct. This refactoring uncovered a few inconsistencies in how allocation length limitations were handled, which were addressed here too. --- src/server/iscsi.c | 445 ++++++++++++++++++++++++----------------------------- src/server/iscsi.h | 229 +-------------------------- 2 files changed, 213 insertions(+), 461 deletions(-) (limited to 'src') diff --git a/src/server/iscsi.c b/src/server/iscsi.c index 9734a4b..d155fc4 100644 --- a/src/server/iscsi.c +++ b/src/server/iscsi.c @@ -77,7 +77,7 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task); static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task); -static void iscsi_scsi_task_create(iscsi_scsi_task *scsi_task); // Allocates and initializes a SCSI task +static void iscsi_scsi_task_init(iscsi_scsi_task *scsi_task); // Initializes a SCSI task static void iscsi_scsi_task_xfer_complete(iscsi_scsi_task *scsi_task, iscsi_pdu *request_pdu); // Callback function when an iSCSI SCSI task completed the data transfer @@ -360,15 +360,12 @@ static iscsi_task *iscsi_task_create(iscsi_connection *conn) task->pos = 0UL; task->len = 0UL; task->id = 0ULL; - task->flags = 0; task->lun_id = 0; task->init_task_tag = 0UL; task->target_xfer_tag = 0UL; - task->des_data_xfer_pos = 0UL; - task->des_data_xfer_len = 0UL; task->data_sn = 0UL; - iscsi_scsi_task_create( &task->scsi_task ); + iscsi_scsi_task_init( &task->scsi_task ); task->scsi_task.connection = conn; return task; @@ -401,17 +398,18 @@ static void iscsi_task_destroy(iscsi_task *task) * associated DNBD3 image as well and sends * it to the initiator. * - * @pararm[in] conn Pointer to iSCSI connection for which the + * @param[in] conn Pointer to iSCSI connection for which the * packet should be sent for. May NOT be * NULL, so be careful. - * @pararm[in] task Pointer to iSCSI task which handles the + * @param[in] task Pointer to iSCSI task which handles the * actual SCSI packet data. NULL is NOT * allowed here, so take caution. - * @pararm[in] pos Offset of data to be sent in bytes. - * @pararm[in] len Length of data to be sent in bytes - * @pararm[in] res_snt Residual Count. - * @pararm[in] data_sn Data Sequence Number (DataSN). - * @pararm[in] flags Flags for this data packet. + * @param[in] pos Offset of data to be sent in bytes. + * @param[in] len Length of data to be sent in bytes + * @param[in] res_cnt Residual Count. + * @param[in] data_sn Data Sequence Number (DataSN). + * @param[in] flags Flags for this data packet. + * @param[in] immediate whether immediate bit was set in this request * @return true success, false error */ static bool iscsi_scsi_data_in_send(iscsi_connection *conn, iscsi_task *task, @@ -514,26 +512,28 @@ static int iscsi_task_xfer_scsi_data_in(iscsi_connection *conn, iscsi_task *task if ( task->scsi_task.status != ISCSI_SCSI_STATUS_GOOD ) return 0; - const uint32_t pos = task->scsi_task.xfer_pos; - uint32_t xfer_len = task->scsi_task.len; - const uint32_t seg_len = conn->session->opts.MaxRecvDataSegmentLength; - uint32_t res_cnt = 0UL; - int8_t flags = 0; + const uint32_t expected_len = task->scsi_task.exp_xfer_len; + uint32_t xfer_len = task->scsi_task.len; + uint32_t res_cnt = 0UL; + int8_t flags = 0; - if ( pos < xfer_len ) { - res_cnt = (xfer_len - pos); - xfer_len = pos; - flags |= ISCSI_SCSI_DATA_IN_RESPONSE_FLAGS_RES_UNDERFLOW; - } else if ( pos > xfer_len ) { - res_cnt = (pos - xfer_len); + if ( expected_len < xfer_len ) { + res_cnt = (xfer_len - expected_len); + xfer_len = expected_len; flags |= ISCSI_SCSI_DATA_IN_RESPONSE_FLAGS_RES_OVERFLOW; + } else if ( expected_len > xfer_len ) { + res_cnt = (expected_len - xfer_len); + flags |= ISCSI_SCSI_DATA_IN_RESPONSE_FLAGS_RES_UNDERFLOW; } if ( xfer_len == 0UL ) return 0; uint32_t data_sn = task->data_sn; uint32_t max_burst_offset = 0UL; + // Max burst length = total length of payload in all PDUs const uint32_t max_burst_len = conn->session->opts.MaxBurstLength; + // Max recv segment length = total length of one individual PDU + const uint32_t seg_len = conn->session->opts.MaxRecvDataSegmentLength; const uint32_t data_in_seq_count = ((xfer_len - 1) / max_burst_len) + 1; int8_t status = 0; @@ -554,7 +554,7 @@ static int iscsi_task_xfer_scsi_data_in(iscsi_connection *conn, iscsi_task *task if ( (offset + len) == seq_end ) { flags |= (int8_t) ISCSI_SCSI_DATA_IN_RESPONSE_FLAGS_FINAL; - if ( (task->scsi_task.sense_data_len == 0U) && ((offset + len) == xfer_len) && (task->des_data_xfer_pos == task->scsi_task.xfer_len) ) { + if ( (task->scsi_task.sense_data_len == 0U) && ((offset + len) == xfer_len) ) { flags |= (int8_t) ISCSI_SCSI_DATA_IN_RESPONSE_FLAGS_STATUS; status |= flags; } @@ -580,7 +580,7 @@ static int iscsi_task_xfer_scsi_data_in(iscsi_connection *conn, iscsi_task *task * @param[in] scsi_task Pointer to SCSI task. This * may NOT be NULL, so be careful. */ -static void iscsi_scsi_task_create(iscsi_scsi_task *scsi_task) +static void iscsi_scsi_task_init(iscsi_scsi_task *scsi_task) { scsi_task->cdb = NULL; scsi_task->sense_data = NULL; @@ -588,9 +588,9 @@ static void iscsi_scsi_task_create(iscsi_scsi_task *scsi_task) scsi_task->must_free = true; scsi_task->len = 0UL; scsi_task->id = 0ULL; - scsi_task->flags = 0; - scsi_task->xfer_pos = 0UL; - scsi_task->xfer_len = 0UL; + scsi_task->is_read = false; + scsi_task->is_write = false; + scsi_task->exp_xfer_len = 0UL; scsi_task->sense_data_len = 0U; scsi_task->status = ISCSI_SCSI_STATUS_GOOD; } @@ -611,15 +611,12 @@ static void iscsi_scsi_task_xfer_complete(iscsi_scsi_task *scsi_task, iscsi_pdu iscsi_task *task = container_of( scsi_task, iscsi_task, scsi_task ); iscsi_connection *conn = task->conn; - task->des_data_xfer_pos += scsi_task->len; - iscsi_scsi_cmd_packet *scsi_cmd_pkt = (iscsi_scsi_cmd_packet *) request_pdu->bhs_pkt; - const uint32_t xfer_len = scsi_task->xfer_len; if ( (scsi_cmd_pkt->flags_task & ISCSI_SCSI_CMD_FLAGS_TASK_READ) != 0 ) { const int rc = iscsi_task_xfer_scsi_data_in( conn, task, (scsi_cmd_pkt->opcode & ISCSI_OPCODE_FLAGS_IMMEDIATE) != 0 ); - if ( (rc > 0) || (task->des_data_xfer_pos != scsi_task->xfer_len) ) + if ( rc > 0 ) return; } @@ -647,17 +644,18 @@ static void iscsi_scsi_task_xfer_complete(iscsi_scsi_task *scsi_task, iscsi_pdu scsi_response_pkt->opcode = ISCSI_OPCODE_SERVER_SCSI_RESPONSE; scsi_response_pkt->flags = -0x80; scsi_response_pkt->response = ISCSI_SCSI_RESPONSE_CODE_OK; + const uint32_t exp_xfer_len = scsi_task->exp_xfer_len; - const uint32_t pos = scsi_task->xfer_pos; + if ( (exp_xfer_len != 0UL) && (scsi_task->status == ISCSI_SCSI_STATUS_GOOD) ) { + const uint32_t resp_len = ds_len; - if ( (xfer_len != 0UL) && (scsi_task->status == ISCSI_SCSI_STATUS_GOOD) ) { - if ( pos < xfer_len ) { - const uint32_t res_cnt = (xfer_len - pos); + if ( resp_len < exp_xfer_len ) { + const uint32_t res_cnt = (exp_xfer_len - resp_len); scsi_response_pkt->flags |= ISCSI_SCSI_RESPONSE_FLAGS_RES_UNDERFLOW; iscsi_put_be32( (uint8_t *) &scsi_response_pkt->res_cnt, res_cnt ); - } else if ( pos > xfer_len ) { - const uint32_t res_cnt = (pos - xfer_len); + } else if ( resp_len > exp_xfer_len ) { + const uint32_t res_cnt = (resp_len - exp_xfer_len); scsi_response_pkt->flags |= ISCSI_SCSI_RESPONSE_FLAGS_RES_OVERFLOW; iscsi_put_be32( (uint8_t *) &scsi_response_pkt->res_cnt, res_cnt ); @@ -771,9 +769,8 @@ static void iscsi_scsi_task_status_set(iscsi_scsi_task *scsi_task, const uint8_t */ static void iscsi_scsi_task_lun_process_none(iscsi_scsi_task *scsi_task) { - scsi_task->len = scsi_task->xfer_len; - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_LU_NOT_SUPPORTED, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - scsi_task->xfer_pos = 0UL; + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, + ISCSI_SCSI_ASC_LU_NOT_SUPPORTED, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); } /** @@ -862,7 +859,6 @@ static inline uint64_t iscsi_scsi_emu_block_get_count(const dnbd3_image_t *image * so take caution. * @param[in] offset_bytes Offset in bytes. * @param[in] num_bytes Number of bytes. - * @param[in] block_size Block size in bytes. * @return 0 if specified offset and number of * bytes is aligned to block size or a * positive value if unaligned. @@ -947,7 +943,12 @@ static int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, dnbd3_imag int rc = 0; uint64_t offset_bytes; const uint64_t num_bytes = iscsi_scsi_emu_blocks_to_bytes( &offset_bytes, offset_blocks, num_blocks ); + + if ( offset_bytes + num_bytes > image->virtualFilesize ) + return -ERANGE; + scsi_task->file_offset = offset_bytes; + scsi_task->len = (uint32_t)num_bytes; dnbd3_cache_map_t *cache = ref_get_cachemap( image ); @@ -991,14 +992,12 @@ static int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, dnbd3_imag } /** - * @brief Executes a read or write operation on a DNBD3 image. + * @brief Executes a read operation on a DNBD3 image. * * This function also sets the SCSI * status result code accordingly. * * @param[in] image Pointer to DNBD3 image to read from - * or to write to. May NOT be NULL, so - * be careful. * @param[in] scsi_task Pointer to iSCSI SCSI task * responsible for this read or write * task. NULL is NOT allowed here, take @@ -1006,37 +1005,11 @@ static int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, dnbd3_imag * @param[in] lba Logical Block Address (LBA) to start * reading from or writing to. * @param[in] xfer_len Transfer length in logical blocks. - * @param[in] flags Flags indicating if a read or write - * operation is in progress. For a - * write operation an optional verify - * can be requested. * @return 0 on successful operation, a negative * error code otherwise. */ -static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task *scsi_task, const uint64_t lba, const uint32_t xfer_len, const int flags) +static int iscsi_scsi_emu_block_read(dnbd3_image_t *image, iscsi_scsi_task *scsi_task, const uint64_t lba, const uint32_t xfer_len) { - scsi_task->xfer_pos = 0UL; - - if ( (flags & ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE) != 0 ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - return ISCSI_SCSI_TASK_RUN_COMPLETE; - } - - if ( (scsi_task->flags & (ISCSI_SCSI_TASK_FLAGS_XFER_READ | ISCSI_SCSI_TASK_FLAGS_XFER_WRITE)) == (ISCSI_SCSI_TASK_FLAGS_XFER_READ | ISCSI_SCSI_TASK_FLAGS_XFER_WRITE) ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - return ISCSI_SCSI_TASK_RUN_COMPLETE; - } - - const uint64_t imgBlockCount = iscsi_scsi_emu_block_get_count( image ); - - if ( (imgBlockCount <= lba) || ((imgBlockCount - lba) < xfer_len) ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - return ISCSI_SCSI_TASK_RUN_COMPLETE; - } - if ( xfer_len == 0UL ) { scsi_task->status = ISCSI_SCSI_STATUS_GOOD; @@ -1045,39 +1018,34 @@ static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task const uint32_t max_xfer_len = ISCSI_MAX_DS_SIZE / ISCSI_SCSI_EMU_BLOCK_SIZE; - if ( xfer_len > max_xfer_len || xfer_len * ISCSI_SCSI_EMU_BLOCK_SIZE != scsi_task->len ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + if ( xfer_len > max_xfer_len || !scsi_task->is_read || scsi_task->is_write ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, + ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return ISCSI_SCSI_TASK_RUN_COMPLETE; } - uint64_t offset_blocks; - uint64_t num_blocks; - - if ( iscsi_scsi_emu_bytes_to_blocks( &offset_blocks, &num_blocks, 0, scsi_task->len ) != 0ULL ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + int rc = iscsi_scsi_emu_io_blocks_read( scsi_task, image, lba, xfer_len ); + if ( rc == 0 ) return ISCSI_SCSI_TASK_RUN_COMPLETE; - } - offset_blocks += lba; + if ( rc == -ENOMEM ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_HARDWARE_ERR, + ISCSI_SCSI_ASC_INTERNAL_TARGET_FAIL, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE ); - int rc = iscsi_scsi_emu_io_blocks_read( scsi_task, image, offset_blocks, num_blocks ); - - if ( rc < 0 ) { - if ( rc == -ENOMEM ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_HARDWARE_ERR, - ISCSI_SCSI_ASC_INTERNAL_TARGET_FAIL, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE ); - - return ISCSI_SCSI_TASK_RUN_COMPLETE; - } + return ISCSI_SCSI_TASK_RUN_COMPLETE; + } - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + if ( rc == -ERANGE ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, + ISCSI_SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return ISCSI_SCSI_TASK_RUN_COMPLETE; } - scsi_task->xfer_pos = scsi_task->len; + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, + ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return ISCSI_SCSI_TASK_RUN_COMPLETE; } @@ -1110,7 +1078,7 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) if ( xfer_len == 0UL ) xfer_len = 256UL; - return iscsi_scsi_emu_block_read_write( image, scsi_task, lba, xfer_len, 0 ); + return iscsi_scsi_emu_block_read( image, scsi_task, lba, xfer_len ); } case ISCSI_SCSI_OPCODE_READ10 : { const iscsi_scsi_cdb_read_write_10 *cdb_read_write_10 = (iscsi_scsi_cdb_read_write_10 *) scsi_task->cdb; @@ -1118,7 +1086,7 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) lba = iscsi_get_be32(cdb_read_write_10->lba); xfer_len = iscsi_get_be16(cdb_read_write_10->xfer_len); - return iscsi_scsi_emu_block_read_write( image, scsi_task, lba, xfer_len, 0 ); + return iscsi_scsi_emu_block_read( image, scsi_task, lba, xfer_len ); } case ISCSI_SCSI_OPCODE_READ12 : { const iscsi_scsi_cdb_read_write_12 *cdb_read_write_12 = (iscsi_scsi_cdb_read_write_12 *) scsi_task->cdb; @@ -1126,7 +1094,7 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) lba = iscsi_get_be32(cdb_read_write_12->lba); xfer_len = iscsi_get_be32(cdb_read_write_12->xfer_len); - return iscsi_scsi_emu_block_read_write( image, scsi_task, lba, xfer_len, 0 ); + return iscsi_scsi_emu_block_read( image, scsi_task, lba, xfer_len ); } case ISCSI_SCSI_OPCODE_READ16 : { const iscsi_scsi_cdb_read_write_16 *cdb_read_write_16 = (iscsi_scsi_cdb_read_write_16 *) scsi_task->cdb; @@ -1134,7 +1102,7 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) lba = iscsi_get_be64(cdb_read_write_16->lba); xfer_len = iscsi_get_be32(cdb_read_write_16->xfer_len); - return iscsi_scsi_emu_block_read_write( image, scsi_task, lba, xfer_len, 0 ); + return iscsi_scsi_emu_block_read( image, scsi_task, lba, xfer_len ); } case ISCSI_SCSI_OPCODE_READCAPACITY10 : { iscsi_scsi_read_capacity_10_parameter_data_packet *buf = (iscsi_scsi_read_capacity_10_parameter_data_packet *) malloc( sizeof(struct iscsi_scsi_read_capacity_10_parameter_data_packet) ); @@ -1156,11 +1124,12 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) uint len = scsi_task->len; - if ( len > sizeof(struct iscsi_scsi_read_capacity_10_parameter_data_packet) ) + if ( len > sizeof(struct iscsi_scsi_read_capacity_10_parameter_data_packet) ) { len = sizeof(struct iscsi_scsi_read_capacity_10_parameter_data_packet); // TODO: Check whether scatter data is required + } scsi_task->buf = (uint8_t *) buf; - scsi_task->xfer_pos = len; + scsi_task->len = len; scsi_task->status = ISCSI_SCSI_STATUS_GOOD; break; @@ -1175,7 +1144,8 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) iscsi_scsi_service_action_in_16_parameter_data_packet *buf = malloc( sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet) ); if ( buf == NULL ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_BECOMING_READY ); + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, + ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_BECOMING_READY ); return ISCSI_SCSI_TASK_RUN_COMPLETE; } @@ -1197,15 +1167,27 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) uint len = cdb_servce_in_action_16->alloc_len; - if ( len > sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet) ) + if ( len > sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet) ) { len = sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet); // TODO: Check whether scatter data is required + } scsi_task->buf = (uint8_t *) buf; - scsi_task->xfer_pos = len; + scsi_task->len = len; scsi_task->status = ISCSI_SCSI_STATUS_GOOD; break; } + case ISCSI_SCSI_OPCODE_WRITE6 : + case ISCSI_SCSI_OPCODE_WRITE10 : + case ISCSI_SCSI_OPCODE_WRITE12 : + case ISCSI_SCSI_OPCODE_WRITE16 : + case ISCSI_SCSI_OPCODE_UNMAP : + case ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE10 : + case ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE16 : { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_WRITE_PROTECTED, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + + break; + } default : { return ISCSI_SCSI_TASK_RUN_UNKNOWN; @@ -1305,15 +1287,14 @@ static size_t iscsi_scsi_emu_pad_scsi_name(uint8_t *buf, const uint8_t *name) * data with. * @param[in] len Length of inquiry result buffer * in bytes. - * @return 0 on successful operation, a negative + * @return length of data on successful operation, a negative * error code otherwise. */ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task *scsi_task, const iscsi_scsi_cdb_inquiry *cdb_inquiry, iscsi_scsi_std_inquiry_data_packet *std_inquiry_data_pkt, const uint len) { if ( len < sizeof(struct iscsi_scsi_std_inquiry_data_packet) ) { - scsi_task->xfer_pos = 0UL; - - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, + ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return -1; } @@ -1322,7 +1303,8 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task const uint pc = cdb_inquiry->page_code; if ( (evpd == 0) && (pc != 0U) ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, + ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return -1; } @@ -1568,8 +1550,6 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task break; } default : { - scsi_task->xfer_pos = 0UL; - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return -1; @@ -1766,6 +1746,7 @@ static int iscsi_scsi_emu_primary_mode_sense_page(dnbd3_image_t *image, iscsi_sc { uint page_len; int len = 0; + int tmplen; switch ( pc ) { case ISCSI_SCSI_CDB_MODE_SENSE_6_PAGE_CONTROL_CURRENT_VALUES : @@ -1774,7 +1755,8 @@ static int iscsi_scsi_emu_primary_mode_sense_page(dnbd3_image_t *image, iscsi_sc break; } default : { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, + ISCSI_SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return -1; @@ -1916,8 +1898,14 @@ static int iscsi_scsi_emu_primary_mode_sense_page(dnbd3_image_t *image, iscsi_sc break; } case ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_CONTROL_ALL : { - len += iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, page, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_CONTROL ); - len += iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, page, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_CONTROL_EXT ); + tmplen = iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, page, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_CONTROL ); + if ( tmplen == -1 ) + return -1; + len += tmplen; + tmplen = iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, page, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_CONTROL_EXT ); + if ( tmplen == -1 ) + return -1; + len += tmplen; break; } @@ -1970,18 +1958,27 @@ static int iscsi_scsi_emu_primary_mode_sense_page(dnbd3_image_t *image, iscsi_sc switch ( sub_page ) { case ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_REPORT_ALL_MODE_PAGES : { for ( i = ISCSI_SCSI_MODE_SENSE_MODE_PAGE_CODE_VENDOR_SPEC; i < ISCSI_SCSI_MODE_SENSE_MODE_PAGE_CODE_REPORT_ALL_MODE_PAGES; i++ ) { - len += iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, i, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_REPORT_ALL_MODE_PAGES ); + tmplen = iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, i, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_REPORT_ALL_MODE_PAGES ); + if ( tmplen == -1 ) + return -1; + len += tmplen; } break; } case ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_REPORT_ALL_MODE_SUB_PAGES : { for ( i = ISCSI_SCSI_MODE_SENSE_MODE_PAGE_CODE_VENDOR_SPEC; i < ISCSI_SCSI_MODE_SENSE_MODE_PAGE_CODE_REPORT_ALL_MODE_PAGES; i++ ) { - len += iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, i, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_REPORT_ALL_MODE_PAGES ); + tmplen = iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, i, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_REPORT_ALL_MODE_PAGES ); + if ( tmplen == -1 ) + return -1; + len += tmplen; } for ( i = ISCSI_SCSI_MODE_SENSE_MODE_PAGE_CODE_VENDOR_SPEC; i < ISCSI_SCSI_MODE_SENSE_MODE_PAGE_CODE_REPORT_ALL_MODE_PAGES; i++ ) { - len += iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, i, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_REPORT_ALL_MODE_SUB_PAGES ); + tmplen = iscsi_scsi_emu_primary_mode_sense_page( image, scsi_task, ((mode_sense_mode_page_pkt != NULL) ? (iscsi_scsi_mode_sense_mode_page_data_packet *) (((uint8_t *) mode_sense_mode_page_pkt) + len) : NULL), pc, i, ISCSI_SCSI_MODE_SENSE_MODE_SUB_PAGE_CODE_REPORT_ALL_MODE_SUB_PAGES ); + if ( tmplen == -1 ) + return -1; + len += tmplen; } break; @@ -2086,6 +2083,39 @@ static int iscsi_scsi_emu_primary_mode_sense(dnbd3_image_t *image, iscsi_scsi_ta return alloc_len; } +/** + * @brief Determines the temporary allocation size for a SCSI reply. + * + * This function calculates the temporary allocation size to be used for SCSI + * commands based on the requested allocation size. It ensures the allocation + * size has a minimum size, to simplify buffer-filling. The response can then + * later be truncated if it's larger than the alloc_size. + * If the requested size exceeds the default maximum allowed size, a SCSI task + * status with an error condition is set, and the allocation size is returned + * as zero. + * + * @param[in] scsi_task Pointer to the SCSI task, used to set error status. + * @param[in] alloc_size The client-requested allocation size in bytes. + * + * @return The determined temporary allocation size. Returns 0 if the size + * exceeds the maximum allowed limit; otherwise, the size is either adjusted + * to the default size or remains the requested size. + */ +static uint32_t iscsi_get_temporary_allocation_size(iscsi_scsi_task *scsi_task, uint32_t alloc_size) +{ + if ( alloc_size > ISCSI_DEFAULT_RECV_DS_LEN ) { + // Don't allocate gigabytes of memory just because the client says so + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, + ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + + return 0; + } + if ( alloc_size < ISCSI_DEFAULT_RECV_DS_LEN ) + return ISCSI_DEFAULT_RECV_DS_LEN; + + return alloc_size; +} + /** * @brief Executes SCSI non-block emulation on a DNBD3 image. * @@ -2102,109 +2132,73 @@ static int iscsi_scsi_emu_primary_mode_sense(dnbd3_image_t *image, iscsi_scsi_ta */ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task) { - uint alloc_len; uint len; int rc; switch ( scsi_task->cdb->opcode ) { case ISCSI_SCSI_OPCODE_INQUIRY : { const iscsi_scsi_cdb_inquiry *cdb_inquiry = (iscsi_scsi_cdb_inquiry *) scsi_task->cdb; + const uint alloc_len = iscsi_get_be16(cdb_inquiry->alloc_len); - alloc_len = iscsi_get_be16(cdb_inquiry->alloc_len); - len = alloc_len; - - if ( len < ISCSI_DEFAULT_RECV_DS_LEN ) - len = ISCSI_DEFAULT_RECV_DS_LEN; - - iscsi_scsi_std_inquiry_data_packet *std_inquiry_data_pkt = NULL; + len = iscsi_get_temporary_allocation_size( scsi_task, alloc_len ); + if ( len == 0 ) + break; - if ( len > 0U ) { - std_inquiry_data_pkt = (iscsi_scsi_std_inquiry_data_packet *) malloc( len ); + iscsi_scsi_std_inquiry_data_packet *std_inquiry_data_pkt = malloc( len ); - if ( std_inquiry_data_pkt == NULL ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_BECOMING_READY ); + if ( std_inquiry_data_pkt == NULL ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, + ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_BECOMING_READY ); - break; - } + break; } rc = iscsi_scsi_emu_primary_inquiry( scsi_task->connection->client->image, scsi_task, cdb_inquiry, std_inquiry_data_pkt, len ); - if ( (rc >= 0) && (len > 0U) ) { - if ( len > alloc_len ) { - len = alloc_len; - } - - scsi_task->buf = (uint8_t *) std_inquiry_data_pkt; - - if ( rc < (int) len ) - memset( (((uint8_t *) std_inquiry_data_pkt) + rc), 0, (len - rc) ); - - rc = len; + if ( rc >= 0 ) { + scsi_task->buf = (uint8_t *) std_inquiry_data_pkt; + scsi_task->len = MIN( rc, alloc_len ); + scsi_task->status = ISCSI_SCSI_STATUS_GOOD; } else { free( std_inquiry_data_pkt ); } - if ( rc >= 0 ) { - scsi_task->xfer_pos = rc; - scsi_task->status = ISCSI_SCSI_STATUS_GOOD; - } - break; } case ISCSI_SCSI_OPCODE_REPORTLUNS : { const iscsi_scsi_cdb_report_luns *cdb_report_luns = (iscsi_scsi_cdb_report_luns *) scsi_task->cdb; + const uint alloc_len = iscsi_get_be32(cdb_report_luns->alloc_len); - alloc_len = iscsi_get_be32(cdb_report_luns->alloc_len); - rc = iscsi_scsi_emu_check_len( scsi_task, alloc_len, (sizeof(struct iscsi_scsi_report_luns_parameter_data_lun_list_packet) + sizeof(struct iscsi_scsi_report_luns_parameter_data_lun_entry_packet)) ); - - if ( rc < 0 ) + len = iscsi_get_temporary_allocation_size( scsi_task, alloc_len ); + if ( len == 0 ) break; - len = alloc_len; - - if ( len < ISCSI_DEFAULT_RECV_DS_LEN ) - len = ISCSI_DEFAULT_RECV_DS_LEN; - - iscsi_scsi_report_luns_parameter_data_lun_list_packet *report_luns_parameter_data_pkt = NULL; + iscsi_scsi_report_luns_parameter_data_lun_list_packet *report_luns_parameter_data_pkt = malloc( len ); - if ( len > 0U ) { - report_luns_parameter_data_pkt = (iscsi_scsi_report_luns_parameter_data_lun_list_packet *) malloc( len ); + if ( report_luns_parameter_data_pkt == NULL ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, + ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_BECOMING_READY ); - if ( report_luns_parameter_data_pkt == NULL ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_BECOMING_READY ); - - break; - } + break; } rc = iscsi_scsi_emu_primary_report_luns( report_luns_parameter_data_pkt, len, cdb_report_luns->select_report ); - if ( rc < 0 ) { + if ( rc >= 0 ) { + scsi_task->buf = (uint8_t *) report_luns_parameter_data_pkt; + scsi_task->len = MIN( rc, alloc_len ); + scsi_task->status = ISCSI_SCSI_STATUS_GOOD; + } else { free( report_luns_parameter_data_pkt ); - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - break; - } - - len = rc; - - if ( len > 0U ) { - if ( len > alloc_len ) - len = alloc_len; - - scsi_task->buf = (uint8_t *) report_luns_parameter_data_pkt; + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, + ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); } - scsi_task->xfer_pos = len; - scsi_task->status = ISCSI_SCSI_STATUS_GOOD; - break; } case ISCSI_SCSI_OPCODE_MODESENSE6 : { const iscsi_scsi_cdb_mode_sense_6 *cdb_mode_sense_6 = (iscsi_scsi_cdb_mode_sense_6 *) scsi_task->cdb; - - alloc_len = cdb_mode_sense_6->alloc_len; + const uint alloc_len = cdb_mode_sense_6->alloc_len; const uint block_desc_len = ((cdb_mode_sense_6->flags & ISCSI_SCSI_CDB_MODE_SENSE_6_FLAGS_DBD) == 0) ? sizeof(struct iscsi_scsi_mode_sense_lba_parameter_block_desc_data_packet) : 0U; const uint pc = ISCSI_SCSI_CDB_MODE_SENSE_6_GET_PAGE_CONTROL(cdb_mode_sense_6->page_code_control); @@ -2228,32 +2222,21 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task) rc = iscsi_scsi_emu_primary_mode_sense( scsi_task->connection->client->image, scsi_task, mode_sense_6_parameter_hdr_data_pkt, sizeof(struct iscsi_scsi_mode_sense_6_parameter_header_data_packet), block_desc_len, 0U, pc, page, sub_page ); - if ( rc < 0 ) { - free( mode_sense_6_parameter_hdr_data_pkt ); - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - break; - } - - if ( (rc >= 0) && (len > 0U) ) { - if ( len > alloc_len ) - len = alloc_len; - - scsi_task->buf = (uint8_t *) mode_sense_6_parameter_hdr_data_pkt; - rc = len; - } - if ( rc >= 0 ) { - scsi_task->xfer_pos = rc; - scsi_task->status = ISCSI_SCSI_STATUS_GOOD; + scsi_task->buf = (uint8_t *) mode_sense_6_parameter_hdr_data_pkt; + scsi_task->len = MIN( rc, alloc_len ); + scsi_task->status = ISCSI_SCSI_STATUS_GOOD; + } else { + free( mode_sense_6_parameter_hdr_data_pkt ); + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, + ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); } break; } case ISCSI_SCSI_OPCODE_MODESENSE10 : { const iscsi_scsi_cdb_mode_sense_10 *cdb_mode_sense_10 = (iscsi_scsi_cdb_mode_sense_10 *) scsi_task->cdb; - - alloc_len = iscsi_get_be16(cdb_mode_sense_10->alloc_len); + const uint alloc_len = iscsi_get_be16(cdb_mode_sense_10->alloc_len); const uint long_lba = (((cdb_mode_sense_10->flags & ISCSI_SCSI_CDB_MODE_SENSE_10_FLAGS_LLBAA) != 0) ? ISCSI_SCSI_MODE_SENSE_10_PARAM_HDR_DATA_LONGLBA : 0U); const uint block_desc_len = (((cdb_mode_sense_10->flags & ISCSI_SCSI_CDB_MODE_SENSE_10_FLAGS_DBD) == 0) ? ((long_lba != 0) ? sizeof(struct iscsi_scsi_mode_sense_long_lba_parameter_block_desc_data_packet) : sizeof(struct iscsi_scsi_mode_sense_lba_parameter_block_desc_data_packet)) : 0U); @@ -2278,36 +2261,24 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task) rc = iscsi_scsi_emu_primary_mode_sense( scsi_task->connection->client->image, scsi_task, (iscsi_scsi_mode_sense_6_parameter_header_data_packet *) mode_sense_10_parameter_hdr_data_pkt, sizeof(struct iscsi_scsi_mode_sense_10_parameter_header_data_packet), block_desc_len, long_lba, pc10, page10, sub_page10 ); - if ( rc < 0 ) { - free( mode_sense_10_parameter_hdr_data_pkt ); - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - break; - } - - if ( (rc >= 0) && (len > 0U) ) { - if ( len > alloc_len ) - len = alloc_len; - - scsi_task->buf = (uint8_t *) mode_sense_10_parameter_hdr_data_pkt; - rc = len; - } - if ( rc >= 0 ) { - scsi_task->xfer_pos = rc; - scsi_task->status = ISCSI_SCSI_STATUS_GOOD; + scsi_task->buf = (uint8_t *) mode_sense_10_parameter_hdr_data_pkt; + scsi_task->len = MIN( rc, alloc_len ); + scsi_task->status = ISCSI_SCSI_STATUS_GOOD; + } else { + free( mode_sense_10_parameter_hdr_data_pkt ); + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, + ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); } break; } case ISCSI_SCSI_OPCODE_TESTUNITREADY : { - scsi_task->xfer_pos = 0UL; scsi_task->status = ISCSI_SCSI_STATUS_GOOD; break; } case ISCSI_SCSI_OPCODE_STARTSTOPUNIT : { - scsi_task->xfer_pos = 0UL; scsi_task->status = ISCSI_SCSI_STATUS_GOOD; break; @@ -3008,8 +2979,6 @@ static inline int iscsi_seq_num_cmp_gt(const uint32_t seq_num, const uint32_t se */ static int iscsi_connection_handle_reject(iscsi_connection *conn, iscsi_pdu *pdu, const int reason_code) { - pdu->flags |= ISCSI_PDU_FLAGS_REJECTED; - const uint32_t ds_len = (uint32_t) sizeof(struct iscsi_bhs_packet) + (uint32_t) (pdu->bhs_pkt->total_ahs_len * ISCSI_ALIGN_SIZE); iscsi_pdu CLEANUP_PDU response_pdu; if ( !iscsi_connection_pdu_init( &response_pdu, ds_len, false ) ) @@ -3266,10 +3235,9 @@ static int iscsi_connection_handle_scsi_cmd(iscsi_connection *conn, iscsi_pdu *r uint32_t exp_xfer_len = iscsi_get_be32(scsi_cmd_pkt->exp_xfer_len); - task->scsi_task.len = (uint) (((uint8_t *) request_pdu->ds_cmd_data) - ((uint8_t *) request_pdu->bhs_pkt)); // Length of BHS + AHS - task->scsi_task.cdb = &scsi_cmd_pkt->scsi_cdb; - task->scsi_task.xfer_len = exp_xfer_len; - task->init_task_tag = iscsi_get_be32(scsi_cmd_pkt->init_task_tag); + task->scsi_task.cdb = &scsi_cmd_pkt->scsi_cdb; + task->scsi_task.exp_xfer_len = exp_xfer_len; + task->init_task_tag = iscsi_get_be32(scsi_cmd_pkt->init_task_tag); const uint64_t lun = iscsi_get_be64(scsi_cmd_pkt->lun); task->lun_id = iscsi_scsi_lun_get_from_iscsi( lun ); @@ -3277,13 +3245,15 @@ static int iscsi_connection_handle_scsi_cmd(iscsi_connection *conn, iscsi_pdu *r if ( (scsi_cmd_pkt->flags_task & ISCSI_SCSI_CMD_FLAGS_TASK_READ) == 0 ) { if ( exp_xfer_len != 0UL ) { // Not a read request, but expecting data - not valid + iscsi_scsi_task_status_set( &task->scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); iscsi_task_destroy( task ); return iscsi_connection_handle_reject( conn, request_pdu, ISCSI_REJECT_REASON_INVALID_PDU_FIELD ); } } else { - task->scsi_task.flags |= ISCSI_SCSI_TASK_FLAGS_XFER_READ; + task->scsi_task.is_read = true; } + task->scsi_task.is_write = (scsi_cmd_pkt->flags_task & ISCSI_SCSI_CMD_FLAGS_TASK_WRITE) != 0; int rc; @@ -3292,11 +3262,6 @@ static int iscsi_connection_handle_scsi_cmd(iscsi_connection *conn, iscsi_pdu *r iscsi_scsi_task_lun_process_none( &task->scsi_task ); rc = ISCSI_CONNECT_PDU_READ_OK; } else { - if ( (task->scsi_task.flags & ISCSI_SCSI_TASK_FLAGS_XFER_READ) != 0 ) { - task->scsi_task.buf = NULL; - task->scsi_task.len = task->scsi_task.xfer_len; - } - task->scsi_task.status = ISCSI_SCSI_STATUS_GOOD; rc = iscsi_scsi_emu_block_process( &task->scsi_task ); @@ -3306,7 +3271,6 @@ static int iscsi_connection_handle_scsi_cmd(iscsi_connection *conn, iscsi_pdu *r if ( rc == ISCSI_SCSI_TASK_RUN_UNKNOWN ) { iscsi_scsi_task_status_set( &task->scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - // TODO: Free task rc = ISCSI_SCSI_TASK_RUN_COMPLETE; } } @@ -3457,16 +3421,6 @@ static int iscsi_connecction_handle_login_response(iscsi_connection *conn, iscsi return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; } iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - int payload_len = iscsi_write_login_options_to_pdu( conn, pairs, login_response_pdu ); - - if ( payload_len < 0 || (uint32_t)payload_len > login_response_pdu->ds_len ) { - logadd( LOG_DEBUG1, "iscsi_connecction_handle_login_response: Invalid payload length %d, ds_len: %u, write_pos: %u", - payload_len, login_response_pdu->ds_len, login_response_pdu->ds_write_pos ); - login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR; - login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES; - - return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; - } // Handle current stage (CSG bits) switch ( ISCSI_LOGIN_RESPONSE_FLAGS_GET_CURRENT_STAGE(login_response_pkt->flags) ) { @@ -3504,7 +3458,18 @@ static int iscsi_connecction_handle_login_response(iscsi_connection *conn, iscsi iscsi_put_be16( (uint8_t *) &login_response_pkt->tsih, 42 ); conn->state = ISCSI_CONNECT_STATE_NORMAL_SESSION; + iscsi_connection_update_key_value_pairs( conn, pairs ); + int payload_len = iscsi_write_login_options_to_pdu( conn, pairs, login_response_pdu ); + + if ( payload_len < 0 || (uint32_t)payload_len > login_response_pdu->ds_len ) { + logadd( LOG_DEBUG1, "iscsi_connecction_handle_login_response: Invalid payload length %d, ds_len: %u, write_pos: %u", + payload_len, login_response_pdu->ds_len, login_response_pdu->ds_write_pos ); + login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR; + login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES; + + return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; + } break; } diff --git a/src/server/iscsi.h b/src/server/iscsi.h index f4fa6b1..d8cd43b 100644 --- a/src/server/iscsi.h +++ b/src/server/iscsi.h @@ -314,22 +314,12 @@ static inline bool iscsi_is_pow2(const uint32_t value) /// iSCSI Default receive DataSegment (DS) size in bytes. -#define ISCSI_DEFAULT_RECV_DS_LEN 131072UL +#define ISCSI_DEFAULT_RECV_DS_LEN 16384UL /// iSCSI default maximum DataSegment receive length in bytes. #define ISCSI_DEFAULT_MAX_RECV_DS_LEN 524288UL -/// iSCSI default maximum Ready To Transfer (R2T) active tasks. -#define ISCSI_DEFAULT_MAX_R2T_PER_CONNECTION 4UL - -/// iSCSI default maximum DataSegment receive length in bytes. -#define ISCSI_DEFAULT_MAX_DATA_IN_PER_CONNECTION 64UL - -/// iSCSI default maximum DataSegment send length in bytes. -#define ISCSI_DEFAULT_MAX_DATA_OUT_PER_CONNECTION 16UL - - /// Current minimum iSCSI protocol version supported by this implementation. #define ISCSI_VERSION_MIN 0 @@ -2325,18 +2315,6 @@ typedef struct __attribute__((packed)) iscsi_scsi_report_luns_parameter_data_lun } iscsi_scsi_report_luns_parameter_data_lun_list_packet; -/** - * @brief iSCSI SCSI command REPORT LUNS parameter data LUN entry packet data. - * - * This returns a single LUN entry of the - * LUN list. - */ -typedef struct __attribute__((packed)) iscsi_scsi_report_luns_parameter_data_lun_entry_packet { - /// Logical Unit Number (LUN). - uint64_t lun; -} iscsi_scsi_report_luns_parameter_data_lun_entry_packet; - - /** * @brief iSCSI SCSI command MODE SELECT(6) parameter list packet data. * @@ -5326,9 +5304,6 @@ typedef struct __attribute__((packed)) iscsi_nop_out_packet { /// Reserved for future usage, always MUST be 0. uint64_t reserved2[2]; - /// Optional header digest. - uint32_t hdr_digest; - /** * @brief DataSegment - Ping Data (optional). * @@ -5338,9 +5313,6 @@ typedef struct __attribute__((packed)) iscsi_nop_out_packet { * for the DataSegmentLength and indicates the absence of ping data. */ iscsi_scsi_ds_cmd_data ds_ping_data; - - /// Optional data digest. - uint32_t data_digest; } iscsi_nop_out_packet; @@ -5425,75 +5397,11 @@ typedef struct __attribute__((packed)) iscsi_nop_in_packet { /// Reserved for future usage, always MUST be 0. uint64_t reserved3; - /// Optional header digest. - uint32_t hdr_digest; - /// DataSegment - Return Ping Data. iscsi_scsi_ds_cmd_data ds_ping_data; - - /// Optional data digest. - uint32_t data_digest; } iscsi_nop_in_packet; -/// iSCSI SCSI transport ID protocol identifier: iSCSI. -#define ISCSI_TRANSPORT_ID_PROTOCOL_ID_ISCSI 0x05 - -/// iSCSI SCSI transport ID protocol identifier: First bit of the four bits. -#define ISCSI_TRANSPORT_ID_PROTOCOL_ID_FIRST_BIT 0 - -/// iSCSI SCSI transport ID protocol identifier: Last bit of the four bits. -#define ISCSI_TRANSPORT_ID_PROTOCOL_ID_LAST_BIT ((ISCSI_TRANSPORT_ID_PROTOCOL_ID_FIRST_BIT) + 4 - 1) - -/// iSCSI SCSI transport ID protocol identifier: Bit mask. -#define ISCSI_TRANSPORT_ID_PROTOCOL_ID_MASK (ISCSI_BITS_GET_MASK(ISCSI_TRANSPORT_ID_PROTOCOL_ID_FIRST_BIT, ISCSI_TRANSPORT_ID_PROTOCOL_ID_LAST_BIT)) - -/// iSCSI SCSI transport ID protocol identifier: Extracts the protocol identifier bits. -#define ISCSI_TRANSPORT_ID_GET_PROTOCOL_ID(x) (ISCSI_BITS_GET((x), ISCSI_TRANSPORT_ID_PROTOCOL_ID_FIRST_BIT, ISCSI_TRANSPORT_ID_PROTOCOL_ID_LAST_BIT)) - -/// iSCSI SCSI transport ID protocol identifier: Stores into the protocol identifier bits. -#define ISCSI_TRANSPORT_ID_PUT_PROTOCOL_ID(x) (ISCSI_BITS_PUT((x), ISCSI_TRANSPORT_ID_PROTOCOL_ID_FIRST_BIT, ISCSI_TRANSPORT_ID_PROTOCOL_ID_LAST_BIT)) - -/// iSCSI SCSI transport ID format. -#define ISCSI_TRANSPORT_ID_FORMAT 0x01 - -/// iSCSI SCSI transport ID format: First bit of the two bits. -#define ISCSI_TRANSPORT_ID_FORMAT_FIRST_BIT 6 - -/// iSCSI SCSI transport ID format: Last bit of the two bits. -#define ISCSI_TRANSPORT_ID_FORMAT_LAST_BIT ((ISCSI_TRANSPORT_ID_FORMAT_FIRST_BIT) + 2 - 1) - -/// iSCSI SCSI transport ID format: Bit mask. -#define ISCSI_TRANSPORT_ID_FORMAT_MASK (ISCSI_BITS_GET_MASK(ISCSI_TRANSPORT_ID_FORMAT_FIRST_BIT, ISCSI_TRANSPORT_ID_FORMAT_LAST_BIT)) - -/// iSCSI SCSI transport ID format: Extracts the format bits. -#define ISCSI_TRANSPORT_ID_GET_FORMAT(x) (ISCSI_BITS_GET((x), ISCSI_TRANSPORT_ID_FORMAT_FIRST_BIT, ISCSI_TRANSPORT_ID_FORMAT_LAST_BIT)) - -/// iSCSI SCSI transport ID format: Stores into the format bits. -#define ISCSI_TRANSPORT_ID_PUT_FORMAT(x) (ISCSI_BITS_PUT((x), ISCSI_TRANSPORT_ID_FORMAT_FIRST_BIT, ISCSI_TRANSPORT_ID_FORMAT_LAST_BIT)) - - -/** - * @brief iSCSI SCSI Transport ID structure. - * - * This structure handles the iSCSI SCSI transport - * identifier data. - */ -typedef struct __attribute__((packed)) iscsi_transport_id { - /// First 4 bits are protocol ID and last 2 bits are format. - uint8_t id; - - /// Reserved for future usage (always MUST be 0). - uint8_t reserved; - - /// Additional length of name. - uint16_t add_len; - - /// Name. - uint8_t name[0]; -} iscsi_transport_id; - - /// Maximum length of a key according to iSCSI specifications. #define ISCSI_TEXT_KEY_MAX_LEN 63U @@ -5503,65 +5411,6 @@ typedef struct __attribute__((packed)) iscsi_transport_id { /// Maximum length of value for a normal key. #define ISCSI_TEXT_VALUE_MAX_LEN 8192U -/// Value data shift value for key value alignment enforcement. -#define ISCSI_TEXT_VALUE_ALIGN_SHIFT 4UL - -/// Value alignment size is a multiple of 16 bytes for a key value for having work space when changing string representation of integer values. -#define ISCSI_TEXT_VALUE_ALIGN (1UL << (ISCSI_TEXT_VALUE_ALIGN_SHIFT)) - - -/// iSCSI text key=value pair type: Invalid. -#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_INVALID -1 - -/// iSCSI text key=value pair type: Unspecified type. -#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_UNSPECIFIED 0 - -/// iSCSI text key=value pair type: List. -#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_LIST 1 - -/// iSCSI text key=value pair type: Numerical minimum. -#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_NUM_MIN 2 - -/// iSCSI text key=value pair type: Numerical maximum. -#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_NUM_MAX 3 - -/// iSCSI text key=value pair type: Numerical declarative. -#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_NUM_DECLARATIVE 4 - -/// iSCSI text key=value pair type: Declarative. -#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_DECLARATIVE 5 - -/// iSCSI text key=value pair type: Boolean OR. -#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_BOOL_OR 6 - -/// iSCSI text key=value pair type: Boolean AND. -#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_BOOL_AND 7 - - -/// iSCSI key value pair flags: Discovery ignored. -#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_DISCOVERY_IGNORE (1 << 0) - -/// iSCSI key value pair flags: Multi negotiation. -#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_MULTI_NEGOTIATION (1 << 1) - -/// iSCSI key value pair flags: Target declarative. -#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_TARGET_DECLARATIVE (1 << 2) - -/// iSCSI key value pair flags: CHAP type. -#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_CHAP_TYPE (1 << 3) - -/// iSCSI key value pair flags: Requires special handling. -#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_SPECIAL_HANDLING (1 << 4) - -/// iSCSI key value pair flags: Use previous default value. -#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_USE_PREVIOUS_VALUE (1 << 5) - -/// iSCSI key value pair flags: Override with default value. -#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_OVERRIDE_DEFAULT (1 << 6) - -/// iSCSI key value pair flags: Uses maximum value depending on secondary key. -#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_USE_OTHER_MAX_VALUE (1 << 7) - /** * @brief iSCSI connection and session lookup table entry, used for allowed key values and determining key type. @@ -5636,18 +5485,6 @@ typedef struct iscsi_key_value_pair_packet { int discovery; } iscsi_key_value_pair_packet; -/// iSCSI main global data flags: Allow duplicate ISIDs. -#define ISCSI_GLOBALS_FLAGS_ISID_ALLOW_DUPLICATES (1 << 0) - -/// iSCSI main global data flags: CHAP authentication is disabled. -#define ISCSI_GLOBALS_FLAGS_CHAP_DISABLE (1 << 1) - -/// iSCSI main global data flags: CHAP authentication is required. -#define ISCSI_GLOBALS_FLAGS_CHAP_REQUIRE (1 << 2) - -/// iSCSI main global data flags: CHAP authentication is mutual. -#define ISCSI_GLOBALS_FLAGS_CHAP_MUTUAL (1 << 3) - /// Read/write lock for iSCSI global vector. MUST be initialized with iscsi_create before any iSCSI functions are used. //extern pthread_rwlock_t iscsi_globvec_rwlock; @@ -5826,28 +5663,6 @@ typedef struct iscsi_key_value_pair_packet { -/// iSCSI SCSI Persistent Reservation (PR) reservation type: Write exclusive. -#define ISCSI_SCSI_PR_RESERVATION_TYPE_WRITE_EXCLUSIVE 0x01 - -/// iSCSI SCSI Persistent Reservation (PR) reservation type: Exclusive access. -#define ISCSI_SCSI_PR_RESERVATION_TYPE_EXCLUSIVE_ACCESS 0x03 - -/// iSCSI SCSI Persistent Reservation (PR) reservation type: Write exclusive - registrants only. -#define ISCSI_SCSI_PR_RESERVATION_TYPE_WRITE_EXCLUSIVE_REGS_ONLY 0x05 - -/// iSCSI SCSI Persistent Reservation (PR) reservation type: Exclusive access - registrants only. -#define ISCSI_SCSI_PR_RESERVATION_TYPE_EXCLUSIVE_ACCESS_REGS_ONLY 0x06 - -/// iSCSI SCSI Persistent Reservation (PR) reservation type: Write exclusive - all registrants. -#define ISCSI_SCSI_PR_RESERVATION_TYPE_WRITE_EXCLUSIVE_ALL_REGS 0x07 - -/// iSCSI SCSI Persistent Reservation (PR) reservation type: Exclusive access - all registrants. -#define ISCSI_SCSI_PR_RESERVATION_TYPE_EXCLUSIVE_ACCESS_ALL_REGS 0x08 - - -/// iSCSI SCSI Persistent Reservation (PR) reservation flags: SPC2 reserve. -#define ISCSI_SCSI_PR_RESERVATION_FLAGS_SPC2_RESERVE (1L << 0L) - /// iSCSI SCSI task run: Unknown. #define ISCSI_SCSI_TASK_RUN_UNKNOWN -1 @@ -5855,19 +5670,10 @@ typedef struct iscsi_key_value_pair_packet { /// iSCSI SCSI task run: Completed. #define ISCSI_SCSI_TASK_RUN_COMPLETE 0 -/// iSCSI SCSI task run: Pending. -#define ISCSI_SCSI_TASK_RUN_PENDING 1 - typedef struct iscsi_scsi_task iscsi_scsi_task; typedef struct iscsi_scsi_lun iscsi_scsi_lun; -/// iSCSI SCSI task flags: Read. -#define ISCSI_SCSI_TASK_FLAGS_XFER_READ (1 << 0) - -/// iSCSI SCSI task flags: Write. -#define ISCSI_SCSI_TASK_FLAGS_XFER_WRITE (1 << 1) - /** * @brief iSCSI SCSI Task. @@ -5897,17 +5703,17 @@ typedef struct iscsi_scsi_task { /// Length of buffer in bytes. uint32_t len; + /// Expected data transfer length (from iSCSI PDU field) + uint32_t exp_xfer_len; + /// Unique identifier for this task. uint64_t id; - /// Flags. - int flags; - - /// Transfer position in bytes. - uint32_t xfer_pos; + /// Whether the R bit was set in the iSCSI request (BHS). + bool is_read; - /// Transfer length in bytes. - uint32_t xfer_len; + /// Whether the W bit was set in the iSCSI request (BHS). + bool is_write; /// Sense data length. uint8_t sense_data_len; @@ -6172,9 +5978,6 @@ typedef struct iscsi_connection { typedef struct iscsi_task iscsi_task; -/// iSCSI PDU flags: Rejected. -#define ISCSI_PDU_FLAGS_REJECTED (1 << 0) - /// iSCSI PDU will contain a small buffer for sending/receiving trivial PDUs with no/very small DS, and small AH #define ISCSI_INTERNAL_BUFFER_SIZE (2 * ISCSI_BHS_SIZE) @@ -6221,13 +6024,6 @@ typedef struct iscsi_pdu { } iscsi_pdu; -/// iSCSI task flags: Ready To Transfer is active. -#define ISCSI_TASK_FLAGS_R2T_ACTIVE (1 << 0) - -/// iSCSI task flags: Task is enqueued in SCSI layer. -#define ISCSI_TASK_FLAGS_QUEUED (1 << 1) - - /** * @brief This structure is used for iSCSI task management. * @@ -6250,9 +6046,6 @@ typedef struct iscsi_task { /// Unique identifier for this task. uint64_t id; - /// Flags. - int flags; - /// LUN identifier associated with this task (always MUST be between 0 and 7), used for hot removal tracking. int lun_id; @@ -6262,12 +6055,6 @@ typedef struct iscsi_task { /// Target Transfer Tag (TTT). uint32_t target_xfer_tag; - /// Desired number of bytes completed. - uint32_t des_data_xfer_pos; - - /// Desired data transfer length. - uint32_t des_data_xfer_len; - /// SCSI Data In Data Sequence Number (DataSN). uint32_t data_sn; } iscsi_task; -- cgit v1.2.3-55-g7522