summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/iscsi.c568
-rw-r--r--src/server/iscsi.h92
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