summaryrefslogtreecommitdiffstats
path: root/src/server/iscsi.h
diff options
context:
space:
mode:
authorSebastian Vater2025-08-14 16:27:10 +0200
committerSimon Rettberg2025-12-09 15:33:20 +0100
commit02d2cd49b4a944021969646653d099e006c2ee4f (patch)
tree3e66cd3d516128b8fcbac2dd788254add1b06ce1 /src/server/iscsi.h
parent[SERVER] iscsi: Implement receive loop, add a lot of new iSCSI structures (diff)
downloaddnbd3-02d2cd49b4a944021969646653d099e006c2ee4f.tar.gz
dnbd3-02d2cd49b4a944021969646653d099e006c2ee4f.tar.xz
dnbd3-02d2cd49b4a944021969646653d099e006c2ee4f.zip
[SERVER] iscsi: Finish login handling, add NOP-In/Out handling
Also a couple bug fixes and other minor improvements
Diffstat (limited to 'src/server/iscsi.h')
-rw-r--r--src/server/iscsi.h179
1 files changed, 143 insertions, 36 deletions
diff --git a/src/server/iscsi.h b/src/server/iscsi.h
index 56e09f9..5990d69 100644
--- a/src/server/iscsi.h
+++ b/src/server/iscsi.h
@@ -141,6 +141,12 @@ uint8_t *iscsi_sprintf_alloc(const char *format, ... ); // Allocates a buffer an
/// Key data size must be multiple of 8 bytes by now.
#define ISCSI_HASHMAP_KEY_ALIGN (1UL << (ISCSI_HASHMAP_KEY_ALIGN_SHIFT))
+/// Value data shift value for alignment enforcement.
+#define ISCSI_HASHMAP_VALUE_ALIGN_SHIFT 4UL
+
+/// Value data size is a multiple of 16 bytes for key and value pairs, which allows us to change their integer values without reallocation of memory.
+#define ISCSI_HASHMAP_VALUE_ALIGN (1UL << (ISCSI_HASHMAP_VALUE_ALIGN_SHIFT))
+
/// Initial hash code.
#define ISCSI_HASHMAP_HASH_INITIAL 0x811C9DC5UL
@@ -253,9 +259,21 @@ int iscsi_hashmap_iterate(iscsi_hashmap *map, iscsi_hashmap_callback callback, u
/* iSCSI protocol stuff (all WORD/DWORD/QWORD values are big endian by default
unless specified otherwise). */
-/// iSCSI Basic Header Segment size.
+/// iSCSI Basic Header Segment (BHS) size.
#define ISCSI_BHS_SIZE 48UL
+/// iSCSI Advanced Header Segment (AHS) maximum allowed size.
+#define ISCSI_MAX_AHS_SIZE (255UL << 2UL)
+
+/// iSCSI DataSegment maximum allowed size.
+#define ISCSI_MAX_DS_SIZE 16777215UL
+
+/// iSCSI packet data alignment (BHS, AHS and DataSegment).
+#define ISCSI_ALIGN_SIZE 4UL
+
+/// iSCSI header and data digest size (CRC32C).
+#define ISCSI_DIGEST_SIZE 4UL
+
/// iSCSI Default receive DataSegment (DS) size in bytes.
#define ISCSI_DEFAULT_RECV_DS_LEN 8192UL
@@ -267,13 +285,6 @@ int iscsi_hashmap_iterate(iscsi_hashmap *map, iscsi_hashmap_callback callback, u
#define ISCSI_DEFAULT_MAX_DATA_OUT_PER_CONNECTION 16UL
-/// iSCSI header and data digest size (CRC32C).
-#define ISCSI_DIGEST_SIZE 4UL
-
-/// iSCSI packet data alignment (BHS, AHS and DataSegment).
-#define ISCSI_ALIGN_SIZE 4UL
-
-
/// Current minimum iSCSI protocol version supported by this implementation.
#define ISCSI_VERSION_MIN 0
@@ -381,6 +392,7 @@ int iscsi_hashmap_iterate(iscsi_hashmap *map, iscsi_hashmap_callback callback, u
/// Macro which extracts iSCSI packet data opcode out of opcode byte
#define ISCSI_GET_OPCODE(x) ((x) & ISCSI_OPCODE_MASK)
+
/**
* @brief iSCSI Basic Header Segment packet data.
*
@@ -4317,7 +4329,7 @@ typedef struct __attribute__((packed)) iscsi_isid {
* this also indicates that the initiator is ready for the Login
* Final-Response.
*/
-#define ISCSI_LOGIN_REQ_FLAGS_TRANSMIT (1 << 7)
+#define ISCSI_LOGIN_REQ_FLAGS_TRANSIT (1 << 7)
/**
@@ -4487,7 +4499,7 @@ typedef struct __attribute__((packed)) iscsi_login_req_packet {
#define ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_MASK ((1 << (ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_FIRST_BIT)) | (1 << (ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_SECOND_BIT)))
/// Login response flags: Extracts the Next Stage (NSG) bits.
-#define ISCSI_LOGIN_RESPONSES_FLAGS_GET_NEXT_STAGE(x) (((x) & ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_MASK) >> ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_FIRST_BIT)
+#define ISCSI_LOGIN_RESPONSE_FLAGS_GET_NEXT_STAGE(x) (((x) & ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_MASK) >> ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_FIRST_BIT)
@@ -4527,7 +4539,7 @@ typedef struct __attribute__((packed)) iscsi_login_req_packet {
#define ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_MASK ((1 << (ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_FIRST_BIT)) | (1 << (ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_SECOND_BIT)))
/// Login request flags: Extracts the Current Stage (CSG) bits.
-#define ISCSI_LOGIN_RESPONSES_FLAGS_GET_CURRENT_STAGE(x) (((x) & ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_MASK) >> ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_FIRST_BIT)
+#define ISCSI_LOGIN_RESPONSE_FLAGS_GET_CURRENT_STAGE(x) (((x) & ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_MASK) >> ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_FIRST_BIT)
/**
@@ -4554,7 +4566,7 @@ typedef struct __attribute__((packed)) iscsi_login_req_packet {
* If the Status-Class is 0, the T bit MUST NOT be set to 1 if the T bit
* in the request was set to 0.
*/
-#define ISCSI_LOGIN_RESPONSE_FLAGS_TRANSMIT (1 << 7)
+#define ISCSI_LOGIN_RESPONSE_FLAGS_TRANSIT (1 << 7)
/**
@@ -5688,6 +5700,7 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint
/// Maximum length of value for a normal key.
#define ISCSI_TEXT_VALUE_MAX_LEN 8192UL
+
/// iSCSI text key=value pair type: Invalid.
#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_INVALID -1L
@@ -5716,6 +5729,55 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint
#define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_BOOL_AND 7L
+/// iSCSI key value pair flags: Discovery ignored.
+#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_DISCOVERY_IGNORE (1 << 0L)
+
+/// iSCSI key value pair flags: Multi negotiation.
+#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_MULTI_NEGOTIATION (1 << 1L)
+
+/// iSCSI key value pair flags: Target declarative.
+#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_TARGET_DECLARATIVE (1 << 2L)
+
+/// iSCSI key value pair flags: CHAP type.
+#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_CHAP_TYPE (1 << 3L)
+
+/// iSCSI key value pair flags: Requires special handling.
+#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_SPECIAL_HANDLING (1 << 4L)
+
+/// iSCSI key value pair flags: Use previous default value.
+#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_USE_PREVIOUS_VALUE (1 << 5L)
+
+/// iSCSI key value pair flags: Override with default value.
+#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_OVERRIDE_DEFAULT (1 << 6L)
+
+/// iSCSI key value pair flags: Uses maximum value depending on secondary key.
+#define ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_USE_OTHER_MAX_VALUE (1 << 7L)
+
+
+/**
+ * @brief iSCSI connection and session lookup table entry, used for allowed key values and determining key type.
+ *
+ * This structure is shared by the iSCSI session
+ * and the iSCSI connection lookup table.
+ */
+typedef struct iscsi_key_value_pair_lut_entry {
+ /// Name of key.
+ uint8_t *key;
+
+ /// Default value of the key, always in string representation.
+ uint8_t *value;
+
+ /// NUL separated list of allowed string values. If key type is numeric: NUL separated minimum and maximum integer range. End is marked with another NUL.
+ uint8_t *list_range;
+
+ /// Type of key and value pair.
+ const int type;
+
+ /// Flags indicating special key attributes.
+ const int flags;
+} iscsi_key_value_pair_lut_entry;
+
+
/**
* @brief iSCSI Text / Login extracted key=value pair.
*
@@ -5724,14 +5786,20 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint
* Text or Login packet data.
*/
typedef struct iscsi_key_value_pair {
+ /// Value of the key which is stored in the hash map.
+ uint8_t *value;
+
+ /// NUL separated list of allowed string values. If key type is numeric: NUL separated minimum and maximum integer range. End is marked with another NUL.
+ uint8_t *list_range;
+
/// Type of key and value pair.
- int type;
+ int type;
- /// State index.
- int state_index;
+ /// Flags indicating special key attributes.
+ int flags;
- /// Value of the key which is stored in the hash map.
- uint8_t *value;
+ /// State bit mask.
+ uint state_mask;
} iscsi_key_value_pair;
/**
@@ -5741,16 +5809,23 @@ typedef struct iscsi_key_value_pair {
* pairs for sending as DataSegment packet data to the client.
*/
typedef struct iscsi_key_value_pair_packet {
+ /// Associated iSCSI connection.
+ struct iscsi_connection *conn;
+
/// Current text buffer containing multiple key=value + NUL terminator pairs.
uint8_t *buf;
+ /// Position of output buffer for next write.
+ uint pos;
+
/// Current length of buffer including final NUL terminator without iSCSI zero padding.
uint len;
+
+ /// Discovery mode.
+ int discovery;
} iscsi_key_value_pair_packet;
int iscsi_parse_key_value_pairs(iscsi_hashmap *pairs, const uint8_t *packet_data, uint len, int c_bit, uint8_t **partial_pairs); // Extracts all text key / value pairs out of an iSCSI packet into a hash map
-int iscsi_create_key_value_pair_packet_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Creates a single partial iSCSI packet stream out of a single text key and value pair
-iscsi_key_value_pair_packet *iscsi_create_key_value_pairs_packet(iscsi_hashmap *key_value_pairs); // Creates a properly aligned iSCSI packet DataSegment out of a hash map containing text key and value pairs
/// iSCSI main global data flags: Allow duplicate ISIDs.
@@ -5785,9 +5860,15 @@ typedef struct iscsi_globals {
/// Hash map containing all iSCSI sessions.
iscsi_hashmap *sessions;
+ /// Hash map containing session key and value pair types and allowed values or ranges.
+ iscsi_hashmap *session_key_value_pairs;
+
/// Hash map containing connections not associated with an iSCSI sessions.
iscsi_hashmap *connections;
+ /// Hash map containing connection key and value pair types and allowed values or ranges.
+ iscsi_hashmap *connection_key_value_pairs;
+
/// Global flags.
int flags;
@@ -5799,10 +5880,14 @@ typedef struct iscsi_globals {
} iscsi_globals;
-/// iSCSI vector for global access.
+/// iSCSI global vector. MUST be initialized with iscsi_create before any iSCSI functions are used.
iscsi_globals *iscsi_globvec = NULL;
+int iscsi_create(); // Allocates and initializes the iSCSI global vector structure
+int iscsi_global_key_value_pair_destroy_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // iSCSI global key and value pair destructor callback for hash map
+void iscsi_destroy(); // Deallocates all resources acquired by iscsi_create
+
/**
* @brief iSCSI portal group: Private portal group if set, public otherwise.
*
@@ -6179,44 +6264,50 @@ typedef struct iscsi_session {
/// iSCSI connection read packet data return code from iscsi_connection_pdu_read function: Packet parsed successfully.
-#define ISCSI_CONNECT_PDU_READ_OK 0L
+#define ISCSI_CONNECT_PDU_READ_OK 0L
/// iSCSI connection read packet data return code from iscsi_connection_pdu_read function: Packet processed successfully.
-#define ISCSI_CONNECT_PDU_READ_PROCESSED 1L
+#define ISCSI_CONNECT_PDU_READ_PROCESSED 1L
/// iSCSI connection read packet data return code from iscsi_connection_pdu_read function: Fatail error during packet parsing.
-#define ISCSI_CONNECT_PDU_READ_ERR_FATAL -1L
+#define ISCSI_CONNECT_PDU_READ_ERR_FATAL -1L
/// iSCSI connection read packet data return code from iscsi_connection_pdu_read function: Login error response.
-#define ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE -2L
+#define ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE -2L
/// iSCSI connection read packet data return code from iscsi_connection_pdu_read function: Login parameter error.
-#define ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER -3L
+#define ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER -3L
+
+/// iSCSI connection read packet data return code from iscsi_connection_pdu_read function: Login parameter not exchanged once error.
+#define ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER_XCHG_NOT_ONCE -4L
/// iSCSI connection flags: Stopped.
-#define ISCSI_CONNECT_FLAGS_STOPPED (1 << 0L)
+#define ISCSI_CONNECT_FLAGS_STOPPED (1 << 0L)
/// iSCSI connection flags: Rejected.
-#define ISCSI_CONNECT_FLAGS_REJECTED (1 << 1L)
+#define ISCSI_CONNECT_FLAGS_REJECTED (1 << 1L)
/// iSCSI connection flags: Logged out.
-#define ISCSI_CONNECT_FLAGS_LOGGED_OUT (1 << 2L)
+#define ISCSI_CONNECT_FLAGS_LOGGED_OUT (1 << 2L)
/// iSCSI connection flags: Full feature.
-#define ISCSI_CONNECT_FLAGS_FULL_FEATURE (1 << 3L)
+#define ISCSI_CONNECT_FLAGS_FULL_FEATURE (1 << 3L)
/// iSCSI connection flags: CHAP authentication is disabled.
-#define ISCSI_CONNECT_FLAGS_CHAP_DISABLE (1 << 4L)
+#define ISCSI_CONNECT_FLAGS_CHAP_DISABLE (1 << 4L)
/// iSCSI connection flags: CHAP authentication is required.
-#define ISCSI_CONNECT_FLAGS_CHAP_REQUIRE (1 << 5L)
+#define ISCSI_CONNECT_FLAGS_CHAP_REQUIRE (1 << 5L)
/// iSCSI connection flags: CHAP authentication is mutual.
-#define ISCSI_CONNECT_FLAGS_CHAP_MUTUAL (1 << 6L)
+#define ISCSI_CONNECT_FLAGS_CHAP_MUTUAL (1 << 6L)
/// iSCSI connection flags: Authenticated.
-#define ISCSI_CONNECT_FLAGS_AUTH (1 << 7L)
+#define ISCSI_CONNECT_FLAGS_AUTH (1 << 7L)
+
+/// iSCSI connection flags: Oustanding NOP.
+#define ISCSI_CONNECT_FLAGS_NOP_OUTSTANDING (1 << 8L)
/// Ready to wait for PDU.
@@ -6302,6 +6393,9 @@ typedef struct iscsi_connection {
/// Login response PDU.
struct iscsi_pdu *login_response_pdu;
+ /// Internal connection identifier (key of iSCSI global vector hash map).
+ int id;
+
/// Connected TCP/IP socket.
int sock;
@@ -6314,6 +6408,9 @@ typedef struct iscsi_connection {
/// iSCSI connection state.
int state;
+ /// iSCSI connection login phase.
+ int login_phase;
+
/// Maximum receive DataSegment length in bytes.
uint max_recv_ds_len;
@@ -6329,6 +6426,12 @@ typedef struct iscsi_connection {
/// Connection ID (CID).
uint16_t cid;
+ /// Bit mask for connection state key negotiation.
+ uint16_t state_negotiated;
+
+ /// Bit mask for session state key negotiation.
+ uint32_t session_state_negotiated;
+
/// Initiator Task Tag (ITT).
uint32_t init_task_tag;
@@ -6403,10 +6506,10 @@ typedef struct iscsi_pdu {
/// DataSegmentLength.
uint ds_len;
- /// Remaining bytes of DataSegment buffer to read.
- uint buf_len;
+ /// Position of DataSegment buffer for next read.
+ uint pos;
- /// Associated connection.
+ /// Associated iSCSI connection.
iscsi_connection *conn;
/// CmdSN.
@@ -6423,6 +6526,8 @@ int iscsi_target_node_access(iscsi_connection *conn, iscsi_target_node *target,
iscsi_session *iscsi_session_create(iscsi_connection *conn, iscsi_target_node *target, const int type); // Creates and initializes an iSCSI session
void iscsi_session_destroy(iscsi_session *session); // Deallocates all resources acquired by iscsi_session_create
+int iscsi_session_init_key_value_pairs(iscsi_hashmap *key_value_pairs); // Initializes a key and value pair hash table with default values
+
iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock); // Creates data structure for an iSCSI connection from iSCSI portal and TCP/IP socket
int iscsi_connection_destroy_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // iSCSI connection destructor callback for hash map
void iscsi_connection_destroy(iscsi_connection *conn); // Deallocates all resources acquired by iscsi_connection_create
@@ -6433,6 +6538,8 @@ void iscsi_connection_schedule(iscsi_connection *conn); // Schedules an iSCSI co
int iscsi_connection_read(const iscsi_connection *conn, uint8_t *buf, const uint len); // Reads data for the specified iSCSI connection from its TCP socket
int iscsi_connection_write(const iscsi_connection *conn, uint8_t *buf, const uint len); // Writes data for the specified iSCSI connection to its TCP socket
+int iscsi_connection_init_key_value_pairs(iscsi_hashmap *key_value_pairs); // Initializes a key and value pair hash table with default values for an iSCSI connection
+int iscsi_negotiate_key_value_pairs(iscsi_connection *conn, iscsi_hashmap *key_value_pairs, uint8_t *buf, const uint pos, const uint len); // Negotiates all key and value pairs required for session authentication
int iscsi_connection_copy_key_value_pairs(iscsi_connection *conn); // Copies retrieved key and value pairs into SCSI connection and session structures
int iscsi_connection_save_incoming_key_value_pairs(iscsi_connection *conn, iscsi_hashmap *key_value_pairs, iscsi_pdu *login_response_pdu, const iscsi_pdu *pdu); // Saves incoming key / value pairs from the client of a login request PDU