summaryrefslogtreecommitdiffstats
path: root/src/server/iscsi.c
diff options
context:
space:
mode:
authorSebastian Vater2025-08-19 16:53:14 +0200
committerSebastian Vater2025-08-19 16:53:14 +0200
commit254dea5ab33170e1c7d7dde19c73b82da35f4e0f (patch)
tree624d8ed8c42400fcd9d32d6ac5a13c02a27401e2 /src/server/iscsi.c
parentAdded iSCSI NOP-In and NOP-Out implementation for keep alive. Also increased ... (diff)
downloaddnbd3-254dea5ab33170e1c7d7dde19c73b82da35f4e0f.tar.gz
dnbd3-254dea5ab33170e1c7d7dde19c73b82da35f4e0f.tar.xz
dnbd3-254dea5ab33170e1c7d7dde19c73b82da35f4e0f.zip
Added iSCSI handling to main server and network handling code and also creation of basic iSCSI portal and initial iSCSI connection. Finally, implemented iSCSI logout response.
Diffstat (limited to 'src/server/iscsi.c')
-rw-r--r--src/server/iscsi.c169
1 files changed, 163 insertions, 6 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c
index bfda85b..7546f00 100644
--- a/src/server/iscsi.c
+++ b/src/server/iscsi.c
@@ -27,7 +27,12 @@
#include <strings.h>
#include <sys/socket.h>
#include <dnbd3/shared/log.h>
+#include <dnbd3/shared/sockhelper.h>
+#include <dnbd3/types.h>
#include <time.h>
+
+#include "globals.h"
+#include "helper.h"
#include "iscsi.h"
/**
@@ -43,6 +48,9 @@
* @see https://www.rfc-editor.org/rfc/rfc7143
*/
+/// iSCSI global vector. MUST be initialized with iscsi_create before any iSCSI functions are used.
+iscsi_globals *iscsi_globvec = NULL;
+
/// iSCSI connection negotation key and value pair lookup table.
static const iscsi_key_value_pair_lut_entry iscsi_connection_key_value_pair_lut[] = {
{ (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_HEADER_DIGEST, (uint8_t *) "None", (uint8_t *) "CRC32C\0None\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_LIST, 0L },
@@ -4717,7 +4725,7 @@ static int iscsi_connection_pdu_header_handle_nop_out(iscsi_connection *conn, is
const uint32_t init_task_tag = iscsi_get_be32(nop_out_pkt->init_task_tag);
const uint32_t target_xfer_tag = iscsi_get_be32(nop_out_pkt->target_xfer_tag);
- if ( (target_xfer_tag != 0xFFFFFFFFUL) && (target_xfer_tag != conn->id) )
+ if ( (target_xfer_tag != 0xFFFFFFFFUL) && (target_xfer_tag != (uint32_t) conn->id) )
return iscsi_connection_handle_reject( conn, pdu, ISCSI_REJECT_REASON_INVALID_PDU_FIELD ); // TODO: Check if this is the correct error code.
if ( (init_task_tag == 0xFFFFFFFFUL) && (nop_out_pkt->opcode & 0x40) == 0 )
@@ -4831,9 +4839,70 @@ static int iscsi_connection_pdu_header_handle_scsi_data_out(iscsi_connection *co
*/
static int iscsi_connection_pdu_header_handle_logout_req(iscsi_connection *conn, iscsi_pdu *pdu)
{
- // TODO: Implement opcode.
+ iscsi_logout_req_packet *logout_req_pkt = (iscsi_logout_req_packet *) pdu->bhs_pkt;
- return 0;
+ if ( (conn->session != NULL) && (conn->session->type == ISCSI_SESSION_TYPE_DISCOVERY) && (logout_req_pkt->reason_code != ISCSI_LOGOUT_REQ_REASON_CODE_CLOSE_SESSION) )
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+
+ iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn );
+
+ if ( response_pdu == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_pdu_header_handle_logout_req: Out of memory while allocating iSCSI logout response PDU" );
+
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+
+ iscsi_logout_response_packet *logout_response_pkt = (iscsi_logout_response_packet *) response_pdu->bhs_pkt;
+
+ if ( conn->header_digest != 0 ) {
+ logout_response_pkt = (iscsi_logout_response_packet *) iscsi_append_header_digest_packet( response_pdu->bhs_pkt, conn->header_digest );
+
+ if ( logout_response_pkt == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_pdu_header_handle_logout_req: Out of memory while allocating iSCSI logout packet data" );
+
+ iscsi_connection_pdu_destroy( response_pdu );
+
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+
+ response_pdu->bhs_pkt = (iscsi_bhs_packet *) logout_response_pkt;
+ response_pdu->header_digest = (iscsi_header_digest *) (((iscsi_bhs_packet *) logout_response_pkt) + 1);
+ response_pdu->header_digest_size = conn->header_digest;
+ }
+
+ logout_response_pkt->opcode = ISCSI_SERVER_LOGOUT_RES;
+ logout_response_pkt->flags = -0x80;
+
+ const uint16_t cid = iscsi_get_be16(logout_req_pkt->cid);
+
+ if ( cid == conn->cid ) {
+ conn->flags |= ISCSI_CONNECT_FLAGS_LOGGED_OUT;
+
+ logout_response_pkt->response = ISCSI_LOGOUT_RESPONSE_CLOSED_SUCCESSFULLY;
+ } else {
+ logout_response_pkt->response = ISCSI_LOGOUT_RESPONSE_CID_NOT_FOUND;
+ }
+
+ logout_response_pkt->init_task_tag = logout_req_pkt->init_task_tag; // Copying over doesn't change endianess.
+ iscsi_put_be32( (uint8_t *) &logout_response_pkt->stat_sn, conn->stat_sn++ );
+
+ if ( conn->session != NULL ) {
+ if ( iscsi_hashmap_size( conn->session->connections ) == 1 )
+ conn->session->max_cmd_sn++;
+
+ iscsi_put_be32( (uint8_t *) &logout_response_pkt->exp_cmd_sn, conn->session->exp_cmd_sn );
+ iscsi_put_be32( (uint8_t *) &logout_response_pkt->max_cmd_sn, conn->session->max_cmd_sn );
+ } else {
+ iscsi_put_be32( (uint8_t *) &logout_response_pkt->exp_cmd_sn, pdu->cmd_sn );
+ iscsi_put_be32( (uint8_t *) &logout_response_pkt->max_cmd_sn, pdu->cmd_sn );
+ }
+
+ logout_response_pkt->time_wait = 0U;
+ logout_response_pkt->time_retain = 0U;
+
+ iscsi_connection_pdu_write( conn, response_pdu, NULL, NULL );
+
+ return ISCSI_CONNECT_PDU_READ_OK;
}
/**
@@ -6027,14 +6096,14 @@ static int iscsi_connection_pdu_read(iscsi_connection *conn)
#define ISCSI_PDU_HANDLE_COUNT 16
/**
- * @brief Handle incoming PDU data, read up to 16 fragments at once.
+ * @brief Handles incoming PDU data, read up to 16 fragments at once.
*
* Until iSCSI processing has been stopped or a
* complete iSCSI packet has been read, this
* function will read, parse and process
* incoming iSCSI protocol data.
*
- * @param[in] iSCSI connection to handle.
+ * @param[in] conn iSCSI connection to handle.
* @return Number of proccessed fragments or return
* code of iscsi_connection_pdu_read in case of a
* fatal error.
@@ -6044,7 +6113,7 @@ int iscsi_connection_pdu_handle(iscsi_connection *conn)
uint i;
for ( i = 0; i < ISCSI_PDU_HANDLE_COUNT; i++ ) {
- int rc = iscsi_connection_pdu_read(conn);
+ int rc = iscsi_connection_pdu_read( conn );
if ( rc == 0 )
break;
@@ -6057,3 +6126,91 @@ int iscsi_connection_pdu_handle(iscsi_connection *conn)
return i;
}
+
+/**
+ * @brief Handles an iSCSI connection until connection is closed.
+ *
+ * This function creates an iSCSI portal group
+ * and iSCSI portal with connection data
+ * delivered from the DNBD3 client and
+ * request data.
+ *
+ * @param[in] client Pointer to DNBD3 client structure,
+ * may NOT be NULL, so be careful.
+ * @param[in] request Pointer to DNBD3 request packet data.
+ * NULL is not allowed here, take caution.
+ * @param[in] len Length of already read DNBD3 request data.
+ */
+void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *request, const int len)
+{
+ _Static_assert( sizeof(dnbd3_request_t) <= sizeof(struct iscsi_bhs_packet) );
+ sock_setTimeout( client->sock, 1000L * 3600L ); // TODO: Remove after finishing iSCSI implementation
+
+ host_to_string( &client->host, client->hostName, HOSTNAMELEN );
+ const uint8_t *port = memchr( client->hostName, ':', HOSTNAMELEN );
+
+ if ( port != NULL )
+ port++;
+
+ iscsi_portal *portal = iscsi_portal_create( (uint8_t *) client->hostName, port );
+
+ if ( portal == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal" );
+
+ return;
+ }
+
+ iscsi_connection *conn = iscsi_connection_create( portal, client->sock );
+
+ if ( conn == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI connection" );
+
+ iscsi_portal_destroy( portal );
+
+ return;
+ }
+
+ const int id = iscsi_hashmap_size( iscsi_globvec->connections ) + 1;
+
+ conn->id = id;
+
+ uint8_t *hash_key = iscsi_hashmap_key_create( (uint8_t *) &id, sizeof(id) );
+
+ if ( hash_key == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI connection" );
+
+ iscsi_connection_destroy( conn );
+ iscsi_portal_destroy( portal );
+
+ return;
+ }
+
+ conn->pdu_processing = iscsi_connection_pdu_create( conn );
+
+ if ( conn->pdu_processing == NULL ) {
+ iscsi_hashmap_key_destroy( hash_key );
+ iscsi_connection_destroy( conn );
+ iscsi_portal_destroy( portal );
+
+ return;
+ }
+
+ memcpy( conn->pdu_processing->bhs_pkt, request, len );
+
+ conn->pdu_processing->bhs_read_len = len;
+ conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_HDR;
+
+ int rc = iscsi_hashmap_put( iscsi_globvec->connections, hash_key, sizeof(id), (uint8_t *) conn );
+
+ if ( rc < 0 ) {
+ iscsi_connection_pdu_destroy( conn->pdu_processing );
+ iscsi_hashmap_key_destroy( hash_key );
+ iscsi_connection_destroy( conn );
+ iscsi_portal_destroy( portal );
+
+ return;
+ }
+
+ while ( iscsi_connection_pdu_handle( conn ) >= ISCSI_CONNECT_PDU_READ_OK ) {
+ }
+}