[stgt] [PATCH] changes in iscsi login/text prototypes, structs

Alexander Nezhinsky alexandern at Voltaire.COM
Tue Sep 21 14:33:31 CEST 2010


This patch breaks the dependence of iscsi login/text code on the
static structures within struct iscsi_conn. Most of the changes
are concerned with the following two issues:

1. changed function prototypes, to include pointers to the relevant
pdu or bhs structures or data buffers. These changes ultimately
start with the new prototype of cmnd_execute(), to which
two new arguments: struct iscsi_pdu *req_pdu, *rsp_pdu
are added. All other functions called from this point and on
are changed according to their needs.

2. struct login_state is defined and added to iscsi_conn.
It encapsulates login/text specific data and status.
All login/text data buffers are copied to the buffers
internal to this new structure. When necessary, data from multiple
pdus is accumulated in a single request buffer, and conversely,
a long response buffer can be sent piecewise within multiple pdus.

These changes enable using dynamically allocated pdus and their
immediate release after processing by the login/text code.
Such scheme is to be employed by the new iser code, i.e. it's
the first step towards its integration.

Verified: discovery and login (auth=None, auth=CHAP)

Signed-off-by: Alexander Nezhinsky <alexandern at voltaire.com>
---
 usr/iscsi/conn.c        |   21 +++
 usr/iscsi/iscsi_proto.h |    2 +-
 usr/iscsi/iscsid.c      |  313 +++++++++++++++++++++++++++++++----------------
 usr/iscsi/iscsid.h      |   25 ++++-
 4 files changed, 254 insertions(+), 107 deletions(-)

diff --git a/usr/iscsi/conn.c b/usr/iscsi/conn.c
index ba7a58f..afc6dd9 100644
--- a/usr/iscsi/conn.c
+++ b/usr/iscsi/conn.c
@@ -56,6 +56,14 @@ int conn_init(struct iscsi_connection *conn)
 	}
 	conn->rsp_buffer_size = INCOMING_BUFSIZE;
 
+	conn->login.rsp_buf = malloc(INCOMING_BUFSIZE);
+	if (!conn->login.rsp_buf) {
+		free(conn->req_buffer);
+		free(conn->rsp_buffer);
+		return -ENOMEM;
+	}
+	conn->login.rsp_buf_sz = INCOMING_BUFSIZE;
+
 	conn->refcount = 1;
 	conn->state = STATE_FREE;
 	param_set_defaults(conn->session_param, session_keys);
@@ -75,6 +83,10 @@ void conn_exit(struct iscsi_connection *conn)
 	free(conn->req_buffer);
 	free(conn->rsp_buffer);
 	free(conn->initiator);
+	if (conn->login.req_buf)
+		free(conn->login.req_buf);
+	if (conn->login.rsp_buf)
+		free(conn->login.rsp_buf);
 
 	if (session)
 		session_put(session);
@@ -175,6 +187,15 @@ void conn_close(struct iscsi_connection *conn)
 			continue;
 		iscsi_free_task(task);
 	}
+
+	if (conn->login.req_buf) {
+		free(conn->login.req_buf);
+		conn->login.req_buf = NULL;
+	}
+	if (conn->login.rsp_buf) {
+		free(conn->login.rsp_buf);
+		conn->login.rsp_buf = NULL;
+	}
 done:
 	conn_put(conn);
 }
diff --git a/usr/iscsi/iscsi_proto.h b/usr/iscsi/iscsi_proto.h
index d5e58df..17e481f 100644
--- a/usr/iscsi/iscsi_proto.h
+++ b/usr/iscsi/iscsi_proto.h
@@ -589,7 +589,7 @@ struct iscsi_reject {
 #define VALUE_MAXLEN		255
 #define TARGET_NAME_MAXLEN	VALUE_MAXLEN
 
-#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH	8192
+#define LOGIN_MAX_RECV_DATA_SEG_LEN	8192
 
 /************************* RFC 3720 End *****************************/
 
diff --git a/usr/iscsi/iscsid.c b/usr/iscsi/iscsid.c
index facc999..306e15a 100644
--- a/usr/iscsi/iscsid.c
+++ b/usr/iscsi/iscsid.c
@@ -99,12 +99,10 @@ static struct iscsi_key login_keys[] = {
 
 char *text_key_find(struct iscsi_connection *conn, char *searchKey)
 {
-	char *data, *key, *value;
-	int keylen, datasize;
-
-	keylen = strlen(searchKey);
-	data = conn->req.data;
-	datasize = conn->req.datasize;
+	char *data = conn->login.req_buf;
+	int datasize = conn->login.req_buf_sz;
+	int keylen = strlen(searchKey);
+	char *key, *value;
 
 	while (1) {
 		for (key = data; datasize > 0 && *data != '='; data++, datasize--)
@@ -154,6 +152,22 @@ static char *next_key(char **data, int *datasize, char **value)
 	return key;
 }
 
+static char *buffer_resize(char **buffer, int *size, int add_size)
+{
+	int new_size = *size + add_size;
+	char *new_ptr;
+
+	if (!*size)
+		new_ptr = malloc(new_size);
+	else
+		new_ptr = realloc(*buffer, new_size);
+	if (new_ptr) {
+		*buffer = new_ptr;
+		*size = new_size;
+	}
+	return new_ptr;
+}
+
 void text_key_add(struct iscsi_connection *conn, char *key, char *value)
 {
 	int keylen = strlen(key);
@@ -165,34 +179,26 @@ void text_key_add(struct iscsi_connection *conn, char *key, char *value)
 	if (conn->state == STATE_FULL)
 		max_len = conn->session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;
 	else
-		max_len = conn->rsp_buffer_size;
-
-	if (!conn->rsp.datasize)
-		conn->rsp.data = conn->rsp_buffer;
-
-	buffer = conn->rsp_buffer;
+		max_len = LOGIN_MAX_RECV_DATA_SEG_LEN;
 
-	if (conn->rsp.datasize + len > max_len &&
+	if (conn->login.rsp_data_sz + len > max_len &&
 	    (conn->req.bhs.opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_TEXT)
 		goto drop;
 
-	if (conn->rsp.datasize + len > conn->rsp_buffer_size) {
-		buffer = realloc(buffer, conn->rsp.datasize + len);
-		if (buffer) {
-			conn->rsp_buffer = buffer;
-			conn->rsp.data = conn->rsp_buffer;
-			conn->rsp_buffer_size = conn->rsp.datasize + len;
-		} else
+	if (conn->login.rsp_data_sz + len > conn->login.rsp_buf_sz) {
+		buffer = buffer_resize(&conn->login.rsp_buf,
+				       &conn->login.rsp_buf_sz,
+				       max_len);
+		if (!buffer)
 			goto drop;
 	}
-
-	buffer += conn->rsp.datasize;
-	conn->rsp.datasize += len;
-
+	buffer = conn->login.rsp_buf + conn->login.rsp_data_sz;
 	strcpy(buffer, key);
 	buffer += keylen;
 	*buffer++ = '=';
 	strcpy(buffer, value);
+	conn->login.rsp_data_sz += len;
+	dprintf("%s=%s (tx)\n", key, value);
 	return;
 drop:
 	log_warning("Dropping key (%s=%s)", key, value);
@@ -204,16 +210,14 @@ static void text_key_add_reject(struct iscsi_connection *conn, char *key)
 	text_key_add(conn, key, "Reject");
 }
 
-static void text_scan_security(struct iscsi_connection *conn)
+static void text_scan_security(struct iscsi_connection *conn,
+			       struct iscsi_login_rsp *rsp)
 {
-	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *)&conn->rsp.bhs;
-	char *key, *value, *data, *nextValue;
-	int datasize;
+	char *req_buf = conn->login.req_buf;
+	int req_size = conn->login.req_buf_sz;
+	char *key, *value, *nextValue;
 
-	data = conn->req.data;
-	datasize = conn->req.datasize;
-
-	while ((key = next_key(&data, &datasize, &value))) {
+	while ((key = next_key(&req_buf, &req_size, &value))) {
 		if (!(param_index_by_name(key, login_keys) < 0))
 			;
 		else if (!strcmp(key, "AuthMethod")) {
@@ -249,10 +253,10 @@ static void text_scan_security(struct iscsi_connection *conn)
 	}
 }
 
-static void login_security_done(struct iscsi_connection *conn)
+static void login_security_done(struct iscsi_connection *conn,
+				struct iscsi_login *req,
+				struct iscsi_login_rsp *rsp)
 {
-	struct iscsi_login *req = (struct iscsi_login *)&conn->req.bhs;
-	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *) &conn->rsp.bhs;
 	struct iscsi_session *session;
 
 	if (!conn->tid)
@@ -299,16 +303,16 @@ static void login_security_done(struct iscsi_connection *conn)
 	}
 }
 
-static void text_scan_login(struct iscsi_connection *conn)
+static void text_scan_login(struct iscsi_connection *conn,
+			    struct iscsi_login_rsp *rsp)
 {
-	char *key, *value, *data;
-	int datasize, idx, is_rdma = 0;
-	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *)&conn->rsp.bhs;
+	char *key, *value;
+	int idx, is_rdma = 0;
+	char *req_buf = conn->login.req_buf;
+	int req_size = conn->login.req_buf_sz;
 
-	data = conn->req.data;
-	datasize = conn->req.datasize;
-
-	while ((key = next_key(&data, &datasize, &value))) {
+	while ((key = next_key(&req_buf, &req_size, &value))) {
+		dprintf("%s=%s (rx)\n", key, value);
 		if (!(param_index_by_name(key, login_keys) < 0))
 			;
 		else if (!strcmp(key, "AuthMethod"))
@@ -424,10 +428,10 @@ static int text_check_param(struct iscsi_connection *conn)
 	return cnt;
 }
 
-static void login_start(struct iscsi_connection *conn)
+static void login_start(struct iscsi_connection *conn,
+			struct iscsi_login *req,
+			struct iscsi_login_rsp *rsp)
 {
-	struct iscsi_login *req = (struct iscsi_login *)&conn->req.bhs;
-	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *)&conn->rsp.bhs;
 	char *name, *alias, *session_type, *target_name;
 	struct iscsi_target *target;
 
@@ -541,6 +545,26 @@ static void login_start(struct iscsi_connection *conn)
 	text_key_add(conn, "TargetPortalGroupTag", "1");
 }
 
+static void login_cleanup(struct iscsi_connection *conn)
+{
+	int max_len = conn->session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;
+
+	if (conn->login.req_buf) {
+		free(conn->login.req_buf);
+		conn->login.req_buf = NULL;
+		conn->login.req_buf_sz = 0;
+	}
+	conn->login.req_data_sz = 0;
+	/* leave enough space for text responces */
+	if (conn->login.rsp_buf && conn->login.rsp_buf_sz > max_len) {
+		conn->login.rsp_buf = realloc(conn->login.rsp_buf, max_len);
+		conn->login.rsp_buf_sz = max_len;
+	}
+	conn->login.rsp_data_sz = 0;
+	conn->login.rsp_offset = 0;
+	conn->login.status = LOGIN_NONE;
+}
+
 static void login_finish(struct iscsi_connection *conn)
 {
 	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *) &conn->rsp.bhs;
@@ -612,9 +636,12 @@ static int cmnd_exec_auth(struct iscsi_connection *conn)
         return res;
 }
 
-static void cmnd_reject(struct iscsi_connection *conn, uint8_t reason)
+static void cmnd_reject(struct iscsi_connection *conn,
+			struct iscsi_pdu *req_pdu,
+			struct iscsi_pdu *rsp_pdu,
+			uint8_t reason)
 {
-	struct iscsi_reject *rsp = (struct iscsi_reject *)&conn->rsp.bhs;
+	struct iscsi_reject *rsp = (struct iscsi_reject *)&rsp_pdu->bhs;
 
 	memset(rsp, 0, BHS_SIZE);
 
@@ -627,24 +654,59 @@ static void cmnd_reject(struct iscsi_connection *conn, uint8_t reason)
 	rsp->exp_cmdsn = cpu_to_be32(conn->exp_cmd_sn);
 	rsp->max_cmdsn = cpu_to_be32(conn->max_cmd_sn);
 
-	conn->rsp.data = conn->rsp_buffer;
-	conn->rsp.datasize = BHS_SIZE;
-	memcpy(conn->rsp.data, &conn->req.bhs, BHS_SIZE);
+	memcpy(conn->login.rsp_buf, &req_pdu->bhs, BHS_SIZE);
+	rsp_pdu->datasize = BHS_SIZE;
 }
 
-static void cmnd_exec_login(struct iscsi_connection *conn)
+static int add_req_login_text_data(struct iscsi_connection *conn,
+				   char *req_data,
+				   int data_size)
 {
-	struct iscsi_login *req = (struct iscsi_login *)&conn->req.bhs;
-	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *)&conn->rsp.bhs;
+	char *buffer;
+
+	if (!data_size)
+		return 0;
+	if (conn->login.req_data_sz + data_size > conn->login.req_buf_sz) {
+		buffer = buffer_resize(&conn->login.req_buf,
+				       &conn->login.req_buf_sz,
+				       INCOMING_BUFSIZE);
+		if (!buffer)
+			return -ENOMEM;
+	}
+	buffer = conn->login.req_buf + conn->login.req_data_sz;
+	memcpy(buffer, req_data, data_size);
+	conn->login.req_data_sz += data_size;
+	return 0;
+}
+
+static void cmnd_exec_login(struct iscsi_connection *conn,
+			    struct iscsi_pdu *req_pdu,
+			    struct iscsi_pdu *rsp_pdu)
+{
+	struct iscsi_login *req = (struct iscsi_login *)&req_pdu->bhs;
+	struct iscsi_login_rsp *rsp = (struct iscsi_login_rsp *)&rsp_pdu->bhs;
 	int stay = 0, nsg_disagree = 0;
 
 	memset(rsp, 0, BHS_SIZE);
 	if ((req->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN ||
 	    !(req->opcode & ISCSI_OP_IMMEDIATE)) {
-		cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
+		cmnd_reject(conn, req_pdu, rsp_pdu,
+			    ISCSI_REASON_PROTOCOL_ERROR);
+		return;
+	}
+
+	if (add_req_login_text_data(conn, req_pdu->data, req_pdu->datasize)) {
+		rsp->status_class = ISCSI_STATUS_CLS_TARGET_ERR;
+		rsp->status_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
+		conn->state = STATE_EXIT;
 		return;
 	}
 
+	if (conn->login.status != LOGIN_IN_PROGRESS) {
+		conn->login.rsp_data_sz = 0;
+		conn->login.rsp_offset = 0;
+	}
+
 	rsp->opcode = ISCSI_OP_LOGIN_RSP;
 	rsp->max_version = ISCSI_DRAFT20_VERSION;
 	rsp->active_version = ISCSI_DRAFT20_VERSION;
@@ -667,12 +729,12 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 		switch (conn->state) {
 		case STATE_FREE:
 			conn->state = STATE_SECURITY;
-			login_start(conn);
+			login_start(conn, req, rsp);
 			if (rsp->status_class)
 				return;
 			/* fall through */
 		case STATE_SECURITY:
-			text_scan_security(conn);
+			text_scan_security(conn, rsp);
 			if (rsp->status_class)
 				return;
 			if (conn->auth_method != AUTH_NONE) {
@@ -705,18 +767,18 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 		case STATE_FREE:
 			conn->state = STATE_LOGIN;
 
-			login_start(conn);
+			login_start(conn, req, rsp);
 			if (account_available(conn->tid, AUTH_DIR_INCOMING))
 				goto auth_err;
 			if (rsp->status_class)
 				return;
-			text_scan_login(conn);
+			text_scan_login(conn, rsp);
 			if (rsp->status_class)
 				return;
 			stay = text_check_param(conn);
 			break;
 		case STATE_LOGIN:
-			text_scan_login(conn);
+			text_scan_login(conn, rsp);
 			if (rsp->status_class)
 				return;
 			stay = text_check_param(conn);
@@ -741,7 +803,7 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 			case STATE_SECURITY:
 			case STATE_SECURITY_DONE:
 				conn->state = STATE_SECURITY_LOGIN;
-				login_security_done(conn);
+				login_security_done(conn, req, rsp);
 				break;
 			default:
 				goto init_err;
@@ -757,7 +819,7 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 					break;
 				}
 				conn->state = STATE_SECURITY_FULL;
-				login_security_done(conn);
+				login_security_done(conn, req, rsp);
 				break;
 			case STATE_LOGIN:
 				if (stay)
@@ -780,6 +842,11 @@ static void cmnd_exec_login(struct iscsi_connection *conn)
 		rsp->flags |= nsg | (stay ? 0 : ISCSI_FLAG_LOGIN_TRANSIT);
 	}
 
+	conn->login.req_data_sz = 0; /* done with the request */
+	if (conn->login.status == LOGIN_NONE)
+		conn->login.status = LOGIN_LAST_TX;
+	rsp_pdu->datasize = conn->login.rsp_data_sz; /* single response */
+
 	memcpy(rsp->isid, conn->isid, sizeof(rsp->isid));
 	rsp->tsih = conn->tsih;
 	rsp->statsn = cpu_to_be32(conn->stat_sn++);
@@ -805,10 +872,11 @@ static void text_scan_text(struct iscsi_connection *conn)
 	char *key, *value, *data;
 	int datasize;
 
-	data = conn->req.data;
-	datasize = conn->req.datasize;
+	data = conn->login.req_buf;
+	datasize = conn->login.req_buf_sz;
 
 	while ((key = next_key(&data, &datasize, &value))) {
+		dprintf("%s=%s (rx)\n", key, value);
 		if (!strcmp(key, "SendTargets")) {
 			struct sockaddr_storage ss;
 			socklen_t slen, blen;
@@ -855,60 +923,74 @@ static void text_scan_text(struct iscsi_connection *conn)
 	}
 }
 
-static void cmnd_exec_text(struct iscsi_connection *conn)
+static void cmnd_exec_text(struct iscsi_connection *conn,
+			   struct iscsi_pdu *req_pdu,
+			   struct iscsi_pdu *rsp_pdu)
 {
-	struct iscsi_text *req = (struct iscsi_text *)&conn->req.bhs;
-	struct iscsi_text_rsp *rsp = (struct iscsi_text_rsp *)&conn->rsp.bhs;
+	struct iscsi_text *req = (struct iscsi_text *)&req_pdu->bhs;
+	struct iscsi_text_rsp *rsp = (struct iscsi_text_rsp *)&rsp_pdu->bhs;
 	int max_len = conn->session_param[ISCSI_PARAM_MAX_XMIT_DLENGTH].val;
+	int rsp_left;
 
-	memset(rsp, 0, BHS_SIZE);
+	dprintf("Text request: %d %d\n", conn->state, max_len);
+
+	if (add_req_login_text_data(conn, req_pdu->data, req_pdu->datasize)) {
+		cmnd_reject(conn, req_pdu, rsp_pdu,
+			    ISCSI_REASON_OUT_OF_RESOURCES);
+		return;
+	}
 
+	if (conn->login.status != TEXT_IN_PROGRESS) {
+		conn->login.rsp_data_sz = 0;
+		conn->login.rsp_offset = 0;
+	}
+
+	memset(rsp, 0, BHS_SIZE);
 	rsp->opcode = ISCSI_OP_TEXT_RSP;
 	rsp->itt = req->itt;
 	conn->exp_cmd_sn = be32_to_cpu(req->cmdsn);
 	if (!(req->opcode & ISCSI_OP_IMMEDIATE))
 		conn->exp_cmd_sn++;
 
-	if (be32_to_cpu(req->ttt) == ISCSI_RESERVED_TAG) {
-		conn->text_datasize = 0;
-
+	if (be32_to_cpu(req->ttt) == ISCSI_RESERVED_TAG) { /* new request */
 		text_scan_text(conn);
-
-		conn->text_rsp_buffer = conn->rsp_buffer;
-		conn->text_datasize = conn->rsp.datasize;
-
-		if (conn->text_datasize > max_len) {
+		if (conn->login.rsp_data_sz <= max_len)
+			conn->ttt = ISCSI_RESERVED_TAG;
+		else {
 			conn->ttt++;
 			if (conn->ttt == ISCSI_RESERVED_TAG)
 				conn->ttt++;
-		} else
-			conn->ttt = ISCSI_RESERVED_TAG;
-	} else if (!conn->text_datasize || conn->ttt != be32_to_cpu(req->ttt)) {
-		cmnd_reject(conn, ISCSI_REASON_INVALID_PDU_FIELD);
+		}
+	} else if (conn->login.status != TEXT_IN_PROGRESS ||
+		   conn->ttt != be32_to_cpu(req->ttt)) {
+		cmnd_reject(conn, req_pdu, rsp_pdu,
+			    ISCSI_REASON_INVALID_PDU_FIELD);
 		return;
 	}
 
-	if (conn->text_datasize <= max_len) {
+	rsp_left = conn->login.rsp_data_sz - conn->login.rsp_offset;
+	if (rsp_left <= max_len) {
+		rsp_pdu->datasize = rsp_left;
 		rsp->flags = ISCSI_FLAG_CMD_FINAL;
-		conn->ttt = ISCSI_RESERVED_TAG;
+		conn->login.status = TEXT_LAST_TX;
+		conn->login.req_data_sz = 0; /* done with the request */
+	} else {
+		rsp_pdu->datasize = max_len;
+		conn->login.status = TEXT_IN_PROGRESS;
 	}
 
-	conn->rsp.datasize = min(max_len, conn->text_datasize);
-	conn->rsp.data = conn->text_rsp_buffer;
-	conn->text_rsp_buffer += conn->rsp.datasize;
-	conn->text_datasize -= conn->rsp.datasize;
-
 	rsp->ttt = cpu_to_be32(conn->ttt);
-
 	rsp->statsn = cpu_to_be32(conn->stat_sn++);
 	rsp->exp_cmdsn = cpu_to_be32(conn->exp_cmd_sn);
 	rsp->max_cmdsn = cpu_to_be32(conn->max_cmd_sn);
 }
 
-static void cmnd_exec_logout(struct iscsi_connection *conn)
+static void cmnd_exec_logout(struct iscsi_connection *conn,
+			     struct iscsi_pdu *req_pdu,
+			     struct iscsi_pdu *rsp_pdu)
 {
-	struct iscsi_logout *req = (struct iscsi_logout *)&conn->req.bhs;
-	struct iscsi_logout_rsp *rsp = (struct iscsi_logout_rsp *)&conn->rsp.bhs;
+	struct iscsi_logout *req = (struct iscsi_logout *)&req_pdu->bhs;
+	struct iscsi_logout_rsp *rsp = (struct iscsi_logout_rsp *)&rsp_pdu->bhs;
 
 	memset(rsp, 0, BHS_SIZE);
 	rsp->opcode = ISCSI_OP_LOGOUT_RSP;
@@ -923,28 +1005,46 @@ static void cmnd_exec_logout(struct iscsi_connection *conn)
 	rsp->max_cmdsn = cpu_to_be32(conn->max_cmd_sn);
 }
 
-static int cmnd_execute(struct iscsi_connection *conn)
+static void finalize_text_rsp_pdu(struct iscsi_connection *conn,
+				  struct iscsi_pdu *rsp_pdu)
+{
+	struct iscsi_hdr *rsp = &rsp_pdu->bhs;
+
+	rsp->hlength = rsp_pdu->ahssize / 4;
+
+	rsp_pdu->data = conn->login.rsp_buf + conn->login.rsp_offset;
+	conn->login.rsp_offset += rsp_pdu->datasize;
+	hton24(rsp->dlength, rsp_pdu->datasize);
+}
+
+static int cmnd_execute(struct iscsi_connection *conn,
+			struct iscsi_pdu *req_pdu,
+			struct iscsi_pdu *rsp_pdu)
 {
+	struct iscsi_hdr *req = &req_pdu->bhs;
+	struct iscsi_hdr *rsp = &rsp_pdu->bhs;
 	int res = 0;
 
-	switch (conn->req.bhs.opcode & ISCSI_OPCODE_MASK) {
+	switch (req->opcode & ISCSI_OPCODE_MASK) {
 	case ISCSI_OP_LOGIN:
-		cmnd_exec_login(conn);
-		conn->rsp.bhs.hlength = conn->rsp.ahssize / 4;
-		hton24(conn->rsp.bhs.dlength, conn->rsp.datasize);
+		cmnd_exec_login(conn, req_pdu, rsp_pdu);
+		finalize_text_rsp_pdu(conn, rsp_pdu);
+		/* clean up on error, otherwise decided internally */
+		if (conn->state == STATE_EXIT)
+			login_cleanup(conn);
 		break;
 	case ISCSI_OP_TEXT:
-		cmnd_exec_text(conn);
-		conn->rsp.bhs.hlength = conn->rsp.ahssize / 4;
-		hton24(conn->rsp.bhs.dlength, conn->rsp.datasize);
+		cmnd_exec_text(conn, req_pdu, rsp_pdu);
+		finalize_text_rsp_pdu(conn, rsp_pdu);
 		break;
 	case ISCSI_OP_LOGOUT:
-		cmnd_exec_logout(conn);
-		conn->rsp.bhs.hlength = conn->rsp.ahssize / 4;
-		hton24(conn->rsp.bhs.dlength, conn->rsp.datasize);
+		cmnd_exec_logout(conn, req_pdu, rsp_pdu);
+		rsp->hlength = rsp_pdu->ahssize / 4;
+		hton24(rsp->dlength, rsp_pdu->datasize);
 		break;
 	default:
-		cmnd_reject(conn, ISCSI_REASON_CMD_NOT_SUPPORTED);
+		cmnd_reject(conn, req_pdu, rsp_pdu,
+			    ISCSI_REASON_CMD_NOT_SUPPORTED);
 		res = 1;
 		break;
 	}
@@ -964,11 +1064,16 @@ static void cmnd_finish(struct iscsi_connection *conn)
 	case STATE_SECURITY_FULL:
 		/* fall through */
 	case STATE_LOGIN_FULL:
+		login_cleanup(conn);
 		if (conn->session_type == SESSION_NORMAL)
 			conn->state = STATE_KERNEL;
 		else
 			conn->state = STATE_FULL;
 		break;
+	case STATE_FULL:
+		if (conn->login.status == TEXT_LAST_TX)
+			login_cleanup(conn);
+		break;
 	}
 }
 
@@ -2066,7 +2171,7 @@ again:
 	} else {
 		conn_write_pdu(conn);
 		conn->tp->ep_event_modify(conn, EPOLLOUT);
-		ret = cmnd_execute(conn);
+		ret = cmnd_execute(conn, &conn->req, &conn->rsp);
 		if (ret)
 			conn->state = STATE_CLOSE;
 	}
diff --git a/usr/iscsi/iscsid.h b/usr/iscsi/iscsid.h
index 35bb068..1de8580 100644
--- a/usr/iscsi/iscsid.h
+++ b/usr/iscsi/iscsid.h
@@ -132,6 +132,27 @@ struct iscsi_task {
 	unsigned long extdata[0];
 };
 
+enum login_status {
+	LOGIN_NONE = 0,
+	LOGIN_IN_PROGRESS,
+	LOGIN_LAST_TX,
+	TEXT_IN_PROGRESS,
+	TEXT_LAST_TX
+};
+
+struct login_state {
+	char *req_buf;
+	int req_buf_sz;
+	int req_data_sz;
+
+	char *rsp_buf;
+	int rsp_buf_sz;
+	int rsp_data_sz;
+	int rsp_offset;
+
+	enum login_status status;
+};
+
 struct iscsi_connection {
 	int state;
 
@@ -173,8 +194,8 @@ struct iscsi_connection {
 	int tx_size;
 
 	uint32_t ttt;
-	int text_datasize;
-	void *text_rsp_buffer;
+
+	struct login_state login;
 
 	struct iscsi_task *rx_task;
 	struct iscsi_task *tx_task;
--
1.6.5
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the stgt mailing list