Merge of IET r194:

- Add support for Reject PDUs and make use of them in appropriate places.

Signed-off-by: Arne Redlich <agr@powerkom-dd.de>



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@651 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2009-01-30 16:36:39 +00:00
parent 4a7cdb58b4
commit 0f68fb5b58
2 changed files with 76 additions and 13 deletions

View File

@@ -223,4 +223,34 @@ struct iscsi_logout_rsp_hdr {
u32 rsvd5;
} __packed;
#define ISCSI_REASON_NO_FULL_FEATURE_PHASE 0x01
#define ISCSI_REASON_DATA_DIGEST_ERROR 0x02
#define ISCSI_REASON_DATA_SNACK_REJECT 0x03
#define ISCSI_REASON_PROTOCOL_ERROR 0x04
#define ISCSI_REASON_UNSUPPORTED_COMMAND 0x05
#define ISCSI_REASON_IMMEDIATE_COMMAND_REJECT 0x06
#define ISCSI_REASON_TASK_IN_PROGRESS 0x07
#define ISCSI_REASON_INVALID_SNACK 0x08
#define ISCSI_REASON_INVALID_PDU_FIELD 0x09
#define ISCSI_REASON_BOOKMARK_REJECT 0x0a
#define ISCSI_REASON_NEGOTIATION_RESET 0x0b
#define ISCSI_REASON_WAITING_LOGOUT 0x0c
struct iscsi_reject_hdr {
u8 opcode;
u8 flags;
u8 reason;
u8 rsvd1;
u8 ahslength;
u8 datalength[3];
u32 rsvd2[2];
u32 ffffffff;
u32 rsvd3;
u32 stat_sn;
u32 exp_cmd_sn;
u32 max_cmd_sn;
u32 data_sn;
u32 rsvd4[2];
} __packed;
#endif /* ISCSI_HDR_H */

View File

@@ -479,6 +479,35 @@ static void login_finish(struct connection *conn)
}
}
static void cmnd_reject(struct connection *conn, u8 reason)
{
struct iscsi_reject_hdr *rej =
(struct iscsi_reject_hdr *)&conn->rsp.bhs;
size_t data_sz = sizeof(struct iscsi_hdr);
struct buf_segment *seg = conn_alloc_buf_segment(conn, data_sz);
conn_free_rsp_buf_list(conn);
memset(rej, 0x0, sizeof *rej);
rej->opcode = ISCSI_OP_REJECT_MSG;
rej->reason = ISCSI_REASON_INVALID_PDU_FIELD;
rej->ffffffff = ISCSI_RESERVED_TAG;
rej->flags |= ISCSI_FLG_FINAL;
rej->stat_sn = cpu_to_be32(conn->stat_sn++);
rej->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
rej->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
if (!seg) {
log_error("Failed to alloc data segment for Reject PDU\n");
return;
}
memcpy(seg->data, &conn->req.bhs, data_sz);
seg->len = data_sz;
list_add_tail(&seg->entry, &conn->rsp_buf_list);
}
static int cmnd_exec_auth(struct connection *conn)
{
int res;
@@ -507,7 +536,8 @@ static void cmnd_exec_login(struct connection *conn)
memset(rsp, 0, BHS_SIZE);
if ((req->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN_CMD ||
!(req->opcode & ISCSI_OP_IMMEDIATE)) {
//reject
cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
return;
}
rsp->opcode = ISCSI_OP_LOGIN_RSP;
@@ -773,13 +803,8 @@ static void cmnd_exec_text(struct connection *conn)
"expected %#x; %stext segments queued\n",
req->ttt, conn->ttt, list_empty(&conn->rsp_buf_list) ?
"no " : "");
/*
* Return a malformed text rsp and close the conn for now.
* The proper response would be a Reject instead.
*/
conn->ttt = rsp->ttt = ISCSI_RESERVED_TAG;
conn_free_rsp_buf_list(conn);
conn->state = STATE_CLOSE;
cmnd_reject(conn, ISCSI_REASON_INVALID_PDU_FIELD);
return;
}
if (list_length_is_one(&conn->rsp_buf_list))
@@ -817,22 +842,30 @@ int cmnd_execute(struct connection *conn)
switch (conn->req.bhs.opcode & ISCSI_OPCODE_MASK) {
case ISCSI_OP_LOGIN_CMD:
//if conn->state == STATE_FULL -> reject
if (conn->state == STATE_FULL) {
cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
break;
}
cmnd_exec_login(conn);
login_rsp = (struct iscsi_login_rsp_hdr *) &conn->rsp.bhs;
if (login_rsp->status_class)
conn_free_rsp_buf_list(conn);
break;
case ISCSI_OP_TEXT_CMD:
//if conn->state != STATE_FULL -> reject
cmnd_exec_text(conn);
if (conn->state != STATE_FULL)
cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
else
cmnd_exec_text(conn);
break;
case ISCSI_OP_LOGOUT_CMD:
//if conn->state != STATE_FULL -> reject
if (conn->state != STATE_FULL)
cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
else
cmnd_exec_logout(conn);
cmnd_exec_logout(conn);
break;
default:
//reject
cmnd_reject(conn, ISCSI_REASON_UNSUPPORTED_COMMAND);
res = 0;
goto out;
}