diff options
| -rw-r--r-- | src/server/iscsi.c | 568 | ||||
| -rw-r--r-- | src/server/iscsi.h | 92 |
2 files changed, 537 insertions, 123 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c index cc97164..306203d 100644 --- a/src/server/iscsi.c +++ b/src/server/iscsi.c @@ -18,6 +18,7 @@ * */ +#include <ctype.h> #include <stdarg.h> #include <stddef.h> #include <stdio.h> @@ -71,7 +72,7 @@ static const iscsi_key_value_pair_lut_entry iscsi_connection_key_value_pair_lut[ /// iSCSI session negotation key and value pair lookup table. static const iscsi_key_value_pair_lut_entry iscsi_session_key_value_pair_lut[] = { - { (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_MAX_CONNECTIONS, (uint8_t *) "1", (uint8_t *) "1\065535\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_NUM_MIN, ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_DISCOVERY_IGNORE }, + { (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_MAX_CONNECTIONS, (uint8_t *) "1", (uint8_t *) "1\0""65535\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_NUM_MIN, ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_DISCOVERY_IGNORE }, { (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_SEND_TARGETS, (uint8_t *) "", (uint8_t *) "\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_DECLARATIVE, ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_SPECIAL_HANDLING }, { (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_NAME, (uint8_t *) "", (uint8_t *) "\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_DECLARATIVE, ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_TARGET_DECLARATIVE }, { (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_INITIATOR_NAME, (uint8_t *) "", (uint8_t *) "\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_DECLARATIVE, 0L }, @@ -232,7 +233,7 @@ int iscsi_create() return -1L; } - int rc = iscsi_global_key_value_pair_init( globvec->session_key_value_pairs, &iscsi_session_key_value_pair_lut[1] ); + int rc = iscsi_global_key_value_pair_init( globvec->session_key_value_pairs, &iscsi_session_key_value_pair_lut[0] ); if ( globvec->connection_key_value_pairs == NULL ) { logadd( LOG_ERROR, "iscsi_create: Out of memory while initializing iSCSI global vector session key and value pairs hash map" ); @@ -478,7 +479,7 @@ iscsi_hashmap *iscsi_hashmap_create(const uint capacity) } if ( capacity > 0UL ) { - uint new_capacity = (capacity + 1); // 1UL << (lg(capacity - 1) + 1) + uint new_capacity = (capacity - 1); // 1UL << (lg(capacity - 1) + 1) new_capacity |= (new_capacity >> 1UL); new_capacity |= (new_capacity >> 2UL); @@ -1665,7 +1666,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint const uint8_t opcode = ISCSI_GET_OPCODE(packet_data->opcode); switch ( opcode ) { - case ISCSI_CLIENT_NOP_OUT : { + case ISCSI_OPCODE_CLIENT_NOP_OUT : { if ( (int8_t) packet_data->opcode < 0 ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // MSB always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1676,7 +1677,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_CLIENT_SCSI_CMD : { + case ISCSI_OPCODE_CLIENT_SCSI_CMD : { if ( (int8_t) packet_data->opcode < 0 ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // MSB always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1687,7 +1688,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_CLIENT_TASK_FUNC_REQ : { + case ISCSI_OPCODE_CLIENT_TASK_FUNC_REQ : { if ( ((int8_t) packet_data->opcode < 0) || (ahs_len != 0) || (ds_len != 0) ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // MSB MUST always be cleared, AHS and DataSegment MUST be zero according to specs -> invalid iSCSI packet data @@ -1698,7 +1699,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_CLIENT_LOGIN_REQ : { + case ISCSI_OPCODE_CLIENT_LOGIN_REQ : { if ( (packet_data->opcode != (opcode | 0x40)) || (ahs_len != 0) ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bit 6 always MUST be set and AHS MUST be zero according to specs -> invalid iSCSI packet data @@ -1714,7 +1715,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_CLIENT_TEXT_REQ : { + case ISCSI_OPCODE_CLIENT_TEXT_REQ : { if ( (int8_t) packet_data->opcode < 0 ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // MSB always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1727,7 +1728,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_CLIENT_SCSI_DATA_OUT : { + case ISCSI_OPCODE_CLIENT_SCSI_DATA_OUT : { if ( packet_data->opcode != opcode ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1738,7 +1739,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_CLIENT_LOGOUT_REQ : { + case ISCSI_OPCODE_CLIENT_LOGOUT_REQ : { if ( (int8_t) packet_data->opcode < 0 ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // MSB always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1749,7 +1750,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_CLIENT_SNACK_REQ : { + case ISCSI_OPCODE_CLIENT_SNACK_REQ : { if ( packet_data->opcode != opcode ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1760,12 +1761,12 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_CLIENT_VENDOR_CODE1 : - case ISCSI_CLIENT_VENDOR_CODE2 : - case ISCSI_CLIENT_VENDOR_CODE3 : { + case ISCSI_OPCODE_CLIENT_VENDOR_CODE1 : + case ISCSI_OPCODE_CLIENT_VENDOR_CODE2 : + case ISCSI_OPCODE_CLIENT_VENDOR_CODE3 : { break; } - case ISCSI_SERVER_NOP_IN : { + case ISCSI_OPCODE_SERVER_NOP_IN : { if ( packet_data->opcode != opcode ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1776,7 +1777,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_SERVER_SCSI_RESPONSE : { + case ISCSI_OPCODE_SERVER_SCSI_RESPONSE : { if ( packet_data->opcode != opcode ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1787,7 +1788,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_SERVER_TASK_FUNC_RES : { + case ISCSI_OPCODE_SERVER_TASK_FUNC_RES : { if ( (packet_data->opcode != opcode) || (ahs_len != 0) || (ds_len != 0) ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared, AHS and DataSegment MUST be zero according to specs -> invalid iSCSI packet data @@ -1798,7 +1799,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_SERVER_LOGIN_RES : { + case ISCSI_OPCODE_SERVER_LOGIN_RES : { if ( packet_data->opcode != opcode ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared for this opcode -> invalid iSCSI packet data is mandatory @@ -1814,7 +1815,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_SERVER_TEXT_RES : { + case ISCSI_OPCODE_SERVER_TEXT_RES : { if ( packet_data->opcode != opcode ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1827,7 +1828,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_SERVER_SCSI_DATA_IN : { + case ISCSI_OPCODE_SERVER_SCSI_DATA_IN : { if ( packet_data->opcode != opcode ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared for this opcode -> invalid iSCSI packet data @@ -1838,7 +1839,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_SERVER_LOGOUT_RES : { + case ISCSI_OPCODE_SERVER_LOGOUT_RES : { if ( (packet_data->opcode != opcode) || (ahs_len != 0) || (ds_len != 0) ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared, AHS and DataSegment MUST be zero according to specs -> invalid iSCSI packet data @@ -1849,7 +1850,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_SERVER_READY_XFER : { + case ISCSI_OPCODE_SERVER_READY_XFER : { if ( (packet_data->opcode != opcode) || (ahs_len != 0) || (ds_len != 0) ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // AHS and DataSegment MUST be zero according to specs -> invalid iSCSI packet data @@ -1860,7 +1861,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_SERVER_ASYNC_MSG : { + case ISCSI_OPCODE_SERVER_ASYNC_MSG : { if ( (packet_data->opcode != opcode) || (ds_len == 0) ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared for this opcode and DataSegment is mandatory -> invalid iSCSI packet data @@ -1871,12 +1872,12 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint break; } - case ISCSI_SERVER_VENDOR_CODE1 : - case ISCSI_SERVER_VENDOR_CODE2 : - case ISCSI_SERVER_VENDOR_CODE3 : { + case ISCSI_OPCODE_SERVER_VENDOR_CODE1 : + case ISCSI_OPCODE_SERVER_VENDOR_CODE2 : + case ISCSI_OPCODE_SERVER_VENDOR_CODE3 : { break; } - case ISCSI_SERVER_REJECT : { + case ISCSI_OPCODE_SERVER_REJECT : { if ( packet_data->opcode != opcode ) return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Bits 6 and 7 always MUST be cleared according to specs -> invalid iSCSI packet data @@ -2814,6 +2815,50 @@ int iscsi_port_transport_id_set(iscsi_port *port, const uint8_t *name, const uin } /** + * @brief Allocates and initializes an iSCSI LUN structure for linkage with a DNBD3 image. + * + * This function does not set the DNBD3 + * image itself. + * + * @param[in] id LUN identifier. + * @return Pointer to ISCSI device LUN or NULL in case + * of an error (memory exhausion). + */ +iscsi_lun *iscsi_lun_create(const uint id) +{ + iscsi_lun *lun = (iscsi_lun *) malloc( sizeof(struct iscsi_lun) ); + + if ( lun == NULL ) { + logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN" ); + + return NULL; + } + + lun->image = NULL; + lun->id = id; + lun->flags = 0U; + + return lun; +} + +/** + * @brief Deallocates all resources acquired by iscsi_lun_create. + * + * This function does not deallocate the + * associated DNBB3 image and therefore + * just calls free. + * + * @param[in] lun Pointer to iSCSI device LUN to be freed. + * May be NULL in which case this function + * does nothing at all. + */ +void iscsi_lun_destroy(iscsi_lun *lun) +{ + if ( lun != NULL ) + free( lun ); +} + +/** * @brief Converts an internal representation of a LUN identifier to an iSCSI LUN required for packet data. * * This function needs to be called prior @@ -2870,6 +2915,140 @@ int iscsi_lun_get_from_iscsi(const uint64_t lun) } /** + * @brief Creates and initializes an iSCSI device with a maximum number of LUNs. + * + * This function creates a virtual SCSI device + * which links the DNBD3 images to their LUNs. + * + * @param[in] name Pointer to name of iSCSI device, + * may NOT be NULL, so be careful. + * @param[in] luns Maximum number of LUNs for this + * iSCSI device. + * @return Pointer to iSCSI device or NULL in + * case of an error. + */ +iscsi_device *iscsi_device_create(const uint8_t *name, const uint luns) +{ + if ( luns == 0 ) + return NULL; + + iscsi_device *device = (iscsi_device *) malloc( sizeof(struct iscsi_device) ); + + if ( device == NULL ) { + logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device" ); + + return NULL; + } + + const uint len = (uint) strlen( (char *) name ) + 1; + + device->name = malloc( len ); + + if ( device->name == NULL ) { + logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device name" ); + + free( device ); + + return NULL; + } + + memcpy( device->name, name, len ); + + device->luns = iscsi_hashmap_create( (luns << 1UL) ); + + if ( device->luns == NULL ) { + logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN hash map" ); + + free( device->name ); + free( device ); + + return NULL; + } + + for ( uint i = 0; i < luns; i++ ) { + iscsi_lun *lun = iscsi_lun_create( i ); + uint8_t *hash_key = iscsi_hashmap_key_create( (uint8_t *) &i, sizeof(i) ); + + if ( hash_key == NULL ) { + logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN hash map" ); + + iscsi_hashmap_iterate( device->luns, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_destroy( device->luns ); + free( device->name ); + free( device ); + + return NULL; + } + + const int rc = iscsi_hashmap_put( device->luns, hash_key, sizeof(i), (uint8_t *) lun ); + + if ( rc < 0 ) { + iscsi_hashmap_iterate( device->luns, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_destroy( device->luns ); + free( device->name ); + free( device ); + + return NULL; + } + } + + device->ports = iscsi_hashmap_create( 0UL ); + + if ( device->ports == NULL ) { + logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device ports hash map" ); + + iscsi_hashmap_iterate( device->luns, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_destroy( device->luns ); + free( device->name ); + free( device ); + + return NULL; + } + + device->id = 0L; + device->flags = 0L; + device->num_ports = 0UL; + + return device; +} + +/** + * @brief Deallocates all resources acquired by iscsi_device_create. + * + * This function also frees the associated + * iSCSI ports, LUNs and the device name. + * + * @param[in] device Pointer to iSCSI device to be freed. May + * be NULL in which case this function does + * nothing at all. + */ +void iscsi_device_destroy(iscsi_device *device) +{ + if ( device != NULL ) { + if ( device->ports != NULL ) { + iscsi_hashmap_destroy( device->ports ); + + device->ports = NULL; + } + + if ( device->luns != NULL ) { + iscsi_hashmap_iterate( device->luns, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_destroy( device->luns ); + + device->luns = NULL; + } + + if ( device->name != NULL ) { + free( device->name ); + + device->name = NULL; + } + + free( device ); + } +} + +/** * @brief Gets an iSCSI device being in use by portal group identifier. * * This function uses the unique portal group @@ -2924,7 +3103,7 @@ int iscsi_device_find_lun_callback(uint8_t *key, const size_t key_size, uint8_t iscsi_device_find_lun_id *lun_find = (iscsi_device_find_lun_id *) user_data; iscsi_lun *lun = (iscsi_lun *) value; - if ( (lun->id != lun_find->lun) || ((lun->flags & ISCSI_LUN_FLAGS_REMOVING) != 0) ) + if ( (lun->id != lun_find->id) || ((lun->flags & ISCSI_LUN_FLAGS_REMOVING) != 0) ) return 0L; lun_find->lun = lun; @@ -2957,6 +3136,187 @@ static iscsi_lun *iscsi_device_find_lun(iscsi_device *device, const int lun_id) } /** + * @brief Checks if an iSCSI target node IQN name is valid. + * + * This function checks the length of the IQN + * and if contains valid characters.\n + * If IQN starts with 'iqn.' it checks for + * valid 'iqn.YYYY-MM.' pattern. + * + * @param[in] name Pointer to IQN name string to be + * validated, may NOT be NULL, so be + * careful. + * @return 0 if all checks passed successfully, + * a negative error code otherwise. + */ +static int iscsi_target_node_check_name(const uint8_t *name) +{ + const size_t len = strlen( (char *) name ); + + if ( len > ISCSI_TARGET_NODE_MAX_NAME_LEN ) + return -1L; + + for ( size_t i = 0; i < len; i++ ) { + const uint8_t c = name[i]; + + if ( (c <= 0x2CU) || (c == 0x2FU) || ((c >= 0x3BU && c <= 0x40U)) || ((c >= 0x5BU) && (c <= 0x60U)) || ((c >= 0x7BU) && (c <= 0x7FU)) ) + return -1L; + } + + if ( (strncasecmp( (char *) name, "iqn.", 4 ) == 0) && (!isdigit(name[4]) || !isdigit(name[5]) || !isdigit(name[6]) || !isdigit(name[7]) || (name[8] != '-') || (name[9] < '0') || (name[9] > '1') || ((name[9] == '0') && ((name[10] < '1') && (name[10] > '9'))) || ((name[9] == '1') && ((name[10] < '0') || (name[10] > '2'))) || (name[11] != '.')) ) + return -1L; + + return 0L; +} + +/** + * @brief Checks if the iSCSI target node flags are valid. + * + * This function checks if the set flags + * are contradicting themselves or are + * okay. + * + * @param[in] flags Target node flags to check. + * @param[in] chap_group CHAP group to check. + * @return 0 if flags are valid, a negative + * error code otherwise. + */ +static int iscsi_target_node_check_flags(const int flags, const int32_t chap_group) +{ + if ( chap_group < 0 ) + return -1L; + + if ( (((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE) == 0) && ((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE) == 0) && ((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL) == 0)) || // Auto + (((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE) != 0) && ((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE) == 0) && ((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL) == 0)) || // None + (((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE) == 0) && ((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE) != 0) && ((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL) == 0)) || // CHAP + (((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE) == 0) && ((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE) != 0) && ((flags & ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL) != 0)) ) // CHAP Mutual + return 0L; + + return -1L; +} + +/** + * @brief Creates and initializes an iSCSI target node. + * + * This function also allocates the underlying SCSI + * device and always initializes the first LUN. + * + * @param[in] name Pointer to IQN name of target node, + * may NOT be NULL, so be careful. + * @param[in] alias Pointer to alias of IQN name. + * @param[in] index Target node index number. + * @param[in] luns Number of LUNs for underlying SCSI device. + * @param[in] queue_depth Maximum queue depth. + * @param[in] flags Flags for this target node. + * @param[in] chap_group CHAP group to associate this node with. + * @param[in] header_digest Header digest size (always MUST be 0 or 4 for now). + * @param[in] data_digest Data digest size (always MUST be 0 or 4 for now). + * @return Pointer to iSCSI target node on successful + * operation or NULL in case of an error. + */ +iscsi_target_node *iscsi_target_node_create(const uint8_t *name, const uint8_t *alias, const int index, const uint luns, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest) +{ + if ( (name == NULL) || (iscsi_target_node_check_name( name ) < 0) || (iscsi_target_node_check_flags( flags, chap_group ) < 0) ) + return NULL; + + iscsi_target_node *target = (iscsi_target_node *) malloc( sizeof(struct iscsi_target_node) ); + + if ( target == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_create: Out of memory allocating iSCSI target node" ); + + return NULL; + } + + const uint name_len = (uint) strlen( (char *) name ) + 1; + + target->name = malloc( name_len ); + + if ( target->name == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_create: Out of memory allocating iSCSI target node name" ); + + free( target ); + + return NULL; + } + + memcpy( target->name, name, name_len ); + + if ( alias != NULL ) { + const uint alias_len = (uint) strlen( (char *) alias ) + 1; + + target->alias = malloc( alias_len ); + + if ( target->alias == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_create: Out of memory allocating iSCSI target node alias" ); + + free( target->name ); + free( target ); + + return NULL; + } + + memcpy( target->alias, alias, alias_len ); + } + + target->device = iscsi_device_create( name, luns ); + + if ( target->device == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_create: Out of memory allocating iSCSI target device" ); + + if ( target->alias != NULL ) + free( target->alias ); + + free( target->name ); + free( target ); + + return NULL; + } + + target->num = index; + target->queue_depth = queue_depth; + target->flags = flags; + target->header_digest = header_digest; + target->data_digest = data_digest; + target->chap_group = chap_group; + target->active_conns = 0UL; + + return target; +} + +/** + * @brief Deallocates all resources acquired by iscsi_target_node_create. + * + * This function also frees the IQN name, + * IQN alias and the associated SCSI device. + * + * @param[in] target Pointer to iSCSI target node to be freed. + * May be NULL in which case this function + * does nothing at all. + */ +void iscsi_target_node_destroy(iscsi_target_node *target) +{ + if ( target != NULL ) { + if ( target->device != NULL ) { + iscsi_device_destroy( target->device ); + + target->device = NULL; + } + + if ( target->alias != NULL ) { + free( target->alias ); + + target->alias = NULL; + } + + if ( target->name != NULL ) { + free( target->name ); + + target->name = NULL; + } + } +} + +/** * @brief Sends a buffer from a source iSCSI IQN to target iSCSI IQNs. * * This function sends a buffer starting from a @@ -3198,8 +3558,8 @@ iscsi_session *iscsi_session_create(iscsi_connection *conn, iscsi_target_node *t * This function also frees the associated key and value pairs, * the attached connections as well as frees the initator port. * - * @param[in] session iSCSI session to be freed. May be NULL - * in which case this function does nothing at all. + * @param[in] session Pointer to iSCSI session to be freed. + * May be NULL in which case this function does nothing at all. */ void iscsi_session_destroy(iscsi_session *session) { @@ -3614,8 +3974,7 @@ int iscsi_connection_init_key_value_pairs(iscsi_hashmap *key_value_pairs) * special key and value pair for. NULL is * a forbidden value here, so take caution. * @param[in] key_value_pair Pointer to special key and value pair - * containing its attributes and may NOT - * be NULL, so be careful. + * containing its attributes. * @param[in] key Pointer to special key to be written to * output buffer. NULL is NOT allowed, * take caution. @@ -3630,6 +3989,9 @@ int iscsi_connection_init_key_value_pairs(iscsi_hashmap *key_value_pairs) */ static int iscsi_append_special_key_value_pair_packet(iscsi_connection *conn, iscsi_key_value_pair *key_value_pair, const uint8_t *key, uint8_t *buf, uint pos, const uint len) { + if ( key_value_pair == NULL ) + return pos; + if ( (key_value_pair->flags & ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_OVERRIDE_DEFAULT) != 0 ) { if ( (int) (len - pos) < 1L ) return -1L; @@ -3672,8 +4034,7 @@ static int iscsi_append_special_key_value_pair_packet(iscsi_connection *conn, is * buffer and truncates if necessary. * * @param[in] key_value_pair Pointer to key and value pair containing - * its attributes and may NOT be NULL, so be - * careful. + * its attributes. * @param[in] key Pointer to key to be written to output * buffer. NULL is NOT allowed, take caution. * @param[in] value Pointer to value of the key that should @@ -3690,7 +4051,7 @@ static int iscsi_append_special_key_value_pair_packet(iscsi_connection *conn, is */ static int iscsi_append_key_value_pair_packet(const iscsi_key_value_pair *key_value_pair, const uint8_t *key, const uint8_t *value, uint8_t *buf, uint pos, const uint len) { - if ( (key_value_pair->type != ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_DECLARATIVE) && (key_value_pair->type != ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_NUM_DECLARATIVE) ) { + if ( (key_value_pair == NULL) || ((key_value_pair->type != ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_DECLARATIVE) && (key_value_pair->type != ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_NUM_DECLARATIVE)) ) { if ( (int) (len - pos) < 1L ) return -1L; @@ -3713,16 +4074,30 @@ static int iscsi_append_key_value_pair_packet(const iscsi_key_value_pair *key_va * @return Pointer to original value, if the value is * allowed or NULL otherwise. */ -static uint8_t *iscsi_negotiate_key_value_pair_list(const iscsi_key_value_pair *key_value_pair, uint8_t *old_value) +static uint8_t *iscsi_negotiate_key_value_pair_list(const iscsi_key_value_pair *key_value_pair, const uint8_t *old_value) { - const uint8_t *list = key_value_pair->list_range; + uint8_t *list = key_value_pair->list_range; + const uint8_t *value = (uint8_t *) strchr( (char *) old_value, ',' ); + size_t val_len = (value != NULL) ? (size_t) (value - old_value) : strlen( (char *) old_value ); - do { - if ( strcasecmp( (char *) list, (char *) old_value ) == 0 ) - return old_value; + for ( ;; ) { + const size_t len = strlen( (char *) list ); - list += (strlen( (char *) list ) + 1); - } while ( list[0] != '\0' ); + if ( (val_len == len) && (strncasecmp( (char *) list, (char *) old_value, len ) == 0) ) + return list; + + list += (len + 1); + + if ( list[0] == '\0' ) { + if ( value == NULL ) + break; + + old_value = value; + list = key_value_pair->list_range; + value = (uint8_t *) strchr( (char *) ++old_value, ',' ); + val_len = (value != NULL) ? (size_t) (value - old_value) : strlen( (char *) old_value ); + } + } return NULL; } @@ -3815,16 +4190,13 @@ static uint8_t *iscsi_negotiate_key_value_pair_bool(const iscsi_key_value_pair * const uint8_t *list_bool_true = key_value_pair->list_range; const uint8_t *list_bool_false = list_bool_true + strlen( (char *) list_bool_true ) + 1; - if ( (strcasecmp( (char *) old_value, (char *) list_bool_true ) == 0) || (strcasecmp( (char *) old_value, (char *) list_bool_false ) == 0) ) { + if ( (strcasecmp( (char *) old_value, (char *) list_bool_true ) != 0) && (strcasecmp( (char *) old_value, (char *) list_bool_false ) != 0) ) { *update_key_value_pair = 0L; return (uint8_t *) "Reject"; } - if ( strcasecmp( (char *) value, (char *) bool_value ) == 0 ) - return bool_value; - - return key_value_pair->value; + return (strcasecmp( (char *) value, (char *) bool_value ) == 0) ? bool_value : old_value; } /** @@ -4349,7 +4721,7 @@ static int iscsi_login_response_init(iscsi_pdu *login_response_pdu, const iscsi_ iscsi_login_req_packet *login_req_pkt = (iscsi_login_req_packet *) pdu->bhs_pkt; iscsi_login_response_packet *bhs_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - bhs_pkt->opcode = ISCSI_SERVER_LOGIN_RES; + bhs_pkt->opcode = ISCSI_OPCODE_SERVER_LOGIN_RES; iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) iscsi_append_ds_packet( (iscsi_bhs_packet *) bhs_pkt, pdu->header_digest_size, ISCSI_DEFAULT_RECV_DS_LEN, pdu->data_digest_size ); @@ -4362,7 +4734,7 @@ static int iscsi_login_response_init(iscsi_pdu *login_response_pdu, const iscsi_ login_response_pdu->bhs_pkt = (iscsi_bhs_packet *) login_response_pkt; login_response_pdu->ds_cmd_data = (iscsi_ds_cmd_data *) (((uint8_t *) login_response_pkt) + sizeof(struct iscsi_bhs_packet) + pdu->header_digest_size); - login_response_pdu->ds_len = ISCSI_DEFAULT_RECV_DS_LEN; + login_response_pdu->len = ISCSI_DEFAULT_RECV_DS_LEN; login_response_pkt->flags |= (int8_t) (login_req_pkt->flags & (ISCSI_LOGIN_REQ_FLAGS_TRANSIT | ISCSI_LOGIN_REQ_FLAGS_CONTINUE | ISCSI_LOGIN_REQ_FLAGS_CURRENT_STAGE_MASK)); @@ -4749,7 +5121,7 @@ void iscsi_login_response_reject_init(iscsi_pdu *login_response_pdu, const iscsi { iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - login_response_pkt->opcode = ISCSI_SERVER_LOGIN_RES; + login_response_pkt->opcode = ISCSI_OPCODE_SERVER_LOGIN_RES; login_response_pkt->version_max = ISCSI_VERSION_MAX; login_response_pkt->version_active = ISCSI_VERSION_MAX; login_response_pkt->init_task_tag = ((iscsi_login_req_packet *) pdu->bhs_pkt)->init_task_tag; @@ -4812,6 +5184,7 @@ iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn) pdu->ahs_read_len = 0UL; pdu->ds_len = 0UL; pdu->pos = 0UL; + pdu->len = 0UL; pdu->conn = conn; pdu->cmd_sn = 0UL; @@ -4824,8 +5197,9 @@ iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn) * All associated data which has been read so * far will be freed as well. * - * @param[in] pdu PDU structure to be deallocated, may be NULL - * in which case this function does nothing. + * @param[in] pdu Pointer to PDU structure to be deallocated, + * may be NULL in which case this function + * does nothing. */ void iscsi_connection_pdu_destroy(iscsi_pdu *pdu) { @@ -4891,7 +5265,7 @@ void iscsi_connection_pdu_write(iscsi_connection *conn, iscsi_pdu *pdu, iscsi_co if ( conn->state >= ISCSI_CONNECT_STATE_EXITING ) return; - if ( ISCSI_GET_OPCODE(pdu->bhs_pkt->opcode) != ISCSI_CLIENT_LOGIN_REQ ) { + if ( ISCSI_GET_OPCODE(pdu->bhs_pkt->opcode) != ISCSI_OPCODE_CLIENT_LOGIN_REQ ) { if ( conn->header_digest != 0 ) iscsi_calc_header_digest( pdu->bhs_pkt ); @@ -5048,7 +5422,7 @@ static int iscsi_connection_handle_reject(iscsi_connection *conn, iscsi_pdu *pdu response_pdu->data_digest_size = conn->data_digest; } - reject_pkt->opcode = ISCSI_SERVER_REJECT; + reject_pkt->opcode = ISCSI_OPCODE_SERVER_REJECT; reject_pkt->flags |= -0x80; reject_pkt->reason = (uint8_t) reason_code; iscsi_put_be24( (uint8_t *) &reject_pkt->ds_len, ds_len ); @@ -5098,9 +5472,9 @@ static int iscsi_connection_update_cmd_sn(iscsi_connection *conn, iscsi_pdu *pdu if ( session->err_recovery_level == 0 ) { if ( (scsi_cmd_pkt->opcode & 0x40) == 0 ) { - if ( (iscsi_seq_num_cmp_lt( pdu->cmd_sn, session->exp_cmd_sn ) || iscsi_seq_num_cmp_gt( pdu->cmd_sn, session->max_cmd_sn )) && ((session->type == ISCSI_SESSION_TYPE_NORMAL) && (opcode != ISCSI_CLIENT_SCSI_DATA_OUT)) ) + if ( (iscsi_seq_num_cmp_lt( pdu->cmd_sn, session->exp_cmd_sn ) || iscsi_seq_num_cmp_gt( pdu->cmd_sn, session->max_cmd_sn )) && ((session->type == ISCSI_SESSION_TYPE_NORMAL) && (opcode != ISCSI_OPCODE_CLIENT_SCSI_DATA_OUT)) ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - } else if ( (pdu->cmd_sn != session->exp_cmd_sn) && (opcode != ISCSI_CLIENT_NOP_OUT) ) + } else if ( (pdu->cmd_sn != session->exp_cmd_sn) && (opcode != ISCSI_OPCODE_CLIENT_NOP_OUT) ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; } @@ -5112,7 +5486,7 @@ static int iscsi_connection_update_cmd_sn(iscsi_connection *conn, iscsi_pdu *pdu if ( session->err_recovery_level > 0 ) iscsi_connection_pdu_ack_remove( conn, exp_stat_sn ); - if ( ((scsi_cmd_pkt->opcode & 0x40) == 0) && (opcode != ISCSI_CLIENT_NOP_OUT) ) + if ( ((scsi_cmd_pkt->opcode & 0x40) == 0) && (opcode != ISCSI_OPCODE_CLIENT_NOP_OUT) ) session->exp_cmd_sn++; return ISCSI_CONNECT_PDU_READ_OK; @@ -5333,7 +5707,7 @@ static int iscsi_r2t_send(iscsi_connection *conn, iscsi_task *task, uint32_t *r2 response_pdu->header_digest_size = conn->header_digest; } - r2t_pkt->opcode = ISCSI_SERVER_READY_XFER; + r2t_pkt->opcode = ISCSI_OPCODE_SERVER_READY_XFER; r2t_pkt->flags = -0x80; const uint64_t lun = iscsi_lun_get_from_scsi( task->lun_id ); @@ -5626,7 +6000,7 @@ static int iscsi_connection_pdu_header_handle_logout_req(iscsi_connection *conn, response_pdu->header_digest_size = conn->header_digest; } - logout_response_pkt->opcode = ISCSI_SERVER_LOGOUT_RES; + logout_response_pkt->opcode = ISCSI_OPCODE_SERVER_LOGOUT_RES; logout_response_pkt->flags = -0x80; const uint16_t cid = iscsi_get_be16(logout_req_pkt->cid); @@ -5705,7 +6079,7 @@ static int iscsi_connection_pdu_header_handle(iscsi_connection *conn, iscsi_pdu const int opcode = ISCSI_GET_OPCODE(pdu->bhs_pkt->opcode); - if ( opcode == ISCSI_CLIENT_LOGIN_REQ ) + if ( opcode == ISCSI_OPCODE_CLIENT_LOGIN_REQ ) return iscsi_connection_pdu_header_handle_login_req( conn, pdu ); if ( ((conn->flags & ISCSI_CONNECT_FLAGS_FULL_FEATURE) == 0) && (conn->state == ISCSI_CONNECT_STATE_RUNNING) ) { @@ -5728,37 +6102,37 @@ static int iscsi_connection_pdu_header_handle(iscsi_connection *conn, iscsi_pdu return rc; switch ( opcode ) { - case ISCSI_CLIENT_NOP_OUT : { + case ISCSI_OPCODE_CLIENT_NOP_OUT : { rc = iscsi_connection_pdu_header_handle_nop_out( conn, pdu ); break; } - case ISCSI_CLIENT_SCSI_CMD : { + case ISCSI_OPCODE_CLIENT_SCSI_CMD : { rc = iscsi_connection_pdu_header_handle_scsi_cmd( conn, pdu ); break; } - case ISCSI_CLIENT_TASK_FUNC_REQ : { + case ISCSI_OPCODE_CLIENT_TASK_FUNC_REQ : { rc = iscsi_connection_pdu_header_handle_task_func_req( conn, pdu ); break; } - case ISCSI_CLIENT_TEXT_REQ : { + case ISCSI_OPCODE_CLIENT_TEXT_REQ : { rc = iscsi_connection_pdu_header_handle_text_req( conn, pdu ); break; } - case ISCSI_CLIENT_SCSI_DATA_OUT : { + case ISCSI_OPCODE_CLIENT_SCSI_DATA_OUT : { rc = iscsi_connection_pdu_header_handle_scsi_data_out( conn, pdu ); break; } - case ISCSI_CLIENT_LOGOUT_REQ : { + case ISCSI_OPCODE_CLIENT_LOGOUT_REQ : { rc = iscsi_connection_pdu_header_handle_logout_req( conn, pdu ); break; } - case ISCSI_CLIENT_SNACK_REQ : { + case ISCSI_OPCODE_CLIENT_SNACK_REQ : { rc = iscsi_connection_pdu_header_handle_snack_req( conn, pdu ); break; @@ -5837,7 +6211,7 @@ static int iscsi_connection_pdu_data_handle_nop_out(iscsi_connection *conn, iscs response_pdu->data_digest_size = conn->data_digest; } - nop_in_pkt->opcode = ISCSI_SERVER_NOP_IN; + nop_in_pkt->opcode = ISCSI_OPCODE_SERVER_NOP_IN; nop_in_pkt->flags = -0x80; iscsi_put_be24( (uint8_t *) &nop_in_pkt->ds_len, ds_len ); iscsi_put_be64( (uint8_t *) &nop_in_pkt->lun, lun ); @@ -6287,7 +6661,7 @@ static int iscsi_connecction_handle_login_response_csg_bit(iscsi_connection *con { iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - switch ( ISCSI_LOGIN_RESPONSE_FLAGS_GET_NEXT_STAGE(login_response_pkt->flags) ) { + switch ( ISCSI_LOGIN_RESPONSE_FLAGS_GET_CURRENT_STAGE(login_response_pkt->flags) ) { case ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_SECURITY_NEGOTIATION : { uint8_t *auth_method; const int rc = iscsi_get_key_value_pair( key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_AUTH_METHOD, (uint8_t **) &auth_method ); @@ -6302,7 +6676,7 @@ static int iscsi_connecction_handle_login_response_csg_bit(iscsi_connection *con if ( strcasecmp( (char *) auth_method, "None" ) == 0 ) { conn->flags |= ISCSI_CONNECT_FLAGS_AUTH; } else { - const int ds_len = iscsi_connection_auth_key_value_pairs( conn, key_value_pairs, auth_method, (uint8_t *) login_response_pdu->ds_cmd_data, login_response_pdu->pos, login_response_pdu->ds_len ); + const int ds_len = iscsi_connection_auth_key_value_pairs( conn, key_value_pairs, auth_method, (uint8_t *) login_response_pdu->ds_cmd_data, login_response_pdu->pos, login_response_pdu->len ); if ( ds_len < 0 ) { login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; @@ -6463,7 +6837,7 @@ static int iscsi_connecction_handle_login_response_t_bit(iscsi_connection *conn, static int iscsi_connecction_handle_login_response(iscsi_connection *conn, iscsi_pdu *login_response_pdu, iscsi_hashmap *key_value_pairs) { iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - const int ds_len = iscsi_negotiate_key_value_pairs( conn, key_value_pairs, (uint8_t *) login_response_pdu->ds_cmd_data, login_response_pdu->pos, login_response_pdu->ds_len ); + const int ds_len = iscsi_negotiate_key_value_pairs( conn, key_value_pairs, (uint8_t *) login_response_pdu->ds_cmd_data, login_response_pdu->pos, login_response_pdu->len ); if ( ds_len < 0 ) { login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; @@ -6651,7 +7025,7 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc return ISCSI_CONNECT_PDU_READ_ERR_FATAL; } - text_response_pkt->opcode = ISCSI_SERVER_TEXT_RES; + text_response_pkt->opcode = ISCSI_OPCODE_SERVER_TEXT_RES; if ( (text_req_pkt->flags & ISCSI_TEXT_REQ_FLAGS_CONTINUE) != 0 ) text_response_pkt->flags |= (int8_t) ISCSI_TEXT_RESPONSE_FLAGS_CONTINUE; @@ -6794,34 +7168,34 @@ static int iscsi_connection_pdu_data_handle(iscsi_connection *conn, iscsi_pdu *p const uint8_t opcode = ISCSI_GET_OPCODE(pdu->bhs_pkt->opcode); switch ( opcode ) { - case ISCSI_CLIENT_NOP_OUT : { + case ISCSI_OPCODE_CLIENT_NOP_OUT : { rc = iscsi_connection_pdu_data_handle_nop_out( conn, pdu ); break; } - case ISCSI_CLIENT_SCSI_CMD : { + case ISCSI_OPCODE_CLIENT_SCSI_CMD : { rc = iscsi_connection_pdu_data_handle_scsi_cmd( conn, pdu ); break; } - case ISCSI_CLIENT_LOGIN_REQ : { + case ISCSI_OPCODE_CLIENT_LOGIN_REQ : { rc = iscsi_connection_pdu_data_handle_login_req( conn, pdu ); break; } - case ISCSI_CLIENT_TEXT_REQ : { + case ISCSI_OPCODE_CLIENT_TEXT_REQ : { rc = iscsi_connection_pdu_data_handle_text_req( conn, pdu ); break; } - case ISCSI_CLIENT_SCSI_DATA_OUT : { + case ISCSI_OPCODE_CLIENT_SCSI_DATA_OUT : { rc = iscsi_connection_pdu_data_handle_scsi_data_out( conn, pdu ); break; } - case ISCSI_CLIENT_TASK_FUNC_REQ : - case ISCSI_CLIENT_LOGOUT_REQ : - case ISCSI_CLIENT_SNACK_REQ : { + case ISCSI_OPCODE_CLIENT_TASK_FUNC_REQ : + case ISCSI_OPCODE_CLIENT_LOGOUT_REQ : + case ISCSI_OPCODE_CLIENT_SNACK_REQ : { break; } default : { @@ -6966,6 +7340,7 @@ static int iscsi_connection_pdu_read(iscsi_connection *conn) pdu->ds_len = iscsi_get_be24(pdu->bhs_pkt->ds_len); pdu->ds_len = iscsi_align(pdu->ds_len, ISCSI_ALIGN_SIZE); pdu->pos = 0UL; + pdu->len = pdu->ds_len; const uint ahs_len = (uint) pdu->bhs_pkt->total_ahs_len << 2UL; @@ -7001,8 +7376,8 @@ static int iscsi_connection_pdu_read(iscsi_connection *conn) if ( pdu->header_digest == NULL ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - pdu->bhs_pkt = (iscsi_bhs_packet *) pdu->header_digest; - pdu->ahs_pkt = (iscsi_ahs_packet *) (((iscsi_bhs_packet *) pdu->bhs_pkt) + 1); + pdu->bhs_pkt = (iscsi_bhs_packet *) pdu->header_digest; + pdu->ahs_pkt = (iscsi_ahs_packet *) (((iscsi_bhs_packet *) pdu->bhs_pkt) + 1); pdu->header_digest = (iscsi_header_digest *) (((uint8_t *) pdu->bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len); } @@ -7181,6 +7556,35 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ portal->group = portal_group; + iscsi_target_node *target = iscsi_target_node_create( (uint8_t *) "iqn.2023-01.com.example:target", NULL, 0L, 8UL, 1UL, 0L, 0L, 0L, 0L ); + + if ( target == NULL ) { + logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI target node" ); + + return; + } + + id = iscsi_hashmap_size( iscsi_globvec->target_nodes ) + 1; + + hash_key = iscsi_hashmap_key_create( (uint8_t *) &id, sizeof(id) ); + + if ( hash_key == NULL ) { + logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI target node" ); + + iscsi_target_node_destroy( target ); + + return; + } + + rc = iscsi_hashmap_put( iscsi_globvec->target_nodes, hash_key, sizeof(id), (uint8_t *) target ); + + if ( rc < 0 ) { + iscsi_hashmap_key_destroy( hash_key ); + iscsi_target_node_destroy( target ); + + return; + } + iscsi_connection *conn = iscsi_connection_create( portal, client->sock ); if ( conn == NULL ) { diff --git a/src/server/iscsi.h b/src/server/iscsi.h index 29b89aa..df737b6 100644 --- a/src/server/iscsi.h +++ b/src/server/iscsi.h @@ -301,90 +301,90 @@ int iscsi_hashmap_iterate(iscsi_hashmap *map, iscsi_hashmap_callback callback, u /// iSCSI initiator (client) command opcode: NOP-Out. -#define ISCSI_CLIENT_NOP_OUT 0x00 +#define ISCSI_OPCODE_CLIENT_NOP_OUT 0x00 /// iSCSI initiator (client) command opcode: SCSI Command (encapsulates a SCSI Command Descriptor Block). -#define ISCSI_CLIENT_SCSI_CMD 0x01 +#define ISCSI_OPCODE_CLIENT_SCSI_CMD 0x01 /// iSCSI initiator (client) command opcode: SCSI Task Management Function Request. -#define ISCSI_CLIENT_TASK_FUNC_REQ 0x02 +#define ISCSI_OPCODE_CLIENT_TASK_FUNC_REQ 0x02 /// iSCSI initiator (client) command opcode: Login Request. -#define ISCSI_CLIENT_LOGIN_REQ 0x03 +#define ISCSI_OPCODE_CLIENT_LOGIN_REQ 0x03 /// iSCSI initiator (client) command opcode: Text Request. -#define ISCSI_CLIENT_TEXT_REQ 0x04 +#define ISCSI_OPCODE_CLIENT_TEXT_REQ 0x04 /// iSCSI initiator (client) command opcode: SCSI Data-Out (for write operations). -#define ISCSI_CLIENT_SCSI_DATA_OUT 0x05 +#define ISCSI_OPCODE_CLIENT_SCSI_DATA_OUT 0x05 /// iSCSI initiator (client) command opcode: Logout Request. -#define ISCSI_CLIENT_LOGOUT_REQ 0x06 +#define ISCSI_OPCODE_CLIENT_LOGOUT_REQ 0x06 /// iSCSI initiator (client) command opcode: Selective Negative / Sequence Number Acknowledgment (SNACK) Request. -#define ISCSI_CLIENT_SNACK_REQ 0x10 +#define ISCSI_OPCODE_CLIENT_SNACK_REQ 0x10 /// iSCSI initiator (client) command opcode: Vendor-specific code #1. -#define ISCSI_CLIENT_VENDOR_CODE1 0x1C +#define ISCSI_OPCODE_CLIENT_VENDOR_CODE1 0x1C /// iSCSI initiator (client) command opcode: Vendor-specific code #2. -#define ISCSI_CLIENT_VENDOR_CODE2 0x1D +#define ISCSI_OPCODE_CLIENT_VENDOR_CODE2 0x1D /// iSCSI initiator (client) command opcode: Vendor-specific code #3. -#define ISCSI_CLIENT_VENDOR_CODE3 0x1E +#define ISCSI_OPCODE_CLIENT_VENDOR_CODE3 0x1E /// First iSCSI initiator (client) command opcode. -#define ISCSI_CLIENT_FIRST_OPCODE 0x00 +#define ISCSI_OPCODE_CLIENT_FIRST 0x00 /// Last iSCSI initiator (client) command opcode. -#define ISCSI_CLIENT_LAST_OPCODE 0x1F +#define ISCSI_OPCODE_CLIENT_LAST 0x1F /// iSCSI target (server) command opcode: NOP-In. -#define ISCSI_SERVER_NOP_IN 0x20 +#define ISCSI_OPCODE_SERVER_NOP_IN 0x20 /// iSCSI target (server) command opcode: SCSI Response - contains SCSI status and possibly sense information or other response information. -#define ISCSI_SERVER_SCSI_RESPONSE 0x21 +#define ISCSI_OPCODE_SERVER_SCSI_RESPONSE 0x21 /// iSCSI target (server) command opcode: SCSI Task Management Function Response. -#define ISCSI_SERVER_TASK_FUNC_RES 0x22 +#define ISCSI_OPCODE_SERVER_TASK_FUNC_RES 0x22 /// iSCSI target (server) command opcode: Login Response. -#define ISCSI_SERVER_LOGIN_RES 0x23 +#define ISCSI_OPCODE_SERVER_LOGIN_RES 0x23 /// iSCSI target (server) command opcode: Text Response. -#define ISCSI_SERVER_TEXT_RES 0x24 +#define ISCSI_OPCODE_SERVER_TEXT_RES 0x24 /// iSCSI target (server) command opcode: SCSI Data-In (for read operations). -#define ISCSI_SERVER_SCSI_DATA_IN 0x25 +#define ISCSI_OPCODE_SERVER_SCSI_DATA_IN 0x25 /// iSCSI target (server) command opcode: Logout Response. -#define ISCSI_SERVER_LOGOUT_RES 0x26 +#define ISCSI_OPCODE_SERVER_LOGOUT_RES 0x26 /// iSCSI target (server) command opcode: Ready To Transfer (R2T) - sent by target when it is ready to receive data. -#define ISCSI_SERVER_READY_XFER 0x31 +#define ISCSI_OPCODE_SERVER_READY_XFER 0x31 /// iSCSI target (server) command opcode: Asynchronous Message - sent by target to indicate certain special conditions. -#define ISCSI_SERVER_ASYNC_MSG 0x32 +#define ISCSI_OPCODE_SERVER_ASYNC_MSG 0x32 /// iSCSI target (server) command opcode: Vendor-specific code #1. -#define ISCSI_SERVER_VENDOR_CODE1 0x3C +#define ISCSI_OPCODE_SERVER_VENDOR_CODE1 0x3C /// iSCSI target (server) command opcode: Vendor-specific code #2. -#define ISCSI_SERVER_VENDOR_CODE2 0x3D +#define ISCSI_OPCODE_SERVER_VENDOR_CODE2 0x3D /// iSCSI target (server) command opcode: Vendor-specific code #3. -#define ISCSI_SERVER_VENDOR_CODE3 0x3E +#define ISCSI_OPCODE_SERVER_VENDOR_CODE3 0x3E /// iSCSI target (server) command opcode: Reject. -#define ISCSI_SERVER_REJECT 0x3F +#define ISCSI_OPCODE_SERVER_REJECT 0x3F /// First iSCSI target (server) command opcode. -#define ISCSI_SERVER_FIRST_OPCODE 0x20 +#define ISCSI_OPCODE_SERVER_FIRST 0x20 /// Last iSCSI target (server) command opcode. -#define ISCSI_SERVER_LAST_OPCODE 0x3F +#define ISCSI_OPCODE_SERVER_LAST 0x3F /// iSCSI opcode bit mask (bits 0-5 used). @@ -6040,6 +6040,9 @@ int iscsi_port_transport_id_set(iscsi_port *port, const uint8_t *name, const uin * and associates a disk image file. */ typedef struct iscsi_lun { + /// Assocated DNBD3 image for this LUN. + dnbd3_image_t *image; + /// LUN identifier (always MUST be between 0 and 7). int id; @@ -6101,10 +6104,7 @@ typedef struct iscsi_device { int flags; /// Number of ports. - int num_ports; - - /// Portocol identifier. - uint8_t protocol_id; + uint num_ports; } iscsi_device; @@ -6123,23 +6123,21 @@ typedef struct iscsi_device_find_lun_id { } iscsi_device_find_lun_id; -/// iSCSI target node flags: Header digest. -#define ISCSI_TARGET_NODE_FLAGS_DIGEST_HEADER (1 << 0L) +/// iSCSI target node maximum length +#define ISCSI_TARGET_NODE_MAX_NAME_LEN 223UL -/// iSCSI target node flags: Data digest. -#define ISCSI_TARGET_NODE_FLAGS_DIGEST_DATA (1 << 1L) /// iSCSI target node flags: CHAP authentication disabled. -#define ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE (1 << 2L) +#define ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE (1 << 0L) /// iSCSI target node flags: CHAP authentication required. -#define ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE (1 << 3L) +#define ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE (1 << 1L) /// iSCSI target node flags: CHAP authentication mutual. -#define ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL (1 << 4L) +#define ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL (1 << 2L) /// iSCSI target node flags: Destroyed. -#define ISCSI_TARGET_NODE_FLAGS_DESTROYED (1 << 5L) +#define ISCSI_TARGET_NODE_FLAGS_DESTROYED (1 << 3L) /** @@ -6615,9 +6613,12 @@ typedef struct iscsi_pdu { /// DataSegmentLength. uint ds_len; - /// Position of DataSegment buffer for next read. + /// Position of DataSegment buffer for next operation. uint pos; + /// Allocated DataSegment buffer length. + uint len; + /// Associated iSCSI connection. iscsi_connection *conn; @@ -6708,11 +6709,20 @@ void iscsi_task_put(iscsi_task *task); // Enqueues an iSCSI task into it's under int iscsi_task_find_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Finds an iSCSI task by Target Transfer Tag (TTT) int iscsi_device_find_lun_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Finds an iSCSI LUN by LUN identifier +iscsi_lun *iscsi_lun_create(const uint id); // Allocates and initializes an iSCSI LUN structure for linkage with a DNBD3 image +void iscsi_lun_destroy(iscsi_lun *lun); // Deallocates all resources acquired by iscsi_lun_create + uint64_t iscsi_lun_get_from_scsi(const int lun_id); // Converts an internal representation of a LUN identifier to an iSCSI LUN required for packet data int iscsi_lun_get_from_iscsi(const uint64_t lun); // Converts an iSCSI LUN from packet data to internal SCSI LUN identifier +iscsi_device *iscsi_device_create(const uint8_t *name, const uint luns); // Creates and initializes an iSCSI device with a maximum number of LUNs +void iscsi_device_destroy(iscsi_device *device); // Deallocates all resources acquired by iscsi_device_create + iscsi_port *iscsi_device_find_port_by_portal_group_tag(const iscsi_device *device, const uint64_t id); // Gets an iSCSI device being in use by portal group identifier +iscsi_target_node *iscsi_target_node_create(const uint8_t *name, const uint8_t *alias, const int index, const uint luns, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest); // Creates and initializes an iSCSI target node +void iscsi_target_node_destroy(iscsi_target_node *target); // Deallocates all resources acquired by iscsi_target_node_create + int iscsi_target_node_send(iscsi_connection *conn, const uint8_t *dst_iqn, const uint8_t *src_iqn, uint8_t *buf, uint pos, const uint len); // Sends a buffer from a source iSCSI IQN to target iSCSI IQNs int iscsi_target_node_find_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Finds an iSCSI target node by case insensitive name search iscsi_target_node *iscsi_target_node_find(uint8_t *target_name); // Searches an iSCSI target node by name using case insensitive search |
