Merge of IET r194:
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 30 Jan 2009 16:36:39 +0000 (16:36 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 30 Jan 2009 16:36:39 +0000 (16:36 +0000)
 - 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: https://scst.svn.sourceforge.net/svnroot/scst/trunk@651 d57e44dd-8a1f-0410-8b47-8ef2f437770f

iscsi-scst/usr/iscsi_hdr.h
iscsi-scst/usr/iscsid.c

index 64b559d..329c85d 100644 (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 */
index a600718..9785203 100644 (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;
        }