diff options
author | Peter Wu <peter@lekensteyn.nl> | 2014-07-04 22:11:49 +0200 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2014-07-08 06:15:45 +0000 |
commit | 46b3dda046b1e6619f50a071d83cf859e335dc98 (patch) | |
tree | 64f51d6a18ac334f3a3d00e74dad6c462b1231e4 | |
parent | 9d5bf53346d3ac8b9d3c37726928b41dc50400e0 (diff) | |
download | wireshark-46b3dda046b1e6619f50a071d83cf859e335dc98.tar.gz |
iscsi: automatically detect data segment digest
Modelled after ccf7ed00b62dcb63cdb3a9851baa767acbb94013 which detects
the header digest field, this patch adds auto-detection for the Data
Digest field which comes after the data segment.
Since the digest is now automatically detected, drop the three related
preferences.
Verified against scsi-osd-example-001.pcap (from SampleCaptures).
Change-Id: Icd89f1be58889c7ab70aca9dff7d3f99c8fe04d6
Reviewed-on: https://code.wireshark.org/review/2882
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r-- | epan/dissectors/packet-iscsi.c | 159 |
1 files changed, 84 insertions, 75 deletions
diff --git a/epan/dissectors/packet-iscsi.c b/epan/dissectors/packet-iscsi.c index 5add3dfb0f..956df5d6d1 100644 --- a/epan/dissectors/packet-iscsi.c +++ b/epan/dissectors/packet-iscsi.c @@ -82,12 +82,6 @@ static int demand_good_f_bit = FALSE; static int enable_bogosity_filter = TRUE; static guint32 bogus_pdu_data_length_threshold = 256 * 1024; -static int enableDataDigests = FALSE; - -static int dataDigestIsCRC32 = TRUE; - -static guint dataDigestSize = 4; - #define TCP_PORT_ISCSI_RANGE "3260" static range_t *global_iscsi_port_range; @@ -113,7 +107,6 @@ static int hf_iscsi_vendor_specific_data = -1; static int hf_iscsi_Opcode = -1; static int hf_iscsi_Flags = -1; static int hf_iscsi_HeaderDigest32 = -1; -static int hf_iscsi_DataDigest = -1; static int hf_iscsi_DataDigest32 = -1; /* #ifdef DRAFT08 */ static int hf_iscsi_X = -1; @@ -213,12 +206,15 @@ static gint ett_iscsi_lun = -1; static gint ett_iscsi_ISID = -1; /* #endif */ -#define ISCSI_HEADER_DIGEST_AUTO 0 -#define ISCSI_HEADER_DIGEST_NONE 1 -#define ISCSI_HEADER_DIGEST_CRC32 2 +enum iscsi_digest { + ISCSI_DIGEST_AUTO, + ISCSI_DIGEST_NONE, + ISCSI_DIGEST_CRC32 +}; /* this structure contains session wide state for a specific tcp conversation */ typedef struct _iscsi_session_t { - guint32 header_digest; + enum iscsi_digest header_digest; + enum iscsi_digest data_digest; wmem_map_t *itlq; /* indexed by ITT */ wmem_map_t *itl; /* indexed by LUN */ } iscsi_session_t; @@ -636,7 +632,7 @@ handleHeaderDigest(iscsi_session_t *iscsi_session, proto_item *ti, tvbuff_t *tvb int available_bytes = tvb_length_remaining(tvb, offset); switch(iscsi_session->header_digest){ - case ISCSI_HEADER_DIGEST_CRC32: + case ISCSI_DIGEST_CRC32: if(available_bytes >= (headerLen + 4)) { guint32 crc = ~crc32c_calculate(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD); guint32 sent = tvb_get_ntohl(tvb, offset + headerLen); @@ -647,15 +643,19 @@ handleHeaderDigest(iscsi_session_t *iscsi_session, proto_item *ti, tvbuff_t *tvb } } return offset + headerLen + 4; + default: + break; } return offset + headerLen; } static gint -handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) { +handleDataDigest(iscsi_session_t *iscsi_session, proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) { int available_bytes = tvb_length_remaining(tvb, offset); - if(enableDataDigests) { - if(dataDigestIsCRC32) { + + if (dataLen > 0) { + switch (iscsi_session->data_digest){ + case ISCSI_DIGEST_CRC32: if(available_bytes >= (dataLen + 4)) { guint32 crc = ~crc32c_calculate(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD); guint32 sent = tvb_get_ntohl(tvb, offset + dataLen); @@ -667,17 +667,15 @@ handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) { } } return offset + dataLen + 4; + default: + break; } - if((unsigned)available_bytes >= (dataLen + dataDigestSize)) { - proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, ENC_NA); - } - return offset + dataLen + dataDigestSize; } return offset + dataLen; } static int -handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) { +handleDataSegment(iscsi_session_t *iscsi_session, proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) { if(endOffset > offset) { int dataOffset = offset; int dataLen = MIN(dataSegmentLen, endOffset - offset); @@ -691,14 +689,14 @@ handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegment offset += padding; } if(dataSegmentLen > 0 && offset < endOffset) - offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset); + offset = handleDataDigest(iscsi_session, ti, tvb, dataOffset, offset - dataOffset); } return offset; } static int -handleDataSegmentAsTextKeys(packet_info *pinfo, proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) { +handleDataSegmentAsTextKeys(iscsi_session_t *iscsi_session, packet_info *pinfo, proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) { if(endOffset > offset) { int dataOffset = offset; int textLen = MIN(dataSegmentLen, endOffset - offset); @@ -713,7 +711,7 @@ handleDataSegmentAsTextKeys(packet_info *pinfo, proto_item *ti, tvbuff_t *tvb, g offset += padding; } if(digestsActive && dataSegmentLen > 0 && offset < endOffset) - offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset); + offset = handleDataDigest(iscsi_session, ti, tvb, dataOffset, offset - dataOffset); } return offset; } @@ -921,7 +919,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, ENC_BIG_ENDIAN); proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN); offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48); - offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data); + offset = handleDataSegment(iscsi_session, ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data); } else if(opcode == ISCSI_OPCODE_NOP_IN) { /* NOP In */ if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) { @@ -935,7 +933,7 @@ 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, ENC_BIG_ENDIAN); proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN); offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48); - offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data); + offset = handleDataSegment(iscsi_session, 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; @@ -1014,7 +1012,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48 + ahsLen); immediate_data_offset=offset; - offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data); + offset = handleDataSegment(iscsi_session, ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data); immediate_data_length=offset-immediate_data_offset; } else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) { /* SCSI Response */ @@ -1052,7 +1050,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48); /* do not update offset here because the data segment is * dissected below */ - handleDataDigest(ti, tvb, offset, paddedDataSegmentLength); + handleDataDigest(iscsi_session, ti, tvb, offset, paddedDataSegmentLength); } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) { /* Task Management Function */ proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, ENC_BIG_ENDIAN); @@ -1153,7 +1151,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off } else { offset += 48; } - offset = handleDataSegmentAsTextKeys(pinfo, ti, tvb, offset, data_segment_len, end_offset, digestsActive); + offset = handleDataSegmentAsTextKeys(iscsi_session, pinfo, ti, tvb, offset, data_segment_len, end_offset, digestsActive); } else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) { /* Login Response */ int digestsActive = 0; @@ -1220,7 +1218,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off } else { offset += 48; } - offset = handleDataSegmentAsTextKeys(pinfo, ti, tvb, offset, data_segment_len, end_offset, digestsActive); + offset = handleDataSegmentAsTextKeys(iscsi_session, pinfo, ti, tvb, offset, data_segment_len, end_offset, digestsActive); } else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) { /* Text Command */ { @@ -1245,7 +1243,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, ENC_BIG_ENDIAN); proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, ENC_BIG_ENDIAN); offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48); - offset = handleDataSegmentAsTextKeys(pinfo, ti, tvb, offset, data_segment_len, end_offset, TRUE); + offset = handleDataSegmentAsTextKeys(iscsi_session, pinfo, ti, tvb, offset, data_segment_len, end_offset, TRUE); } else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) { /* Text Response */ { @@ -1271,7 +1269,7 @@ 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, ENC_BIG_ENDIAN); proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, ENC_BIG_ENDIAN); offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48); - offset = handleDataSegmentAsTextKeys(pinfo, ti, tvb, offset, data_segment_len, end_offset, TRUE); + offset = handleDataSegmentAsTextKeys(iscsi_session, pinfo, ti, tvb, offset, data_segment_len, end_offset, TRUE); } else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) { /* SCSI Data Out (write) */ { @@ -1296,7 +1294,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48); /* do not update offset here because the data segment is * dissected below */ - handleDataDigest(ti, tvb, offset, paddedDataSegmentLength); + handleDataDigest(iscsi_session, ti, tvb, offset, paddedDataSegmentLength); } else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) { /* SCSI Data In (read) */ { @@ -1354,7 +1352,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48); /* do not update offset here because the data segment is * dissected below */ - handleDataDigest(ti, tvb, offset, paddedDataSegmentLength); + handleDataDigest(iscsi_session, ti, tvb, offset, paddedDataSegmentLength); } else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) { /* Logout Command */ if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) { @@ -1521,7 +1519,7 @@ dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint off } proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, tvb_get_ntoh24(tvb, offset + 5)); offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48); - offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_vendor_specific_data); + offset = handleDataSegment(iscsi_session, ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_vendor_specific_data); } @@ -2238,6 +2236,7 @@ dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean chec guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1); int badPdu = FALSE; guint8 ahsLen=0; + guint32 data_segment_offset, data_segment_len_padded; /* mask out any extra bits in the opcode byte */ opcode = tvb_get_guint8(tvb, offset + 0); @@ -2327,25 +2326,21 @@ dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean chec pduLen += ahsLen * 4; } - pduLen += data_segment_len; - if((pduLen & 3) != 0) - pduLen += 4 - (pduLen & 3); + data_segment_offset = pduLen; + data_segment_len_padded = data_segment_len; + if((data_segment_len_padded & 3) != 0) + data_segment_len_padded += 4 - (data_segment_len_padded & 3); + pduLen += data_segment_len_padded; - if(digestsActive && data_segment_len > 0 && enableDataDigests) { - if(dataDigestIsCRC32) - pduLen += 4; - else - pduLen += dataDigestSize; - } - /* make sure we have a conversation for this session */ conversation = find_or_create_conversation(pinfo); iscsi_session=(iscsi_session_t *)conversation_get_proto_data(conversation, proto_iscsi); if(!iscsi_session){ iscsi_session = wmem_new(wmem_file_scope(), iscsi_session_t); - iscsi_session->header_digest = ISCSI_HEADER_DIGEST_AUTO; + iscsi_session->header_digest = ISCSI_DIGEST_AUTO; + iscsi_session->data_digest = ISCSI_DIGEST_AUTO; iscsi_session->itlq = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); iscsi_session->itl = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); conversation_add_proto_data(conversation, proto_iscsi, iscsi_session); @@ -2358,14 +2353,15 @@ dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean chec conversation_set_dissector(conversation, iscsi_handle); } /* try to autodetect if header digest is used or not */ - if(digestsActive && (available_bytes>=(guint32) (48+4+ahsLen*4)) && (iscsi_session->header_digest==ISCSI_HEADER_DIGEST_AUTO) ){ + if (digestsActive && (available_bytes >= (guint32) (48+4+ahsLen*4)) && + (iscsi_session->header_digest == ISCSI_DIGEST_AUTO)) { guint32 crc; /* we have enough data to test if HeaderDigest is enabled */ crc= ~crc32c_calculate(tvb_get_ptr(tvb, offset, 48+ahsLen*4), 48+ahsLen*4, CRC32C_PRELOAD); if(crc==tvb_get_ntohl(tvb,48+ahsLen*4)){ - iscsi_session->header_digest=ISCSI_HEADER_DIGEST_CRC32; + iscsi_session->header_digest = ISCSI_DIGEST_CRC32; } else { - iscsi_session->header_digest=ISCSI_HEADER_DIGEST_NONE; + iscsi_session->header_digest = ISCSI_DIGEST_NONE; } } @@ -2373,12 +2369,13 @@ dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean chec /* Add header digest length to pdulen */ if(digestsActive){ switch(iscsi_session->header_digest){ - case ISCSI_HEADER_DIGEST_CRC32: + case ISCSI_DIGEST_CRC32: pduLen += 4; + data_segment_offset += 4; break; - case ISCSI_HEADER_DIGEST_NONE: + case ISCSI_DIGEST_NONE: break; - case ISCSI_HEADER_DIGEST_AUTO: + case ISCSI_DIGEST_AUTO: /* oops we didnt know what digest is used yet */ /* here we should use some default */ break; @@ -2387,6 +2384,36 @@ dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean chec } } + /* try to autodetect whether data digest is used */ + if (digestsActive && + (available_bytes >= data_segment_offset + data_segment_len_padded + 4) && + (iscsi_session->data_digest == ISCSI_DIGEST_AUTO)) { + guint32 crc; + /* we have enough data to test if DataDigest is enabled */ + crc = ~crc32c_calculate(tvb_get_ptr(tvb, data_segment_offset, data_segment_len_padded), data_segment_len_padded, CRC32C_PRELOAD); + if (crc == tvb_get_ntohl(tvb, data_segment_offset + data_segment_len_padded)) { + iscsi_session->data_digest = ISCSI_DIGEST_CRC32; + } else { + iscsi_session->data_digest = ISCSI_DIGEST_NONE; + } + } + + /* Add data digest length to pdulen */ + if (digestsActive && data_segment_len > 0) { + switch (iscsi_session->data_digest) { + case ISCSI_DIGEST_CRC32: + pduLen += 4; + break; + case ISCSI_DIGEST_NONE: + break; + case ISCSI_DIGEST_AUTO: + /* unknown digest, perhaps a new field was introduced? */ + break; + default: + DISSECTOR_ASSERT_NOT_REACHED(); + } + } + /* * Desegmentation check. */ @@ -2560,11 +2587,6 @@ proto_register_iscsi(void) FT_UINT32, BASE_HEX, NULL, 0, "Header Digest", HFILL } }, - { &hf_iscsi_DataDigest, - { "DataDigest", "iscsi.datadigest", - FT_BYTES, BASE_NONE, NULL, 0, - "Data Digest", HFILL } - }, { &hf_iscsi_DataDigest32, { "DataDigest", "iscsi.datadigest32", FT_UINT32, BASE_HEX, NULL, 0, @@ -3060,25 +3082,6 @@ proto_register_iscsi(void) 10, &iscsi_system_port); - 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, - "data_digest_is_crc32c", - "Data digest is CRC32C", - "When enabled, data digests are assumed to be CRC32C", - &dataDigestIsCRC32); - - prefs_register_uint_preference(iscsi_module, - "data_digest_size", - "Data digest size", - "The size of a data digest (bytes)", - 10, - &dataDigestSize); - /* Preference supported in older versions. Register them as obsolete. */ prefs_register_obsolete_preference(iscsi_module, @@ -3091,6 +3094,12 @@ proto_register_iscsi(void) "header_digest_size"); prefs_register_obsolete_preference(iscsi_module, "enable_header_digests"); + prefs_register_obsolete_preference(iscsi_module, + "data_digest_is_crc32c"); + prefs_register_obsolete_preference(iscsi_module, + "data_digest_size"); + prefs_register_obsolete_preference(iscsi_module, + "enable_data_digests"); } |