aboutsummaryrefslogtreecommitdiffstats
path: root/packet-iscsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'packet-iscsi.c')
-rw-r--r--packet-iscsi.c563
1 files changed, 349 insertions, 214 deletions
diff --git a/packet-iscsi.c b/packet-iscsi.c
index 1fe316a873..6cd8fa11bc 100644
--- a/packet-iscsi.c
+++ b/packet-iscsi.c
@@ -4,7 +4,7 @@
*
* Conforms to the protocol described in: draft-ietf-ips-iscsi-08.txt
*
- * $Id: packet-iscsi.c,v 1.12 2001/10/20 18:30:50 guy Exp $
+ * $Id: packet-iscsi.c,v 1.13 2001/10/21 17:20:10 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -50,14 +50,25 @@
#include "packet.h"
#include "prefs.h"
+static uint iscsi_desegment = TRUE;
+
static int enable_bogosity_filter = TRUE;
-static guint32 bogus_pdu_data_length_threshold = 1024 * 1024;
-static guint32 bogus_pdu_max_digest_padding = 20;
+static guint32 bogus_pdu_data_length_threshold = 256 * 1024;
+
+static int enableDataDigests = FALSE;
+static int enableHeaderDigests = FALSE;
+
+static int dataDigestIsCRC32 = TRUE;
+static int headerDigestIsCRC32 = TRUE;
+
+static int dataDigestSize = 4;
+static int headerDigestSize = 4;
-static int enable_force_header_digest_crc32 = FALSE;
+static uint iscsi_port = 5003;
/* Initialize the protocol and registered fields */
static int proto_iscsi = -1;
+static int hf_iscsi_AHS = -1;
static int hf_iscsi_Padding = -1;
static int hf_iscsi_ping_data = -1;
static int hf_iscsi_immediate_data = -1;
@@ -67,7 +78,10 @@ static int hf_iscsi_read_data = -1;
static int hf_iscsi_error_pdu_data = -1;
static int hf_iscsi_Opcode = -1;
static int hf_iscsi_Flags = -1;
+static int hf_iscsi_HeaderDigest = -1;
static int hf_iscsi_HeaderDigest32 = -1;
+static int hf_iscsi_DataDigest = -1;
+static int hf_iscsi_DataDigest32 = -1;
static int hf_iscsi_X = -1;
static int hf_iscsi_I = -1;
static int hf_iscsi_SCSICommand_F = -1;
@@ -170,6 +184,8 @@ static gint ett_iscsi_Flags = -1;
#define ISCSI_OPCODE_ASYNC_MESSAGE (0x32 | X_BIT | I_BIT)
#define ISCSI_OPCODE_REJECT (0x3f | X_BIT | I_BIT)
+#define CSG_MASK 0x0c
+
static const value_string iscsi_opcodes[] = {
{ ISCSI_OPCODE_NOP_OUT, "NOP Out" },
{ ISCSI_OPCODE_SCSI_COMMAND, "SCSI Command" },
@@ -555,25 +571,97 @@ addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
static gint
handleHeaderDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
int available_bytes = tvb_length_remaining(tvb, offset);
- if(available_bytes >= (headerLen + 4)) {
- guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
- guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
- if(crc == sent || enable_force_header_digest_crc32) {
- if(crc == sent) {
- proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
- return 4;
+ if(enableHeaderDigests) {
+ if(headerDigestIsCRC32) {
+ if(available_bytes >= (headerLen + 4)) {
+ guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
+ guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
+ if(crc == sent) {
+ proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
+ }
+ else {
+ proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Bad CRC32)", sent);
+ }
}
- else {
- proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Bad CRC32)", sent);
- return 4;
+ return offset + headerLen + 4;
+ }
+ if(available_bytes >= (headerLen + headerDigestSize)) {
+ proto_tree_add_item(ti, hf_iscsi_HeaderDigest, tvb, offset + headerLen, headerDigestSize, FALSE);
+ }
+ return offset + headerLen + headerDigestSize;
+ }
+ return offset + headerLen;
+}
+
+static gint
+handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) {
+ int available_bytes = tvb_length_remaining(tvb, offset);
+ if(enableDataDigests) {
+ if(dataDigestIsCRC32) {
+ if(available_bytes >= (dataLen + 4)) {
+ guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
+ guint32 sent = tvb_get_ntohl(tvb, offset + dataLen);
+ if(crc == sent) {
+ proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Good CRC32)", sent);
+ }
+ else {
+ proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Bad CRC32)", sent);
+ }
}
+ return offset + dataLen + 4;
}
+ if(available_bytes >= (dataLen + dataDigestSize)) {
+ proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, FALSE);
+ }
+ return offset + dataLen + dataDigestSize;
}
- return 0;
+ return offset + dataLen;
}
-/* Code to actually dissect the packets */
static int
+handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) {
+ if(endOffset > offset) {
+ int dataOffset = offset;
+ int dataLen = iscsi_min(dataSegmentLen, endOffset - offset);
+ if(dataLen > 0) {
+ proto_tree_add_item(ti, hf_id, tvb, offset, dataLen, FALSE);
+ offset += dataLen;
+ }
+ if(offset < endOffset && (offset & 3) != 0) {
+ int padding = 4 - (offset & 3);
+ proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
+ offset += padding;
+ }
+ if(dataSegmentLen > 0 && offset < endOffset)
+ offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
+ }
+
+ return offset;
+}
+
+static int
+handleDataSegmentAsTextKeys(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) {
+ if(endOffset > offset) {
+ int dataOffset = offset;
+ int textLen = iscsi_min(dataSegmentLen, endOffset - offset);
+ if(textLen > 0) {
+ proto_item *tf = proto_tree_add_text(ti, tvb, offset, textLen, "Key/Value Pairs");
+ proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
+ offset = addTextKeys(tt, tvb, offset, textLen);
+ }
+ if(offset < endOffset && (offset & 3) != 0) {
+ int padding = 4 - (offset & 3);
+ proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
+ offset += padding;
+ }
+ if(digestsActive && dataSegmentLen > 0 && offset < endOffset)
+ offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
+ }
+ return offset;
+}
+
+/* Code to actually dissect the packets */
+static void
dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 opcode, const char *opcode_str, guint32 data_segment_len) {
guint original_offset = offset;
proto_item *ti;
@@ -653,19 +741,8 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int ping_data_len = iscsi_min(data_segment_len, end_offset - offset);
- if(ping_data_len > 0) {
- proto_tree_add_item(ti, hf_iscsi_ping_data, tvb, offset, ping_data_len, FALSE);
- offset += ping_data_len;
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
}
else if(opcode == ISCSI_OPCODE_NOP_IN) {
/* NOP In */
@@ -676,22 +753,12 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int ping_data_len = iscsi_min(data_segment_len, end_offset - offset);
- if(ping_data_len > 0) {
- proto_tree_add_item(ti, hf_iscsi_ping_data, tvb, offset, ping_data_len, FALSE);
- offset += ping_data_len;
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
}
else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
/* SCSI Command */
+ guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
{
gint b = tvb_get_guint8(tvb, offset + 1);
proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
@@ -737,20 +804,13 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_CDB);
proto_tree_add_item(tt, hf_iscsi_SCSICommand_CDB, tvb, cdb_offset, cdb_len, FALSE);
}
- offset = cdb_offset + cdb_len + handleHeaderDigest(ti, tvb, offset, cdb_offset + cdb_len);
- }
- if(end_offset > offset) {
- int immediate_data_len = iscsi_min(data_segment_len, end_offset - offset);
- if(immediate_data_len > 0) {
- proto_tree_add_item(ti, hf_iscsi_immediate_data, tvb, offset, immediate_data_len, FALSE);
- offset += immediate_data_len;
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
+ if(ahsLen > 0) {
+ /* FIXME - disssect AHS? */
+ proto_tree_add_item(ti, hf_iscsi_AHS, tvb, offset + 48, ahsLen, FALSE);
}
+ offset = handleHeaderDigest(ti, tvb, offset, 48 + ahsLen);
}
+ offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
}
else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
/* SCSI Response */
@@ -774,19 +834,8 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int sense_data_len = iscsi_min(data_segment_len, end_offset - offset);
- if(sense_data_len > 0) {
- proto_tree_add_item(ti, hf_iscsi_sense_data, tvb, offset, sense_data_len, FALSE);
- offset += sense_data_len;
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_sense_data);
}
else if(opcode == ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_COMMAND) {
/* SCSI Task Command */
@@ -797,7 +846,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
}
else if(opcode == ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_RESPONSE) {
/* SCSI Task Response */
@@ -807,12 +856,18 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
}
else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
/* Login Command */
+ int digestsActive = 1;
{
gint b = tvb_get_guint8(tvb, offset + 1);
+ if((b & CSG_MASK) == 0) {
+ /* current stage is SecurityNegotiation, digests
+ * are not yet turned on */
+ digestsActive = 0;
+ }
#if 0
proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
@@ -831,25 +886,22 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int text_len = iscsi_min(data_segment_len, end_offset - offset);
- if(text_len > 0) {
- proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
- proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
- offset = addTextKeys(tt, tvb, offset, text_len);
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ if(digestsActive)
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ else
+ offset += 48;
+ offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
}
else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
/* Login Response */
+ int digestsActive = 1;
{
gint b = tvb_get_guint8(tvb, offset + 1);
+ if((b & CSG_MASK) == 0) {
+ /* current stage is SecurityNegotiation, digests
+ * are not yet turned on */
+ digestsActive = 0;
+ }
#if 0
proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
@@ -870,20 +922,11 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int text_len = iscsi_min(data_segment_len, end_offset - offset);
- if(text_len > 0) {
- proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
- proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
- offset = addTextKeys(tt, tvb, offset, text_len);
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ if(digestsActive)
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ else
+ offset += 48;
+ offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
}
else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
/* Text Command */
@@ -899,20 +942,8 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int text_len = iscsi_min(data_segment_len, end_offset - offset);
- if(text_len > 0) {
- proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
- proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
- offset = addTextKeys(tt, tvb, offset, text_len);
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
}
else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
/* Text Response */
@@ -929,20 +960,8 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int text_len = iscsi_min(data_segment_len, end_offset - offset);
- if(text_len > 0) {
- proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
- proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
- offset = addTextKeys(tt, tvb, offset, text_len);
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
}
else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
/* SCSI Data Out (write) */
@@ -960,19 +979,8 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int write_data_len = iscsi_min(data_segment_len, end_offset - offset);
- if(write_data_len > 0) {
- proto_tree_add_item(ti, hf_iscsi_write_data, tvb, offset, write_data_len, FALSE);
- offset += write_data_len;
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_write_data);
}
else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
/* SCSI Data In (read) */
@@ -995,19 +1003,8 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int read_data_len = iscsi_min(data_segment_len, end_offset - offset);
- if(read_data_len > 0) {
- proto_tree_add_item(ti, hf_iscsi_read_data, tvb, offset, read_data_len, FALSE);
- offset += read_data_len;
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_read_data);
}
else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
/* Logout Command */
@@ -1015,7 +1012,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, FALSE);
proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
}
else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
/* Logout Response */
@@ -1025,7 +1022,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, FALSE);
proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
}
else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
/* SNACK Request */
@@ -1043,7 +1040,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
}
else if(opcode == ISCSI_OPCODE_R2T) {
/* R2T */
@@ -1055,7 +1052,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_R2TSN, tvb, offset + 36, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
}
else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
/* Asynchronous Message */
@@ -1069,7 +1066,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, FALSE);
proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
}
else if(opcode == ISCSI_OPCODE_REJECT) {
/* Reject */
@@ -1079,50 +1076,38 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off
proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
- offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
- if(end_offset > offset) {
- int error_pdu_len = iscsi_min(data_segment_len, end_offset - offset);
- if(error_pdu_len > 0) {
- proto_tree_add_item(ti, hf_iscsi_error_pdu_data, tvb, offset, error_pdu_len, FALSE);
- offset += error_pdu_len;
- }
- if(offset < end_offset && (offset & 3) != 0) {
- int padding = 4 - (offset & 3);
- proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
- offset += padding;
- }
- }
+ offset = handleHeaderDigest(ti, tvb, offset, 48);
+ offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_error_pdu_data);
}
proto_item_set_len(ti, offset - original_offset);
}
- else {
- /* FIXME - this really should gobble up digests and data segment */
- offset += 48;
- }
-
- return offset - original_offset;
}
static gboolean
dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
-
/* Set up structures needed to add the protocol subtree and manage it */
+ guint iSCSIPdusDissected = 0;
guint offset = 0;
guint32 available_bytes = tvb_length_remaining(tvb, offset);
- /* quick check to see if the packet is long enough to contain a
- * whole iSCSI header segment */
- if (available_bytes < 48) {
+ if (!proto_is_protocol_enabled(proto_iscsi))
+ return FALSE; /* iSCSI has been disabled */
+
+ /* quick check to see if the packet is long enough to contain the
+ * minimum amount of information we need */
+ if (available_bytes < 48 && (!iscsi_desegment || available_bytes < 8)) {
/* no, so give up */
return FALSE;
}
- /* (potentially) process multiple iSCSI PDUs per packet */
- while(available_bytes >= 48) {
+ /* process multiple iSCSI PDUs per packet */
+ while(available_bytes >= 48 || (iscsi_desegment && available_bytes >= 8)) {
const char *opcode_str = NULL;
guint32 data_segment_len;
guint8 opcode = tvb_get_guint8(tvb, offset + 0);
+ guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1);
+ int badPdu = FALSE;
if((opcode & TARGET_OPCODE_BIT) == 0) {
/* initiator -> target */
@@ -1130,46 +1115,133 @@ dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
opcode &= ~(X_BIT | I_BIT);
}
opcode_str = match_strval(opcode, iscsi_opcodes);
- data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
-
- /* try and distinguish between data and real headers */
- if(opcode_str == NULL ||
- (enable_bogosity_filter &&
- (data_segment_len > bogus_pdu_data_length_threshold ||
- available_bytes > (data_segment_len + 48 + bogus_pdu_max_digest_padding)))) {
-#if 1
- /* scanning a packet for a valid header is very slow so
- * for the moment we just give up */
- return FALSE;
-#else
- /* see if the next word starts a header */
- int inc = 4;
- offset += inc;
- available_bytes -= inc;
-#endif
+ if(opcode == ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_COMMAND ||
+ opcode == ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_RESPONSE ||
+ opcode == ISCSI_OPCODE_R2T ||
+ opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
+ opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
+ opcode == ISCSI_OPCODE_SNACK_REQUEST)
+ data_segment_len = 0;
+ else
+ data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
+
+ if(opcode_str == NULL) {
+ badPdu = TRUE;
+ }
+ else if(iscsi_port != 0 &&
+ (((opcode & TARGET_OPCODE_BIT) && pinfo->srcport != iscsi_port) ||
+ (!(opcode & TARGET_OPCODE_BIT) && pinfo->destport != iscsi_port))) {
+ badPdu = TRUE;
+ }
+ else if(enable_bogosity_filter) {
+ /* try and distinguish between data and real headers */
+ if(data_segment_len > bogus_pdu_data_length_threshold) {
+ badPdu = TRUE;
+ }
+ else if(!(secondPduByte & 0x80) &&
+ (opcode == ISCSI_OPCODE_NOP_OUT ||
+ opcode == ISCSI_OPCODE_NOP_IN ||
+ opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
+ opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
+ opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
+ opcode == ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_RESPONSE ||
+ opcode == ISCSI_OPCODE_R2T ||
+ opcode == ISCSI_OPCODE_ASYNC_MESSAGE ||
+ opcode == ISCSI_OPCODE_SNACK_REQUEST ||
+ opcode == ISCSI_OPCODE_REJECT)) {
+ badPdu = TRUE;
+ }
+ }
+
+ if(badPdu) {
+ return iSCSIPdusDissected > 0;
}
else {
+ guint32 pduLen = 48;
+ int digestsActive = 1;
+
+ if(opcode == ISCSI_OPCODE_LOGIN_COMMAND ||
+ opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
+ if((secondPduByte & CSG_MASK) == 0) {
+ /* current stage is SecurityNegotiation, digests
+ * are not yet turned on */
+ digestsActive = 0;
+ }
+ }
+
+ if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
+ /* ahsLen */
+ pduLen += tvb_get_guint8(tvb, offset + 4) * 4;
+ }
+
+ pduLen += data_segment_len;
+ if((pduLen & 3) != 0)
+ pduLen += 4 - (pduLen & 3);
+
+ if(digestsActive && enableHeaderDigests) {
+ if(headerDigestIsCRC32)
+ pduLen += 4;
+ else
+ pduLen += headerDigestSize;
+ }
+
+ if(digestsActive && data_segment_len > 0 && enableDataDigests) {
+ if(dataDigestIsCRC32)
+ pduLen += 4;
+ else
+ pduLen += dataDigestSize;
+ }
+
+ /*
+ * Desegmentation check.
+ */
+ if(iscsi_desegment && pinfo->can_desegment) {
+ if(pduLen > available_bytes) {
+ /*
+ * This frame doesn't have all of the data for
+ * this message, but we can do reassembly on it.
+ *
+ * Tell the TCP dissector where the data for this
+ * message starts in the data it handed us, and
+ * how many more bytes we need, and return.
+ */
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = pduLen - available_bytes;
+ return TRUE;
+ }
+ }
+
dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len);
- return TRUE;
+ if(pduLen > available_bytes)
+ pduLen = available_bytes;
+ offset += pduLen;
+ available_bytes -= pduLen;
+ ++iSCSIPdusDissected;
}
}
- return FALSE;
+ return iSCSIPdusDissected > 0;
}
/* Register the protocol with Ethereal */
-/* this format is require because a script is used to build the C function
- that calls all the protocol registration.
+/*
+ * this format is require because a script is used to build the C
+ * function that calls all the protocol registration.
*/
void
proto_register_iscsi(void)
{
- /* Setup list of header fields See Section 1.6.1 for details*/
+ /* Setup list of header fields See Section 1.6.1 for details*/
static hf_register_info hf[] = {
+ { &hf_iscsi_AHS,
+ { "AHS", "iscsi.ahs",
+ FT_BYTES, BASE_HEX, NULL, 0,
+ "Additional header segment", HFILL }
+ },
{ &hf_iscsi_Padding,
{ "Padding", "iscsi.padding",
FT_BYTES, BASE_HEX, NULL, 0,
@@ -1205,11 +1277,26 @@ proto_register_iscsi(void)
FT_BYTES, BASE_HEX, NULL, 0,
"Error PDU Data", HFILL }
},
- { &hf_iscsi_HeaderDigest32,
+ { &hf_iscsi_HeaderDigest,
{ "HeaderDigest", "iscsi.headerdigest",
+ FT_BYTES, BASE_HEX, NULL, 0,
+ "Header Digest", HFILL }
+ },
+ { &hf_iscsi_HeaderDigest32,
+ { "HeaderDigest", "iscsi.headerdigest32",
FT_UINT32, BASE_HEX, NULL, 0,
"Header Digest", HFILL }
},
+ { &hf_iscsi_DataDigest,
+ { "DataDigest", "iscsi.datadigest",
+ FT_BYTES, BASE_HEX, NULL, 0,
+ "Data Digest", HFILL }
+ },
+ { &hf_iscsi_DataDigest32,
+ { "DataDigest", "iscsi.datadigest32",
+ FT_UINT32, BASE_HEX, NULL, 0,
+ "Data Digest", HFILL }
+ },
{ &hf_iscsi_Opcode,
{ "Opcode", "iscsi.opcode",
FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
@@ -1447,7 +1534,7 @@ proto_register_iscsi(void)
},
{ &hf_iscsi_Login_CSG,
{ "CSG", "iscsi.login.csg",
- FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), 0x0c,
+ FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), CSG_MASK,
"Current stage", HFILL }
},
{ &hf_iscsi_Login_NSG,
@@ -1582,7 +1669,8 @@ proto_register_iscsi(void)
/* Register the protocol name and description */
proto_iscsi = proto_register_protocol("iSCSI", "ISCSI", "iscsi");
- /* Required function calls to register the header fields and subtrees used */
+ /* Required function calls to register the header fields and
+ * subtrees used */
proto_register_field_array(proto_iscsi, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
@@ -1590,6 +1678,12 @@ proto_register_iscsi(void)
module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
prefs_register_bool_preference(iscsi_module,
+ "desegment_iscsi_messages",
+ "Desegment iSCSI messages",
+ "When enabled, iSCSI messages that span multiple TCP segments are desegmented",
+ &iscsi_desegment);
+
+ prefs_register_bool_preference(iscsi_module,
"bogus_pdu_filter",
"Enable bogus pdu filter",
"When enabled, packets that appear bogus are ignored",
@@ -1601,20 +1695,61 @@ proto_register_iscsi(void)
"Treat packets whose data segment length is greater than this value as bogus",
10,
&bogus_pdu_data_length_threshold);
+
prefs_register_uint_preference(iscsi_module,
- "bogus_pdu_max_digest_padding",
- "Bogus pdu max digest padding",
- "Treat packets whose apparent total digest size is greater than this value as bogus",
+ "iscsi_port",
+ "Target port",
+ "Port number of iSCSI target",
10,
- &bogus_pdu_max_digest_padding);
+ &iscsi_port);
+
+ prefs_register_bool_preference(iscsi_module,
+ "enable_header_digests",
+ "Enable header digests",
+ "When enabled, pdus are assumed to contain a header digest",
+ &enableHeaderDigests);
+ prefs_register_bool_preference(iscsi_module,
+ "enable_data_digests",
+ "Enable data digests",
+ "When enabled, pdus are assumed to contain a data digest",
+ &enableDataDigests);
+
+ prefs_register_bool_preference(iscsi_module,
+ "header_digest_is_crc32c",
+ "Header digest is CRC32C",
+ "When enabled, header digests are assumed to be CRC32C",
+ &headerDigestIsCRC32);
+ prefs_register_bool_preference(iscsi_module,
+ "data_digest_is_crc32c",
+ "Data digest is CRC32C",
+ "When enabled, data digests are assumed to be CRC32C",
+ &dataDigestIsCRC32);
+
+ prefs_register_uint_preference(iscsi_module,
+ "header_digest_size",
+ "Header digest size",
+ "The size of a header digest (bytes)",
+ 10,
+ &headerDigestSize);
+ prefs_register_uint_preference(iscsi_module,
+ "data_digest_size",
+ "Data digest size",
+ "The size of a data digest (bytes)",
+ 10,
+ &dataDigestSize);
}
}
-/* If this dissector uses sub-dissector registration add a registration routine.
- This format is required because a script is used to find these routines and
- create the code that calls these routines.
-*/
+/*
+ * If this dissector uses sub-dissector registration add a
+ * registration routine.
+ */
+
+/*
+ * This format is required because a script is used to find these
+ * routines and create the code that calls these routines.
+ */
void
proto_reg_handoff_iscsi(void)
{