summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/iscsi.c1186
-rw-r--r--src/server/iscsi.h268
2 files changed, 1259 insertions, 195 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c
index 8d7b0e5..baee49c 100644
--- a/src/server/iscsi.c
+++ b/src/server/iscsi.c
@@ -26,6 +26,7 @@
#include <inttypes.h>
#include <sys/socket.h>
#include <dnbd3/shared/log.h>
+#include <time.h>
#include "iscsi.h"
/**
@@ -58,7 +59,7 @@ uint8_t *iscsi_vsprintf_append_realloc(char *buf, const char *format, va_list ar
uint orig_size = 0;
if ( buf != NULL )
- orig_size = strlen( (char *) buf );
+ orig_size = (uint) strlen( (char *) buf );
va_copy( args_copy, args );
uint new_size = vsnprintf( NULL, 0, format, args_copy );
@@ -187,7 +188,7 @@ iscsi_hashmap *iscsi_hashmap_create(const uint capacity)
return NULL;
}
- map->cap_load = (map->capacity * 3UL) >> 2UL; // 75% of capacity
+ map->cap_load = (uint) ((map->capacity * 3UL) >> 2UL); // 75% of capacity
map->count = 0;
map->removed_count = 0;
map->first = NULL;
@@ -274,7 +275,7 @@ static int iscsi_hashmap_resize(iscsi_hashmap *map)
return -1;
}
- map->cap_load = (map->capacity * 3UL) >> 2UL; // 75% of capacity
+ map->cap_load = (uint) ((map->capacity * 3UL) >> 2UL); // 75% of capacity
map->last = (iscsi_hashmap_bucket *) &map->first;
map->count -= map->removed_count;
map->removed_count = 0;
@@ -456,7 +457,7 @@ int iscsi_hashmap_key_destroy_value_callback(uint8_t *key, const size_t key_size
* memory exhaustion).
* @retval 0 Key / value pair was added successfully.
*/
-int iscsi_hashmap_put(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t *value)
+int iscsi_hashmap_put(iscsi_hashmap *map, uint8_t *key, const size_t key_size, uint8_t *value)
{
if ( ((map->count + 1) > map->cap_load) && (iscsi_hashmap_resize( map ) < 0) )
return -1;
@@ -513,7 +514,7 @@ int iscsi_hashmap_put(iscsi_hashmap *map, const uint8_t *key, const size_t key_s
* @retval 0 Key / value pair was added successfully.
* @retval 1 Key already existed.
*/
-int iscsi_hashmap_get_put(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t **out_in_value)
+int iscsi_hashmap_get_put(iscsi_hashmap *map, uint8_t *key, const size_t key_size, uint8_t **out_in_value)
{
if ( ((map->count + 1) > map->cap_load) && (iscsi_hashmap_resize( map ) < 0) )
return -1;
@@ -581,7 +582,7 @@ int iscsi_hashmap_get_put(iscsi_hashmap *map, const uint8_t *key, const size_t k
* the callback function also returned 0, otherwise
* the return value got by the callbuck function.
*/
-int iscsi_hashmap_put_free(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t *value, iscsi_hashmap_callback callback, uint8_t *user_data)
+int iscsi_hashmap_put_free(iscsi_hashmap *map, uint8_t *key, const size_t key_size, uint8_t *value, iscsi_hashmap_callback callback, uint8_t *user_data)
{
if ( ((map->count + 1) > map->cap_load) && (iscsi_hashmap_resize( map ) < 0) )
return -1;
@@ -752,7 +753,7 @@ void iscsi_hashmap_remove_free(iscsi_hashmap *map, const uint8_t *key, const siz
* @return Number of elements currently in use by the
* hash map. Buckets marked for removal are not counted.
*/
-int iscsi_hashmap_size(iscsi_hashmap *map)
+uint iscsi_hashmap_size(const iscsi_hashmap *map)
{
return (map->count - map->removed_count);
}
@@ -816,16 +817,16 @@ iscsi_bhs_packet *iscsi_create_packet()
return bhs_pkt;
}
- bhs_pkt->opcode = 0; // Initialize everything to zero
+ bhs_pkt->opcode = 0; // Initialize everything to zero
bhs_pkt->opcode_fields[0] = 0;
bhs_pkt->opcode_fields[1] = 0;
bhs_pkt->opcode_fields[2] = 0;
- bhs_pkt->total_ahs_len = 0;
- bhs_pkt->ds_len[0] = 0;
- bhs_pkt->ds_len[1] = 0;
- bhs_pkt->ds_len[2] = 0;
- bhs_pkt->lun_opcode.lun = 0ULL;
- bhs_pkt->init_task_tag = 0UL;
+ bhs_pkt->total_ahs_len = 0;
+ bhs_pkt->ds_len[0] = 0;
+ bhs_pkt->ds_len[1] = 0;
+ bhs_pkt->ds_len[2] = 0;
+ bhs_pkt->lun_opcode.lun = 0ULL;
+ bhs_pkt->init_task_tag = 0UL;
memset( bhs_pkt->opcode_spec_fields, 0, sizeof(bhs_pkt->opcode_spec_fields) );
@@ -871,7 +872,7 @@ iscsi_bhs_packet *iscsi_append_ahs_packet(iscsi_bhs_packet *packet_data, const u
}
const uint32_t old_pkt_size = (const uint32_t) sizeof(struct iscsi_bhs_packet) + (packet_data->total_ahs_len << 2UL);
- const uint32_t new_pkt_size = old_pkt_size + iscsi_align(ahs_len, ISCSI_ALIGN_SIZE);
+ const uint32_t new_pkt_size = (uint32_t) (old_pkt_size + iscsi_align(ahs_len, ISCSI_ALIGN_SIZE));
if ( new_pkt_size > (sizeof(struct iscsi_bhs_packet) + 1020UL) ) {
logadd( LOG_ERROR, "iscsi_append_ahs_packet: Total numer of AHS packet size exceeds 255 DWORDs" );
@@ -888,11 +889,11 @@ iscsi_bhs_packet *iscsi_append_ahs_packet(iscsi_bhs_packet *packet_data, const u
}
iscsi_ahs_packet *ahs_pkt = (iscsi_ahs_packet *) ((uint8_t *) packet_data + old_pkt_size);
- ahs_pkt->len = iscsi_get_be16(ahs_len);
+ ahs_pkt->len = iscsi_get_be16((uint16_t) ahs_len);
ahs_pkt->type = 0;
ahs_pkt->specific = 0;
memset( ahs_pkt->data, 0, (new_pkt_size - old_pkt_size) - offsetof(struct iscsi_ahs_packet, data) );
- packet_data->total_ahs_len += (ahs_len + (ISCSI_ALIGN_SIZE - 1)) >> 2UL;
+ packet_data->total_ahs_len += (uint8_t) ((ahs_len + (ISCSI_ALIGN_SIZE - 1)) >> 2UL);
return packet_data;
}
@@ -923,7 +924,7 @@ int iscsi_get_ahs_packets(const iscsi_bhs_packet *packet_data)
len = iscsi_align(len, ISCSI_ALIGN_SIZE);
ahs_len -= len;
- ahs_pkt = ((uint8_t *) ahs_pkt) + (len - offsetof(struct iscsi_ahs_packet, data)); // Advance pointer to next AHS packet
+ ahs_pkt = (iscsi_ahs_packet *) (((uint8_t *) ahs_pkt) + (len - offsetof(struct iscsi_ahs_packet, data))); // Advance pointer to next AHS packet
count++;
}
@@ -960,7 +961,7 @@ iscsi_ahs_packet *iscsi_get_ahs_packet(const iscsi_bhs_packet *packet_data, cons
len = iscsi_align(len, ISCSI_ALIGN_SIZE);
ahs_len -= len;
- ahs_pkt = ((uint8_t *) ahs_pkt) + (len - offsetof(struct iscsi_ahs_packet, data)); // Advance pointer to next AHS packet
+ ahs_pkt = (iscsi_ahs_packet *) (((uint8_t *) ahs_pkt) + (len - offsetof(struct iscsi_ahs_packet, data))); // Advance pointer to next AHS packet
}
logadd( LOG_ERROR, "iscsi_get_ahs_packet: Specified index for AHS packet does not exist" );
@@ -1050,7 +1051,7 @@ iscsi_bhs_packet *iscsi_append_ds_packet(iscsi_bhs_packet *packet_data, const in
}
const uint32_t old_pkt_size = (const uint32_t) sizeof(struct iscsi_bhs_packet) + ((uint32_t) packet_data->total_ahs_len << 2UL);
- const uint32_t new_pkt_size = old_pkt_size + header_digest_size + iscsi_align(ds_len, ISCSI_ALIGN_SIZE) + data_digest_size;
+ const uint32_t new_pkt_size = (uint32_t) (old_pkt_size + header_digest_size + iscsi_align(ds_len, ISCSI_ALIGN_SIZE) + data_digest_size);
packet_data = (iscsi_bhs_packet *) realloc( packet_data, new_pkt_size );
@@ -1060,7 +1061,7 @@ iscsi_bhs_packet *iscsi_append_ds_packet(iscsi_bhs_packet *packet_data, const in
return packet_data;
}
- iscsi_put_be24( &packet_data->ds_len, ds_len );
+ iscsi_put_be24( (uint8_t *) &packet_data->ds_len, ds_len );
memset( ((uint8_t *) packet_data) + old_pkt_size, 0, (new_pkt_size - old_pkt_size) );
return packet_data;
@@ -1226,13 +1227,13 @@ int iscsi_validate_data_digest(const iscsi_bhs_packet *packet_data, const int he
*/
static int iscsi_validate_text_key_value_pair(const uint8_t *packet_data, const uint32_t len)
{
- const uint key_val_len = strnlen( packet_data, len );
+ const uint key_val_len = (uint) strnlen( (char *) packet_data, len );
const uint8_t *key_end = memchr( packet_data, '=', key_val_len );
if ( key_end == NULL )
return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Missing separator '=' for key / value pair -> invalid iSCSI packet data
- const uint key_len = (key_end - packet_data);
+ const uint key_len = (uint) (key_end - packet_data);
if ( key_len == 0 )
return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Zero length is not allowed -> invalid iSCSI packet data
@@ -1240,13 +1241,13 @@ static int iscsi_validate_text_key_value_pair(const uint8_t *packet_data, const
if ( key_len > ISCSI_TEXT_KEY_MAX_LEN )
return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS;
- const uint val_len = strnlen( key_end + 1UL, key_val_len - key_len - 1UL );
+ const uint val_len = (uint) strnlen( (char *) (key_end + 1UL), key_val_len - key_len - 1UL );
const uint max_len = (memcmp( packet_data, "CHAP_C=", (key_len + 1UL) ) == 0) || (memcmp( packet_data, "CHAP_R=", (key_len + 1UL) ) == 0) ? ISCSI_TEXT_VALUE_MAX_LEN : ISCSI_TEXT_VALUE_MAX_SIMPLE_LEN;
if ( val_len > max_len )
return ISCSI_VALIDATE_PACKET_RESULT_ERROR_PROTOCOL_SPECS; // Value exceeds maximum length -> invalid iSCSI packet data
- return key_len + 1UL + val_len + 1UL; // Number of bytes for processed key / value pair (+1 for '=' and NUL terminator)
+ return (int) (key_len + 1UL + val_len + 1UL); // Number of bytes for processed key / value pair (+1 for '=' and NUL terminator)
}
/**
@@ -1269,7 +1270,7 @@ static int iscsi_validate_key_value_pairs(const uint8_t *packet_data, uint len)
int offset = 0L;
- while ( (offset < len) && (packet_data[offset] != '\0') ) {
+ while ( ((uint) offset < len) && (packet_data[offset] != '\0') ) {
const int rc = iscsi_validate_text_key_value_pair( (packet_data + offset), (len - offset) );
if ( rc < ISCSI_VALIDATE_PACKET_RESULT_OK )
@@ -1582,7 +1583,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint
*/
static int iscsi_parse_text_key_value_pair(iscsi_hashmap *pairs, const uint8_t *packet_data, const uint32_t len)
{
- const uint key_val_len = strnlen( packet_data, len );
+ const uint key_val_len = (uint) strnlen( (char *) packet_data, len );
const uint8_t *key_end = memchr( packet_data, '=', key_val_len );
if ( key_end == NULL ) {
@@ -1591,7 +1592,7 @@ static int iscsi_parse_text_key_value_pair(iscsi_hashmap *pairs, const uint8_t *
return -1L;
}
- const uint key_len = (key_end - packet_data);
+ const uint key_len = (uint) (key_end - packet_data);
if ( key_len == 0 ) {
logadd( LOG_ERROR, "iscsi_parse_text_key_value_pair: Empty key found which is NOT allowed according to iSCSI specs" );
@@ -1621,8 +1622,8 @@ static int iscsi_parse_text_key_value_pair(iscsi_hashmap *pairs, const uint8_t *
return -1L;
}
- const uint val_len = strnlen( key_end + 1UL, key_val_len - key_len - 1UL );
- const uint max_len = (strcmp( hash_key, "CHAP_C" ) == 0) || (strcmp( hash_key, "CHAP_R" ) == 0) ? ISCSI_TEXT_VALUE_MAX_LEN : ISCSI_TEXT_VALUE_MAX_SIMPLE_LEN;
+ const uint val_len = (uint) strnlen( (char *) (key_end + 1UL), key_val_len - key_len - 1UL );
+ const uint max_len = (strcmp( (char *) hash_key, "CHAP_C" ) == 0) || (strcmp( (char *) hash_key, "CHAP_R" ) == 0) ? ISCSI_TEXT_VALUE_MAX_LEN : ISCSI_TEXT_VALUE_MAX_SIMPLE_LEN;
if ( val_len > max_len ) {
logadd( LOG_ERROR, "iscsi_parse_text_key_value_pair: Value length larger than iSCSI specs allow" );
@@ -1649,7 +1650,7 @@ static int iscsi_parse_text_key_value_pair(iscsi_hashmap *pairs, const uint8_t *
if ( rc < 0 )
return -1L;
- return hash_key_len + val_len + 1UL; // Number of bytes for processed key / value pair (+1 for '=' and NUL terminator)
+ return (int) (hash_key_len + val_len + 1UL); // Number of bytes for processed key / value pair (+1 for '=' and NUL terminator)
}
/**
@@ -1687,7 +1688,7 @@ int iscsi_parse_key_value_pairs(iscsi_hashmap *pairs, const uint8_t *packet_data
if ( tmp_partial_buf == NULL )
return -1L;
- const int rc = iscsi_parse_text_key_value_pair( pairs, tmp_partial_buf, (key_val_pair_len + strlen( *partial_pairs )) );
+ const int rc = iscsi_parse_text_key_value_pair( pairs, tmp_partial_buf, (uint32_t) (key_val_pair_len + strlen( (char *) *partial_pairs )) );
free( tmp_partial_buf );
if ( rc < 0 )
@@ -1733,7 +1734,7 @@ int iscsi_parse_key_value_pairs(iscsi_hashmap *pairs, const uint8_t *packet_data
int offset = 0L;
- while ( (offset < len) && (packet_data[offset] != '\0') ) {
+ while ( ((uint) offset < len) && (packet_data[offset] != '\0') ) {
const int rc = iscsi_parse_text_key_value_pair( pairs, (packet_data + offset), (len - offset) );
if ( rc < 0 )
@@ -1770,7 +1771,7 @@ int iscsi_parse_key_value_pairs(iscsi_hashmap *pairs, const uint8_t *packet_data
int iscsi_create_key_value_pair_packet_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data)
{
iscsi_key_value_pair_packet *packet_data = (iscsi_key_value_pair_packet *) user_data;
- const uint8_t *buf = iscsi_sprintf_alloc( "%s=%s", key, ((value != NULL) ? value : "") );
+ uint8_t *buf = iscsi_sprintf_alloc( "%s=%s", key, ((value != NULL) ? value : (uint8_t *) "") );
if ( buf == NULL ) {
logadd( LOG_ERROR, "iscsi_create_key_value_pair_packet_callback: Out of memory generating text key / value pair DataSegment" );
@@ -1778,7 +1779,7 @@ int iscsi_create_key_value_pair_packet_callback(uint8_t *key, const size_t key_s
return -1L;
}
- const uint len = strlen( buf ) + 1;
+ const uint len = (uint) strlen( (char *) buf ) + 1;
const uint new_len = packet_data->len + len;
uint8_t *new_buf = realloc( packet_data->buf, new_len );
@@ -1808,7 +1809,7 @@ int iscsi_create_key_value_pair_packet_callback(uint8_t *key, const size_t key_s
* be attached to a BHS/AHS packet and sent
* via TCP/IP.
*
- * @param[in] pairs Pointer to hash map containing
+ * @param[in] key_value_pairs Pointer to hash map containing
* the key and value pairs to construct the
* DataSegment from, may NOT be NULL, so be careful.
* @return Pointer to iscsi_key_value_pair_packet
@@ -1817,7 +1818,7 @@ int iscsi_create_key_value_pair_packet_callback(uint8_t *key, const size_t key_s
* NULL in case of an error (most likely due to
* memory exhaustion).
*/
-iscsi_key_value_pair_packet *iscsi_create_key_value_pairs_packet(const iscsi_hashmap *pairs)
+iscsi_key_value_pair_packet *iscsi_create_key_value_pairs_packet(iscsi_hashmap *key_value_pairs)
{
iscsi_key_value_pair_packet *packet_data = (iscsi_key_value_pair_packet *) malloc( sizeof(struct iscsi_key_value_pair_packet) );
@@ -1830,7 +1831,7 @@ iscsi_key_value_pair_packet *iscsi_create_key_value_pairs_packet(const iscsi_has
packet_data->buf = NULL;
packet_data->len = 0UL;
- if ( iscsi_hashmap_iterate( pairs, iscsi_create_key_value_pair_packet_callback, packet_data ) < 0L ) {
+ if ( iscsi_hashmap_iterate( key_value_pairs, iscsi_create_key_value_pair_packet_callback, (uint8_t *) packet_data ) < 0L ) {
if ( packet_data->buf != NULL )
free( packet_data->buf );
@@ -1872,9 +1873,9 @@ iscsi_key_value_pair_packet *iscsi_create_key_value_pairs_packet(const iscsi_has
* @retval 0 The value of the key has been successfully
* stored in the 'out_value'.
*/
-static int iscsi_get_key_value_pair(const iscsi_hashmap *key_value_pairs, const uint8_t *key, uint8_t **out_value)
+static int iscsi_get_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_t *key, uint8_t **out_value)
{
- const uint32_t key_len = strlen( key ) + 1;
+ const uint key_len = (uint) strlen( (char *) key ) + 1;
return iscsi_hashmap_get( key_value_pairs, key, key_len, out_value );
}
@@ -1896,7 +1897,7 @@ static int iscsi_get_key_value_pair(const iscsi_hashmap *key_value_pairs, const
*/
static int iscsi_add_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_t *key, const uint8_t *value)
{
- const uint key_len = strlen( key ) + 1;
+ const uint key_len = (uint) strlen( (char *) key ) + 1;
uint8_t *hash_key = iscsi_hashmap_key_create( key, key_len );
if ( hash_key == NULL ) {
@@ -1905,7 +1906,7 @@ static int iscsi_add_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_
return -1L;
}
- const uint val_len = strlen( value ) + 1;
+ const uint val_len = (uint) strlen( (char *) value ) + 1;
uint8_t *hash_val = (uint8_t *) malloc( val_len );
if ( hash_val == NULL ) {
@@ -1934,13 +1935,13 @@ static int iscsi_add_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_
* @retval 0 The value of the key has been successfully
* stored in the 'out_value'.
*/
-static int iscsi_get_int_key_value_pair(const iscsi_hashmap *key_value_pairs, const uint8_t *key, int32_t *out_value)
+static int iscsi_get_int_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_t *key, int32_t *out_value)
{
uint8_t *str_val;
int rc = iscsi_get_key_value_pair( key_value_pairs, key, &str_val );
if ( rc == 0 )
- *out_value = atol( str_val );
+ *out_value = (int32_t) atol( (char *) str_val );
return rc;
}
@@ -1988,13 +1989,13 @@ static int iscsi_add_int_key_value_pair(iscsi_hashmap *key_value_pairs, const ui
* @retval 0 The value of the key has been successfully
* stored in the 'out_value'.
*/
-static int iscsi_get_bool_key_value_pair(const iscsi_hashmap *key_value_pairs, const uint8_t *key, int32_t *out_value)
+static int iscsi_get_bool_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_t *key, int32_t *out_value)
{
uint8_t *value;
int rc = iscsi_get_key_value_pair( key_value_pairs, key, &value );
if ( rc == 0 )
- *out_value = (strcasecmp( value, "Yes" ) == 0) ? true : false;
+ *out_value = (strcasecmp( (char *) value, "Yes" ) == 0) ? true : false;
return rc;
}
@@ -2019,7 +2020,7 @@ static int iscsi_get_bool_key_value_pair(const iscsi_hashmap *key_value_pairs, c
*/
static int iscsi_add_bool_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_t *key, const int value)
{
- const uint8_t *hash_val = ((value != 0) ? "Yes" : "No");
+ const uint8_t *hash_val = (uint8_t *) ((value != 0) ? "Yes" : "No");
return iscsi_add_key_value_pair( key_value_pairs, key, hash_val );
}
@@ -2131,7 +2132,7 @@ int iscsi_portal_group_add_portal(iscsi_portal_group *portal_group, iscsi_portal
if ( tmp_buf == NULL )
return -1L;
- const uint key_len = strlen( tmp_buf ) + 1;
+ const uint key_len = (uint) strlen( (char *) tmp_buf ) + 1;
uint8_t *key = iscsi_hashmap_key_create( tmp_buf, key_len );
free( tmp_buf );
@@ -2142,7 +2143,7 @@ int iscsi_portal_group_add_portal(iscsi_portal_group *portal_group, iscsi_portal
return -1L;
}
- int rc = iscsi_hashmap_put( portal_group->portals, key, key_len, (iscsi_portal *) portal );
+ int rc = iscsi_hashmap_put( portal_group->portals, key, key_len, (uint8_t *) portal );
if ( rc < 0 ) {
logadd( LOG_ERROR, "iscsi_portal_group_add_portal: Adding portal to hash map containing iSCSI portal group failed" );
@@ -2180,7 +2181,7 @@ iscsi_portal *iscsi_portal_create(const uint8_t *host, const uint8_t *port)
portal->group = NULL;
- const uint host_len = strlen( host ) + 1;
+ const uint host_len = (uint) strlen( (char *) host ) + 1;
portal->host = (uint8_t *) malloc( host_len );
@@ -2192,7 +2193,7 @@ iscsi_portal *iscsi_portal_create(const uint8_t *host, const uint8_t *port)
memcpy( portal->host, host, host_len );
- const uint port_len = strlen( port ) + 1;
+ const uint port_len = (uint) strlen( (char *) port ) + 1;
portal->port = (uint8_t *) malloc( port_len );
@@ -2261,7 +2262,7 @@ iscsi_port *iscsi_port_create(const uint8_t *name, const uint64_t id, const uint
return NULL;
}
- const uint name_len = strlen( name ) + 1;
+ const uint name_len = (uint) strlen( (char *) name ) + 1;
port->name = (uint8_t *) malloc( name_len );
@@ -2313,6 +2314,213 @@ void iscsi_port_destroy(iscsi_port *port)
}
/**
+ * @brief Retrieves the name of an iSCSI port.
+ *
+ * This function is just a getter.
+ *
+ * @param[in] port Pointer to iSCSI port to retrieve
+ * the name from and may NOT be NULL, so be
+ * careful.
+ * @return Pointer to string containing the name
+ * of the iSCSI port.
+ */
+uint8_t *iscsi_port_get_name(const iscsi_port *port)
+{
+ return port->name;
+}
+
+/**
+ * @brief Sets the SCSI transport ID of the iSCSI port.
+ *
+ * This function constructs the SCSI packet data
+ * for the SCSI transport id by assigning a name
+ * and the Initiator Session ID (ISID).\n
+ * Currently, always transport ID format 0x1 will
+ * be created.
+ *
+ * @param[in] Pointer to iSCSI port to assign the
+ * SCSI transport ID to. May NOT be NULL, so be
+ * careful.
+ * @param[in] Pointer to iSCSI name to assign
+ * along with the ISID as name.
+ * @param[in] Initiator Session ID (ISID).
+ * @return 0 if transport ID could be created
+ * successfully, a negative error code
+ * otherwise.
+ */
+int iscsi_port_transport_id_set(iscsi_port *port, const uint8_t *name, const uint64_t isid)
+{
+ uint8_t *tmp_buf = iscsi_sprintf_alloc( "%s,i,0x%12.12" PRIx64, name, isid );
+
+ if ( tmp_buf == NULL ) {
+ logadd( LOG_ERROR, "iscsi_port_transport_id_set: Out of memory allocating SCSI transport ID name for iSCSI port" );
+
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+
+ const uint name_len = (uint) strlen( (char *) tmp_buf ) + 1;
+ const uint len = iscsi_align(name_len, ISCSI_ALIGN_SIZE);
+
+ if ( (len < 20UL) || ((len + offsetof(struct iscsi_transport_id, name)) >= 65536UL) ) {
+ logadd( LOG_ERROR, "iscsi_port_transport_id_set: Out of memory allocating SCSI transport ID for iSCSI port" );
+
+ free( tmp_buf );
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER;
+ }
+
+ port->transport_id = (iscsi_transport_id *) malloc( sizeof(struct iscsi_transport_id) + len );
+
+ if ( port->transport_id == NULL ) {
+ logadd( LOG_ERROR, "iscsi_port_transport_id_set: Out of memory allocating SCSI transport ID for iSCSI port" );
+
+ free( tmp_buf );
+
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+
+ port->transport_id->id = (ISCSI_TRANSPORT_ID_FORMAT << 6U) | ISCSI_TRANSPORT_ID_PROTOCOL_ID_ISCSI;
+ port->transport_id->reserved = 0U;
+ iscsi_put_be16( (uint8_t *) &port->transport_id->add_len, (uint16_t) len );
+
+ memcpy( ((uint8_t *) port->transport_id) + offsetof(struct iscsi_transport_id, name), tmp_buf, name_len );
+ memset( ((uint8_t *) port->transport_id) + offsetof(struct iscsi_transport_id, name) + name_len, 0, (name_len & (ISCSI_ALIGN_SIZE - 1)) );
+
+ port->transport_id_len = (uint16_t) (offsetof(struct iscsi_transport_id, name) + len);
+
+ return ISCSI_CONNECT_PDU_READ_OK;
+}
+
+/**
+ * @brief Gets an iSCSI device being in use by portal group identifier.
+ *
+ * This function uses the unique portal group
+ * identifier in order to get the port.
+ *
+ * @param[in] device Pointer to iSCSI device to be searched. May
+ * NOT be NULL, so take caution.
+ * @param[in] id Portal group ID to be searched for.
+ * @return Pointer to iSCSI port belonging to the iSCSI
+ * portal group ID or NULL if either the portal
+ * group ID does not exist or the port is NOT in use.
+ */
+iscsi_port *iscsi_device_find_port_by_portal_group_tag(const iscsi_device *device, const uint64_t id)
+{
+ iscsi_port *port;
+
+ if ( iscsi_hashmap_get( device->ports, (uint8_t *) &id, sizeof(id), (uint8_t **) &port ) < 0 )
+ return NULL;
+
+ if ( (port == NULL) || ((port->flags & ISCSI_PORT_FLAGS_IN_USE) == 0) )
+ return NULL;
+
+ return port;
+}
+
+/**
+ * @brief Finds an iSCSI target node by case insensitive name search.
+ *
+ * Callback function for each element while iterating
+ * through the iSCSI target nodes.
+ *
+ * @param[in] key Pointer to zero padded key. NULL is
+ * an invalid pointer here, so be careful.
+ * @param[in] key_size Number of bytes for the key, MUST
+ * be a multiple of 8 bytes which is NOT checked, so
+ * be careful.
+ * @param[in] value Value of the key, NULL creates an
+ * empty key assignment.
+ * @param[in,out] user_data Pointer to a data structure
+ * containing the iSCSI target node and the name to be
+ * searched for and may NOT be NULL, so be careful.
+ * @retval -1 The target node has been found and stored
+ * in the result strcuture. Therefore, no further
+ * searching is needed.
+ * @retval 0 The target node has not been found yet.
+ */
+int iscsi_target_node_find_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data)
+{
+ iscsi_target_node_find_name *target_find = (iscsi_target_node_find_name *) user_data;
+ iscsi_target_node *target = (iscsi_target_node *) value;
+
+ if ( strcasecmp( (char *) target->name, (char *) target_find->name ) != 0 )
+ return 0L;
+
+ target_find->target = target;
+
+ return -1L;
+}
+
+/**
+ * @brief Searches an iSCSI target node by name using case insensitive search.
+ *
+ * This function searches for an iSCSI target node
+ * by iterating through the iSCSI global target node
+ * hash map.
+ *
+ * @param[in] target_name Pointer to string containing the name
+ * of the iSCSI target node to be searched for.
+ * @return Pointer to found iSCSI target node or NULL
+ * in case no iSCSI target node has a matching name.
+ */
+iscsi_target_node *iscsi_target_node_find(uint8_t *target_name)
+{
+ if ( target_name == NULL )
+ return NULL;
+
+ iscsi_target_node_find_name target_find = {NULL, target_name};
+
+ iscsi_hashmap_iterate( iscsi_globvec->target_nodes, iscsi_target_node_find_callback, (uint8_t *) &target_find );
+
+ return target_find.target;
+}
+
+/**
+ * @brief Retrieves target node redirection address.
+ *
+ * This function checks whether the target node needs
+ * a redirect and is used for informing the client
+ * about a necessary redirection.
+ *
+ * @param[in] conn Pointer to iSCSI connection, may NOT
+ * be NULL, so be careful.
+ * @param[in] target Pointer to iSCSI target node where
+ * NULL is NOT allowed, so take caution.
+ * @return Pointer to redirect target address or NULL
+ * if no redirection.
+ */
+uint8_t *iscsi_target_node_get_redirect(iscsi_connection *conn, iscsi_target_node *target)
+{
+ // TODO: Implement function
+
+ return NULL;
+}
+
+/**
+ * @brief Checks if target node is accessible.
+ *
+ * This function checks whether access is possible
+ * to a specific iSCSI IQN and IP address.
+ *
+ * @param[in] conn Pointer to iSCSI connection which
+ * may NOT be NULL, so be careful.
+ * @param[in] target Pointer to iSCSI target node. NULL
+ * is not allowed here, to take caution.
+ * @param[in] iqn Pointer to iSCSI IQN string. This
+ * is not allowed to be NULL, so be careful.
+ * @param[in] adr Pointer to IP address, NULL is not
+ * allowed, so take care.
+ * @return 0 if access is possible, a negative error
+ * code otherwise.
+ */
+int iscsi_target_node_access(iscsi_connection *conn, iscsi_target_node *target, const uint8_t *iqn, const uint8_t *adr)
+{
+ // TODO: Implement access check function
+
+ return 0L;
+}
+
+/**
* @brief Creates and initializes an iSCSI session.
*
* This function creates and initializes all relevant
@@ -2327,7 +2535,7 @@ void iscsi_port_destroy(iscsi_port *port)
* @return Pointer to initialized iSCSI session or NULL in case an error
* occured (usually due to memory exhaustion).
*/
-iscsi_session *iscsi_session_create(iscsi_connection *conn, const iscsi_target_node *target, const int type)
+iscsi_session *iscsi_session_create(iscsi_connection *conn, iscsi_target_node *target, const int type)
{
iscsi_session *session = (iscsi_session *) malloc( sizeof(struct iscsi_session) );
@@ -2371,7 +2579,7 @@ iscsi_session *iscsi_session_create(iscsi_connection *conn, const iscsi_target_n
return NULL;
}
- iscsi_hashmap_put( session->connections, conn_key, sizeof(conn->cid), (iscsi_connection *) conn );
+ iscsi_hashmap_put( session->connections, conn_key, sizeof(conn->cid), (uint8_t *) conn );
session->target = target;
session->isid = 0LL;
@@ -2491,7 +2699,15 @@ iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock)
}
conn->partial_pairs = NULL;
+ conn->device = NULL;
+ conn->init_port = NULL;
conn->init_name = NULL;
+ conn->init_adr = NULL;
+ conn->target = NULL;
+ conn->target_port = NULL;
+ conn->target_name_short = NULL;
+ conn->portal_host = NULL;
+ conn->portal_port = NULL;
conn->header_digest = 0L;
conn->data_digest = 0L;
conn->pdu_processing = NULL;
@@ -2507,8 +2723,10 @@ iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock)
conn->isid.c = 0;
conn->isid.d = 0;
conn->tsih = 0U;
- conn->init_task_tag = 0UL;
conn->cid = 0U;
+ conn->init_task_tag = 0UL;
+ conn->auth_chap.phase = ISCSI_AUTH_CHAP_PHASE_NONE;
+ conn->chap_group = 0L;
conn->stat_sn = 0UL;
conn->exp_stat_sn = 0UL;
@@ -2557,6 +2775,30 @@ int iscsi_connection_destroy_callback(uint8_t *key, const size_t key_size, uint8
void iscsi_connection_destroy(iscsi_connection *conn)
{
if ( conn != NULL ) {
+ if ( conn->portal_port != NULL ) {
+ free ( conn->portal_port );
+
+ conn->portal_port = NULL;
+ }
+
+ if ( conn->portal_host != NULL ) {
+ free ( conn->portal_host );
+
+ conn->portal_host = NULL;
+ }
+
+ if ( conn->target_name_short != NULL ) {
+ free ( conn->target_name_short );
+
+ conn->target_name_short = NULL;
+ }
+
+ if ( conn->init_adr != NULL ) {
+ free ( conn->init_adr );
+
+ conn->init_adr = NULL;
+ }
+
if ( conn->init_name != NULL ) {
free ( conn->init_name );
@@ -2582,6 +2824,24 @@ void iscsi_connection_destroy(iscsi_connection *conn)
}
/**
+ * @brief Drops all connections based on matching pattern.
+ *
+ * @param[in] conn Pointer to iSCSI connection which may
+ * NOT be NULL, so be careful.
+ * @param[in] conn_match Pointer to match string, NULL is
+ * not allowd here, so take caution.
+ * @param[in] all Non-zero number indicating removing all
+ * connections.
+ * @return 0 on success, a negative error code otherwise.
+ */
+int iscsi_connection_drop(iscsi_connection *conn, const uint8_t *conn_match, const int all)
+{
+ // TODO: Implement function.
+
+ return 0;
+}
+
+/**
* @brief Schedules an iSCSI connection.
*
* @param[in] conn Pointer to ISCSI connection to be
@@ -2609,7 +2869,7 @@ int iscsi_connection_read(const iscsi_connection *conn, uint8_t *buf, const uint
if ( len == 0 )
return 0;
- const int rc = recv( conn->sock, buf, len, MSG_WAITALL );
+ const int rc = (int) recv( conn->sock, buf, len, MSG_WAITALL );
return (rc > 0) ? rc : ISCSI_CONNECT_PDU_READ_ERR_FATAL;
}
@@ -2631,7 +2891,7 @@ int iscsi_connection_write(const iscsi_connection *conn, uint8_t *buf, const uin
if ( len == 0 )
return 0;
- const int rc = send( conn->sock, buf, len, 0L );
+ const int rc = (int) send( conn->sock, buf, len, 0L );
return (rc > 0) ? rc : ISCSI_CONNECT_PDU_READ_ERR_FATAL;
}
@@ -2657,7 +2917,7 @@ int iscsi_connection_copy_key_value_pairs(iscsi_connection *conn)
if ( rc != 0 )
return rc;
- if ( (int_val <= 0L) || (int_val > ISCSI_DEFAULT_MAX_RECV_DS_LEN) )
+ if ( (int_val <= 0L) || (int_val > (int32_t) ISCSI_DEFAULT_MAX_RECV_DS_LEN) )
int_val = ISCSI_DEFAULT_MAX_RECV_DS_LEN;
conn->max_recv_ds_len = int_val;
@@ -2669,14 +2929,14 @@ int iscsi_connection_copy_key_value_pairs(iscsi_connection *conn)
if ( rc != 0 )
return rc;
- conn->header_digest = (strcasecmp( value, "CRC32C" ) == 0) ? ISCSI_DIGEST_SIZE : 0L;
+ conn->header_digest = (strcasecmp( (char *) value, "CRC32C" ) == 0) ? ISCSI_DIGEST_SIZE : 0L;
rc = iscsi_get_key_value_pair( conn->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_DATA_DIGEST, &value);
if ( rc != 0 )
return rc;
- conn->data_digest = (strcasecmp( value, "CRC32C" ) == 0) ? ISCSI_DIGEST_SIZE : 0L;
+ conn->data_digest = (strcasecmp( (char *) value, "CRC32C" ) == 0) ? ISCSI_DIGEST_SIZE : 0L;
rc = iscsi_get_int_key_value_pair( conn->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_MAX_CONNECTIONS, &int_val);
@@ -2764,8 +3024,6 @@ static int iscsi_connection_check_key_value_pairs(iscsi_connection *conn)
*/
static int iscsi_connection_update_key_value_pairs(iscsi_connection *conn)
{
- uint32_t recv_buf_size;
-
int rc = iscsi_connection_copy_key_value_pairs( conn );
if ( rc < 0 ) {
@@ -2786,11 +3044,11 @@ static int iscsi_connection_update_key_value_pairs(iscsi_connection *conn)
uint recv_buf_len = conn->session->first_burst_len;
if ( recv_buf_len < 4096 )
- recv_buf_len = 4096;
+ recv_buf_len = 4096UL;
else if ( recv_buf_len > 8192 )
- recv_buf_len > 8192;
+ recv_buf_len = 8192UL;
- recv_buf_len += (sizeof(struct iscsi_bhs_packet) + 1020UL + conn->header_digest + conn->data_digest); // BHS + maximum AHS size + header and data digest overhead
+ recv_buf_len += (uint) (sizeof(struct iscsi_bhs_packet) + 1020UL + conn->header_digest + conn->data_digest); // BHS + maximum AHS size + header and data digest overhead
recv_buf_len <<= 2UL; // Receive up to four streams at once.
setsockopt( conn->sock, SOL_SOCKET, SO_RCVBUF, &recv_buf_len, sizeof(recv_buf_len)); // Not being able to set the buffer is NOT fatal, so ignore error.
@@ -2820,19 +3078,19 @@ static void iscsi_connection_pdu_login_response(iscsi_connection *conn, iscsi_pd
login_response_pkt->version_max = ISCSI_VERSION_MAX;
login_response_pkt->version_active = ISCSI_VERSION_MAX;
- iscsi_put_be24( &login_response_pkt->ds_len, login_response_pdu->ds_len );
- iscsi_put_be32( &login_response_pkt->stat_sn, conn->stat_sn++ );
+ iscsi_put_be24( (uint8_t *) &login_response_pkt->ds_len, login_response_pdu->ds_len );
+ iscsi_put_be32( (uint8_t *) &login_response_pkt->stat_sn, conn->stat_sn++ );
if ( conn->session != NULL ) {
- iscsi_put_be32( &login_response_pkt->exp_cmd_sn, conn->session->exp_cmd_sn );
- iscsi_put_be32( &login_response_pkt->max_cmd_sn, conn->session->max_cmd_sn );
+ iscsi_put_be32( (uint8_t *) &login_response_pkt->exp_cmd_sn, conn->session->exp_cmd_sn );
+ iscsi_put_be32( (uint8_t *) &login_response_pkt->max_cmd_sn, conn->session->max_cmd_sn );
} else {
- iscsi_put_be32( &login_response_pkt->exp_cmd_sn, login_response_pdu->cmd_sn );
- iscsi_put_be32( &login_response_pkt->max_cmd_sn, login_response_pdu->cmd_sn );
+ iscsi_put_be32( (uint8_t *) &login_response_pkt->exp_cmd_sn, login_response_pdu->cmd_sn );
+ iscsi_put_be32( (uint8_t *) &login_response_pkt->max_cmd_sn, login_response_pdu->cmd_sn );
}
if ( login_response_pkt->status_class != ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SUCCESS )
- login_response_pkt->flags &= ~(ISCSI_LOGIN_RESPONSE_FLAGS_TRANSMIT | ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_MASK | ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_MASK );
+ login_response_pkt->flags &= (int8_t) ~(ISCSI_LOGIN_RESPONSE_FLAGS_TRANSMIT | ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_MASK | ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_MASK );
iscsi_hashmap_iterate( key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL );
iscsi_hashmap_destroy( key_value_pairs );
@@ -2883,37 +3141,40 @@ static void iscsi_connection_pdu_login_ok_complete(uint8_t *user_data)
}
/**
- * @brief Creates and initializes an iSCSI login response PDU structure.
+ * @brief Initializes an iSCSI login response PDU structure.
*
- * This function creates and initializes the internal
+ * This function initializes the internal login
* response data structure which is part of the iSCSI
* login procedure.
*
- * @param[in] pdu Pointer to PDU, may NOT be NULL, so take
- * caution.
- * @param[in] login_req_pkt Pointer to login request from client,
+ * @param[in] login_response_pdu Pointer to login response PDU, NULL
+ * is not an allowed value here, so take caution.
+ * @param[in] pdu Pointer to login request PDU from client,
* may NOT be NULL, so be careful.
- * @return Pointer to initialized login response PDU.
+ * @return 0 if initialization was successful, a negative error
+ * code otherwise.
*/
-static iscsi_login_response_packet *iscsi_login_response_create(iscsi_pdu *pdu, const iscsi_login_req_packet *login_req_pkt)
+static int iscsi_login_response_init(iscsi_pdu *login_response_pdu, const iscsi_pdu *pdu)
{
- iscsi_login_response_packet *bhs_pkt = (iscsi_login_response_packet *) iscsi_create_packet();
-
- if ( bhs_pkt == NULL )
- return NULL;
+ 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;
- iscsi_login_response_packet *login_response_pkt = iscsi_append_ds_packet( bhs_pkt, pdu->header_digest_size, ISCSI_DEFAULT_RECV_DS_LEN, pdu->data_digest_size );
+ 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 );
if ( login_response_pkt == NULL ) {
bhs_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR;
bhs_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES;
- return bhs_pkt;
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
}
- login_response_pkt->flags |= (login_req_pkt->flags & (ISCSI_LOGIN_REQ_FLAGS_TRANSMIT | ISCSI_LOGIN_REQ_FLAGS_CONTINUE | ISCSI_LOGIN_REQ_FLAGS_CURRENT_STAGE_MASK));
+ 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_pkt->flags |= (int8_t) (login_req_pkt->flags & (ISCSI_LOGIN_REQ_FLAGS_TRANSMIT | ISCSI_LOGIN_REQ_FLAGS_CONTINUE | ISCSI_LOGIN_REQ_FLAGS_CURRENT_STAGE_MASK));
if ( (login_response_pkt->flags & ISCSI_LOGIN_RESPONSE_FLAGS_TRANSMIT) != 0 )
login_response_pkt->flags |= (login_req_pkt->flags & ISCSI_LOGIN_REQ_FLAGS_NEXT_STAGE_MASK);
@@ -2924,7 +3185,7 @@ static iscsi_login_response_packet *iscsi_login_response_create(iscsi_pdu *pdu,
login_response_pkt->isid.d = login_req_pkt->isid.d; // Copying over doesn't change endianess.
login_response_pkt->tsih = login_req_pkt->tsih; // Copying over doesn't change endianess.'
login_response_pkt->init_task_tag = login_req_pkt->init_task_tag; // Copying over doesn't change endianess.
- pdu->cmd_sn = iscsi_get_be32(login_req_pkt->cmd_sn);
+ login_response_pdu->cmd_sn = iscsi_get_be32(login_req_pkt->cmd_sn);
if ( login_response_pkt->tsih != 0 )
login_response_pkt->stat_sn = login_req_pkt->exp_stat_sn; // Copying over doesn't change endianess.'
@@ -2932,23 +3193,29 @@ static iscsi_login_response_packet *iscsi_login_response_create(iscsi_pdu *pdu,
if ( ((login_response_pkt->flags & ISCSI_LOGIN_RESPONSE_FLAGS_TRANSMIT) != 0) && ((login_response_pkt->flags & ISCSI_LOGIN_RESPONSE_FLAGS_CONTINUE) != 0) ) {
login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISC;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
} else if ( (ISCSI_VERSION_MIN < login_req_pkt->version_min) || (ISCSI_VERSION_MAX > login_req_pkt->version_max) ) {
login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_WRONG_VERSION;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
} else if ( (ISCSI_LOGIN_RESPONSES_FLAGS_GET_NEXT_STAGE(login_response_pkt->flags) == ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_RESERVED) && ((login_response_pkt->flags & ISCSI_LOGIN_RESPONSE_FLAGS_TRANSMIT) != 0) ) {
- login_response_pkt->flags &= ~(ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_MASK | ISCSI_LOGIN_RESPONSE_FLAGS_TRANSMIT | ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_MASK);
+ login_response_pkt->flags &= (int8_t) ~(ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_MASK | ISCSI_LOGIN_RESPONSE_FLAGS_TRANSMIT | ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_MASK);
login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISC;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
} else {
login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SUCCESS;
login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SUCCESS;
}
- return login_response_pkt;
+ return ISCSI_CONNECT_PDU_READ_OK;
}
/**
- * @brief Saves incoming key / value pairs from the client of a login request packet.
+ * @brief Saves incoming key / value pairs from the client of a login request PDU.
*
* The login response structure has status detail
* invalid login request type set in case of an error.
@@ -2957,28 +3224,28 @@ static iscsi_login_response_packet *iscsi_login_response_create(iscsi_pdu *pdu,
* used for key and value pair extraction.
* @param[out] key_value_pairs Pointer to hash map which
* stores all the parsed key and value pairs.
- * @param[in] login_response_pkt Pointer to iSCSI login response
- * packet data, may NOT be NULL, so be careful.
- * @param[in] login_req_pkt Pointer to iSCSI login request packet
- * data, may NOT be NULL, so be careful.
+ * @param[in] login_response_pdu Pointer to iSCSI login response
+ * PDU, may NOT be NULL, so be careful.
+ * @param[in] pdu Pointer to iSCSI login request packet
+ * PDU, may NOT be NULL, so be careful.
* @retval -1 An error occured during parse of
* key and value pairs (memory exhaustion).
* @retval 0 All key and value pairs have been parsed successfully.
*/
-int iscsi_connection_save_incoming_key_value_pairs(iscsi_connection *conn, iscsi_hashmap *key_value_pairs, iscsi_login_response_packet *login_response_pkt, const iscsi_login_req_packet *login_req_pkt)
+int iscsi_connection_save_incoming_key_value_pairs(iscsi_connection *conn, iscsi_hashmap *key_value_pairs, iscsi_pdu *login_response_pdu, const iscsi_pdu *pdu)
{
- const uint32_t ds_idx = (const uint32_t) sizeof(struct iscsi_bhs_packet) + ((const uint32_t) login_req_pkt->total_ahs_len << 2UL) + conn->header_digest;
- const uint8_t *login_data = ((uint8_t *) login_req_pkt) + ds_idx;
- const uint32_t login_len = iscsi_get_be24(login_req_pkt->ds_len);
+ iscsi_login_req_packet *login_req_pkt = (iscsi_login_req_packet *) pdu->bhs_pkt;
+ iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt;
+ const int rc = iscsi_parse_key_value_pairs( key_value_pairs, (uint8_t *) pdu->ds_cmd_data, pdu->ds_len, ((login_req_pkt->flags & ISCSI_LOGIN_REQ_FLAGS_CONTINUE) != 0), &conn->partial_pairs );
- if ( iscsi_parse_key_value_pairs( key_value_pairs, login_data, login_len, ((login_req_pkt->flags & ISCSI_LOGIN_REQ_FLAGS_CONTINUE) != 0), &conn->partial_pairs ) < 0L ) {
+ if ( rc < 0 ) {
login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISC;
- return -1L;
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER;
}
- return 0L;
+ return ISCSI_CONNECT_PDU_READ_OK;
}
/**
@@ -3022,11 +3289,11 @@ static inline uint64_t iscsi_connection_get_isid(const iscsi_isid *isid)
* in which case the status class and detail are
* set as well.
*/
-static int iscsi_connection_login_init_port(iscsi_connection *conn, iscsi_pdu *response_pdu, const iscsi_hashmap *key_value_pairs, uint8_t **init_port_name)
+static int iscsi_connection_login_init_port(iscsi_connection *conn, iscsi_pdu *response_pdu, iscsi_hashmap *key_value_pairs, uint8_t **init_port_name)
{
iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) response_pdu->bhs_pkt;
uint8_t *init_name;
- int rc = iscsi_get_key_value_pair( key_value_pairs, ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_INITIATOR_NAME, &init_name );
+ int rc = iscsi_get_key_value_pair( key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_INITIATOR_NAME, &init_name );
if ( rc != 0 ) {
login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
@@ -3056,38 +3323,248 @@ static int iscsi_connection_login_init_port(iscsi_connection *conn, iscsi_pdu *r
return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
}
- return 0L;
+ return ISCSI_CONNECT_PDU_READ_OK;
}
/**
- * @brief Creates a rejecting login response packet.
+ * @brief Determines the session type of login.
*
- * The login response structure has status detail
- * invalid login request type set.
+ * This function is used to retrieve the
+ * login session type and checks the
+ * relevant key and value pair for
+ * errors.
*
- * @param[in] login_req_pkt Pointer to iSCSI login request packet data, may NOT
- * be NULL, so be careful.
- * @return Pointer to initialized iSCSI login response packet data
- * or NULL in case of memory exhaustion.
+ * @param[in] login_response_pdu Pointer to login response PDU,
+ * NULL is not allowed, so take caution.
+ * @param[in] key_value_pairs Pointer to key and value pairs which
+ * contain the session type parameter to be evaluated,
+ * which may NOT be NULL, so take caution.
+ * @param[out] type Pointer to integer which stores the
+ * determined session type and is NOT allowed to be
+ * NULL, so be careful.
+ * @return 0 on successful operation, a negative error code
+ * otherwise. The output session 'type' is unchanged, if
+ * an invalid session type value was retrieved.
*/
-static iscsi_login_response_packet *iscsi_login_response_reject_create(const iscsi_login_req_packet *login_req_pkt)
+static int iscsi_connection_login_session_type(iscsi_pdu *login_response_pdu, iscsi_hashmap *key_value_pairs, int *type )
{
- iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) iscsi_create_packet();
+ iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt;
+ uint8_t *type_str;
+ int rc = iscsi_get_key_value_pair( key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_SESSION_TYPE, &type_str );
- if ( login_response_pkt == NULL ) {
- logadd( LOG_ERROR, "iscsi_login_response_reject_create: Out of memory while allocating iSCSI rejected login response packet data" );
+ if ( (rc == 0) && (type_str != NULL) ) {
+ if ( strcasecmp( (char *) type_str, "Discovery" ) == 0 ) {
+ *type = ISCSI_SESSION_TYPE_DISCOVERY;
+ } else if ( strcasecmp( (char *) type_str, "Normal" ) == 0 ) {
+ *type = ISCSI_SESSION_TYPE_NORMAL;
+ } else {
+ *type = ISCSI_SESSION_TYPE_INVALID;
+
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISSING_PARAMETER;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+ } else {
+ if ( login_response_pkt->tsih != 0 ) {
+ *type = ISCSI_SESSION_TYPE_NORMAL;
+ } else {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISSING_PARAMETER;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+ }
+
+ return ISCSI_CONNECT_PDU_READ_OK;
+}
+
+/**
+ * @brief Checks the target node info and sets login response PDU accordingly.
+ *
+ * This function also checks if the target node is
+ * redirected and if so, sets the response to the
+ * client response to the temporarily redirection
+ * URL.\n
+ * THe accessibility of the target node is
+ * also checked.
+ *
+ * @param[in] conn Pointer to iSCSI connection which may NOT be
+ * NULL, so be careful.
+ * @param[in] login_response_pdu Pointer to login response PDU
+ * to set the parameters for. NULL is NOT allowed
+ * here, so take caution.
+ * @param[in] target_name Pointer to target node name and may
+ * NOT be NULL, be careful.
+ * @param[out] Pointer where to store the target node belonging
+ * to the target name. May NOT be NULL, so take caution.
+ * @return 0 if the check was successful or a negative
+ * error code otherwise.
+ */
+static int iscsi_connection_login_check_target(iscsi_connection *conn, iscsi_pdu *login_response_pdu, uint8_t *target_name, iscsi_target_node **target)
+{
+ iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt;
+
+ *target = iscsi_target_node_find( target_name );
+
+ if ( *target == NULL ) {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_NOT_FOUND;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+
+ if ( ((*target)->flags & ISCSI_TARGET_NODE_FLAGS_DESTROYED) != 0 ) {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_TARGET_REMOVED;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+
+ uint8_t *redirect_adr = iscsi_target_node_get_redirect( conn, *target );
+
+ if ( redirect_adr != NULL ) {
+ if ( iscsi_add_key_value_pair( login_response_pdu->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_ADDRESS, redirect_adr ) == 0 ) {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_REDIRECT;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_REDIRECT_TEMP;
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+
+ if ( iscsi_target_node_access( conn, *target, conn->init_name, conn->init_adr ) < 0 ) {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_AUTH_FAIL;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+
+ return ISCSI_CONNECT_PDU_READ_OK;
+}
+
+/**
+ * @brief Retrieves iSCSI session by Target Session Identifying Handle (TSIH).
+ *
+ * This function checks if the TSIH is valid and if so,
+ * retrieves the pointer to its iSCSI session structure.
+ *
+ * @param[in] tsih Target Session Identifying Handle (TSIH).
+ * @return Pointer to related iSCSI session or NULL in case
+ * the TSIH is invalid or not found.
+ */
+static iscsi_session *iscsi_session_get_by_tsih(const uint16_t tsih)
+{
+ if ( tsih == 0 )
return NULL;
+
+ const uint64_t hash_key = tsih;
+ iscsi_session *session;
+ int rc = iscsi_hashmap_get( iscsi_globvec->sessions, (uint8_t *) &hash_key, sizeof(hash_key), (uint8_t **) &session );
+
+ return (rc == 0) ? session : NULL;
+}
+
+/**
+ * @brief Appends an iSCSI connection to a session.
+ *
+ * This function checks if the maximum number of
+ * connections per session is not exceeded and if
+ * there is session spanning.
+ * @param[in] conn Pointer to iSCSI connection, may NOT
+ * be NULL, so be careful.
+ * @param[in] init_port_name Pointer to initiator port name,
+ * may NOT be NULL, so take caution.
+ * @param[in] tsih Target Session Identifying Handle (TSIH).
+ * @param[in] cid Connection ID (CID).
+ * @return Upper 8 bits of contain status class, lower 8
+ * bits status detail. All 16 bits set to zero
+ * indicate success.
+ */
+static uint16_t iscsi_session_append(iscsi_connection *conn, const uint8_t *init_port_name, const uint16_t tsih, const uint16_t cid)
+{
+ iscsi_session *session = iscsi_session_get_by_tsih( tsih );
+
+ if ( (session == NULL) || (conn->pg_tag != session->tag) || (strcasecmp( (char *) init_port_name, (char *) iscsi_port_get_name( session->initiator_port ) ) != 0) || (conn->target != session->target) )
+ return (ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR << 8U) | ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_NO_SESSION_SPANNING;
+
+ if ( iscsi_hashmap_size( session->connections ) >= session->max_conns )
+ return (ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR << 8U) | ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_TOO_MANY_CONNECTIONS;
+
+ conn->session = session;
+
+ uint8_t *conn_key = iscsi_hashmap_key_create( (uint8_t *) &cid, sizeof(cid) );
+
+ if ( conn_key == NULL )
+ return (ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR << 8U) | ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES;
+
+ iscsi_hashmap_put( session->connections, conn_key, sizeof(cid), (uint8_t *) conn );
+
+ return (ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SUCCESS << 8U) | ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SUCCESS;
+}
+
+/**
+ * @brief Checks whether the session is valid.
+ *
+ * This function also appends the connection
+ * to a session if it's valid.'
+ *
+ * @param[in] conn Pointer to iSCSI connection,
+ * may NOT be NULL, so take caution.
+ * @param[in] login_response_pdu Pointer to login response PDU,
+ * NULL is not allowed, hence be careful.
+ * @param[in] init_port_name Pointer to initiator port name.
+ * Non-NULL only, so be careful.
+ * @param[in] cid Connection ID (CID).
+ * @return 0 if valid session, a negative error code
+ * otherwise.
+ */
+static int iscsi_connection_login_check_session(iscsi_connection *conn, iscsi_pdu *login_response_pdu, uint8_t *init_port_name, uint cid)
+{
+ iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt;
+ int rc = 0L;
+
+ if ( login_response_pkt->tsih != 0 ) {
+ rc = iscsi_session_append( conn, init_port_name, iscsi_get_be16(login_response_pkt->tsih), (uint16_t) cid );
+
+ if ( rc != 0 ) {
+ login_response_pkt->status_class = (uint8_t) (rc >> 8U);
+ login_response_pkt->status_detail = (uint8_t) rc;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+ } else if ( (iscsi_globvec->flags & ISCSI_GLOBALS_FLAGS_ISID_ALLOW_DUPLICATES) != 0 ) {
+ iscsi_connection_drop( conn, init_port_name, 0 );
}
+ return rc;
+}
+
+/**
+ * @brief Initializes a rejecting login response packet.
+ *
+ * The login response structure has status detail
+ * invalid login request type set.
+ *
+ * @param[in] login_response_pdu Pointer to iSCSI login response PDU,
+ * NULL is an invalid value here, so take caution.
+ * @param[in] pdu Pointer to iSCSI login request PDU, may NOT
+ * be NULL, so be careful.
+ */
+void iscsi_login_response_reject_init(iscsi_pdu *login_response_pdu, const iscsi_pdu *pdu)
+{
+ 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->version_max = ISCSI_VERSION_MAX;
login_response_pkt->version_active = ISCSI_VERSION_MAX;
- login_response_pkt->init_task_tag = login_req_pkt->init_task_tag;
+ login_response_pkt->init_task_tag = ((iscsi_login_req_packet *) pdu->bhs_pkt)->init_task_tag;
login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_INVALID_LOGIN_REQ_TYPE;
-
- return login_response_pkt;
}
/**
@@ -3124,6 +3601,14 @@ iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn)
pdu->header_digest = NULL;
pdu->ds_cmd_data = NULL;
pdu->data_digest = NULL;
+ pdu->key_value_pairs = iscsi_hashmap_create( 32UL );
+
+ if ( pdu->key_value_pairs == NULL ) {
+ free( pdu );
+
+ return NULL;
+ }
+
pdu->flags = 0L;
pdu->header_digest_size = 0L;
pdu->header_digest_read_len = 0UL;
@@ -3152,6 +3637,13 @@ iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn)
void iscsi_connection_pdu_destroy(iscsi_pdu *pdu)
{
if ( pdu != NULL ) {
+ if ( pdu->key_value_pairs != NULL ) {
+ iscsi_hashmap_iterate( pdu->key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL );
+ iscsi_hashmap_destroy( pdu->key_value_pairs );
+
+ pdu->key_value_pairs = NULL;
+ }
+
if ( pdu->bhs_pkt != NULL ) {
free( pdu->bhs_pkt );
@@ -3194,7 +3686,7 @@ void iscsi_connection_pdu_write(iscsi_connection *conn, iscsi_pdu *pdu, iscsi_co
iscsi_calc_data_digest( pdu->bhs_pkt, conn->header_digest );
}
- const uint len = sizeof(struct iscsi_bhs_packet) + pdu->ahs_len + conn->header_digest + iscsi_align(pdu->ds_len, ISCSI_ALIGN_SIZE) + conn->data_digest;
+ const uint len = (uint) (sizeof(struct iscsi_bhs_packet) + pdu->ahs_len + conn->header_digest + iscsi_align(pdu->ds_len, ISCSI_ALIGN_SIZE) + conn->data_digest);
// TODO: Do the writing in a queue.
iscsi_connection_write( conn, (uint8_t *) pdu->bhs_pkt, len );
@@ -3230,7 +3722,7 @@ static int iscsi_connection_handle_reject(iscsi_connection *conn, iscsi_pdu *pdu
return -1L;
}
- const uint32_t ds_len = sizeof(struct iscsi_bhs_packet) + ((uint32_t) pdu->bhs_pkt->total_ahs_len << 2UL) + conn->header_digest;
+ const uint32_t ds_len = (uint32_t) sizeof(struct iscsi_bhs_packet) + ((uint32_t) pdu->bhs_pkt->total_ahs_len << 2UL) + conn->header_digest;
iscsi_reject_packet *reject_pkt = (iscsi_reject_packet *) iscsi_append_ds_packet( pdu->bhs_pkt, conn->header_digest, ds_len, conn->data_digest );
if ( reject_pkt == NULL ) {
@@ -3244,31 +3736,31 @@ static int iscsi_connection_handle_reject(iscsi_connection *conn, iscsi_pdu *pdu
response_pdu->bhs_pkt = (iscsi_bhs_packet *) reject_pkt;
if ( conn->header_digest != 0 ) {
- response_pdu->header_digest = ((iscsi_bhs_packet *) reject_pkt) + 1;
+ response_pdu->header_digest = (iscsi_header_digest *) (((iscsi_bhs_packet *) reject_pkt) + 1);
response_pdu->header_digest_size = conn->header_digest;
}
- response_pdu->ds_cmd_data = ((uint8_t *) reject_pkt) + sizeof(struct iscsi_bhs_packet) + conn->header_digest;
+ response_pdu->ds_cmd_data = (iscsi_ds_cmd_data *) (((uint8_t *) reject_pkt) + sizeof(struct iscsi_bhs_packet) + conn->header_digest);
response_pdu->ds_len = ds_len;
if ( conn->data_digest != 0 ) {
- response_pdu->data_digest = ((uint8_t *) response_pdu->ds_cmd_data) + iscsi_align(ds_len, ISCSI_ALIGN_SIZE);
+ response_pdu->data_digest = (iscsi_data_digest *) (((uint8_t *) response_pdu->ds_cmd_data) + iscsi_align(ds_len, ISCSI_ALIGN_SIZE));
response_pdu->data_digest_size = conn->data_digest;
}
reject_pkt->opcode = ISCSI_SERVER_REJECT;
reject_pkt->flags |= -0x80;
- reject_pkt->reason = reason_code;
- iscsi_put_be24( &reject_pkt->ds_len, ds_len );
+ reject_pkt->reason = (uint8_t) reason_code;
+ iscsi_put_be24( (uint8_t *) &reject_pkt->ds_len, ds_len );
reject_pkt->tag = 0xFFFFFFFFUL;
- iscsi_put_be32( &reject_pkt->stat_sn, conn->stat_sn++ );
+ iscsi_put_be32( (uint8_t *) &reject_pkt->stat_sn, conn->stat_sn++ );
if ( conn->session != NULL ) {
- iscsi_put_be32( &reject_pkt->exp_cmd_sn, conn->session->exp_cmd_sn );
- iscsi_put_be32( &reject_pkt->max_cmd_sn, conn->session->max_cmd_sn );
+ iscsi_put_be32( (uint8_t *) &reject_pkt->exp_cmd_sn, conn->session->exp_cmd_sn );
+ iscsi_put_be32( (uint8_t *) &reject_pkt->max_cmd_sn, conn->session->max_cmd_sn );
} else {
- iscsi_put_be32( &reject_pkt->exp_cmd_sn, 1 );
- iscsi_put_be32( &reject_pkt->max_cmd_sn, 1 );
+ iscsi_put_be32( (uint8_t *) &reject_pkt->exp_cmd_sn, 1 );
+ iscsi_put_be32( (uint8_t *) &reject_pkt->max_cmd_sn, 1 );
}
memcpy( ((uint8_t *) reject_pkt) + sizeof(struct iscsi_bhs_packet), pdu->bhs_pkt, ds_len );
@@ -3331,9 +3823,9 @@ static int iscsi_connection_pdu_header_handle_login_req(iscsi_connection *conn,
if ( login_response_pdu == NULL )
return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
- iscsi_login_response_packet *login_response_pkt = iscsi_login_response_create( conn, pdu );
+ const int rc = iscsi_login_response_init( login_response_pdu, pdu );
- if ( login_response_pkt == NULL ) {
+ if ( rc < 0 ) {
iscsi_connection_pdu_login_response( conn, login_response_pdu, NULL, iscsi_connection_pdu_login_err_complete );
return ISCSI_CONNECT_PDU_READ_OK;
@@ -3529,8 +4021,7 @@ static int iscsi_connection_pdu_header_handle(iscsi_connection *conn, iscsi_pdu
if ( login_response_pdu == NULL )
return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
- iscsi_login_response_packet *login_response_pkt = iscsi_login_response_reject_create( (iscsi_login_req_packet *) pdu->bhs_pkt );
-
+ iscsi_login_response_reject_init( login_response_pdu, pdu );
iscsi_connection_pdu_write( conn, login_response_pdu, NULL, NULL );
return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
@@ -3634,6 +4125,373 @@ static int iscsi_connection_pdu_data_handle_scsi_cmd(iscsi_connection *conn, isc
}
/**
+ * @brief Allocates and replaces a string value to a key / value hash map pair.
+ *
+ * This function allocates memory for a string key
+ * and its string value and replaces a original
+ * key and value pair if it exists.
+ *
+ * @param[in] conn Pointer to iSCSI connection to update the
+ * login key and value pair for and may NOT
+ * be NULL, so take care.
+ * @param[in] key_value_pairs Pointer to the hash map which should
+ * contain the replaced string key and value pair. NULL is NOT
+ * allowed here, so be careful.
+ * @param[in] key String containing the key name as string. May
+ * NOT be NULL, so take caution.
+ * @param[in] value String containing the value to be stored.
+ * @return 0 on successful operation, or a negative value on
+ * error (memory exhaustion).
+ */
+static int iscsi_connection_login_update_key_value_pair(iscsi_connection *conn, const uint8_t *key, const uint8_t *value)
+{
+ const uint key_len = (uint) strlen( (char *) key ) + 1;
+ uint8_t *hash_key = iscsi_hashmap_key_create( key, key_len );
+
+ if ( hash_key == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_login_update_key_value_pair: Out of memory allocating key." );
+
+ return -1L;
+ }
+
+ const uint val_len = (uint) strlen( (char *) value ) + 1;
+ uint8_t *hash_val = (uint8_t *) malloc( val_len );
+
+ if ( hash_val == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_login_update_key_value_pair: Out of memory allocating string value." );
+
+ return -1L;
+ }
+
+ memcpy( hash_val, value, val_len );
+
+ return iscsi_hashmap_put_free( conn->key_value_pairs, hash_key, key_len, hash_val, iscsi_hashmap_key_destroy_value_callback, NULL );
+}
+
+/**
+ * @brief Negotiates connection authentication method (none or CHAP).
+ *
+ * This function updates the key and value pairs if, and only if
+ * CHAP is either disabled or required.
+ *
+ * @param[in] conn Pointer to iSCSI connection to update the key
+ * and value pairs for. May NOT be NULL, so be careful.
+ * @return 0 on successful update, a negative error code otherwise.
+ */
+static int iscsi_connection_chap_negotiate(iscsi_connection *conn)
+{
+ int rc = 0;
+
+ if ( (conn->flags & ISCSI_CONNECT_FLAGS_CHAP_DISABLE) != 0 )
+ rc = iscsi_connection_login_update_key_value_pair( conn, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_AUTH_METHOD, (uint8_t *) "None" );
+ else if ( (conn->flags & ISCSI_CONNECT_FLAGS_CHAP_REQUIRE) != 0 )
+ rc = iscsi_connection_login_update_key_value_pair( conn, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_AUTH_METHOD, (uint8_t *) "CHAP" );
+
+ return rc;
+}
+
+/**
+ * @brief Discovers iSCSI CHAP authentication session.
+ *
+ * This function copies over the global CHAP configuration
+ * into the iSCSI connection structure and then negotiates.
+ *
+ * @param[in] conn Pointer to iSCSI connection for iSCSI
+ * CHAP authentication discovery. May NOT be
+ * NULL, so be careful.
+ * @return 0 on successful negotiation, a negative error
+ * code otherwise.
+ */
+static int iscsi_connection_login_session_chap_discovery(iscsi_connection *conn)
+{
+ conn->flags &= ~(ISCSI_CONNECT_FLAGS_CHAP_DISABLE | ISCSI_CONNECT_FLAGS_CHAP_REQUIRE | ISCSI_CONNECT_FLAGS_CHAP_MUTUAL);
+
+ if ( (iscsi_globvec->flags & ISCSI_GLOBALS_FLAGS_CHAP_DISABLE) != 0 )
+ conn->flags |= ISCSI_CONNECT_FLAGS_CHAP_DISABLE;
+
+ if ( (iscsi_globvec->flags & ISCSI_GLOBALS_FLAGS_CHAP_REQUIRE) != 0 )
+ conn->flags |= ISCSI_CONNECT_FLAGS_CHAP_REQUIRE;
+
+ if ( (iscsi_globvec->flags & ISCSI_GLOBALS_FLAGS_CHAP_MUTUAL) != 0 )
+ conn->flags |= ISCSI_CONNECT_FLAGS_CHAP_MUTUAL;
+
+ conn->chap_group = iscsi_globvec->chap_group;
+
+ return iscsi_connection_chap_negotiate( conn );
+}
+
+/**
+ * @brief Negotiates CHAP authentication.
+ *
+ * This function updates the key and value pairs if, and only if
+ * CHAP authentication is either disabled or required in the
+ * target node.
+ *
+ * @param[in] conn Pointer to iSCSI connection to update the key
+ * and value pairs for. May NOT be NULL, so be careful.
+ * @param[in] target Pointer to iSCSI target node used to check
+ * the CHAP authentication. NULL is not allowed here,
+ * so take caution.
+ * @return 0 on successful update, a negative error code otherwise.
+ */
+static int iscsi_connection_login_chap_negotiate(iscsi_connection *conn, const iscsi_target_node *target)
+{
+ conn->flags &= ~(ISCSI_CONNECT_FLAGS_CHAP_DISABLE | ISCSI_CONNECT_FLAGS_CHAP_REQUIRE | ISCSI_CONNECT_FLAGS_CHAP_MUTUAL);
+
+ if ( (target->flags & ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE) != 0 )
+ conn->flags |= ISCSI_CONNECT_FLAGS_CHAP_DISABLE;
+
+ if ( (target->flags & ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE) != 0 )
+ conn->flags |= ISCSI_CONNECT_FLAGS_CHAP_REQUIRE;
+
+ if ( (target->flags & ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL) != 0 )
+ conn->flags |= ISCSI_CONNECT_FLAGS_CHAP_MUTUAL;
+
+ conn->chap_group = target->chap_group;
+
+ return iscsi_connection_chap_negotiate( conn );
+}
+
+/**
+ * @brief Negotiates connection header and data digest (CRC32C).
+ *
+ * This function updates the key and value pairs if, and only if
+ * header and data digests are enabled in the target node.
+ *
+ * @param[in] conn Pointer to iSCSI connection to update the key
+ * and value pairs for. May NOT be NULL, so be careful.
+ * @param[in] target Pointer to iSCSI target node used to check
+ * the digest status. NULL is not allowed here, so take
+ * caution.
+ * @return 0 on successful update, a negative error code otherwise.
+ */
+static int iscsi_connection_login_digest_negotiate(iscsi_connection *conn, const iscsi_target_node *target)
+{
+ if ( target->header_digest != 0 ) {
+ const int rc = iscsi_connection_login_update_key_value_pair( conn, (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_HEADER_DIGEST, (uint8_t *) "CRC32C" );
+
+ return rc;
+ }
+
+ if ( target->data_digest != 0 ) {
+ const int rc = iscsi_connection_login_update_key_value_pair( conn, (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_DATA_DIGEST, (uint8_t *) "CRC32C" );
+
+ return rc;
+ }
+
+ return 0L;
+}
+
+/**
+ * @brief Determines iSCSI session login steps for normal authentication.
+ *
+ * This function also does related validation checks.
+ *
+ * @param[in] conn Pointer to iSCSI connection, may NOT be
+ * NULL, so take caution.
+ * @param[in] login_response_pdu Pointer to login response PDU where
+ * NULL is not allowed, so be careful.
+ * @param[in] key_value_pairs Pointer to hash map containing the login
+ * request key and value pairs and may NOT be NULL, so
+ * take caution.
+ * @param[in] init_port_name Pointer to iSCSI initiator port name. NULL
+ * is NOT an allowed value, so be careful.
+ * @param[in] cid Connection ID (CID).
+ * @return 0 on successful operation, a negative error code
+ * otherwise.
+ */
+static int iscsi_connection_login_session_normal(iscsi_connection *conn, iscsi_pdu *login_response_pdu, iscsi_hashmap *key_value_pairs, uint8_t *init_port_name, const uint cid)
+{
+ iscsi_target_node *target = NULL;
+ uint8_t *target_name;
+ iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt;
+ int rc = iscsi_get_key_value_pair( key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_NAME, &target_name );
+
+ if ( (rc < 0) || (target_name == NULL) ) {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISSING_PARAMETER;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+
+ const uint8_t *target_name_short = (uint8_t *) strstr( (char *) target_name, ":" );
+
+ conn->target_name_short = iscsi_sprintf_alloc( "%s", ((target_name_short != NULL) ? ++target_name_short : target_name) );
+
+ if ( conn->target_name_short == NULL ) {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+
+ rc = iscsi_connection_login_check_target( conn, login_response_pdu, target_name, &target );
+
+ if ( rc < 0 )
+ return rc;
+
+ conn->device = target->device;
+ conn->target = target;
+ conn->target_port = iscsi_device_find_port_by_portal_group_tag( target->device, conn->pg_tag );
+
+ rc = iscsi_connection_login_check_session( conn, login_response_pdu, init_port_name, cid );
+
+ if ( rc < 0 )
+ return rc;
+
+ rc = iscsi_connection_login_chap_negotiate( conn, target );
+
+ if ( rc == 0 )
+ rc = iscsi_connection_login_digest_negotiate( conn, target );
+
+ if (rc != 0) {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_INVALID_LOGIN_REQ_TYPE;
+ }
+
+ return rc;
+}
+
+/*
+ * This function is used to set the info in the connection data structure
+ * return
+ * 0: success
+ * otherwise: error
+ */
+static int iscsi_connection_login_set_info(iscsi_connection *conn, iscsi_pdu *login_response_pdu, const uint8_t *init_port_name, const int type, const uint cid)
+{
+ conn->flags &= ~ISCSI_CONNECT_FLAGS_AUTH;
+ conn->auth_chap.phase = ISCSI_AUTH_CHAP_PHASE_WAIT_A;
+ conn->cid = (uint16_t) cid;
+
+ if ( conn->session == NULL ) {
+ iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt;
+ iscsi_target_node *target = conn->target;
+ const uint64_t isid = iscsi_connection_get_isid( &login_response_pkt->isid );
+ iscsi_port *init_port = iscsi_port_create( init_port_name, isid, 0U );
+
+ if ( init_port == NULL ) {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+
+ conn->session = iscsi_session_create( conn, target, type );
+
+ if ( conn->session == NULL ) {
+ iscsi_port_destroy( init_port );
+
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+
+ conn->session->initiator_port = init_port;
+ conn->stat_sn = iscsi_get_be32(login_response_pkt->stat_sn);
+ conn->session->isid = isid;
+
+ const int rc = iscsi_port_transport_id_set( conn->session->initiator_port, conn->init_name, isid );
+
+ if ( rc < 0 ) {
+ iscsi_session_destroy( conn->session );
+ conn->session = NULL;
+
+ iscsi_port_destroy( init_port );
+
+ return rc;
+ }
+
+ conn->session->queue_depth = (target != NULL) ? target->queue_depth : 1UL;
+ conn->session->exp_cmd_sn = login_response_pdu->cmd_sn;
+ conn->session->max_cmd_sn = login_response_pdu->cmd_sn + conn->session->queue_depth - 1;
+ }
+
+ conn->init_port = conn->session->initiator_port;
+
+ return ISCSI_CONNECT_PDU_READ_OK;
+}
+
+/**
+ * @brief Sets iSCSI session target info key and value pairs.
+ *
+ * This function also sets the login response PDU
+ * key and value pairs.
+ *
+ * @param[in] conn Pointer to iSCSI connection of which
+ * the target info should be set, may NOT be NULL,
+ * so take caution.
+ * @param[in] login_response_pdu Pointer to login response PDU and
+ * NULL is not allowed here, so be careful.
+ * @param[in] type iSCSI session type.
+ * @return 0 on successfully setting target info, a
+ * negative error code otherwise.
+ */
+static int iscsi_connection_login_set_target_info(iscsi_connection *conn, iscsi_pdu *login_response_pdu, const int type)
+{
+ iscsi_target_node *target = conn->target;
+ int rc;
+
+ if ( target != NULL ) {
+ rc = iscsi_add_key_value_pair( conn->session->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_ALIAS, ((target->alias != NULL) ? target->alias : (uint8_t *) "") );
+
+ if ( rc < 0 )
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER;
+ }
+
+ uint8_t *tmp_buf = iscsi_sprintf_alloc( "%s:%s,%d", conn->portal_host, conn->portal_port, conn->pg_tag );
+
+ if ( tmp_buf == NULL )
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+
+ rc = iscsi_add_key_value_pair( conn->session->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_ADDRESS, tmp_buf );
+
+ free( tmp_buf );
+
+ if ( rc < 0 )
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER;
+
+ rc = iscsi_add_int_key_value_pair( conn->session->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_PORTAL_GROUP_TAG, conn->pg_tag );
+
+ if ( rc < 0 )
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER;
+
+ if ( target != NULL ) {
+ rc = iscsi_get_key_value_pair( conn->session->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_ALIAS, &tmp_buf );
+
+ if ( (rc == 0) && (strlen( (char *) tmp_buf ) != 0) ) {
+ rc = iscsi_add_key_value_pair( login_response_pdu->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_ALIAS, tmp_buf );
+
+ if ( rc < 0 )
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+
+ if ( type == ISCSI_SESSION_TYPE_DISCOVERY ) {
+ rc = iscsi_get_key_value_pair( conn->session->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_ADDRESS, &tmp_buf );
+
+ if ( (rc == 0) && (strlen( (char *) tmp_buf ) != 0) ) {
+ rc = iscsi_add_key_value_pair( login_response_pdu->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_ADDRESS, tmp_buf );
+
+ if ( rc < 0 )
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+ }
+
+ rc = iscsi_get_key_value_pair( conn->session->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_PORTAL_GROUP_TAG, &tmp_buf );
+
+ if ( rc == 0 ) {
+ rc = iscsi_add_key_value_pair( login_response_pdu->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_PORTAL_GROUP_TAG, tmp_buf );
+
+ if ( rc < 0 )
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+ }
+
+ return ISCSI_CONNECT_PDU_READ_OK;
+}
+
+/**
* @brief Handles iSCSI connection login phase none.
*
* This function negotiates the login phase
@@ -3650,9 +4508,55 @@ static int iscsi_connection_pdu_data_handle_scsi_cmd(iscsi_connection *conn, isc
*/
static int iscsi_connection_handle_login_phase_none(iscsi_connection *conn, iscsi_pdu *login_response_pdu, iscsi_hashmap *key_value_pairs, uint cid)
{
- // TODO: Implement function.
+ uint8_t *init_port_name;
+ iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt;
- return 0L;
+ conn->device = NULL;
+ conn->target = NULL;
+
+ int rc = iscsi_connection_login_init_port( conn, login_response_pdu, key_value_pairs, &init_port_name );
+
+ if ( rc < 0 )
+ return rc;
+
+ int type;
+
+ rc = iscsi_connection_login_session_type( login_response_pdu, key_value_pairs, &type );
+
+ if ( rc < 0 )
+ return rc;
+
+ if ( type == ISCSI_SESSION_TYPE_NORMAL ) {
+ rc = iscsi_connection_login_session_normal( conn, login_response_pdu, key_value_pairs, init_port_name, cid );
+ } else if ( type == ISCSI_SESSION_TYPE_DISCOVERY ) {
+ login_response_pkt->tsih = 0U;
+
+ rc = iscsi_connection_login_session_chap_discovery( conn );
+ } else {
+ login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR;
+ login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISSING_PARAMETER;
+
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE;
+ }
+
+ if ( rc < 0 )
+ return rc;
+
+ rc = iscsi_connection_login_set_info( conn, login_response_pdu, init_port_name, type, cid );
+
+ if ( rc < 0 )
+ return rc;
+
+ if ( type == ISCSI_SESSION_TYPE_DISCOVERY ) {
+ conn->session->max_conns = 1;
+
+ rc = iscsi_add_int_key_value_pair( conn->session->key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_MAX_CONNECTIONS, conn->session->max_conns );
+
+ if ( rc < 0 )
+ return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER;
+ }
+
+ return iscsi_connection_login_set_target_info( conn, login_response_pdu, type );
}
/**
@@ -3705,7 +4609,7 @@ static int iscsi_connection_pdu_data_handle_login_req(iscsi_connection *conn, is
iscsi_login_req_packet *login_req_pkt = (iscsi_login_req_packet *) pdu->bhs_pkt;
uint cid = iscsi_get_be16(login_req_pkt->cid);
- int rc = iscsi_connection_save_incoming_key_value_pairs( conn, key_value_pairs, pdu, login_response_pdu );
+ int rc = iscsi_connection_save_incoming_key_value_pairs( conn, key_value_pairs, login_response_pdu, pdu );
if ( rc < 0 ) {
iscsi_connection_pdu_login_response( conn, login_response_pdu, NULL, iscsi_connection_pdu_login_err_complete );
@@ -3933,12 +4837,12 @@ static int iscsi_connection_pdu_read(iscsi_connection *conn)
if ( pdu->ahs_read_len < ahs_len ) {
if ( pdu->ahs_pkt == NULL ) {
- pdu->ahs_pkt = iscsi_append_ahs_packet( pdu->bhs_pkt, (uint32_t) ahs_len );
+ pdu->ahs_pkt = (iscsi_ahs_packet *) iscsi_append_ahs_packet( pdu->bhs_pkt, (uint32_t) ahs_len );
if ( pdu->ahs_pkt == NULL )
return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
- pdu->ahs_pkt = ((iscsi_bhs_packet *) pdu->bhs_pkt) + 1;
+ pdu->ahs_pkt = (iscsi_ahs_packet *) (((iscsi_bhs_packet *) pdu->bhs_pkt) + 1);
}
const int len = iscsi_connection_read( conn, (((uint8_t *) pdu->ahs_pkt) + pdu->ahs_read_len), (ahs_len - pdu->ahs_read_len) );
@@ -3957,12 +4861,12 @@ static int iscsi_connection_pdu_read(iscsi_connection *conn)
if ( conn->header_digest != 0 ) {
if ( pdu->header_digest == NULL ) {
- pdu->header_digest = iscsi_append_header_digest_packet( pdu->bhs_pkt, ISCSI_DIGEST_SIZE );
+ pdu->header_digest = (iscsi_header_digest *) iscsi_append_header_digest_packet( pdu->bhs_pkt, ISCSI_DIGEST_SIZE );
if ( pdu->header_digest == NULL )
return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
- pdu->header_digest = ((uint8_t *) pdu->bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len;
+ pdu->header_digest = (iscsi_header_digest *) (((uint8_t *) pdu->bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len);
}
if ( pdu->header_digest_read_len < (uint) conn->header_digest ) {
diff --git a/src/server/iscsi.h b/src/server/iscsi.h
index c167987..56e09f9 100644
--- a/src/server/iscsi.h
+++ b/src/server/iscsi.h
@@ -36,7 +36,7 @@
#if defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN) || (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define iscsi_get_be16(x) (x)
-#define iscsi_get_be24(x) ((x) & 0xFFFFFFUL)
+#define iscsi_get_be24(x) (iscsi_get_be32((*(uint32_t *) ((uint8_t *) x - 1))) & 0xFFFFFFUL)
#define iscsi_get_be32(x) (x)
#define iscsi_get_be64(x) (x)
@@ -64,18 +64,20 @@ static inline void iscsi_put_be64(uint8_t *data, const uint64_t val)
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
// GCC or CLang
#define iscsi_get_be16(x) (__builtin_bswap16(x))
-#define iscsi_get_be24(x) (iscsi_get_be32(x) & 0xFFFFFFUL)
+#define iscsi_get_be24(x) (iscsi_get_be32((*(uint32_t *) ((uint8_t *) x - 1))) & 0xFFFFFFUL)
#define iscsi_get_be32(x) (__builtin_bswap32(x))
#define iscsi_get_be64(x) (__builtin_bswap64(x))
#elif defined(_MSC_VER)
#include <intrin.h>
// MVSC
#define iscsi_get_be16(x) (_byteswap_ushort(x))
+#define iscsi_get_be24(x) (iscsi_get_be32((*(uint32_t *) ((uint8_t *) x - 1))) & 0xFFFFFFUL)
#define iscsi_get_be32(x) (_byteswap_ulong(x))
#define iscsi_get_be64(x) (_byteswap_uint64(x))
#else
// Other compilers (use slow conversion method with bit rotation, bit shift and logcal AND)
#define iscsi_get_be16(x) ((((uint16_t) (x)) << 8U) | (((uint16_t) (x)) >> 8U))
+#define iscsi_get_be24(x) (iscsi_get_be32((*(uint32_t *) ((uint8_t *) x - 1))) & 0xFFFFFFUL)
#define iscsi_get_be32(x) ((((uint32_t) (x) & 0xFFUL) << 24UL) | (((uint32_t) (x) & 0xFF00UL) << 8UL) | (((uint32_t) (x) & 0xFF0000UL) >> 8UL) | (((uint32_t) (x) >> 24UL)))
#define iscsi_get_be64(x) ((uint64_t)((((x) & 0xFFULL) << 56ULL) | (((x) & 0xFF00ULL) << 40ULL) | (((x) & 0xFF0000ull) << 24ULL) | (((x) & 0xFF000000ULL) << 8ULL) | (((x) & 0xFF00000000ULL) >> 8ULL) | (((x) & 0xFF0000000000ULL) >> 24ULL) | (((x) & 0xFF000000000000ULL) >> 40ULL) | (((x) & 0xFF00000000000000ULL) >> 56ULL)))
#endif
@@ -234,9 +236,9 @@ uint8_t *iscsi_hashmap_key_create(const uint8_t *data, const size_t len); // Cre
void iscsi_hashmap_key_destroy(uint8_t *key); // Deallocates all resources acquired by iscsi_hashmap_create_key
int iscsi_hashmap_key_destroy_value_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Deallocates all key / value pairs in a hash map by calling free (default destructor)
-int iscsi_hashmap_put(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t *value); // Assigns key / value pair to hash map without making copies
-int iscsi_hashmap_get_put(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t **out_in_value); // Assigns key / value pair to hash map without making copies
-int iscsi_hashmap_put_free(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t *value, iscsi_hashmap_callback callback, uint8_t *user_data); // Assigns key / value pair to hash map without making copies
+int iscsi_hashmap_put(iscsi_hashmap *map, uint8_t *key, const size_t key_size, uint8_t *value); // Assigns key / value pair to hash map without making copies
+int iscsi_hashmap_get_put(iscsi_hashmap *map, uint8_t *key, const size_t key_size, uint8_t **out_in_value); // Assigns key / value pair to hash map without making copies
+int iscsi_hashmap_put_free(iscsi_hashmap *map, uint8_t *key, const size_t key_size, uint8_t *value, iscsi_hashmap_callback callback, uint8_t *user_data); // Assigns key / value pair to hash map without making copies
// with callback function in case the key already exists
int iscsi_hashmap_contains(iscsi_hashmap *map, const uint8_t *key, const size_t key_size); // Checks whether a specified key exists
int iscsi_hashmap_get(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, uint8_t **out_value); // Retrieves the value of a specified key
@@ -244,7 +246,7 @@ int iscsi_hashmap_get(iscsi_hashmap *map, const uint8_t *key, const size_t key_s
void iscsi_hashmap_remove(iscsi_hashmap *map, const uint8_t *key, const size_t key_size); // Marks an element for removal by setting key and value both to NULL
void iscsi_hashmap_remove_free(iscsi_hashmap *map, const uint8_t *key, const size_t key_size, iscsi_hashmap_callback callback, uint8_t *user_data); // Marks an element for removal by setting key and value both to NULL,
// but invokes a callback function before actual marking for removal.
-int iscsi_hashmap_size(iscsi_hashmap *map); // Retrieves the number of elements of the hash map, ignoring elements marked for removal
+uint iscsi_hashmap_size(const iscsi_hashmap *map); // Retrieves the number of elements of the hash map, ignoring elements marked for removal
int iscsi_hashmap_iterate(iscsi_hashmap *map, iscsi_hashmap_callback callback, uint8_t *user_data); // Iterator with callback function invoked on each element which has not been removed
@@ -5607,6 +5609,28 @@ typedef struct __attribute__((packed)) iscsi_nop_in_packet {
} iscsi_nop_in_packet;
+/// iSCSI SCSI transport ID protocol identifier.
+#define ISCSI_TRANSPORT_ID_PROTOCOL_ID_ISCSI 0x05
+
+/// iSCSI SCSI transport ID format.
+#define ISCSI_TRANSPORT_ID_FORMAT 0x01
+
+
+typedef struct __attribute__((packed)) iscsi_transport_id {
+ /// First 4 bits are protocol ID and last 2 bits are format.
+ uint8_t id;
+
+ /// Reserved for future usage (always MUST be 0).
+ uint8_t reserved;
+
+ /// Additional length of name.
+ uint16_t add_len;
+
+ /// Name.
+ uint8_t name[0];
+} iscsi_transport_id;
+
+
/// iSCSI packet validation return code from iscsi_validate_packet function: Validation successful -> iSCSI packet recognized and compliance to protocol specification.
#define ISCSI_VALIDATE_PACKET_RESULT_OK 0L
@@ -5726,30 +5750,20 @@ typedef struct iscsi_key_value_pair_packet {
int iscsi_parse_key_value_pairs(iscsi_hashmap *pairs, const uint8_t *packet_data, uint len, int c_bit, uint8_t **partial_pairs); // Extracts all text key / value pairs out of an iSCSI packet into a hash map
int iscsi_create_key_value_pair_packet_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Creates a single partial iSCSI packet stream out of a single text key and value pair
-iscsi_key_value_pair_packet *iscsi_create_key_value_pairs_packet(const iscsi_hashmap *pairs); // Creates a properly aligned iSCSI packet DataSegment out of a hash map containing text key and value pairs
+iscsi_key_value_pair_packet *iscsi_create_key_value_pairs_packet(iscsi_hashmap *key_value_pairs); // Creates a properly aligned iSCSI packet DataSegment out of a hash map containing text key and value pairs
-/**
- * @brief iSCSI portal group: Private portal group if set, public otherwise.
- *
- * When redirecting logins, there are two portal group types: public and
- * private.\n
- * Public portal groups return their portals during discovery session.
- * A redirection private portal may also be specified for non-discovery
- * logins.\n
- * Private portal groups instead do not return their portals during
- * the discovery session.
- */
-#define ISCSI_PORTAL_GROUP_PRIVATE (1 << 0)
+/// iSCSI main global data flags: Allow duplicate ISIDs.
+#define ISCSI_GLOBALS_FLAGS_ISID_ALLOW_DUPLICATES (1 << 0L)
-/// iSCSI portal group: CHAP authentication is disabled.
-#define ISCSI_PORTAL_GROUP_CHAP_DISABLE (1 << 1)
+/// iSCSI main global data flags: CHAP authentication is disabled.
+#define ISCSI_GLOBALS_FLAGS_CHAP_DISABLE (1 << 1L)
-/// iSCSI portal group: CHAP authentication is required.
-#define ISCSI_PORTAL_GROUP_CHAP_REQUIRE (1 << 2)
+/// iSCSI main global data flags: CHAP authentication is required.
+#define ISCSI_GLOBALS_FLAGS_CHAP_REQUIRE (1 << 2L)
-/// iSCSI portal group: Mutual.
-#define ISCSI_PORTAL_GROUP_CHAP_MUTUAL (1 << 3)
+/// iSCSI main global data flags: CHAP authentication is mutual.
+#define ISCSI_GLOBALS_FLAGS_CHAP_MUTUAL (1 << 3L)
/**
@@ -5759,6 +5773,9 @@ iscsi_key_value_pair_packet *iscsi_create_key_value_pairs_packet(const iscsi_has
* connections are stored here for global access.
*/
typedef struct iscsi_globals {
+ /// Hash map containing all iSCSI devices.
+ iscsi_hashmap *devices;
+
/// Hash map containing all registered iSCSI portal groups.
iscsi_hashmap *portal_groups;
@@ -5770,9 +5787,45 @@ typedef struct iscsi_globals {
/// Hash map containing connections not associated with an iSCSI sessions.
iscsi_hashmap *connections;
+
+ /// Global flags.
+ int flags;
+
+ /// Maximum number of allowed sessions.
+ uint max_sessions;
+
+ /// CHAP group id.
+ int32_t chap_group;
} iscsi_globals;
+/// iSCSI vector for global access.
+iscsi_globals *iscsi_globvec = NULL;
+
+
+/**
+ * @brief iSCSI portal group: Private portal group if set, public otherwise.
+ *
+ * When redirecting logins, there are two portal group types: public and
+ * private.\n
+ * Public portal groups return their portals during discovery session.
+ * A redirection private portal may also be specified for non-discovery
+ * logins.\n
+ * Private portal groups instead do not return their portals during
+ * the discovery session.
+ */
+#define ISCSI_PORTAL_GROUP_PRIVATE (1 << 0L)
+
+/// iSCSI portal group: CHAP authentication is disabled.
+#define ISCSI_PORTAL_GROUP_CHAP_DISABLE (1 << 1L)
+
+/// iSCSI portal group: CHAP authentication is required.
+#define ISCSI_PORTAL_GROUP_CHAP_REQUIRE (1 << 2L)
+
+/// iSCSI portal group: CHAP authentication is mutual.
+#define ISCSI_PORTAL_GROUP_CHAP_MUTUAL (1 << 3L)
+
+
/**
* @brief iSCSI portal group.
*
@@ -5827,7 +5880,7 @@ void iscsi_portal_destroy(iscsi_portal *portal);
/// ISCSI port flags: In use.
-#define ISCSI_PORT_FLAGS_IN_USE (1 << 0)
+#define ISCSI_PORT_FLAGS_IN_USE (1 << 0L)
/**
@@ -5839,7 +5892,7 @@ void iscsi_portal_destroy(iscsi_portal *portal);
*/
typedef struct iscsi_port {
/// Transport ID.
- uint8_t *transport_id;
+ iscsi_transport_id *transport_id;
/// Name.
uint8_t *name;
@@ -5861,12 +5914,15 @@ typedef struct iscsi_port {
iscsi_port *iscsi_port_create(const uint8_t *name, const uint64_t id, const uint16_t index); // Allocates and initializes an iSCSI port
void iscsi_port_destroy(iscsi_port *port); // Deallocates all resource acquired iscsi_port_create
+uint8_t *iscsi_port_get_name(const iscsi_port *port); // Retrieves the name of an iSCSI port
+
+int iscsi_port_transport_id_set(iscsi_port *port, const uint8_t *name, const uint64_t isid); // Sets the SCSI transport ID of the iSCSI port
/// iSCSI device flags: Allocated.
-#define ISCSI_DEVICE_FLAGS_ALLOCATED (1 << 0)
+#define ISCSI_DEVICE_FLAGS_ALLOCATED (1 << 0L)
/// iSCSI device flags: Removed.
-#define ISCSI_DEVICE_FLAGS_REMOVED (1 << 1)
+#define ISCSI_DEVICE_FLAGS_REMOVED (1 << 1L)
/**
@@ -5901,22 +5957,22 @@ typedef struct iscsi_device {
/// iSCSI target node flags: Header digest.
-#define ISCSI_TARGET_NODE_FLAGS_DIGEST_HEADER (1 << 0)
+#define ISCSI_TARGET_NODE_FLAGS_DIGEST_HEADER (1 << 0L)
/// iSCSI target node flags: Data digest.
-#define ISCSI_TARGET_NODE_FLAGS_DIGEST_DATA (1 << 1)
+#define ISCSI_TARGET_NODE_FLAGS_DIGEST_DATA (1 << 1L)
/// iSCSI target node flags: CHAP authentication disabled.
-#define ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE (1 << 2)
+#define ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE (1 << 2L)
/// iSCSI target node flags: CHAP authentication required.
-#define ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE (1 << 3)
+#define ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE (1 << 3L)
/// iSCSI target node flags: CHAP authentication mutual.
-#define ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL (1 << 4)
+#define ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL (1 << 4L)
-/// iSCSI target node flags: CHAP authentication mutual.
-#define ISCSI_TARGET_NODE_FLAGS_DESTROYED (1 << 5)
+/// iSCSI target node flags: Destroyed.
+#define ISCSI_TARGET_NODE_FLAGS_DESTROYED (1 << 5L)
/**
@@ -5945,14 +6001,60 @@ typedef struct iscsi_target_node {
/// Flags.
int flags;
+ /// Header digest size (always must be 0 or 4 for now).
+ int header_digest;
+
+ /// Data digest size (always must be 0 or 4 for now).
+ int data_digest;
+
/// CHAP group ID.
- int chap_group;
+ int32_t chap_group;
/// Number of active connections for this target node.
uint32_t active_conns;
} iscsi_target_node;
+/**
+ * @brief iSCSI target node search by name.
+ *
+ * This structure is used by iterating through
+ * all iSCSI target nodes finding by name.
+ */
+typedef struct iscsi_target_node_find_name {
+ /// Found iSCSI target node is stored here, should be initialized to NULL.
+ iscsi_target_node *target;
+
+ /// The name of the target node to search for.
+ uint8_t *name;
+} iscsi_target_node_find_name;
+
+
+/// iSCSI authentication CHAP phase: None.
+#define ISCSI_AUTH_CHAP_PHASE_NONE 0L
+
+/// iSCSI authentication CHAP phase: Wait A.
+#define ISCSI_AUTH_CHAP_PHASE_WAIT_A 1L
+
+/// iSCSI authentication CHAP phase: Wait NR.
+#define ISCSI_AUTH_CHAP_PHASE_WAIT_NR 2L
+
+/// iSCSI authentication CHAP phase: End.
+#define ISCSI_AUTH_CHAP_PHASE_END 3L
+
+
+/**
+ * @brief iSCSI CHAP authentication data structure.
+ *
+ * This structure maintains all data required for
+ * CHAP authentication method.
+ */
+typedef struct iscsi_auth_chap {
+ /// CHAP phase.
+ int phase;
+} iscsi_auth_chap;
+
+
/// iSCSI session: Default maximum number of connections.
#define ISCSI_SESSION_DEFAULT_MAX_CONNECTIONS 2UL
@@ -6027,7 +6129,7 @@ typedef struct iscsi_session {
iscsi_target_node *target;
/// Queue depth.
- int queue_depth;
+ uint queue_depth;
/// iSCSI session type.
int type;
@@ -6104,6 +6206,18 @@ typedef struct iscsi_session {
/// iSCSI connection flags: Full feature.
#define ISCSI_CONNECT_FLAGS_FULL_FEATURE (1 << 3L)
+/// iSCSI connection flags: CHAP authentication is disabled.
+#define ISCSI_CONNECT_FLAGS_CHAP_DISABLE (1 << 4L)
+
+/// iSCSI connection flags: CHAP authentication is required.
+#define ISCSI_CONNECT_FLAGS_CHAP_REQUIRE (1 << 5L)
+
+/// iSCSI connection flags: CHAP authentication is mutual.
+#define ISCSI_CONNECT_FLAGS_CHAP_MUTUAL (1 << 6L)
+
+/// iSCSI connection flags: Authenticated.
+#define ISCSI_CONNECT_FLAGS_AUTH (1 << 7L)
+
/// Ready to wait for PDU.
#define ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_READY 0L
@@ -6149,9 +6263,33 @@ typedef struct iscsi_connection {
/// Temporarily storage for partially received parameter.
uint8_t *partial_pairs;
+ /// iSCSI device.
+ iscsi_device *device;
+
+ /// iSCSI initiator port.
+ iscsi_port *init_port;
+
/// Initiator name.
uint8_t *init_name;
+ //// Initiator IP address.
+ uint8_t *init_adr;
+
+ /// iSCSI target node.
+ iscsi_target_node *target;
+
+ /// iSCSI target port.
+ iscsi_port *target_port;
+
+ /// iSCSI target short name.
+ uint8_t *target_name_short;
+
+ /// iSCSI portal host name.
+ uint8_t *portal_host;
+
+ /// iSCSI portal host port.
+ uint8_t *portal_port;
+
/// iSCSI connection contains a header digest (CRC32), always MUST be 0 or 4 for now.
int header_digest;
@@ -6177,7 +6315,7 @@ typedef struct iscsi_connection {
int state;
/// Maximum receive DataSegment length in bytes.
- int max_recv_ds_len;
+ uint max_recv_ds_len;
/// Portal group tag.
int pg_tag;
@@ -6188,11 +6326,17 @@ typedef struct iscsi_connection {
/// Target Session Identifying Handle (TSIH).
uint16_t tsih;
+ /// Connection ID (CID).
+ uint16_t cid;
+
/// Initiator Task Tag (ITT).
uint32_t init_task_tag;
- /// Connection ID (CID).
- uint16_t cid;
+ /// CHAP authentication.
+ iscsi_auth_chap auth_chap;
+
+ /// CHAP group id.
+ int32_t chap_group;
/// StatSN.
uint32_t stat_sn;
@@ -6201,19 +6345,9 @@ typedef struct iscsi_connection {
uint32_t exp_stat_sn;
} iscsi_connection;
-iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock); // Creates data structure for an iSCSI connection from iSCSI portal and TCP/IP socket
-int iscsi_connection_destroy_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // iSCSI connection destructor callback for hash map
-void iscsi_connection_destroy(iscsi_connection *conn); // Deallocates all resources acquired by iscsi_connection_create
-
-void iscsi_connection_schedule(iscsi_connection *conn); // Schedules an iSCSI connection
-
-int iscsi_connection_read(const iscsi_connection *conn, uint8_t *buf, const uint len); // Reads data for the specified iSCSI connection from its TCP socket
-int iscsi_connection_write(const iscsi_connection *conn, uint8_t *buf, const uint len); // Writes data for the specified iSCSI connection to its TCP socket
-
-int iscsi_connection_copy_key_value_pairs(iscsi_connection *conn); // Copies retrieved key and value pairs into SCSI connection and session structures
/// iSCSI PDU flags: Rejected.
-#define ISCSI_PDU_FLAGS_REJECTED (1 << 0)
+#define ISCSI_PDU_FLAGS_REJECTED (1 << 0L)
/**
@@ -6239,6 +6373,9 @@ typedef struct iscsi_pdu {
/// Data digest (CRC32C) packet data for fast access and is straight after BHS, AHS, header digest and DataSegment packet in memory.
iscsi_data_digest *data_digest;
+ /// Key and value pairs to send to client.
+ iscsi_hashmap *key_value_pairs;
+
/// Flags.
int flags;
@@ -6276,13 +6413,36 @@ typedef struct iscsi_pdu {
uint32_t cmd_sn;
} iscsi_pdu;
+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
+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
+
+uint8_t *iscsi_target_node_get_redirect(iscsi_connection *conn, iscsi_target_node *target); // Retrieves target node redirection address
+int iscsi_target_node_access(iscsi_connection *conn, iscsi_target_node *target, const uint8_t *iqn, const uint8_t *adr); // Checks if target node is accessible
+
+iscsi_session *iscsi_session_create(iscsi_connection *conn, iscsi_target_node *target, const int type); // Creates and initializes an iSCSI session
+void iscsi_session_destroy(iscsi_session *session); // Deallocates all resources acquired by iscsi_session_create
+
+iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock); // Creates data structure for an iSCSI connection from iSCSI portal and TCP/IP socket
+int iscsi_connection_destroy_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // iSCSI connection destructor callback for hash map
+void iscsi_connection_destroy(iscsi_connection *conn); // Deallocates all resources acquired by iscsi_connection_create
+
+int iscsi_connection_drop(iscsi_connection *conn, const uint8_t *conn_match, const int all); // Drops all connections based on matching pattern
+void iscsi_connection_schedule(iscsi_connection *conn); // Schedules an iSCSI connection
+
+int iscsi_connection_read(const iscsi_connection *conn, uint8_t *buf, const uint len); // Reads data for the specified iSCSI connection from its TCP socket
+int iscsi_connection_write(const iscsi_connection *conn, uint8_t *buf, const uint len); // Writes data for the specified iSCSI connection to its TCP socket
+
+int iscsi_connection_copy_key_value_pairs(iscsi_connection *conn); // Copies retrieved key and value pairs into SCSI connection and session structures
+int iscsi_connection_save_incoming_key_value_pairs(iscsi_connection *conn, iscsi_hashmap *key_value_pairs, iscsi_pdu *login_response_pdu, const iscsi_pdu *pdu); // Saves incoming key / value pairs from the client of a login request PDU
+
typedef void (*iscsi_connection_xfer_complete_callback)(uint8_t *user_data); // iSCSI transfer completed callback function.
iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn); // Creates an iSCSI PDU structure used by connections
void iscsi_connection_pdu_destroy(iscsi_pdu *pdu); // Destroys an iSCSI PDU structure used by connections
-int iscsi_connection_read_data(struct spdk_iscsi_conn *conn, int len, void *buf);
-int iscsi_connection_read_iov_data(struct spdk_iscsi_conn *conn, struct iovec *iov, int iov_count);
+int iscsi_connection_read_data(iscsi_connection *conn, int len, void *buf);
+int iscsi_connection_read_iov_data(iscsi_connection *conn, struct iovec *iov, int iov_count);
void iscsi_connection_pdu_write(iscsi_connection *conn, iscsi_pdu *pdu, iscsi_connection_xfer_complete_callback callback, uint8_t *user_data);
#endif /* DNBD3_ISCSI_H_ */