summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Vater2025-10-20 13:51:47 +0200
committerSebastian Vater2025-10-20 13:51:47 +0200
commit8e555d9a232286f19b4aeb934732dcd305de005b (patch)
tree223edbb106eaa2daa0e0facbfe1a289ec9ca12a7
parentFixed ISCSI_STRLEN macro for iSCSI login authentication keys. (diff)
downloaddnbd3-8e555d9a232286f19b4aeb934732dcd305de005b.tar.gz
dnbd3-8e555d9a232286f19b4aeb934732dcd305de005b.tar.xz
dnbd3-8e555d9a232286f19b4aeb934732dcd305de005b.zip
Implemented iSCSI discovery and related portal group and portals handling. Also fixed some bugs and iSCSI emulation layer now handles any block size. Finally, more multipath related stuff.
-rw-r--r--README.md66
-rw-r--r--pkg/config/iscsi.conf66
-rw-r--r--pkg/config/server.conf34
-rw-r--r--src/server/iscsi.c1257
-rw-r--r--src/server/iscsi.h226
5 files changed, 1182 insertions, 467 deletions
diff --git a/README.md b/README.md
index 15b0d78..f4e8efc 100644
--- a/README.md
+++ b/README.md
@@ -490,11 +490,29 @@ The _iscsi.conf_ file is the main configuration file for the iSCSI implementatio
; scsi-device- sections will be processed in order, always inherit from the [iscsi] and [scsi]
; sections and are matched case sensitive
+[iscsi-portal-group-1]
+; Portal group access level (warning) specifying invalid access levels will default to private
+; access!). Default is Private
+; Private All target nodes in this portal group will not be sent in discovery requests
+; Public All target nodes in this portal group are visible in discovery requests
+Access=Private
+
+[iscsi-portal-group-2]
+; Portal group access level (warning) specifying invalid access levels will default to private
+; access!). Default is Private
+; Private All target nodes in this portal group will not be sent in discovery requests
+; Public All target nodes in this portal group are visible in discovery requests
+Access=Public
+
[iscsi]
-; Target name check level (warning) specifying invalid check levels will default to full
+; Default portal group tag (warning) specifying invalid portal group tags will default to first
+; portal group!). Default is 1
+PortalGroupTag=1
+
+; Target name check level (warning) specifying invalid check levels will default to relaxed
; validation!). Default is Relaxed
; Full Target name is checked for full standaard compliance (recommended)
-; Relaxed All invalid characters according to standard will be allowed if not an IQN, NAA or EUI.
+; Relaxed All invalid characters according to standard will be allowed if not an IQN, NAA or EUI
; None No checking at all (be careful)
TargetNameCheck=Relaxed
@@ -525,14 +543,14 @@ MaxRecvDataSegmentLength=65536
; MediaChanger Media changer device
DeviceType=Direct
-; Physical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; physical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Physical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed physical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
PhysicalBlockSize=512
-; Logical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; logical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Logical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed logical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
LogicalBlockSize=512
; Device is emulated as removable. Should be enabled for CD-ROM, DVD and BluRay and disabled for
@@ -545,14 +563,18 @@ Removable=true
; end with .iso extension. Block sizes are set to 2 KiB for CD-ROM, DVD and BluRay type devices
; and the physical read only emulation flag is enabled
[scsi-device-*.iso]
-; Physical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; physical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Default portal group tag (warning) specifying invalid portal group tags will default to first
+; portal group!). Default is 1
+PortalGroupTag=2
+
+; Physical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed physical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
PhysicalBlockSize=2048
-; Logical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; logical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Logical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed logical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
LogicalBlockSize=2048
; Device is emulated as removable. Should be enabled for CD-ROM, DVD and BluRay and disabled for
@@ -567,14 +589,18 @@ PhysicalReadOnly=true
; end with .ISO extension. Block sizes are set to 2 KiB for CD-ROM, DVD and BluRay type devices
; and the physical read only emulation flag is enabled
[scsi-device-*.ISO]
-; Physical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; physical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Default portal group tag (warning) specifying invalid portal group tags will default to first
+; portal group!). Default is 1
+PortalGroupTag=2
+
+; Physical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed physical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
PhysicalBlockSize=2048
-; Logical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; logical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Logical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed logical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
LogicalBlockSize=2048
; Device is emulated as removable. Should be enabled for CD-ROM, DVD and BluRay and disabled for
diff --git a/pkg/config/iscsi.conf b/pkg/config/iscsi.conf
index 0e1ca49..85c31a1 100644
--- a/pkg/config/iscsi.conf
+++ b/pkg/config/iscsi.conf
@@ -8,11 +8,29 @@
; scsi-device- sections will be processed in order, always inherit from the [iscsi] and [scsi]
; sections and are matched case sensitive
+[iscsi-portal-group-1]
+; Portal group access level (warning) specifying invalid access levels will default to private
+; access!). Default is Private
+; Private All target nodes in this portal group will not be sent in discovery requests
+; Public All target nodes in this portal group are visible in discovery requests
+Access=Private
+
+[iscsi-portal-group-2]
+; Portal group access level (warning) specifying invalid access levels will default to private
+; access!). Default is Private
+; Private All target nodes in this portal group will not be sent in discovery requests
+; Public All target nodes in this portal group are visible in discovery requests
+Access=Public
+
[iscsi]
-; Target name check level (warning) specifying invalid check levels will default to full
+; Default portal group tag (warning) specifying invalid portal group tags will default to first
+; portal group!). Default is 1
+PortalGroupTag=1
+
+; Target name check level (warning) specifying invalid check levels will default to relaxed
; validation!). Default is Relaxed
; Full Target name is checked for full standaard compliance (recommended)
-; Relaxed All invalid characters according to standard will be allowed if not an IQN, NAA or EUI.
+; Relaxed All invalid characters according to standard will be allowed if not an IQN, NAA or EUI
; None No checking at all (be careful)
TargetNameCheck=Relaxed
@@ -170,14 +188,14 @@ ErrorRecoveryLevel=0
; MediaChanger Media changer device
DeviceType=Direct
-; Physical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; physical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Physical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed physical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
PhysicalBlockSize=512
-; Logical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; logical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Logical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed logical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
LogicalBlockSize=512
; Device is emulated as removable. Should be enabled for CD-ROM, DVD and BluRay and disabled for
@@ -208,14 +226,18 @@ WriteCache=false
; end with .iso extension. Block sizes are set to 2 KiB for CD-ROM, DVD and BluRay type devices
; and the physical read only emulation flag is enabled
[scsi-device-*.iso]
-; Physical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; physical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Default portal group tag (warning) specifying invalid portal group tags will default to first
+; portal group!). Default is 1
+PortalGroupTag=2
+
+; Physical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed physical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
PhysicalBlockSize=2048
-; Logical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; logical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Logical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed logical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
LogicalBlockSize=2048
; Device is emulated as removable. Should be enabled for CD-ROM, DVD and BluRay and disabled for
@@ -230,14 +252,18 @@ PhysicalReadOnly=true
; end with .ISO extension. Block sizes are set to 2 KiB for CD-ROM, DVD and BluRay type devices
; and the physical read only emulation flag is enabled
[scsi-device-*.ISO]
-; Physical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; physical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Default portal group tag (warning) specifying invalid portal group tags will default to first
+; portal group!). Default is 1
+PortalGroupTag=2
+
+; Physical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed physical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
PhysicalBlockSize=2048
-; Logical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; logical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Logical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed logical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
LogicalBlockSize=2048
; Device is emulated as removable. Should be enabled for CD-ROM, DVD and BluRay and disabled for
diff --git a/pkg/config/server.conf b/pkg/config/server.conf
index 3a7cd04..443a76e 100644
--- a/pkg/config/server.conf
+++ b/pkg/config/server.conf
@@ -93,11 +93,29 @@ consoleMask=ERROR WARNING MINOR INFO
; Whether timestamps should be output to console too (or just to file if false)
consoleTimestamps=false
+[iscsi-portal-group-1]
+; Portal group access level (warning) specifying invalid access levels will default to private
+; access!). Default is Private
+; Private All target nodes in this portal group will not be sent in discovery requests
+; Public All target nodes in this portal group are visible in discovery requests
+Access=Private
+
+[iscsi-portal-group-2]
+; Portal group access level (warning) specifying invalid access levels will default to private
+; access!). Default is Private
+; Private All target nodes in this portal group will not be sent in discovery requests
+; Public All target nodes in this portal group are visible in discovery requests
+Access=Public
+
[iscsi]
-; Target name check level (warning) specifying invalid check levels will default to full
+; Default portal group tag (warning) specifying invalid portal group tags will default to first
+; portal group!). Default is 1
+PortalGroupTag=1
+
+; Target name check level (warning) specifying invalid check levels will default to relaxed
; validation!). Default is Relaxed
; Full Target name is checked for full standaard compliance (recommended)
-; Relaxed All invalid characters according to standard will be allowed if not an IQN, NAA or EUI.
+; Relaxed All invalid characters according to standard will be allowed if not an IQN, NAA or EUI
; None No checking at all (be careful)
TargetNameCheck=Relaxed
@@ -255,14 +273,14 @@ ErrorRecoveryLevel=0
; MediaChanger Media changer device
DeviceType=Direct
-; Physical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; physical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Physical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed physical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
PhysicalBlockSize=512
-; Logical block size of emulated device, rounded up to nearest power of two). Default is 512 for
-; supporting ancient systems. Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed
-; logical block sizes range from 256 to 32768 bytes (32 KiB). Default is 512 bytes
+; Logical block size of emulated device). Default is 512 for supporting ancient systems.
+; Should be set to 2048 for CD-ROM, DVD and BluRay devices. Allowed logical block sizes range
+; from 1 to 2147483647 bytes (2 GiB). Default is 512 bytes
LogicalBlockSize=512
; Device is emulated as removable. Should be enabled for CD-ROM, DVD and BluRay and disabled for
diff --git a/src/server/iscsi.c b/src/server/iscsi.c
index c4a124c..b56df20 100644
--- a/src/server/iscsi.c
+++ b/src/server/iscsi.c
@@ -30,9 +30,13 @@
#include <string.h>
#include <inttypes.h>
#include <strings.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <sys/un.h>
#include <dnbd3/config.h>
+#include <dnbd3/config/server.h>
#include <dnbd3/shared/log.h>
#include <dnbd3/shared/sockhelper.h>
#include <dnbd3/types.h>
@@ -40,6 +44,7 @@
#include <time.h>
#include <unistd.h>
+#include "altservers.h"
#include "fileutil.h"
#include "globals.h"
#include "helper.h"
@@ -1075,7 +1080,7 @@ int iscsi_create()
return -1;
}
- globvec->devices = iscsi_hashmap_create( _maxImages );
+ globvec->devices = iscsi_hashmap_create( 0U );
if ( globvec->devices == NULL ) {
logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector devices hash map" );
@@ -1096,7 +1101,7 @@ int iscsi_create()
return -1;
}
- globvec->portal_groups = iscsi_hashmap_create( 1U );
+ globvec->portal_groups = iscsi_hashmap_create( 0U );
if ( globvec->portal_groups == NULL ) {
logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector portal groups hash map" );
@@ -1121,7 +1126,7 @@ int iscsi_create()
return -1;
}
- globvec->target_nodes = iscsi_hashmap_create( _maxImages );
+ globvec->target_nodes = iscsi_hashmap_create( 0U );
if ( globvec->target_nodes == NULL ) {
logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector target nodes hash map" );
@@ -1150,7 +1155,7 @@ int iscsi_create()
return -1;
}
- globvec->sessions = iscsi_hashmap_create( _maxClients );
+ globvec->sessions = iscsi_hashmap_create( 0U );
if ( globvec->sessions == NULL ) {
logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector sessions hash map" );
@@ -1312,25 +1317,25 @@ int iscsi_create()
return -1;
}
- globvec->flags = (ISCSI_GLOBALS_FLAGS_CHAP_DISABLE | ISCSI_GLOBALS_FLAGS_INIT_R2T | ISCSI_GLOBALS_FLAGS_IMMEDIATE_DATA | ISCSI_GLOBALS_FLAGS_DATA_PDU_IN_ORDER | ISCSI_GLOBALS_FLAGS_DATA_SEQ_IN_ORDER | ISCSI_GLOBALS_FLAGS_SCSI_IO_REMOVABLE | ISCSI_GLOBALS_FLAGS_SCSI_IO_WRITE_PROTECT);
- globvec->target_name_check = ISCSI_GLOBALS_TARGET_NAME_CHECK_RELAXED;
- globvec->max_sessions = 0U;
- globvec->header_digest = 0;
- globvec->data_digest = 0;
- globvec->scsi_device_type = ISCSI_SCSI_BASIC_INQUIRY_DATA_PERIPHERAL_TYPE_DIRECT;
- globvec->max_recv_ds_len = ISCSI_DEFAULT_MAX_RECV_DS_LEN;
- globvec->max_session_conns = ISCSI_GLOBALS_DEFAULT_MAX_CONNECTIONS;
- globvec->max_outstanding_r2t = ISCSI_GLOBALS_DEFAULT_MAX_OUTSTANDING_R2T;
- globvec->default_time_to_wait = ISCSI_GLOBALS_DEFAULT_TIME_TO_WAIT;
- globvec->default_time_to_retain = ISCSI_GLOBALS_DEFAULT_TIME_TO_RETAIN;
- globvec->first_burst_len = ISCSI_GLOBALS_DEFAULT_FIRST_BURST_LEN;
- globvec->max_burst_len = ISCSI_GLOBALS_DEFAULT_MAX_BURST_LEN;
- globvec->err_recovery_level = ISCSI_GLOBALS_DEFAULT_ERR_RECOVERY_LEVEL;
- globvec->chap_group = 0L;
- globvec->scsi_physical_block_size = ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE;
- globvec->scsi_physical_block_size_shift = iscsi_get_log2_of_pow2( globvec->scsi_physical_block_size );
- globvec->scsi_logical_block_size = ISCSI_SCSI_EMU_BLOCK_SIZE;
- globvec->scsi_logical_block_size_shift = iscsi_get_log2_of_pow2( globvec->scsi_logical_block_size );
+ globvec->flags = (ISCSI_GLOBALS_FLAGS_CHAP_DISABLE | ISCSI_GLOBALS_FLAGS_INIT_R2T | ISCSI_GLOBALS_FLAGS_IMMEDIATE_DATA | ISCSI_GLOBALS_FLAGS_DATA_PDU_IN_ORDER | ISCSI_GLOBALS_FLAGS_DATA_SEQ_IN_ORDER | ISCSI_GLOBALS_FLAGS_SCSI_IO_REMOVABLE | ISCSI_GLOBALS_FLAGS_SCSI_IO_WRITE_PROTECT);
+ globvec->target_name_check = ISCSI_GLOBALS_TARGET_NAME_CHECK_RELAXED;
+ globvec->max_sessions = 0U;
+ globvec->header_digest = 0;
+ globvec->data_digest = 0;
+ globvec->scsi_device_type = ISCSI_SCSI_BASIC_INQUIRY_DATA_PERIPHERAL_TYPE_DIRECT;
+ atomic_init( &globvec->connections, 0 );
+ globvec->pg_tag = 1UL;
+ globvec->max_recv_ds_len = ISCSI_DEFAULT_MAX_RECV_DS_LEN;
+ globvec->max_session_conns = ISCSI_GLOBALS_DEFAULT_MAX_CONNECTIONS;
+ globvec->max_outstanding_r2t = ISCSI_GLOBALS_DEFAULT_MAX_OUTSTANDING_R2T;
+ globvec->default_time_to_wait = ISCSI_GLOBALS_DEFAULT_TIME_TO_WAIT;
+ globvec->default_time_to_retain = ISCSI_GLOBALS_DEFAULT_TIME_TO_RETAIN;
+ globvec->first_burst_len = ISCSI_GLOBALS_DEFAULT_FIRST_BURST_LEN;
+ globvec->max_burst_len = ISCSI_GLOBALS_DEFAULT_MAX_BURST_LEN;
+ globvec->err_recovery_level = ISCSI_GLOBALS_DEFAULT_ERR_RECOVERY_LEVEL;
+ globvec->chap_group = 0L;
+ globvec->scsi_physical_block_size = ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE;
+ globvec->scsi_logical_block_size = ISCSI_SCSI_EMU_BLOCK_SIZE;
iscsi_config_load( globvec );
@@ -1553,7 +1558,56 @@ static int iscsi_config_load_from_ini(void *user_data, const char *section, cons
{
iscsi_globals *globvec = (iscsi_globals *) user_data;
- if ( strcasecmp( section, ISCSI_GLOBALS_SECTION_ISCSI ) == 0 ) {
+ if ( (strncasecmp( section, ISCSI_GLOBALS_SECTION_ISCSI_PORTAL_GROUP_PREFIX, ISCSI_STRLEN(ISCSI_GLOBALS_SECTION_ISCSI_PORTAL_GROUP_PREFIX) ) == 0) ) {
+ int32_t num_value = iscsi_config_parse_int( (((uint8_t *) section) + ISCSI_STRLEN(ISCSI_GLOBALS_SECTION_ISCSI_PORTAL_GROUP_PREFIX)) );
+
+ if ( num_value <= 0L )
+ num_value = 1L;
+
+ uint64_t pg_tag = (uint64_t) num_value;
+ int flags = ISCSI_PORTAL_GROUP_FLAGS_PRIVATE;
+
+ pthread_rwlock_rdlock( &globvec->portal_groups_rwlock );
+
+ iscsi_portal_group *portal_group = NULL;
+ int rc = iscsi_hashmap_get( globvec->portal_groups, (uint8_t *) &pg_tag, sizeof(pg_tag), (uint8_t **) &portal_group );
+
+ if ( portal_group == NULL ) {
+ pthread_rwlock_unlock( &globvec->portal_groups_rwlock );
+ pthread_rwlock_wrlock( &globvec->portal_groups_rwlock );
+ rc = iscsi_hashmap_get( globvec->portal_groups, (uint8_t *) &pg_tag, sizeof(pg_tag), (uint8_t **) &portal_group );
+
+ if ( portal_group == NULL ) {
+ portal_group = iscsi_portal_group_create( pg_tag, flags );
+
+ if ( portal_group == NULL ) {
+ pthread_rwlock_unlock( &globvec->portal_groups_rwlock );
+
+ return 0;
+ }
+
+ rc = iscsi_hashmap_put( globvec->portal_groups, (uint8_t *) &portal_group->tag, sizeof(portal_group->tag), (uint8_t *) portal_group );
+
+ if ( rc < 0 ) {
+ iscsi_portal_group_destroy( portal_group );
+ pthread_rwlock_unlock( &globvec->portal_groups_rwlock );
+
+ return 0;
+ }
+ }
+ } else {
+ portal_group->tag = pg_tag;
+ }
+
+ if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_ISCSI_PORTAL_GROUP_KEY_ACCESS ) == 0 ) {
+ if ( strcasecmp( value, "Public" ) == 0 )
+ flags &= ~ISCSI_PORTAL_GROUP_FLAGS_PRIVATE;
+
+ portal_group->flags = flags;
+ }
+
+ pthread_rwlock_unlock( &globvec->portal_groups_rwlock );
+ } else if ( strcasecmp( section, ISCSI_GLOBALS_SECTION_ISCSI ) == 0 ) {
const int32_t num_value = iscsi_config_parse_int( (uint8_t *) value );
if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_ISCSI_KEY_TARGET_NAME_CHECK ) == 0 ) {
@@ -1569,6 +1623,9 @@ static int iscsi_config_load_from_ini(void *user_data, const char *section, cons
globvec->header_digest = ((strcasecmp( value, "CRC32C" ) == 0) ? ISCSI_DIGEST_SIZE : 0);
} else if ( strcasecmp( key, ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_DATA_DIGEST ) == 0 ) {
globvec->data_digest = ((strcasecmp( value, "CRC32C" ) == 0) ? ISCSI_DIGEST_SIZE : 0);
+ } else if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_ISCSI_KEY_PORTAL_GROUP_TAG ) == 0 ) {
+ if ( num_value > 0L )
+ globvec->pg_tag = num_value;
} else if ( strcasecmp( key, ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_MAX_RECV_DS_LEN ) == 0 ) {
if ( (num_value >= 512L) && (num_value <= (int32_t) ISCSI_MAX_DS_SIZE) )
globvec->max_recv_ds_len = num_value;
@@ -1639,19 +1696,11 @@ static int iscsi_config_load_from_ini(void *user_data, const char *section, cons
else
globvec->scsi_device_type = ISCSI_SCSI_BASIC_INQUIRY_DATA_PERIPHERAL_TYPE_DIRECT;
} else if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_SCSI_KEY_PHYSICAL_BLOCK_SIZE ) == 0 ) {
- num_value = iscsi_align_pow2_ceil( num_value );
-
- if ( (num_value >= 256L) && (num_value <= 32768L) ) {
- globvec->scsi_physical_block_size = num_value;
- globvec->scsi_physical_block_size_shift = iscsi_get_log2_of_pow2( num_value );
- }
+ if ( num_value > 0L )
+ globvec->scsi_physical_block_size = num_value;
} else if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_SCSI_KEY_LOGICAL_BLOCK_SIZE ) == 0 ) {
- num_value = iscsi_align_pow2_ceil( num_value );
-
- if ( (num_value >= 256L) && (num_value <= 32768L) ) {
- globvec->scsi_logical_block_size = num_value;
- globvec->scsi_logical_block_size_shift = iscsi_get_log2_of_pow2( num_value );
- }
+ if ( num_value > 0L )
+ globvec->scsi_logical_block_size = num_value;
} else if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_SCSI_KEY_REMOVABLE ) == 0 ) {
if ( num_value != ISCSI_GLOBALS_CONFIG_TYPE_VALUE_ERROR ) {
if ( num_value != 0L )
@@ -1756,21 +1805,20 @@ static int iscsi_config_load_from_ini(void *user_data, const char *section, cons
if ( (globvec->flags & ISCSI_GLOBALS_FLAGS_SCSI_IO_WRITE_CACHE) != 0 )
scsi_device_config->flags |= ISCSI_GLOBALS_SCSI_DEVICE_CONFIG_FLAGS_SCSI_IO_WRITE_CACHE;
- scsi_device_config->header_digest = globvec->header_digest;
- scsi_device_config->data_digest = globvec->data_digest;
- scsi_device_config->scsi_device_type = globvec->scsi_device_type;
- scsi_device_config->max_recv_ds_len = globvec->max_recv_ds_len;
- scsi_device_config->max_session_conns = globvec->max_session_conns;
- scsi_device_config->max_outstanding_r2t = globvec->max_outstanding_r2t;
- scsi_device_config->default_time_to_wait = globvec->default_time_to_wait;
- scsi_device_config->default_time_to_retain = globvec->default_time_to_retain;
- scsi_device_config->first_burst_len = globvec->first_burst_len;
- scsi_device_config->max_burst_len = globvec->max_burst_len;
- scsi_device_config->err_recovery_level = globvec->err_recovery_level;
- scsi_device_config->scsi_physical_block_size = globvec->scsi_physical_block_size;
- scsi_device_config->scsi_physical_block_size_shift = globvec->scsi_physical_block_size_shift;
- scsi_device_config->scsi_logical_block_size = globvec->scsi_logical_block_size;
- scsi_device_config->scsi_logical_block_size_shift = globvec->scsi_logical_block_size_shift;
+ scsi_device_config->header_digest = globvec->header_digest;
+ scsi_device_config->data_digest = globvec->data_digest;
+ scsi_device_config->scsi_device_type = globvec->scsi_device_type;
+ scsi_device_config->pg_tag = globvec->pg_tag;
+ scsi_device_config->max_recv_ds_len = globvec->max_recv_ds_len;
+ scsi_device_config->max_session_conns = globvec->max_session_conns;
+ scsi_device_config->max_outstanding_r2t = globvec->max_outstanding_r2t;
+ scsi_device_config->default_time_to_wait = globvec->default_time_to_wait;
+ scsi_device_config->default_time_to_retain = globvec->default_time_to_retain;
+ scsi_device_config->first_burst_len = globvec->first_burst_len;
+ scsi_device_config->max_burst_len = globvec->max_burst_len;
+ scsi_device_config->err_recovery_level = globvec->err_recovery_level;
+ scsi_device_config->scsi_physical_block_size = globvec->scsi_physical_block_size;
+ scsi_device_config->scsi_logical_block_size = globvec->scsi_logical_block_size;
rc = iscsi_hashmap_put( globvec->scsi_device_config, hash_key, key_len, (uint8_t *) scsi_device_config );
@@ -1790,6 +1838,9 @@ static int iscsi_config_load_from_ini(void *user_data, const char *section, cons
scsi_device_config->header_digest = ((strcasecmp( value, "CRC32C" ) == 0) ? ISCSI_DIGEST_SIZE : 0);
} else if ( strcasecmp( key, ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_DATA_DIGEST ) == 0 ) {
scsi_device_config->data_digest = ((strcasecmp( value, "CRC32C" ) == 0) ? ISCSI_DIGEST_SIZE : 0);
+ } else if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_ISCSI_KEY_PORTAL_GROUP_TAG ) == 0 ) {
+ if ( num_value > 0L )
+ scsi_device_config->pg_tag = num_value;
} else if ( strcasecmp( key, ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_MAX_RECV_DS_LEN ) == 0 ) {
if ( (num_value >= 512L) && (num_value <= (int32_t) ISCSI_MAX_DS_SIZE) )
scsi_device_config->max_recv_ds_len = num_value;
@@ -1856,19 +1907,11 @@ static int iscsi_config_load_from_ini(void *user_data, const char *section, cons
else
scsi_device_config->scsi_device_type = ISCSI_SCSI_BASIC_INQUIRY_DATA_PERIPHERAL_TYPE_DIRECT;
} else if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_SCSI_KEY_PHYSICAL_BLOCK_SIZE ) == 0 ) {
- num_value = iscsi_align_pow2_ceil( num_value );
-
- if ( (num_value >= 256L) && (num_value <= 32768L) ) {
- scsi_device_config->scsi_physical_block_size = num_value;
- scsi_device_config->scsi_physical_block_size_shift = iscsi_get_log2_of_pow2( num_value );
- }
+ if ( num_value > 0L )
+ scsi_device_config->scsi_physical_block_size = num_value;
} else if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_SCSI_KEY_LOGICAL_BLOCK_SIZE ) == 0 ) {
- num_value = iscsi_align_pow2_ceil( num_value );
-
- if ( (num_value >= 256L) && (num_value <= 32768L) ) {
- scsi_device_config->scsi_logical_block_size = num_value;
- scsi_device_config->scsi_logical_block_size_shift = iscsi_get_log2_of_pow2( num_value );
- }
+ if ( num_value > 0L )
+ scsi_device_config->scsi_logical_block_size = num_value;
} else if ( strcasecmp( key, ISCSI_GLOBALS_SECTION_SCSI_KEY_REMOVABLE ) == 0 ) {
if ( num_value != ISCSI_GLOBALS_CONFIG_TYPE_VALUE_ERROR ) {
if ( num_value != 0L )
@@ -2091,6 +2134,11 @@ int32_t iscsi_config_get(uint8_t *name, const int type)
break;
}
+ case ISCSI_GLOBALS_CONFIG_TYPE_PORTAL_GROUP_TAG : {
+ return scsi_device_config->pg_tag;
+
+ break;
+ }
case ISCSI_GLOBALS_CONFIG_TYPE_MAX_RECV_DS_LEN : {
return scsi_device_config->max_recv_ds_len;
@@ -2131,18 +2179,13 @@ int32_t iscsi_config_get(uint8_t *name, const int type)
break;
}
- case ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE : {
- return scsi_device_config->scsi_physical_block_size;
-
- break;
- }
case ISCSI_GLOBALS_CONFIG_TYPE_SCSI_DEVICE_TYPE : {
return scsi_device_config->scsi_device_type;
break;
}
- case ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE_SHIFT : {
- return scsi_device_config->scsi_physical_block_size_shift;
+ case ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE : {
+ return scsi_device_config->scsi_physical_block_size;
break;
}
@@ -2151,11 +2194,6 @@ int32_t iscsi_config_get(uint8_t *name, const int type)
break;
}
- case ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE_SHIFT : {
- return scsi_device_config->scsi_logical_block_size_shift;
-
- break;
- }
case ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_INIT_R2T : {
return (((scsi_device_config->flags & ISCSI_GLOBALS_SCSI_DEVICE_CONFIG_FLAGS_INIT_R2T) != 0) ? 1L : 0L);
@@ -2224,6 +2262,11 @@ int32_t iscsi_config_get(uint8_t *name, const int type)
break;
}
+ case ISCSI_GLOBALS_CONFIG_TYPE_PORTAL_GROUP_TAG : {
+ return iscsi_globvec->pg_tag;
+
+ break;
+ }
case ISCSI_GLOBALS_CONFIG_TYPE_MAX_RECV_DS_LEN : {
return iscsi_globvec->max_recv_ds_len;
@@ -2279,21 +2322,11 @@ int32_t iscsi_config_get(uint8_t *name, const int type)
break;
}
- case ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE_SHIFT : {
- return iscsi_globvec->scsi_physical_block_size_shift;
-
- break;
- }
case ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE : {
return iscsi_globvec->scsi_logical_block_size;
break;
}
- case ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE_SHIFT : {
- return iscsi_globvec->scsi_logical_block_size_shift;
-
- break;
- }
case ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_CHAP_DISABLE : {
return (((iscsi_globvec->flags & ISCSI_GLOBALS_FLAGS_CHAP_DISABLE) != 0) ? 1L : 0L);
@@ -2699,7 +2732,7 @@ static int iscsi_get_int_key_value_pair(iscsi_hashmap *key_value_pairs, const ui
*/
static int iscsi_add_int_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_t *key, const int32_t value)
{
- const uint8_t *hash_val = iscsi_sprintf_alloc( "%" PRId32, value );
+ uint8_t *hash_val = iscsi_sprintf_alloc( "%" PRId32, value );
if ( hash_val == NULL ) {
logadd( LOG_ERROR, "iscsi_add_int_key_value_pair: Out of memory allocating integer value." );
@@ -2707,7 +2740,11 @@ static int iscsi_add_int_key_value_pair(iscsi_hashmap *key_value_pairs, const ui
return -1;
}
- return iscsi_add_key_value_pair( key_value_pairs, key, hash_val );
+ const int rc = iscsi_add_key_value_pair( key_value_pairs, key, hash_val );
+
+ free( hash_val );
+
+ return rc;
}
/**
@@ -3755,10 +3792,11 @@ void iscsi_portal_group_del_portal(iscsi_portal_group *portal_group, iscsi_porta
*
* @param[in] host Host / IP address of the portal.
* @param[in] port Port of the portal.
+ * @param[in] type Type of socket.
* @return Pointer to iSCSI portal structure or NULL
* in case of an error (memory exhausted).
*/
-iscsi_portal *iscsi_portal_create(const uint8_t *host, const uint8_t *port)
+iscsi_portal *iscsi_portal_create(const uint8_t *host, const uint8_t *port, const uint type)
{
iscsi_portal *portal = (iscsi_portal *) malloc( sizeof(struct iscsi_portal) );
@@ -3794,6 +3832,7 @@ iscsi_portal *iscsi_portal_create(const uint8_t *host, const uint8_t *port)
memcpy( portal->port, port, port_len );
+ portal->type = type;
portal->sock = -1;
return portal;
@@ -3907,6 +3946,12 @@ void iscsi_scsi_task_create(iscsi_scsi_task *scsi_task, iscsi_scsi_task_xfer_com
void iscsi_scsi_task_destroy(iscsi_scsi_task *scsi_task)
{
if ( (scsi_task != NULL) && (--scsi_task->ref == 0UL) ) {
+ if ( scsi_task->sense_data != NULL ) {
+ free( scsi_task->sense_data );
+
+ scsi_task->sense_data = NULL;
+ }
+
if ( scsi_task->buf != NULL ) {
if ( (scsi_task->flags & ISCSI_SCSI_TASK_FLAGS_XFER_WRITE) == 0 )
free( scsi_task->buf );
@@ -5056,34 +5101,14 @@ static inline bool iscsi_scsi_emu_io_type_is_supported(const dnbd3_image_t *imag
*/
static inline uint64_t iscsi_scsi_emu_physical_block_get_count(const dnbd3_image_t *image)
{
- int32_t block_size_shift = iscsi_config_get( (uint8_t *) image->name, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE_SHIFT );
-
- if ( block_size_shift <= 0L )
- block_size_shift = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE_SHIFT );
-
- return (((image->realFilesize + ((1ULL << (uint64_t) block_size_shift) - 1ULL)) ) >> (uint32_t) block_size_shift);
-}
+ int32_t block_size = iscsi_config_get( (uint8_t *) image->name, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE );
-/**
- * @brief Retrieves the bit shift of a physical block in bytes for a DNBD3 image.
- *
- * This function depends on DNBD3 image
- * properties.
- *
- * @param[in] image Pointer to DNBD3 image to retrieve
- * the physical bit shift size. May NOT
- * be NULL, so be careful.
- * @return The physical block size in bytes as a
- * bit shift count.
- */
-static inline uint32_t iscsi_scsi_emu_physical_block_get_size_shift(const dnbd3_image_t *image)
-{
- int32_t block_size_shift = iscsi_config_get( (uint8_t *) image->name, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE_SHIFT );
+ if ( block_size <= 0L )
+ block_size = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE );
- if ( block_size_shift <= 0L )
- block_size_shift = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE_SHIFT );
+ const uint64_t block_end = (image->realFilesize + ((uint64_t) block_size - 1ULL));
- return block_size_shift;
+ return (iscsi_is_pow2( block_size ) ? (block_end >> (uint64_t) iscsi_get_log2_of_pow2( block_size )) : (block_end / (uint64_t) block_size));
}
/**
@@ -5104,7 +5129,7 @@ static inline uint32_t iscsi_scsi_emu_physical_block_get_size(const dnbd3_image_
if ( block_size <= 0L )
block_size = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE );
- return block_size;
+ return (uint32_t) block_size;
}
/**
@@ -5120,34 +5145,14 @@ static inline uint32_t iscsi_scsi_emu_physical_block_get_size(const dnbd3_image_
*/
static inline uint64_t iscsi_scsi_emu_block_get_count(const dnbd3_image_t *image)
{
- int32_t block_size_shift = iscsi_config_get( (uint8_t *) image->name, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE_SHIFT );
-
- if ( block_size_shift <= 0L )
- block_size_shift = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE_SHIFT );
-
- return (((image->realFilesize + ((1ULL << (uint64_t) block_size_shift) - 1ULL)) ) >> (uint32_t) block_size_shift);
-}
+ int32_t block_size = iscsi_config_get( (uint8_t *) image->name, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE );
-/**
- * @brief Retrieves the bit shift of a logical block in bytes for a DNBD3 image.
- *
- * This function depends on DNBD3 image
- * properties.
- *
- * @param[in] image Pointer to DNBD3 image to retrieve
- * the logical block bit shift size.
- * May NOT be NULL, so be careful.
- * @return The logical block size in bytes as a
- * bit shift count.
- */
-static inline uint32_t iscsi_scsi_emu_block_get_size_shift(const dnbd3_image_t *image)
-{
- int32_t block_size_shift = iscsi_config_get( (uint8_t *) image->name, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE_SHIFT );
+ if ( block_size <= 0L )
+ block_size = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE );
- if ( block_size_shift <= 0L )
- block_size_shift = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE_SHIFT );
+ const uint64_t block_end = (image->realFilesize + ((uint64_t) block_size - 1ULL));
- return block_size_shift;
+ return (iscsi_is_pow2( block_size ) ? (block_end >> (uint64_t) iscsi_get_log2_of_pow2( block_size )) : (block_end / (uint64_t) block_size));
}
/**
@@ -5168,26 +5173,7 @@ static inline uint32_t iscsi_scsi_emu_block_get_size(const dnbd3_image_t *image)
if ( block_size <= 0L )
block_size = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE );
- return block_size;
-}
-
-/**
- * @brief Retrieves the bit shift ratio between logical and physical block size for a DNBD3 image.
- *
- * This function depends on DNBD3 image
- * properties.
- *
- * @param[in] image Pointer to DNBD3 image to retrieve
- * the ratio between the logical and
- * physical block size. May NOT be
- * NULL, so be careful.
- * @return The ratio between logical and physical
- * block size as a logical bit shift
- * count.
- */
-static inline uint32_t iscsi_scsi_emu_block_get_ratio_shift(const dnbd3_image_t *image)
-{
- return (iscsi_scsi_emu_physical_block_get_size_shift( image ) - iscsi_scsi_emu_block_get_size_shift( image ));
+ return (uint32_t) block_size;
}
/**
@@ -5205,7 +5191,26 @@ static inline uint32_t iscsi_scsi_emu_block_get_ratio_shift(const dnbd3_image_t
*/
static inline uint32_t iscsi_scsi_emu_block_get_ratio(const dnbd3_image_t *image)
{
- return (1UL << iscsi_scsi_emu_block_get_ratio_shift( image ));
+ int32_t physical_block_size = iscsi_config_get( (uint8_t *) image->name, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE );
+
+ if ( physical_block_size <= 0L )
+ physical_block_size = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE );
+
+ int32_t logical_block_size = iscsi_config_get( (uint8_t *) image->name, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE );
+
+ if ( logical_block_size <= 0L )
+ logical_block_size = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE );
+
+ if ( physical_block_size < logical_block_size )
+ return 0UL;
+
+ const bool logical_block_size_pow2 = iscsi_is_pow2( logical_block_size );
+ uint32_t logical_block_size_shift;
+
+ if ( logical_block_size_pow2 )
+ logical_block_size_shift = iscsi_get_log2_of_pow2( logical_block_size );
+
+ return ((logical_block_size_pow2 ? ((uint32_t) physical_block_size >> logical_block_size_shift) : ((uint32_t) physical_block_size / (uint32_t) logical_block_size)));
}
/**
@@ -5656,7 +5661,7 @@ static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task
uint32_t block_size_shift;
if ( block_size_pow2 )
- block_size_shift = iscsi_scsi_emu_block_get_size_shift( image );
+ block_size_shift = iscsi_get_log2_of_pow2( block_size );
const uint32_t max_xfer_len = (block_size_pow2 ? (ISCSI_SCSI_EMU_MAX_XFER_LEN >> block_size_shift) : (ISCSI_SCSI_EMU_MAX_XFER_LEN / block_size));
@@ -6084,7 +6089,8 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
buf->flags = 0;
- const uint8_t exponent = (uint8_t) iscsi_scsi_emu_block_get_ratio_shift( lun->image );
+ const uint32_t ratio = iscsi_scsi_emu_block_get_ratio( lun->image );
+ const uint8_t exponent = (uint8_t) ((ratio != 0UL) ? iscsi_get_log2_of_pow2( ratio ) : 0UL);
buf->exponents = ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_PUT_LBPPB_EXPONENT((exponent <= ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_MASK) ? exponent : 0U);
@@ -6635,22 +6641,28 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task
vpd_page_block_limits_inquiry_data_pkt->flags = 0;
- const uint32_t block_size_shift = iscsi_scsi_emu_block_get_size_shift( image );
- uint32_t blocks = (ISCSI_SCSI_EMU_MAX_XFER_LEN >> block_size_shift);
+ const uint32_t block_size = iscsi_scsi_emu_block_get_size( image );
+ const bool block_size_pow2 = iscsi_is_pow2( block_size );
+ uint32_t block_size_shift;
+
+ if ( block_size_pow2 )
+ block_size_shift = iscsi_get_log2_of_pow2( block_size );
+
+ uint32_t blocks = (block_size_pow2 ? (ISCSI_SCSI_EMU_MAX_XFER_LEN >> block_size_shift) : (ISCSI_SCSI_EMU_MAX_XFER_LEN / block_size));
if ( blocks > 255UL )
blocks = 255UL;
vpd_page_block_limits_inquiry_data_pkt->max_cmp_write_len = (uint8_t) blocks;
- uint32_t optimal_blocks = (ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE >> block_size_shift);
+ uint32_t optimal_blocks = (block_size_pow2 ? (ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE >> block_size_shift) : (ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE / block_size));
if ( optimal_blocks == 0UL )
optimal_blocks = 1UL;
iscsi_put_be16( (uint8_t *) &vpd_page_block_limits_inquiry_data_pkt->optimal_granularity_xfer_len, (uint16_t) optimal_blocks );
- blocks = (ISCSI_SCSI_EMU_MAX_UNMAP_LBA_COUNT >> block_size_shift);
+ blocks = (block_size_pow2 ? (ISCSI_SCSI_EMU_MAX_UNMAP_LBA_COUNT >> block_size_shift) : (ISCSI_SCSI_EMU_MAX_UNMAP_LBA_COUNT / block_size));
iscsi_put_be32( (uint8_t *) &vpd_page_block_limits_inquiry_data_pkt->max_xfer_len, blocks );
iscsi_put_be32( (uint8_t *) &vpd_page_block_limits_inquiry_data_pkt->optimal_xfer_len, blocks );
@@ -8489,7 +8501,7 @@ static iscsi_scsi_lun *iscsi_target_node_device_lun_find(iscsi_device *device, c
* @param[in] name Pointer to IQN name of target node,
* may NOT be NULL, so be careful.
* @param[in] alias Pointer to alias of IQN name.
- * @param[in] index Target node index number.
+ * @param[in] pg_tag Portal group tag associated with this target node.
* @param[in] lun_id LUN identifier to associate with underlying SCSI device.
* @param[in] queue_depth Maximum queue depth.
* @param[in] flags Flags for this target node.
@@ -8499,7 +8511,7 @@ static iscsi_scsi_lun *iscsi_target_node_device_lun_find(iscsi_device *device, c
* @return Pointer to iSCSI target node on successful
* operation or NULL in case of an error.
*/
-iscsi_target_node *iscsi_target_node_create(uint8_t *name, const uint8_t *alias, const int index, const int lun_id, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest)
+iscsi_target_node *iscsi_target_node_create(uint8_t *name, const uint8_t *alias, const uint64_t pg_tag, const int lun_id, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest)
{
if ( (name == NULL) || (iscsi_target_node_check_name( name ) < 0) || (iscsi_target_node_check_flags( flags, chap_group ) < 0) )
return NULL;
@@ -8667,7 +8679,7 @@ iscsi_target_node *iscsi_target_node_create(uint8_t *name, const uint8_t *alias,
return NULL;
}
- target->num = index;
+ target->pg_tag = pg_tag;
target->queue_depth = queue_depth;
target->flags = flags;
target->header_digest = header_digest;
@@ -8732,7 +8744,38 @@ void iscsi_target_node_destroy(iscsi_target_node *target)
}
/**
- * @brief Sends a buffer from a source iSCSI IQN to target iSCSI IQNs.
+ * @brief Checks if an initiator iSCSI IQN name is allowed to access a specified target node be shown in discovery.
+ *
+ * This function currently checks whether the
+ * portal group is private and if the IQN name
+ * itself for correctness since there is no
+ * access control support.
+ *
+ * @param[in] target Pointer to iSCSI target node which
+ * should be checked. May NOT be NULL, so be
+ * careful.
+ * @param[in] iqn Pointer to string containing the IQN
+ * name to be allowed. NULL is an prohibited
+ * value here, so take caution.
+ * @retval true The iSCSI IQN name is allowed for discovery.
+ * @retval false The iSCSI IQN name is ignored in discovery.
+ */
+static bool iscsi_target_node_iscsi_name_allowed(iscsi_target_node *target, const uint8_t *iqn)
+{
+ if ( (target == NULL) || (iqn == NULL) )
+ return false;
+
+ iscsi_portal_group *portal_group = NULL;
+ const int rc = iscsi_hashmap_get( iscsi_globvec->portal_groups, (uint8_t *) &target->pg_tag, sizeof(target->pg_tag), (uint8_t **) &portal_group );
+
+ if ( (portal_group == NULL) || (portal_group->flags & ISCSI_PORTAL_GROUP_FLAGS_PRIVATE) != 0 )
+ return false;
+
+ return (iscsi_target_node_check_name( iqn ) >= 0);
+}
+
+/**
+ * @brief Sends a target node discovery source iSCSI IQN to a buffer for target IQNs.
*
* This function sends a buffer starting from a
* specified position to one, multiple or all
@@ -8740,22 +8783,277 @@ void iscsi_target_node_destroy(iscsi_target_node *target)
* This function also checks the input and output
* IQN for conforming to iSCSI specifications.
*
- * @param[in] conn Pointer to iSCSI connection to write the buffer.
+ * @param[in] target_send Pointer to iSCSI target discovery send
+ * structure and may NOT be NULL, so be careful.
+ * @param[in] src Pointer to string containing the source IQN.
+ * NULL is not allowed here, take caution.
+ * @param[in] src_len Length of source buffer in bytes.
+ * @return The new position of the written data or a
+ * negative error code otherwise.
+ */
+static bool iscsi_target_node_send_copy(iscsi_target_node_send_name *target_send, const uint8_t *src, const uint32_t src_len)
+{
+ const uint32_t pos = target_send->pos;
+ const uint32_t len = target_send->len;
+
+ if ( pos >= len )
+ return true;
+
+ const uint32_t prev_target_send_total_size = target_send->prev_target_send_total_size;
+
+ if ( prev_target_send_total_size < src_len ) {
+ const uint32_t exp_len = (src_len - prev_target_send_total_size);
+ uint32_t buf_len = (len - pos);
+
+ if ( buf_len > exp_len )
+ buf_len = exp_len;
+
+ memcpy( (target_send->buf + pos), (src + prev_target_send_total_size), buf_len );
+
+ target_send->pos += buf_len;
+ target_send->prev_target_send_total_size = 0UL;
+ } else {
+ target_send->prev_target_send_total_size -= src_len;
+ }
+
+ return false;
+}
+
+/**
+ * @brief Sends an iSCSI portal for iSCSI discovery to a buffer.
+ *
+ * Callback function for each element while iterating
+ * through the iSCSI portals to send for discovery.
+ *
+ * @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.
+ * @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 connection, the destination
+ * target node IQN to be searched for, the source
+ * target node IQN, the pointer to output buffer, the
+ * position in bytes to put the next target address, the
+ * buffer length in bytes and the pointer to a
+ * boolean value indicating if the buffer is full
+ * and may NOT be NULL, so be careful.
+ * @retval -2 Memory exhausted during execution. Therefore,
+ * no further searching is needed.
+ * @retval -1 The portal has been sent. Therefore,
+ * no further searching is needed.
+ * @retval 0 The portal to be sent has not been found
+ * yet.
+ */
+int iscsi_target_node_portals_send_callback(uint8_t *key UNUSED, const size_t key_size UNUSED, uint8_t *value, uint8_t *user_data)
+{
+ iscsi_target_node_send_name *target_send = (iscsi_target_node_send_name *) user_data;
+ iscsi_portal *portal = (iscsi_portal *) value;
+ uint8_t *server_host = portal->host;
+
+ if ( (strcmp( (char *) server_host, "[::]" ) == 0) || (strcmp( (char *) server_host, "0.0.0.0" ) == 0) ) {
+ switch ( portal->type ) {
+ case ISCSI_PORTAL_TYPE_IPV4 :
+ case ISCSI_PORTAL_TYPE_IPV6 : {
+ server_host = target_send->conn->target_host;
+
+ break;
+ }
+ default : {
+ return 0;
+
+ break;
+ }
+ }
+ }
+
+ const uint32_t len = snprintf( NULL, 0, "%s=%s:%s,%" PRIu64, ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_ADDRESS, server_host, portal->port, portal->group->tag );
+ uint8_t *tmp_buf;
+
+ if ( len > target_send->tmp_len ) {
+ target_send->tmp_len = iscsi_align_pow2_ceil((len + len));
+
+ tmp_buf = realloc( target_send->tmp_buf, target_send->tmp_len );
+
+ if ( tmp_buf == NULL ) {
+ logadd( LOG_ERROR, "iscsi_target_node_portals_send_callback: Out of memory while allocating temporary buffer for iSCSI target node discovery" );
+
+ target_send->pos = -1L;
+
+ return -2;
+ }
+
+ target_send->tmp_buf = tmp_buf;
+ } else {
+ tmp_buf = target_send->tmp_buf;
+ }
+
+ memset( tmp_buf, 0, (len + 1UL) );
+
+ if ( target_send->prev_target_send_total_size < len )
+ snprintf( (char *) tmp_buf, (len + 1UL), "%s=%s:%s,%" PRIu64, ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_ADDRESS, server_host, portal->port, portal->group->tag );
+
+ target_send->buf_full = iscsi_target_node_send_copy( target_send, tmp_buf, (len + 1UL) );
+
+ if ( target_send->buf_full )
+ return -1;
+
+ return 0;
+}
+
+/**
+ * @brief Sends all iSCSI portals for iSCSI discovery to a buffer.
+ *
+ * This function retrieves the relevant portal group
+ * in order to iterate its portals.
+ *
+ * @param[in] target Pointer to iSCSI target node and may
+ * NOT be NULL, so be careful.
+ * @param[in] target_send Pointer to iSCSI target discovery send
+ * structure. NULL is NOT allowed here, so
+ * take caution.
+ * @return Current buffer position in bytes or a negative
+ * error code otherwise.
+ */
+static uint32_t iscsi_target_node_portals_send(iscsi_target_node *target, iscsi_target_node_send_name *target_send)
+{
+ iscsi_portal_group *portal_group = NULL;
+ const int rc = iscsi_hashmap_get( iscsi_globvec->portal_groups, (uint8_t *) &target->pg_tag, sizeof(target->pg_tag), (uint8_t **) &portal_group );
+
+ if ( (portal_group == NULL) || (portal_group->flags & ISCSI_PORTAL_GROUP_FLAGS_PRIVATE) != 0 )
+ return target_send->pos;
+
+ iscsi_hashmap_iterate( portal_group->portals, iscsi_target_node_portals_send_callback, (uint8_t *) target_send );
+
+ return target_send->pos;
+}
+
+/**
+ * @brief Sends an iSCSI discovery source target node IQN for a specific target IQN to a buffer.
+ *
+ * Callback function for each element while iterating
+ * through the iSCSI target nodes to send for
+ * discovery.
+ *
+ * @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.
+ * @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 connection, the destination
+ * target node IQN to be searched for, the source
+ * target node IQN, the pointer to output buffer, the
+ * position in bytes to put the next target address, the
+ * buffer length in bytes and the pointer to a
+ * boolean value indicating if the buffer is full
+ * and may NOT be NULL, so be careful.
+ * @retval -2 Memory exhausted during execution. Therefore,
+ * no further searching is needed.
+ * @retval -1 The target node has been sent. Therefore,
+ * no further searching is needed.
+ * @retval 0 The target node to be sent has not been found
+ * yet.
+ */
+int iscsi_target_node_send_callback(uint8_t *key UNUSED, const size_t key_size UNUSED, uint8_t *value, uint8_t *user_data)
+{
+ iscsi_target_node_send_name *target_send = (iscsi_target_node_send_name *) user_data;
+ iscsi_target_node *target = (iscsi_target_node *) value;
+
+ if ( (target_send->dst_iqn != NULL) && (strcasecmp( (char *) target_send->dst_iqn, (char *) target->name ) != 0) )
+ return 0;
+
+ const bool rc = iscsi_target_node_iscsi_name_allowed( target, target_send->src_iqn );
+
+ if ( !rc )
+ return 0;
+
+ const uint32_t len = snprintf( NULL, 0, "%s=%s", ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_NAME, target->name );
+ uint8_t *tmp_buf;
+
+ if ( len > target_send->tmp_len ) {
+ target_send->tmp_len = iscsi_align_pow2_ceil((len + len));
+
+ tmp_buf = realloc( target_send->tmp_buf, target_send->tmp_len );
+
+ if ( tmp_buf == NULL ) {
+ logadd( LOG_ERROR, "iscsi_target_node_send_callback: Out of memory while allocating temporary buffer for iSCSI target node discovery" );
+
+ target_send->pos = -1L;
+
+ return -2;
+ }
+
+ target_send->tmp_buf = tmp_buf;
+ } else {
+ tmp_buf = target_send->tmp_buf;
+ }
+
+ memset( tmp_buf, 0, (len + 1UL) );
+
+ if ( target_send->prev_target_send_total_size < len )
+ snprintf( (char *) tmp_buf, (len + 1UL), "%s=%s", ISCSI_LOGIN_AUTH_SECURITY_TEXT_KEY_TARGET_NAME, target->name );
+
+ target_send->buf_full = iscsi_target_node_send_copy( target_send, tmp_buf, (len + 1UL) );
+
+ if ( target_send->buf_full )
+ return -1;
+
+ target_send->pos = iscsi_target_node_portals_send( target, target_send );
+
+ if ( target_send->buf_full )
+ return -1;
+
+ return 0;
+}
+
+/**
+ * @brief Sends a target node discovery source iSCSI IQN to a buffer for target IQNs.
+ *
+ * This function sends a buffer starting from a
+ * specified position to one, multiple or all
+ * target IQNs.\n
+ * This function also checks the input and output
+ * IQN for conforming to iSCSI specifications.
+ *
+ * @param[in] conn Pointer to iSCSI connection to write the buffer,
+ * may NOT be NULL, so be careful.
* @param[in] dst_iqn Pointer to string containing the target IQNs,
* NULL is not allowed here, take caution.
* @param[in] src_iqn Pointer to string containing the source IQN.
* May NOT be NULL, so be careful.
- * @param[in] buf Pointer to output buffer.
+ * @param[out] buf Pointer to output buffer. NULL is forbidden
+ * here, so take caution.
* @param[in] pos Position in buffer in bytes to start sending.
* @param[in] len Length of buffer in bytes.
* @return The new position of the written data or a
* negative error code otherwise.
*/
-int32_t iscsi_target_node_send(iscsi_connection *conn, const uint8_t *dst_iqn, const uint8_t *src_iqn, uint8_t *buf, const uint32_t pos, const uint32_t len)
+int32_t iscsi_target_node_send(iscsi_connection *conn, uint8_t *dst_iqn, uint8_t *src_iqn, uint8_t *buf, const uint32_t pos, const uint32_t len)
{
- // TODO: Implement function.
+ if ( pos >= len ) {
+ buf[len - 1] = '\0';
- return -1;
+ return (int32_t) len;
+ }
+
+ iscsi_target_node_send_name target_send = {conn, ((strcasecmp( (char *) dst_iqn, "ALL" ) != 0) ? dst_iqn : NULL), src_iqn, NULL, buf, pos, len, 0UL, conn->target_send_total_size, false};
+
+ pthread_rwlock_rdlock( &iscsi_globvec->target_nodes_rwlock );
+ pthread_rwlock_rdlock( &iscsi_globvec->portal_groups_rwlock );
+ iscsi_hashmap_iterate( iscsi_globvec->target_nodes, iscsi_target_node_send_callback, (uint8_t *) &target_send );
+ pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
+ pthread_rwlock_unlock( &iscsi_globvec->target_nodes_rwlock );
+
+ if ( target_send.tmp_buf != NULL )
+ free( target_send.tmp_buf );
+
+ if ( target_send.buf_full )
+ conn->target_send_total_size += target_send.pos;
+ else
+ conn->target_send_total_size = 0UL;
+
+ return (int32_t) target_send.pos;
}
/**
@@ -9050,7 +9348,12 @@ iscsi_target_node *iscsi_target_node_find(uint8_t *target_name)
if ( data_digest < 0L )
data_digest = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_DATA_DIGEST );
- target = iscsi_target_node_create( target_name, NULL, 0, image->rid, 16U, 0, 0L, (int) header_digest, (int) data_digest );
+ int32_t pg_tag = iscsi_config_get( (uint8_t *) image->name, ISCSI_GLOBALS_CONFIG_TYPE_PORTAL_GROUP_TAG );
+
+ if ( pg_tag <= 0L )
+ pg_tag = iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_PORTAL_GROUP_TAG );
+
+ target = iscsi_target_node_create( target_name, NULL, pg_tag, image->rid, 16U, 0, 0L, (int) header_digest, (int) data_digest );
if ( target == NULL ) {
logadd( LOG_ERROR, "iscsi_target_node_find: iSCSI target node not found" );
@@ -9072,11 +9375,11 @@ iscsi_target_node *iscsi_target_node_find(uint8_t *target_name)
return NULL;
}
- int rc = iscsi_hashmap_put( iscsi_globvec->target_nodes, (uint8_t *) hash_key, key_len, (uint8_t *) target );
+ int rc = iscsi_hashmap_put( iscsi_globvec->target_nodes, hash_key, key_len, (uint8_t *) target );
if ( rc < 0 ) {
pthread_rwlock_unlock( &iscsi_globvec->target_nodes_rwlock );
- iscsi_hashmap_key_destroy( (uint8_t *) hash_key );
+ iscsi_hashmap_key_destroy( hash_key );
iscsi_target_node_destroy( target );
return NULL;
@@ -9492,29 +9795,19 @@ iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock)
}
conn->partial_pairs = NULL;
- conn->text_key_value_pairs = iscsi_hashmap_create( ((sizeof(iscsi_connection_key_value_pair_lut) / sizeof(struct iscsi_key_value_pair_lut_entry)) - 1) );
-
- if ( conn->text_key_value_pairs == NULL ) {
- logadd( LOG_ERROR, "iscsi_create_connection: Out of memory while allocating iSCSI text key / value pair hash map" );
-
- iscsi_hashmap_iterate( conn->key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL );
- iscsi_hashmap_destroy( conn->key_value_pairs );
- free( conn );
-
- return NULL;
- }
-
- conn->text_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->pdu_processing = NULL;
+ conn->text_key_value_pairs = NULL;
+ conn->text_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->target_host = NULL;
+ conn->portal_host = NULL;
+ conn->portal_port = NULL;
+ conn->pdu_processing = NULL;
iscsi_list_create( &conn->scsi_data_in_queued_tasks );
@@ -9525,7 +9818,6 @@ iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock)
iscsi_list_create( &conn->r2t_tasks_active );
iscsi_list_create( &conn->r2t_tasks_queue );
- conn->target_send_total_size = 0U;
conn->scsi_data_in_cnt = 0U;
conn->scsi_data_out_cnt = 0U;
conn->task_cnt = 0U;
@@ -9538,6 +9830,7 @@ iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock)
conn->flags = 0;
conn->state = ISCSI_CONNECT_STATE_INVALID;
conn->login_phase = ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_SECURITY_NEGOTIATION;
+ conn->target_send_total_size = 0UL;
conn->max_recv_ds_len = ISCSI_DEFAULT_RECV_DS_LEN;
conn->pg_tag = portal->group->tag;
conn->isid.a = 0;
@@ -9557,7 +9850,7 @@ iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock)
iscsi_list_create( &conn->exec_queue );
- conn->stat_iscsi_opcodes = iscsi_hashmap_create( 256U );
+ conn->stat_iscsi_opcodes = iscsi_hashmap_create( 0U );
if ( conn->stat_iscsi_opcodes == NULL ) {
logadd( LOG_ERROR, "iscsi_create: Out of memory while initializing iSCSI global vector iSCSI opcode statistics" );
@@ -9570,7 +9863,7 @@ iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock)
return NULL;
}
- conn->stat_scsi_opcodes = iscsi_hashmap_create( 256U );
+ conn->stat_scsi_opcodes = iscsi_hashmap_create( 0U );
if ( conn->stat_scsi_opcodes == NULL ) {
logadd( LOG_ERROR, "iscsi_create: Out of memory while initializing iSCSI global vector iSCSI SCSI opcode statistics" );
@@ -9723,6 +10016,12 @@ void iscsi_connection_destroy(iscsi_connection *conn)
conn->portal_host = NULL;
}
+ if ( conn->target_host != NULL ) {
+ free( conn->target_host );
+
+ conn->target_host = NULL;
+ }
+
if ( conn->target_name_short != NULL ) {
free( conn->target_name_short );
@@ -10246,7 +10545,7 @@ static uint8_t *iscsi_negotiate_key_value_pair_all(const iscsi_key_value_pair *k
}
}
- return key_value_pair->value;
+ return old_value;
}
/**
@@ -10407,7 +10706,7 @@ int iscsi_negotiate_key_value_pair_callback(uint8_t *key, const size_t key_size,
*/
int32_t iscsi_negotiate_key_value_pairs(iscsi_connection *conn, iscsi_hashmap *key_value_pairs, uint8_t *buf, const uint32_t pos, const uint32_t len)
{
- if ( pos > len ) {
+ if ( pos >= len ) {
buf[len - 1UL] = '\0';
return len;
@@ -11094,13 +11393,9 @@ static iscsi_session *iscsi_session_get_by_tsih(const uint16_t tsih)
const uint64_t hash_key = tsih;
iscsi_session *session;
- pthread_rwlock_rdlock( &iscsi_globvec->sessions_rwlock );
-
- int rc = iscsi_hashmap_get( iscsi_globvec->sessions, (uint8_t *) &hash_key, sizeof(hash_key), (uint8_t **) &session );
+ const int rc = iscsi_hashmap_get( iscsi_globvec->sessions, (uint8_t *) &hash_key, sizeof(hash_key), (uint8_t **) &session );
- pthread_rwlock_unlock( &iscsi_globvec->sessions_rwlock );
-
- return ((rc == 0) ? session : NULL);
+ return ((rc >= 0) ? session : NULL);
}
/**
@@ -11120,20 +11415,46 @@ static iscsi_session *iscsi_session_get_by_tsih(const uint16_t tsih)
*/
static uint16_t iscsi_session_append(iscsi_connection *conn, const uint8_t *init_port_name, const uint16_t tsih)
{
+ pthread_rwlock_rdlock( &iscsi_globvec->sessions_rwlock );
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->init_port ) ) != 0) || (conn->target != session->target) )
+ if ( (session == NULL) || (conn->pg_tag != session->tag) || (strcasecmp( (char *) init_port_name, (char *) iscsi_port_get_name( session->init_port ) ) != 0) || (conn->target != session->target) ) {
+ pthread_rwlock_unlock( &iscsi_globvec->sessions_rwlock );
+
return (ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR << 8U) | ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_NO_SESSION_SPANNING;
+ }
+
+ if ( atomic_load_explicit( &session->conns, memory_order_acquire ) >= session->max_conns ) {
+ pthread_rwlock_unlock( &iscsi_globvec->sessions_rwlock );
- if ( atomic_load_explicit( &session->conns, memory_order_acquire ) >= 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;
+ pthread_rwlock_unlock( &iscsi_globvec->sessions_rwlock );
+ pthread_rwlock_wrlock( &iscsi_globvec->sessions_rwlock );
+
+ 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->init_port ) ) != 0) || (conn->target != session->target) ) {
+ pthread_rwlock_unlock( &iscsi_globvec->sessions_rwlock );
+
+ return (ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR << 8U) | ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_NO_SESSION_SPANNING;
+ }
+
+ if ( atomic_load_explicit( &session->conns, memory_order_acquire ) >= session->max_conns ) {
+ pthread_rwlock_unlock( &iscsi_globvec->sessions_rwlock );
+
+ return (ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR << 8U) | ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_TOO_MANY_CONNECTIONS;
+ }
iscsi_list_enqueue( &session->conn_list, &conn->node );
atomic_fetch_add_explicit( &session->conns, 1UL, memory_order_release );
+ pthread_rwlock_unlock( &iscsi_globvec->sessions_rwlock );
+
+ conn->session = session;
+
return (ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SUCCESS << 8U) | ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SUCCESS;
}
@@ -12226,7 +12547,7 @@ static int iscsi_connection_pdu_header_handle_text_req(iscsi_connection *conn, i
if ( conn->session->current_text_init_task_tag == 0xFFFFFFFFUL )
conn->session->current_text_init_task_tag = init_task_tag;
- else
+ else if ( conn->session->current_text_init_task_tag != init_task_tag )
return iscsi_connection_handle_reject( conn, pdu, ISCSI_REJECT_REASON_PROTOCOL_ERR );
return ISCSI_CONNECT_PDU_READ_OK;
@@ -12317,7 +12638,6 @@ int iscsi_r2t_send(iscsi_connection *conn, iscsi_task *task, uint32_t *r2t_sn, c
iscsi_put_be32( (uint8_t *) &r2t_pkt->stat_sn, conn->stat_sn );
iscsi_put_be32( (uint8_t *) &r2t_pkt->exp_cmd_sn, atomic_load_explicit( &conn->session->exp_cmd_sn, memory_order_acquire ) );
iscsi_put_be32( (uint8_t *) &r2t_pkt->max_cmd_sn, atomic_load_explicit( &conn->session->max_cmd_sn, memory_order_acquire ) );
- r2t_pkt->data_sn = 0UL;
iscsi_put_be32( (uint8_t *) &r2t_pkt->r2t_sn, (*r2t_sn)++ );
task->r2t_data_sn = 0UL;
@@ -13181,10 +13501,19 @@ static int iscsi_connection_login_session_normal(iscsi_connection *conn, iscsi_p
return rc;
iscsi_device *device = target->device;
+ uint64_t pg_tag = (uint64_t) iscsi_config_get( device->name, ISCSI_GLOBALS_CONFIG_TYPE_PORTAL_GROUP_TAG );
+
+ if ((int64_t) pg_tag <= 0L )
+ pg_tag = (uint64_t) iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_PORTAL_GROUP_TAG );
+
+ if ( conn->pg_tag != pg_tag ) {
+ conn->pg_tag = pg_tag;
+ target->pg_tag = pg_tag;
+ }
conn->device = device;
conn->target = target;
- conn->target_port = iscsi_device_find_port_by_portal_group_tag( device, conn->pg_tag );
+ conn->target_port = iscsi_device_find_port_by_portal_group_tag( device, pg_tag );
rc = iscsi_connection_login_check_session( conn, login_response_pdu, init_port_name, cid );
@@ -13452,7 +13781,7 @@ static int iscsi_connection_handle_login_phase_none(iscsi_connection *conn, iscs
if ( type == ISCSI_SESSION_TYPE_DISCOVERY ) {
conn->session->max_conns = 1UL;
- 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 );
+ rc = iscsi_update_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;
@@ -13790,10 +14119,13 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc
return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
}
- if ( (pdu->ds_len == 0UL) && (iscsi_hashmap_size( key_value_pairs ) == 0U) ) {
- iscsi_hashmap *tmp_hashmap = key_value_pairs;
+ const bool text_ack = ((pdu->ds_len == 0UL) && (iscsi_hashmap_size( key_value_pairs ) == 0U) && (conn->text_key_value_pairs != NULL));
+
+ if ( text_ack ) {
+ iscsi_hashmap_destroy( key_value_pairs );
+
key_value_pairs = conn->text_key_value_pairs;
- conn->text_key_value_pairs = tmp_hashmap;
+ conn->text_key_value_pairs = NULL;
}
iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, 0U, conn->header_digest, conn->max_recv_ds_len, conn->data_digest );
@@ -13830,7 +14162,7 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc
if ( (text_req_pkt->flags & ISCSI_TEXT_REQ_FLAGS_FINAL) != 0 )
text_response_pkt->flags |= (int8_t) ISCSI_TEXT_RESPONSE_FLAGS_FINAL;
- text_req_pkt->reserved = 0U;
+ text_response_pkt->reserved = 0U;
uint8_t *send_targets_val;
rc = iscsi_get_key_value_pair( key_value_pairs, (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_SEND_TARGETS, &send_targets_val );
@@ -13857,7 +14189,7 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc
ds_len = iscsi_target_node_send( conn, send_targets_val, conn->init_name, (uint8_t *) response_pdu->ds_cmd_data, ds_len, response_pdu->len );
} else {
if ( send_targets_val[0] == '\0' )
- send_targets_val = conn->target_port->name;
+ send_targets_val = conn->target->name;
if ( strcasecmp( (char *) send_targets_val, "ALL" ) == 0 ) {
iscsi_key_value_pair *key_value_pair;
@@ -13877,7 +14209,7 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc
}
}
- if ( conn->target_send_total_size == 0U ) {
+ if ( conn->target_send_total_size != 0UL ) {
text_response_pkt->flags |= (int8_t) ISCSI_TEXT_RESPONSE_FLAGS_CONTINUE;
text_response_pkt->flags &= (int8_t) ~ISCSI_TEXT_RESPONSE_FLAGS_FINAL;
}
@@ -13891,7 +14223,10 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc
return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
}
- if ( conn->target_send_total_size == 0U ) {
+ if ( conn->target_send_total_size == 0UL ) {
+ if ( text_ack )
+ conn->text_key_value_pairs = NULL;
+
iscsi_hashmap_iterate( key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL );
iscsi_hashmap_destroy( key_value_pairs );
} else {
@@ -13904,7 +14239,7 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc
text_response_pkt->lun = text_req_pkt->lun; // Copying over doesn't change endianess.
text_response_pkt->init_task_tag = text_req_pkt->init_task_tag; // Copying over doesn't change endianess.
- if ( (text_req_pkt->flags & ISCSI_TEXT_REQ_FLAGS_FINAL) != 0 ) {
+ if ( (text_response_pkt->flags & ISCSI_TEXT_RESPONSE_FLAGS_FINAL) != 0 ) {
text_response_pkt->target_xfer_tag = 0xFFFFFFFFUL; // Minus one does not require endianess conversion
conn->session->current_text_init_task_tag = 0xFFFFFFFFUL;
@@ -13914,13 +14249,13 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc
iscsi_put_be32( (uint8_t *) &text_response_pkt->stat_sn, conn->stat_sn++ );
- if ( (text_response_pkt->opcode & ISCSI_OPCODE_FLAGS_IMMEDIATE) == 0 )
+ if ( (text_req_pkt->opcode & ISCSI_OPCODE_FLAGS_IMMEDIATE) == 0 )
atomic_fetch_add_explicit( &conn->session->max_cmd_sn, 1UL, memory_order_release );
iscsi_put_be32( (uint8_t *) &text_response_pkt->exp_cmd_sn, atomic_load_explicit( &conn->session->exp_cmd_sn, memory_order_acquire ) );
iscsi_put_be32( (uint8_t *) &text_response_pkt->max_cmd_sn, atomic_load_explicit( &conn->session->max_cmd_sn, memory_order_acquire ) );
- text_response_pkt->reserved2[0] = 0ULL;
- text_response_pkt->reserved2[1] = 0ULL;
+ text_response_pkt->reserved2 = 0ULL;
+ text_response_pkt->reserved3 = 0UL;
iscsi_connection_pdu_write( conn, response_pdu, iscsi_connection_pdu_text_complete, (uint8_t *) conn );
@@ -14314,6 +14649,310 @@ int iscsi_connection_pdu_handle(iscsi_connection *conn)
}
/**
+ * @brief Adds iSCSI portals to a specified iSCSI portal group.
+ *
+ * Callback function for each element while iterating
+ * through the iSCSI portal groups.
+ *
+ * @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.
+ * @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 client socket, the iSCSI portal of
+ * this running instance, the host name, the port and
+ * a write locked flag which indicates changes to either
+ * the portal group or portals have been added and may
+ * NOT be NULL, so be careful.
+ * @retval -1 One of the iSCSI portals could NOT be
+ * added and therefore, an error occured and no further
+ * processing is needed.
+ * @retval 0 The iSCSI portal has been created and added
+ * successfully.
+ */
+int iscsi_connection_handle_add_portals_callback(uint8_t *key UNUSED, const size_t key_size UNUSED, uint8_t *value, uint8_t *user_data)
+{
+ struct sockaddr_storage server_addr;
+ char server_hostname[sizeof(struct sockaddr_un)];
+ iscsi_connection_handle_add_portals *add_portals = (iscsi_connection_handle_add_portals *) user_data;
+ iscsi_portal_group *portal_group = (iscsi_target_node *) value;
+ socklen_t server_addr_len = sizeof(server_addr);
+ const int sock = add_portals->sock;
+
+ if ( getpeername( sock, (struct sockaddr *) &server_addr, &server_addr_len ) != 0 )
+ return -1;
+
+ void *server_host;
+ int server_port;
+ uint server_type;
+
+ switch ( server_addr.ss_family ) {
+ case AF_UNIX : {
+ server_host = &((struct sockaddr_un *) &server_addr)->sun_path;
+
+ break;
+ }
+ case AF_INET : {
+ server_host = &((struct sockaddr_in *) &server_addr)->sin_addr;
+
+ break;
+ }
+ case AF_INET6 : {
+ server_host = &((struct sockaddr_in6 *) &server_addr)->sin6_addr;
+
+ break;
+ }
+ default : {
+ return -1;
+
+ break;
+ }
+ }
+
+ inet_ntop( server_addr.ss_family, server_host, server_hostname, sizeof(server_hostname) );
+
+ if ( getsockname( sock, (struct sockaddr *) &server_addr, &server_addr_len ) != 0 )
+ return -1;
+
+ switch ( server_addr.ss_family ) {
+ case AF_UNIX : {
+ server_port = ntohs( ((struct sockaddr_un *) &server_addr)->sun_family );
+ server_type = ISCSI_PORTAL_TYPE_SOCK;
+
+ break;
+ }
+ case AF_INET : {
+ server_port = ntohs( ((struct sockaddr_in *) &server_addr)->sin_port );
+ server_type = ISCSI_PORTAL_TYPE_IPV4;
+
+ break;
+ }
+ case AF_INET6 : {
+ server_port = ntohs( ((struct sockaddr_in6 *) &server_addr)->sin6_port );
+ server_type = ISCSI_PORTAL_TYPE_IPV6;
+
+ break;
+ }
+ default : {
+ return -1;
+
+ break;
+ }
+ }
+
+ uint8_t *port = iscsi_sprintf_alloc( "%" PRIu16, server_port );
+
+ if ( port == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle_add_portals_callback: Out of memory while allocating iSCSI portal port number" );
+
+ return -1;
+ }
+
+ uint host_len = (uint) strlen( server_hostname );
+ uint8_t *host = malloc( (host_len + 1U) );
+
+ if ( host == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle_add_portals_callback: Out of memory while allocating iSCSI portal host name" );
+
+ free( port );
+
+ return -1;
+ }
+
+ memcpy( host, server_hostname, host_len );
+ host[host_len] = '\0';
+
+ uint8_t *tmp_buf = iscsi_sprintf_alloc( "%s:%s", host, port );
+
+ if ( tmp_buf == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle_add_portals_callback: Out of memory while allocating temporarily iSCSI portal name" );
+
+ free( host );
+ free( port );
+
+ return -1;
+ }
+
+ uint key_len = (uint) (strlen( (char *) tmp_buf ) + 1U);
+ uint8_t *hash_key = iscsi_hashmap_key_create( tmp_buf, key_len );
+
+ free( tmp_buf );
+
+ if ( hash_key == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle_add_portals_callback: Out of memory while allocating temporarily iSCSI portal name hash key" );
+
+ free( host );
+ free( port );
+
+ return -1;
+ }
+
+ iscsi_portal *portal = NULL;
+ int rc = iscsi_hashmap_get( portal_group->portals, hash_key, key_len, (uint8_t **) &portal );
+
+ if ( portal == NULL ) {
+ if ( !add_portals->write_locked ) {
+ add_portals->write_locked = true;
+
+ pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
+ pthread_rwlock_wrlock( &iscsi_globvec->portal_groups_rwlock );
+ }
+
+ rc = iscsi_hashmap_get( portal_group->portals, hash_key, key_len, (uint8_t **) &portal );
+
+ if ( portal == NULL ) {
+ portal = iscsi_portal_create( host, port, server_type );
+
+ if ( portal == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle_add_portals_callback: Out of memory while allocating iSCSI portal" );
+
+ iscsi_hashmap_key_destroy( hash_key );
+ free( host );
+ free( port );
+
+ return -1;
+ }
+
+ rc = iscsi_portal_group_add_portal( portal_group, portal );
+
+ if ( rc < 0 ) {
+ iscsi_portal_destroy( portal );
+ iscsi_hashmap_key_destroy( hash_key );
+ free( host );
+ free( port );
+
+ return -1;
+ }
+ }
+ }
+
+ iscsi_hashmap_key_destroy( hash_key );
+
+ if ( add_portals->portal == NULL )
+ add_portals->portal = portal;
+
+ if ( add_portals->host == NULL )
+ add_portals->host = host;
+
+ if ( add_portals->port == NULL )
+ add_portals->port = port;
+
+ for ( int i = 0; i < SERVER_MAX_ALTS; i++ ) {
+ altservers_toString( i, server_hostname, sizeof(server_hostname) );
+
+ if ( (server_hostname[0] == '\0') || (server_hostname[0] == '<') )
+ continue;
+
+ uint8_t *alt_server_port = memchr( server_hostname, ':', sizeof(server_hostname) );
+ const uint alt_server_host_len = ((alt_server_port != NULL) ? (uint) (alt_server_port++ - (uint8_t *) server_hostname) : (uint) strlen( server_hostname ));
+ uint8_t *alt_server_host = malloc( (alt_server_host_len + 1U) );
+ const uint alt_server_type = ((server_hostname[0] == '[') ? ISCSI_PORTAL_TYPE_IPV6 : ISCSI_PORTAL_TYPE_IPV4);
+
+ if ( alt_server_host == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle_add_portals_callback: Out of memory while allocating iSCSI alternative portal host name" );
+
+ free( host );
+ free( port );
+
+ return -1;
+ }
+
+ memcpy( alt_server_host, server_hostname, alt_server_host_len );
+ alt_server_host[alt_server_host_len] = '\0';
+
+ uint8_t *tmp_buf;
+
+ if ( alt_server_port != NULL )
+ tmp_buf = iscsi_sprintf_alloc( "%s:%s", alt_server_host, alt_server_port );
+ else
+ tmp_buf = iscsi_sprintf_alloc( "%s:%u", alt_server_host, PORT );
+
+ if ( tmp_buf == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle_add_portals_callback: Out of memory while allocating temporarily iSCSI alternative portal name" );
+
+ free( alt_server_host );
+ free( host );
+ free( port );
+
+ return -1;
+ }
+
+ key_len = (uint) (strlen( (char *) tmp_buf ) + 1U);
+ hash_key = iscsi_hashmap_key_create( tmp_buf, key_len );
+
+ free( tmp_buf );
+
+ if ( hash_key == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle_add_portals_callback: Out of memory while allocating temporarily iSCSI alternative portal name hash key" );
+
+ free( alt_server_host );
+ free( host );
+ free( port );
+
+ return -1;
+ }
+
+ if ( alt_server_port == NULL ) {
+ alt_server_port = (uint8_t *) strchr( (char *) hash_key, ':' );
+ alt_server_port++;
+ }
+
+ iscsi_portal *portal = NULL;
+ rc = iscsi_hashmap_get( portal_group->portals, hash_key, key_len, (uint8_t **) &portal );
+
+ if ( portal == NULL ) {
+ if ( !add_portals->write_locked ) {
+ add_portals->write_locked = true;
+
+ pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
+ pthread_rwlock_wrlock( &iscsi_globvec->portal_groups_rwlock );
+ }
+
+ rc = iscsi_hashmap_get( portal_group->portals, hash_key, key_len, (uint8_t **) &portal );
+
+ if ( portal == NULL ) {
+ portal = iscsi_portal_create( alt_server_host, alt_server_port, alt_server_type );
+
+ if ( portal == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle_add_portals_callback: Out of memory while allocating iSCSI alternative portal" );
+
+ iscsi_hashmap_key_destroy( hash_key );
+ free( alt_server_host );
+ free( host );
+ free( port );
+
+ return -1;
+ }
+
+ rc = iscsi_portal_group_add_portal( portal_group, portal );
+
+ if ( rc < 0 ) {
+ iscsi_portal_destroy( portal );
+ iscsi_hashmap_key_destroy( hash_key );
+ free( alt_server_host );
+ free( host );
+ free( port );
+
+ return -1;
+ }
+ }
+ }
+
+ iscsi_hashmap_key_destroy( hash_key );
+ free( alt_server_host );
+ }
+
+ if ( add_portals->host != host )
+ free( host );
+
+ if ( add_portals->port != port )
+ free( port );
+
+ return 0;
+}
+
+/**
* @brief Handles an iSCSI connection until connection is closed.
*
* This function creates an iSCSI portal group
@@ -14339,8 +14978,7 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ
return;
}
- // sock_setTimeout( client->sock, 1000L * 3600L ); // TODO: Remove after finishing iSCSI implementation
-
+ const int sock = client->sock;
uint recv_buf_len = (uint) iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_FIRST_BURST_LEN );
if ( recv_buf_len < 4096U )
@@ -14354,53 +14992,38 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ
uint send_buf_len = recv_buf_len;
recv_buf_len = (uint) ISCSI_ALIGN(recv_buf_len, ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE);
- setsockopt( client->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.
+ setsockopt( 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.
send_buf_len += (uint) (ISCSI_DEFAULT_RECV_DS_LEN << 2UL);
send_buf_len = (uint) ISCSI_ALIGN(send_buf_len, ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE);
- setsockopt( client->sock, SOL_SOCKET, SO_SNDBUF, &send_buf_len, sizeof(send_buf_len)); // Not being able to set the buffer is NOT fatal, so ignore error.
+ setsockopt( sock, SOL_SOCKET, SO_SNDBUF, &send_buf_len, sizeof(send_buf_len)); // Not being able to set the buffer is NOT fatal, so ignore error.
+
+ // sock_setTimeout( sock, 1000L * 3600L ); // TODO: Remove after finishing iSCSI implementation
pthread_rwlock_rdlock( &iscsi_globvec->portal_groups_rwlock );
- uint64_t *hash_key;
iscsi_portal_group *portal_group = NULL;
- const uint64_t pg_tag = 1ULL;
+ const uint64_t pg_tag = (uint64_t) iscsi_config_get( NULL, ISCSI_GLOBALS_CONFIG_TYPE_PORTAL_GROUP_TAG );
int rc = iscsi_hashmap_get( iscsi_globvec->portal_groups, (uint8_t *) &pg_tag, sizeof(pg_tag), (uint8_t **) &portal_group );
+ bool write_locked = false;
if ( portal_group == NULL ) {
+ write_locked = true;
+
pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
pthread_rwlock_wrlock( &iscsi_globvec->portal_groups_rwlock );
rc = iscsi_hashmap_get( iscsi_globvec->portal_groups, (uint8_t *) &pg_tag, sizeof(pg_tag), (uint8_t **) &portal_group );
if ( portal_group == NULL ) {
- hash_key = (uint64_t *) malloc( sizeof(uint64_t) );
-
- if ( hash_key == NULL ) {
- logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal group" );
-
- pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
- pthread_rwlock_unlock( &iscsi_globvec_rwlock );
-
- return;
- }
-
- iscsi_hashmap_key_create_id( iscsi_globvec->portal_groups, hash_key );
- portal_group = iscsi_portal_group_create( *hash_key, 0 );
+ portal_group = iscsi_portal_group_create( pg_tag, ISCSI_PORTAL_GROUP_FLAGS_PRIVATE );
if ( portal_group == NULL ) {
- logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal group" );
-
- iscsi_hashmap_key_destroy( (uint8_t *) hash_key );
pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
pthread_rwlock_unlock( &iscsi_globvec_rwlock );
return;
}
- portal_group->tag = *hash_key;
-
- iscsi_hashmap_key_destroy( (uint8_t *) hash_key );
-
rc = iscsi_hashmap_put( iscsi_globvec->portal_groups, (uint8_t *) &portal_group->tag, sizeof(portal_group->tag), (uint8_t *) portal_group );
if ( rc < 0 ) {
@@ -14413,141 +15036,78 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ
}
}
+ iscsi_connection_handle_add_portals add_portals = {sock, NULL, NULL, NULL, write_locked};
+ rc = iscsi_hashmap_iterate( iscsi_globvec->portal_groups, iscsi_connection_handle_add_portals_callback, (uint8_t *) &add_portals );
pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
- host_to_string( &client->host, client->hostName, HOSTNAMELEN );
-
- const uint8_t *port = memchr( client->hostName, ':', HOSTNAMELEN );
- const uint host_len = ((port != NULL) ? (uint) (port++ - (uint8_t *) client->hostName) : (uint) strlen( client->hostName ));
- uint8_t *host = malloc( (host_len + 1U) );
-
- if ( host == NULL ) {
- logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal host name" );
-
- pthread_rwlock_unlock( &iscsi_globvec_rwlock );
- return;
- }
-
- memcpy( host, client->hostName, host_len );
- host[host_len] = '\0';
-
- uint8_t *tmp_buf;
-
- if ( port != NULL )
- tmp_buf = iscsi_sprintf_alloc( "%s:%s", host, port );
- else
- tmp_buf = iscsi_sprintf_alloc( "%s:%u", host, PORT );
-
- if ( tmp_buf == NULL ) {
- logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating temporarily iSCSI portal name" );
-
- free( host );
- pthread_rwlock_unlock( &iscsi_globvec_rwlock );
-
- return;
- }
-
- const uint key_len = (uint) (strlen( (char *) tmp_buf ) + 1U);
-
- hash_key = (uint64_t *) iscsi_hashmap_key_create( tmp_buf, key_len );
-
- free( tmp_buf );
-
- if ( hash_key == NULL ) {
- logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating temporarily iSCSI portal name hash key" );
-
- free( host );
- pthread_rwlock_unlock( &iscsi_globvec_rwlock );
-
- return;
- }
-
- if ( port == NULL ) {
- port = (uint8_t *) strchr( (char *) hash_key, ':' );
- port++;
- }
-
- iscsi_portal *portal = iscsi_portal_create( host, port );
-
- if ( portal == NULL ) {
- logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal" );
-
- iscsi_hashmap_key_destroy( (uint8_t *) hash_key );
- free( host );
+ if ( rc < 0 ) {
pthread_rwlock_unlock( &iscsi_globvec_rwlock );
return;
}
- pthread_rwlock_wrlock( &iscsi_globvec->portal_groups_rwlock );
+ iscsi_connection *conn = iscsi_connection_create( add_portals.portal, sock );
- rc = iscsi_portal_group_add_portal( portal_group, portal );
+ if ( conn == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI connection" );
- if ( rc < 0 ) {
- pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
- iscsi_portal_destroy( portal );
- iscsi_hashmap_key_destroy( (uint8_t *) hash_key );
- free( host );
+ free( add_portals.host );
+ free( add_portals.port );
pthread_rwlock_unlock( &iscsi_globvec_rwlock );
return;
}
- iscsi_hashmap_key_destroy( (uint8_t *) hash_key );
- free( host );
+ conn->target_host = (uint8_t *) strdup( (char *) add_portals.host );
- iscsi_connection *conn = iscsi_connection_create( portal, client->sock );
+ if ( conn->target_host == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI connection target host name" );
- if ( conn == NULL ) {
- logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI connection" );
-
- iscsi_portal_group_del_portal( portal_group, portal );
- pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
- iscsi_portal_destroy( portal );
+ iscsi_connection_destroy( conn );
+ free( add_portals.host );
+ free( add_portals.port );
pthread_rwlock_unlock( &iscsi_globvec_rwlock );
return;
}
+ conn->portal_host = add_portals.host;
+ conn->portal_port = add_portals.port;
conn->pdu_processing = iscsi_connection_pdu_create( conn, 0U, 0, 0UL, 0 );
if ( conn->pdu_processing == NULL ) {
iscsi_connection_destroy( conn );
- iscsi_portal_group_del_portal( portal_group, portal );
- pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
- iscsi_portal_destroy( portal );
pthread_rwlock_unlock( &iscsi_globvec_rwlock );
return;
}
- pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
-
memcpy( conn->pdu_processing->bhs_pkt, request, len );
conn->pdu_processing->bhs_pos = len;
+ conn->id = atomic_fetch_add_explicit( &iscsi_globvec->connections, 1, memory_order_acq_rel );
conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_HDR;
logadd( LOG_INFO, "" );
- logadd( LOG_INFO, "iSCSI connection opened for device %s from initiator %s using port %s and portal %s:%s", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) portal->host, (char *) portal->port );
+ logadd( LOG_INFO, "iSCSI connection opened for device %s from initiator %s using port %s and portal %s:%s", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) add_portals.portal->host, (char *) add_portals.portal->port );
while ( iscsi_connection_pdu_handle( conn ) >= ISCSI_CONNECT_PDU_READ_OK ) {
}
iscsi_hashmap_bucket *stat_bucket;
- logadd( LOG_INFO, "iSCSI connection closed for device %s from initiator %s using port %s and portal %s:%s", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) portal->host, (char *) portal->port );
+ logadd( LOG_INFO, "iSCSI connection closed for device %s from initiator %s using port %s and portal %s:%s", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) add_portals.portal->host, (char *) add_portals.portal->port );
iscsi_list_foreach_node ( &conn->stat_iscsi_opcodes->list, stat_bucket ) {
uint64_t *stat_opcode = (uint64_t *) stat_bucket->value;
- logadd( LOG_INFO, "iSCSI opcode usage statistics for device %s from initiator %s using port %s and portal %s:%s: Opcode 0x%02" PRIX64 " has been received %" PRIu64 " times until connection drop.", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) portal->host, (char *) portal->port, *(uint64_t *) stat_bucket->key, *stat_opcode );
+ logadd( LOG_INFO, "iSCSI opcode usage statistics for device %s from initiator %s using port %s and portal %s:%s: Opcode 0x%02" PRIX64 " has been received %" PRIu64 " times until connection drop.", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) add_portals.portal->host, (char *) add_portals.portal->port, *(uint64_t *) stat_bucket->key, *stat_opcode );
}
iscsi_list_foreach_node ( &conn->stat_scsi_opcodes->list, stat_bucket ) {
uint64_t *stat_opcode = (uint64_t *) stat_bucket->value;
- logadd( LOG_INFO, "iSCSI SCSI CDB opcode usage statistics for device %s from initiator %s using port %s and portal %s:%s: SCSI CDB opcode 0x%02" PRIX64 " has been received %" PRIu64 " times until connection drop.", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) portal->host, (char *) portal->port, *(uint64_t *) stat_bucket->key, *stat_opcode );
+ logadd( LOG_INFO, "iSCSI SCSI CDB opcode usage statistics for device %s from initiator %s using port %s and portal %s:%s: SCSI CDB opcode 0x%02" PRIX64 " has been received %" PRIu64 " times until connection drop.", (conn->device != NULL ? (char *) conn->device->name : "(null)"), (char *) conn->init_name, ((conn->init_port != NULL) ? (char *) conn->init_port->name : "(null)"), (char *) add_portals.portal->host, (char *) add_portals.portal->port, *(uint64_t *) stat_bucket->key, *stat_opcode );
}
iscsi_session *session = conn->session;
@@ -14579,13 +15139,13 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ
conn->device = NULL;
const uint key_len = (uint) (strlen( (char *) device->name ) + 1U);
- hash_key = (uint64_t *) iscsi_hashmap_key_create( device->name, key_len );
+ uint8_t *hash_key = iscsi_hashmap_key_create( device->name, key_len );
if ( hash_key != NULL ) {
target->device = NULL;
- iscsi_hashmap_remove_free( iscsi_globvec->devices, (uint8_t *) hash_key, key_len, iscsi_device_destroy_callback, NULL );
- iscsi_hashmap_key_destroy( (uint8_t *) hash_key );
+ iscsi_hashmap_remove_free( iscsi_globvec->devices, hash_key, key_len, iscsi_device_destroy_callback, NULL );
+ iscsi_hashmap_key_destroy( hash_key );
}
}
@@ -14601,11 +15161,11 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ
conn->target = NULL;
const uint key_len = (uint) (strlen( (char *) target->name ) + 1U);
- hash_key = (uint64_t *) iscsi_hashmap_key_create( target->name, key_len );
+ uint8_t *hash_key = iscsi_hashmap_key_create( target->name, key_len );
if ( hash_key != NULL ) {
- iscsi_hashmap_remove_free( iscsi_globvec->target_nodes, (uint8_t *) hash_key, key_len, iscsi_target_node_destroy_callback, NULL );
- iscsi_hashmap_key_destroy( (uint8_t *) hash_key );
+ iscsi_hashmap_remove_free( iscsi_globvec->target_nodes, hash_key, key_len, iscsi_target_node_destroy_callback, NULL );
+ iscsi_hashmap_key_destroy( hash_key );
}
}
@@ -14615,10 +15175,5 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ
iscsi_connection_destroy( conn );
- pthread_rwlock_wrlock( &iscsi_globvec->portal_groups_rwlock );
- iscsi_portal_group_del_portal( portal_group, portal );
- iscsi_portal_destroy( portal );
- pthread_rwlock_unlock( &iscsi_globvec->portal_groups_rwlock );
-
pthread_rwlock_unlock( &iscsi_globvec_rwlock );
}
diff --git a/src/server/iscsi.h b/src/server/iscsi.h
index 29121c6..4d825f4 100644
--- a/src/server/iscsi.h
+++ b/src/server/iscsi.h
@@ -776,7 +776,6 @@ void iscsi_hashmap_destroy(iscsi_hashmap *map); // Deallocates the hash map obje
// Use iscsi_hashmap_iterate to deallocate the elements themselves
uint8_t *iscsi_hashmap_key_create(const uint8_t *data, const size_t len); // Creates a key suitable for hashmap usage (ensures 8-byte boundary and zero padding)
-void iscsi_hashmap_key_create_id(iscsi_hashmap *map, uint64_t *key); // Creates an unique key identifier suitable for hashmap usage (ensures 8-byte boundary and zero padding)
void iscsi_hashmap_key_destroy(uint8_t *key); // Deallocates all resources acquired by iscsi_hashmap_create_key
int iscsi_hashmap_key_destroy_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Deallocates a key in a hash map
int iscsi_hashmap_destroy_value_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Deallocates a value in a hash map
@@ -6026,9 +6025,6 @@ typedef struct __attribute__((packed)) iscsi_r2t_packet {
/// MaxCmdSN.
uint32_t max_cmd_sn;
- /// DataSN.
- uint32_t data_sn;
-
/// Ready To Transfer Sequence Number (R2TSN) is the R2T PDU input PDU number within the command identified by the Initiator Task Tag. For bidirectional commands, R2T and Data-In PDUs share the input PDU numbering sequence.
uint32_t r2t_sn;
@@ -6488,7 +6484,10 @@ typedef struct __attribute__((packed)) iscsi_text_response_packet {
uint32_t max_cmd_sn;
/// Reserved for future usage, always MUST be 0.
- uint64_t reserved2[2];
+ uint64_t reserved2;
+
+ /// Reserved for future usage, always MUST be 0.
+ uint32_t reserved3;
/// Optional header digest.
iscsi_header_digest hdr_digest;
@@ -9340,7 +9339,7 @@ typedef struct __attribute__((packed)) iscsi_snack_req_packet {
uint32_t exp_stat_sn;
/// Reserved for future usage, always MUST be 0.
- uint32_t reserved3;
+ uint64_t reserved3;
/**
* @brief BegRun.
@@ -9938,6 +9937,9 @@ int iscsi_parse_key_value_pairs(iscsi_hashmap *key_value_pairs, const uint8_t *p
#define ISCSI_GLOBALS_SECTION_SCSI "scsi"
+/// iSCSI main global data: iSCSI INI configuration iSCSI section portal group tag key identifier string.
+#define ISCSI_GLOBALS_SECTION_ISCSI_KEY_PORTAL_GROUP_TAG "PortalGroupTag"
+
/// iSCSI main global data: iSCSI INI configuration iSCSI section target name check key identifier string.
#define ISCSI_GLOBALS_SECTION_ISCSI_KEY_TARGET_NAME_CHECK "TargetNameCheck"
@@ -9976,96 +9978,101 @@ int iscsi_parse_key_value_pairs(iscsi_hashmap *key_value_pairs, const uint8_t *p
#define ISCSI_GLOBALS_SECTION_SCSI_KEY_WRITE_CACHE "WriteCache"
+/// iSCSI main global data: iSCSI portal group specific INI configuration section prefix identifier string.
+#define ISCSI_GLOBALS_SECTION_ISCSI_PORTAL_GROUP_PREFIX "iscsi-portal-group-"
+
+
+/// iSCSI main global data: iSCSI INI configuration iSCSI section portal group tag key identifier string.
+#define ISCSI_GLOBALS_SECTION_ISCSI_PORTAL_GROUP_KEY_ACCESS "Access"
+
+
/// iSCSI main global data: iSCSI SCSI device specific INI configuration section prefix identifier string.
#define ISCSI_GLOBALS_SECTION_SCSI_DEVICE_PREFIX "scsi-device-"
+/// iSCSI main global data config type: Portal group tag.
+#define ISCSI_GLOBALS_CONFIG_TYPE_PORTAL_GROUP_TAG 0
+
/// iSCSI main global data config type: Header digest (CRC32), always MUST be 0 or 4 for now.
-#define ISCSI_GLOBALS_CONFIG_TYPE_HEADER_DIGEST 0
+#define ISCSI_GLOBALS_CONFIG_TYPE_HEADER_DIGEST 1
/// iSCSI main global data config type: Data digest (CRC32), always MUST be 0 or 4 for now.
-#define ISCSI_GLOBALS_CONFIG_TYPE_DATA_DIGEST 1
+#define ISCSI_GLOBALS_CONFIG_TYPE_DATA_DIGEST 2
/// iSCSI main global data config type: Maximum receive DataSegment length in bytes.
-#define ISCSI_GLOBALS_CONFIG_TYPE_MAX_RECV_DS_LEN 2
+#define ISCSI_GLOBALS_CONFIG_TYPE_MAX_RECV_DS_LEN 3
/// iSCSI main global data config type: Maximum number of connections per session.
-#define ISCSI_GLOBALS_CONFIG_TYPE_MAX_SESSION_CONNS 3
+#define ISCSI_GLOBALS_CONFIG_TYPE_MAX_SESSION_CONNS 4
/// iSCSI main global data config type: Ready to transfer maximum outstanding value.
-#define ISCSI_GLOBALS_CONFIG_TYPE_MAX_OUTSTANDING_R2T 4
+#define ISCSI_GLOBALS_CONFIG_TYPE_MAX_OUTSTANDING_R2T 5
/// iSCSI main global data config type: Default time to wait.
-#define ISCSI_GLOBALS_CONFIG_TYPE_DEFAULT_TIME_TO_WAIT 5
+#define ISCSI_GLOBALS_CONFIG_TYPE_DEFAULT_TIME_TO_WAIT 6
/// iSCSI main global data config type: Default time to retain.
-#define ISCSI_GLOBALS_CONFIG_TYPE_DEFAULT_TIME_TO_RETAIN 6
+#define ISCSI_GLOBALS_CONFIG_TYPE_DEFAULT_TIME_TO_RETAIN 7
/// iSCSI main global data config type: First burst length.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FIRST_BURST_LEN 7
+#define ISCSI_GLOBALS_CONFIG_TYPE_FIRST_BURST_LEN 8
/// iSCSI main global data config type: Maximum burst length.
-#define ISCSI_GLOBALS_CONFIG_TYPE_MAX_BURST_LEN 8
+#define ISCSI_GLOBALS_CONFIG_TYPE_MAX_BURST_LEN 9
/// iSCSI main global data config type: Error recovery level.
-#define ISCSI_GLOBALS_CONFIG_TYPE_ERR_RECOVERY_LEVEL 9
+#define ISCSI_GLOBALS_CONFIG_TYPE_ERR_RECOVERY_LEVEL 10
/// iSCSI main global data config type: CHAP authentication group.
-#define ISCSI_GLOBALS_CONFIG_TYPE_CHAP_GROUP 10
+#define ISCSI_GLOBALS_CONFIG_TYPE_CHAP_GROUP 11
/// iSCSI main global data config type: SCSI emulation for device type.
-#define ISCSI_GLOBALS_CONFIG_TYPE_SCSI_DEVICE_TYPE 11
+#define ISCSI_GLOBALS_CONFIG_TYPE_SCSI_DEVICE_TYPE 12
/// iSCSI main global data config type: SCSI emulation for physical block size.
-#define ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE 12
-
-/// iSCSI main global data config type: SCSI emulation for physical block size shift count.
-#define ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE_SHIFT 13
+#define ISCSI_GLOBALS_CONFIG_TYPE_SCSI_PHYSICAL_BLOCK_SIZE 13
/// iSCSI main global data config type: SCSI emulation for logical block size.
#define ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE 14
-/// iSCSI main global data config type: SCSI emulation for logical block size shift count.
-#define ISCSI_GLOBALS_CONFIG_TYPE_SCSI_LOGICAL_BLOCK_SIZE_SHIFT 15
-
/// iSCSI main global data config type: CHAP authentication is disabled.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_CHAP_DISABLE 16
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_CHAP_DISABLE 15
/// iSCSI main global data config type: CHAP authentication is required.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_CHAP_REQUIRE 17
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_CHAP_REQUIRE 16
/// iSCSI main global data config type: CHAP authentication is mutual.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_CHAP_MUTUAL 18
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_CHAP_MUTUAL 17
/// iSCSI main global data config type: Initial ready to transfer.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_INIT_R2T 19
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_INIT_R2T 18
/// iSCSI main global data config type: Immediate data.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_IMMEDIATE_DATA 20
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_IMMEDIATE_DATA 19
/// iSCSI main global data config type: Data PDU in order.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_DATA_PDU_IN_ORDER 21
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_DATA_PDU_IN_ORDER 20
/// iSCSI main global data config type: Data sequence in order.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_DATA_SEQ_IN_ORDER 22
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_DATA_SEQ_IN_ORDER 21
/// iSCSI main global data config type: SCSI emulation for I/O removable device.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_REMOVABLE 23
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_REMOVABLE 22
/// iSCSI main global data config type: SCSI emulation for I/O UNMAP supporting device.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_UNMAP 24
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_UNMAP 23
/// iSCSI main global data config type: SCSI emulation for I/O non-rotating device.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_NO_ROTATION 25
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_NO_ROTATION 24
/// iSCSI main global data config type: SCSI emulation for I/O physical read only device.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_PHYSICAL_READ_ONLY 26
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_PHYSICAL_READ_ONLY 25
/// iSCSI main global data config type: SCSI emulation for I/O write protected device.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_WRITE_PROTECT 27
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_WRITE_PROTECT 26
/// iSCSI main global data config type: SCSI emulation for I/O write cache device.
-#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_WRITE_CACHE 28
+#define ISCSI_GLOBALS_CONFIG_TYPE_FLAGS_SCSI_IO_WRITE_CACHE 27
/// iSCSI main global data config type: Value error result.
@@ -10123,6 +10130,9 @@ typedef struct iscsi_scsi_device_config {
/// SCSI emulation: Device type.
uint scsi_device_type;
+ /// Default portal group tag;
+ uint32_t pg_tag;
+
/// Maximum receive DataSegment length in bytes.
uint32_t max_recv_ds_len;
@@ -10150,14 +10160,8 @@ typedef struct iscsi_scsi_device_config {
/// SCSI emulation: Physical block size.
uint32_t scsi_physical_block_size;
- /// SCSI emulation: Physical block size shift count.
- uint32_t scsi_physical_block_size_shift;
-
/// SCSI emulation: Logical block size.
uint32_t scsi_logical_block_size;
-
- /// SCSI emulation: Logical block size shift count.
- uint32_t scsi_logical_block_size_shift;
} iscsi_scsi_device_config;
@@ -10315,6 +10319,12 @@ typedef struct iscsi_globals {
/// SCSI emulation: Device type.
uint scsi_device_type;
+ /// Total number of connections so far.
+ _Atomic int connections;
+
+ /// Default portal group tag;
+ uint32_t pg_tag;
+
/// Maximum receive DataSegment length in bytes.
uint32_t max_recv_ds_len;
@@ -10345,14 +10355,8 @@ typedef struct iscsi_globals {
/// SCSI emulation: Physical block size.
uint32_t scsi_physical_block_size;
- /// SCSI emulation: Physical block size shift count.
- uint32_t scsi_physical_block_size_shift;
-
/// SCSI emulation: Logical block size.
uint32_t scsi_logical_block_size;
-
- /// SCSI emulation: Logical block size shift count.
- uint32_t scsi_logical_block_size_shift;
} iscsi_globals;
@@ -10372,7 +10376,7 @@ int32_t iscsi_config_get(uint8_t *name, const int type); // Retrieves a configur
/**
- * @brief iSCSI portal group: Private portal group if set, public otherwise.
+ * @brief iSCSI portal group flags: Private portal group if set, public otherwise.
*
* When redirecting logins, there are two portal group types: public and
* private.\n
@@ -10382,16 +10386,16 @@ int32_t iscsi_config_get(uint8_t *name, const int type); // Retrieves a configur
* Private portal groups instead do not return their portals during
* the discovery session.
*/
-#define ISCSI_PORTAL_GROUP_PRIVATE (1 << 0)
+#define ISCSI_PORTAL_GROUP_FLAGS_PRIVATE (1 << 0)
-/// iSCSI portal group: CHAP authentication is disabled.
-#define ISCSI_PORTAL_GROUP_CHAP_DISABLE (1 << 1)
+/// iSCSI portal group flags: CHAP authentication is disabled.
+#define ISCSI_PORTAL_GROUP_FLAGS_CHAP_DISABLE (1 << 1)
-/// iSCSI portal group: CHAP authentication is required.
-#define ISCSI_PORTAL_GROUP_CHAP_REQUIRE (1 << 2)
+/// iSCSI portal group flags: CHAP authentication is required.
+#define ISCSI_PORTAL_GROUP_FLAGS_CHAP_REQUIRE (1 << 2)
-/// iSCSI portal group: CHAP authentication is mutual.
-#define ISCSI_PORTAL_GROUP_CHAP_MUTUAL (1 << 3)
+/// iSCSI portal group flags: CHAP authentication is mutual.
+#define ISCSI_PORTAL_GROUP_FLAGS_CHAP_MUTUAL (1 << 3)
/**
@@ -10418,6 +10422,19 @@ typedef struct iscsi_portal_group {
} iscsi_portal_group;
+/// iSCSI portal type: None.
+#define ISCSI_PORTAL_TYPE_NONE 0U
+
+/// iSCSI portal type: Local (unix) socket.
+#define ISCSI_PORTAL_TYPE_SOCK 1U
+
+/// iSCSI portal type: IPv4 socket.
+#define ISCSI_PORTAL_TYPE_IPV4 2U
+
+/// iSCSI portal type: IPv6 socket.
+#define ISCSI_PORTAL_TYPE_IPV6 3U
+
+
/**
* @brief iSCSI portal.
*
@@ -10434,7 +10451,10 @@ typedef struct iscsi_portal {
/// Port of the portal.
uint8_t *port;
- /// TCP/IP socket for the portal.
+ /// Socket type.
+ uint type;
+
+ /// Socket file descriptor for the portal.
int sock;
} iscsi_portal;
@@ -10445,7 +10465,7 @@ void iscsi_portal_group_destroy(iscsi_portal_group *portal_group); // Deallocate
int iscsi_portal_group_add_portal(iscsi_portal_group *portal_group, iscsi_portal *portal); // Adds an iSCSI portal to the iSCSI portal group hash map
void iscsi_portal_group_del_portal(iscsi_portal_group *portal_group, iscsi_portal *portal); // Removes an iSCSI portal from the iSCSI portal group hash map
-iscsi_portal *iscsi_portal_create(const uint8_t *host, const uint8_t *port); // Allocates and initializes an iSCSI portal structure
+iscsi_portal *iscsi_portal_create(const uint8_t *host, const uint8_t *port, const uint type); // Allocates and initializes an iSCSI portal structure
int iscsi_portal_destroy_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // iSCSI portal destructor callback for hash map
void iscsi_portal_destroy(iscsi_portal *portal);
@@ -11171,8 +11191,8 @@ typedef struct iscsi_target_node {
/// Associated iSCSI device.
iscsi_device *device;
- /// Target node number.
- uint num;
+ /// Portal group tag associated with this target node.
+ uint64_t pg_tag;
/// Queue depth.
uint queue_depth;
@@ -11195,6 +11215,45 @@ typedef struct iscsi_target_node {
/**
+ * @brief iSCSI target node send by name.
+ *
+ * This structure is used by iterating through
+ * all iSCSI target nodes sending by name.
+ */
+typedef struct iscsi_target_node_send_name {
+ /// iSCSI connection sending the target nodes.
+ iscsi_connection *conn;
+
+ /// The IQN of the target node to send. NULL matches all target nodes.
+ uint8_t *dst_iqn;
+
+ /// The initiator IQN to send.
+ uint8_t *src_iqn;
+
+ /// Copy buffer for key and value pairs.
+ uint8_t *tmp_buf;
+
+ /// Buffer where to store the key and value pairs of target nodes to send.
+ uint8_t *buf;
+
+ /// Position of buffer in bytes where to start filling key and value pairs of target nodes to send.
+ uint32_t pos;
+
+ /// Length of buffer in bytes where to start filling key and value pairs of target nodes to send.
+ uint32_t len;
+
+ /// Length of copy buffer in bytes for key and value pairs.
+ uint32_t tmp_len;
+
+ /// Previous iSCSI SendTargets total number of bytes completed.
+ uint32_t prev_target_send_total_size;
+
+ /// True if the submitted buffer would overflow.
+ bool buf_full;
+} iscsi_target_node_send_name;
+
+
+/**
* @brief iSCSI target node search by name.
*
* This structure is used by iterating through
@@ -11458,6 +11517,9 @@ typedef struct iscsi_connection {
/// iSCSI target short name.
uint8_t *target_name_short;
+ /// iSCSI target host name.
+ uint8_t *target_host;
+
/// iSCSI portal host name.
uint8_t *portal_host;
@@ -11485,9 +11547,6 @@ typedef struct iscsi_connection {
/// Doubly linked list containing queued Ready To Transfer (R2T) tasks.
iscsi_list r2t_tasks_queue;
- /// iSCSI SendTargets total number of bytes completed.
- uint target_send_total_size;
-
/// iSCSI SCSI Data In count.
uint scsi_data_in_cnt;
@@ -11506,7 +11565,7 @@ typedef struct iscsi_connection {
/// iSCSI connection contains a data digest (CRC32), always MUST be 0 or 4 for now.
int data_digest;
- /// Internal connection identifier (key of iSCSI global vector hash map).
+ /// Internal unique connection identifier.
int id;
/// Connected TCP/IP socket.
@@ -11524,6 +11583,9 @@ typedef struct iscsi_connection {
/// iSCSI connection login phase.
int login_phase;
+ /// iSCSI SendTargets total number of bytes completed.
+ uint32_t target_send_total_size;
+
/// Maximum receive DataSegment length in bytes.
uint32_t max_recv_ds_len;
@@ -11845,6 +11907,31 @@ typedef struct iscsi_task {
} iscsi_task;
+/**
+ * @brief iSCSI portal group iterator for adding portals.
+ *
+ * This structure is used by iterating through
+ * all iSCSI portal groups and adding all
+ * portals to each portal group.
+ */
+typedef struct iscsi_connection_handle_add_portals {
+ /// DNBD3 client socket to be used for a specified iSCSI connection.
+ int sock;
+
+ /// iSCSI portal which contains the portal to be used for a specified iSCSI connection.
+ iscsi_portal *portal;
+
+ /// Host IP address string to be used for a specified iSCSI connection.
+ uint8_t *host;
+
+ /// Port string to be used for a specified iSCSI connection.
+ uint8_t *port;
+
+ /// iSCSI portal group or portals have been added and write lock is necessary.
+ bool write_locked;
+} iscsi_connection_handle_add_portals;
+
+
iscsi_task *iscsi_task_create(iscsi_connection *conn, iscsi_task *parent, iscsi_scsi_task_xfer_complete_callback callback); // Allocates and initializes an iSCSI task structure
void iscsi_task_destroy_callback(iscsi_scsi_task *scsi_task); // Deallocates all resources of the iSCSI task of an iSCSI SCSI task
void iscsi_task_destroy(iscsi_task *task); // Deallocates resources acquired by iscsi_task_create
@@ -11869,11 +11956,13 @@ int iscsi_device_port_add(iscsi_device *device, const uint8_t *name, const uint6
void iscsi_device_scsi_task_queue(iscsi_device *device, iscsi_scsi_task *scsi_task); // Enqueues an iSCSI SCSI task to the first LUN of an iSCSI device
int iscsi_target_node_create_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Creates, initializes and adds a portal group to an iSCSI target node
-iscsi_target_node *iscsi_target_node_create(uint8_t *name, const uint8_t *alias, const int index, const int lun_id, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest); // Creates and initializes an iSCSI target node
+iscsi_target_node *iscsi_target_node_create(uint8_t *name, const uint8_t *alias, const uint64_t pg_tag, const int lun_id, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest); // Creates and initializes an iSCSI target node
int iscsi_target_node_destroy_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // iSCSI target node destructor callback for hash map
void iscsi_target_node_destroy(iscsi_target_node *target); // Deallocates all resources acquired by iscsi_target_node_create
-int32_t iscsi_target_node_send(iscsi_connection *conn, const uint8_t *dst_iqn, const uint8_t *src_iqn, uint8_t *buf, const uint32_t pos, const uint32_t len); // Sends a buffer from a source iSCSI IQN to target iSCSI IQNs
+int iscsi_target_node_portals_send_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Sends an iSCSI portal for iSCSI discovery to a buffer
+int iscsi_target_node_send_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Sends an iSCSI discovery source target node IQN for a specific target IQN to a buffer
+int32_t iscsi_target_node_send(iscsi_connection *conn, uint8_t *dst_iqn, uint8_t *src_iqn, uint8_t *buf, const uint32_t pos, const uint32_t len); // Sends a target node discovery source iSCSI IQN to a buffer for target IQNs
uint64_t iscsi_target_node_wwn_get(const uint8_t *name); // Calculates the WWN using 64-bit IEEE Extended NAA for a name
dnbd3_image_t *iscsi_target_node_image_get(uint8_t *iqn); // Extracts the DNBD3 image out of an iSCSI IQN string and opens the DNBD3 image
iscsi_device *iscsi_target_node_device_attach(iscsi_target_node *target, uint8_t *target_name); // Creates a new iSCSI device and attaches it to a specified iSCSI target node if no device was connected yet
@@ -11928,6 +12017,7 @@ int iscsi_connection_read_iov_data(iscsi_connection *conn, struct iovec *iov, in
void iscsi_connection_pdu_write(iscsi_connection *conn, iscsi_pdu *pdu, iscsi_connection_xfer_complete_callback callback, uint8_t *user_data);
int iscsi_connection_pdu_handle(iscsi_connection *conn); // Handles incoming PDU data, read up to 16 fragments at once
+int iscsi_connection_handle_add_portals_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Adds iSCSI portals to a specified iSCSI portal group
void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *request, const int len); // Handles an iSCSI connection until connection is closed
#ifdef __cplusplus