summaryrefslogtreecommitdiffstats
path: root/src/server
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
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')
-rw-r--r--src/server/iscsi.c169
-rw-r--r--src/server/iscsi.h7
-rw-r--r--src/server/net.c2
-rw-r--r--src/server/server.c8
4 files changed, 178 insertions, 8 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 ) {
+ }
+}
diff --git a/src/server/iscsi.h b/src/server/iscsi.h
index 5990d69..c802d05 100644
--- a/src/server/iscsi.h
+++ b/src/server/iscsi.h
@@ -5880,8 +5880,8 @@ typedef struct iscsi_globals {
} iscsi_globals;
-/// iSCSI global vector. MUST be initialized with iscsi_create before any iSCSI functions are used.
-iscsi_globals *iscsi_globvec = NULL;
+/// Reference to iSCSI global vector. MUST be initialized with iscsi_create before any iSCSI functions are used.
+extern iscsi_globals *iscsi_globvec;
int iscsi_create(); // Allocates and initializes the iSCSI global vector structure
@@ -6552,4 +6552,7 @@ int iscsi_connection_read_data(iscsi_connection *conn, int len, void *buf);
int iscsi_connection_read_iov_data(iscsi_connection *conn, struct iovec *iov, int iov_count);
void iscsi_connection_pdu_write(iscsi_connection *conn, iscsi_pdu *pdu, iscsi_connection_xfer_complete_callback callback, uint8_t *user_data);
+int iscsi_connection_pdu_handle(iscsi_connection *conn); // Handles incoming PDU data, read up to 16 fragments at once
+void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *request, const int len); // Handles an iSCSI connection until connection is closed
+
#endif /* DNBD3_ISCSI_H_ */
diff --git a/src/server/net.c b/src/server/net.c
index 629c491..af31f4a 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -20,6 +20,7 @@
#include "helper.h"
#include "image.h"
+#include "iscsi.h"
#include "uplink.h"
#include "locks.h"
#include "rpc.h"
@@ -178,6 +179,7 @@ void* net_handleNewConnection(void *clientPtr)
// Close enough...
rpc_sendStatsJson( client->sock, &client->host, &request, ret );
} else {
+ iscsi_connection_handle( client, &request, ret );
logadd( LOG_DEBUG1, "Magic in client handshake incorrect" );
}
goto fail_preadd;
diff --git a/src/server/server.c b/src/server/server.c
index d086930..bfda12d 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -27,6 +27,7 @@
#include "net.h"
#include "altservers.h"
#include "integrity.h"
+#include "iscsi.h"
#include "threadpool.h"
#include "rpc.h"
#include "fuse.h"
@@ -176,6 +177,9 @@ _Noreturn static void dnbd3_cleanup()
threadpool_waitEmpty();
+ // Destroy iSCSI global vector
+ iscsi_destroy();
+
// Clean up images
retries = 5;
while ( !image_tryFreeAll() && --retries > 0 ) {
@@ -365,6 +369,10 @@ int main(int argc, char *argv[])
altservers_init();
integrity_init();
net_init();
+
+ if ( iscsi_create() < 0 )
+ return EXIT_FAILURE;
+
uplink_globalsInit();
rpc_init();
if ( mountDir != NULL && !dfuse_init( "-oallow_other", mountDir ) ) {