summaryrefslogtreecommitdiffstats
path: root/src/server/iscsi.c
diff options
context:
space:
mode:
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 ) {
+ }
+}