diff options
-rw-r--r-- | AUTHORS | 4 | ||||
-rw-r--r-- | Makefile.am | 7 | ||||
-rw-r--r-- | Makefile.nmake | 7 | ||||
-rw-r--r-- | doc/ethereal.pod.template | 1 | ||||
-rw-r--r-- | packet-iscsi.c | 1601 |
5 files changed, 1614 insertions, 6 deletions
@@ -660,6 +660,10 @@ Martina Obermeier <Martina.Obermeier@icn.siemens.de> { ISUP (ISDN User Part, ITU-T recommendation Q.763) support } +Mark Burton <markb@ordern.com> { + iSCSI support +} + Alain Magloire <alainm@rcsm.ece.mcgill.ca> was kind enough to give his permission to use his version of snprintf.c. diff --git a/Makefile.am b/Makefile.am index 67ead76bed..5b9a34ec2a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # Makefile.am # Automake file for Ethereal # -# $Id: Makefile.am,v 1.328 2001/05/27 07:37:46 guy Exp $ +# $Id: Makefile.am,v 1.329 2001/05/30 18:52:36 guy Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs <gerald@ethereal.com> @@ -120,6 +120,8 @@ DISSECTOR_SRC = \ packet-icmpv6.c\ packet-icp.c \ packet-icq.c \ + packet-ieee80211.c \ + packet-ieee8023.c \ packet-igmp.c \ packet-igrp.c \ packet-imap.c \ @@ -129,9 +131,8 @@ DISSECTOR_SRC = \ packet-ipv6.c \ packet-ipx.c \ packet-irc.c \ - packet-ieee80211.c \ - packet-ieee8023.c \ packet-isakmp.c\ + packet-iscsi.c \ packet-isis.c \ packet-isis-clv.c \ packet-isis-hello.c \ diff --git a/Makefile.nmake b/Makefile.nmake index f333846589..fe62a2eb16 100644 --- a/Makefile.nmake +++ b/Makefile.nmake @@ -1,7 +1,7 @@ ## Makefile for building ethereal.exe with Microsoft C and nmake ## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake # -# $Id: Makefile.nmake,v 1.111 2001/05/25 16:17:22 guy Exp $ +# $Id: Makefile.nmake,v 1.112 2001/05/30 18:52:36 guy Exp $ include config.nmake include <win32.mak> @@ -73,6 +73,8 @@ DISSECTOR_SRC = \ packet-icmpv6.c\ packet-icp.c \ packet-icq.c \ + packet-ieee80211.c \ + packet-ieee8023.c \ packet-igmp.c \ packet-igrp.c \ packet-imap.c \ @@ -82,9 +84,8 @@ DISSECTOR_SRC = \ packet-ipv6.c \ packet-ipx.c \ packet-irc.c \ - packet-ieee80211.c \ - packet-ieee8023.c \ packet-isakmp.c\ + packet-iscsi.c \ packet-isis.c \ packet-isis-clv.c \ packet-isis-hello.c \ diff --git a/doc/ethereal.pod.template b/doc/ethereal.pod.template index 13f50db40a..a651e40ca4 100644 --- a/doc/ethereal.pod.template +++ b/doc/ethereal.pod.template @@ -1109,6 +1109,7 @@ B<http://www.ethereal.com>. Randy McEoin <rmceoin@pe.net> Edgar Iglesias <edgar.iglesias@axis.com> Martina Obermeier <Martina.Obermeier@icn.siemens.de> + Mark Burton <markb@ordern.com> Alain Magloire <alainm@rcsm.ece.mcgill.ca> was kind enough to give his permission to use his version of snprintf.c. diff --git a/packet-iscsi.c b/packet-iscsi.c new file mode 100644 index 0000000000..64ea686bb1 --- /dev/null +++ b/packet-iscsi.c @@ -0,0 +1,1601 @@ +/* packet-iscsi.c + * Routines for iSCSI dissection + * Copyright 2001, Eurologic and Mark Burton <markb@ordern.com> + * + * Conforms to the protocol described in: draft-ietf-ips-iscsi-06.txt + * Optionally, supports the protocol described in: draft-ietf-ips-iscsi-03.txt + * + * $Id: packet-iscsi.c,v 1.1 2001/05/30 18:52:37 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#include <glib.h> + +#ifdef NEED_SNPRINTF_H +# include "snprintf.h" +#endif + +#include "packet.h" +#include "prefs.h" + +static int enable_03_mode = TRUE; +static int enable_bogosity_filter = TRUE; +static int bogus_pdu_data_length_threshold = 1024 * 1024; +static int bogus_pdu_max_digest_padding = 20; + +/* Initialize the protocol and registered fields */ +static int proto_iscsi = -1; +static int hf_iscsi_Payload = -1; +static int hf_iscsi_Opcode = -1; +static int hf_iscsi_Opcode_03 = -1; +#if 0 +static int hf_iscsi_X = -1; +static int hf_iscsi_I = -1; +#endif +static int hf_iscsi_SCSICommand_X03 = -1; +static int hf_iscsi_SCSICommand_F = -1; +static int hf_iscsi_SCSICommand_R = -1; +static int hf_iscsi_SCSICommand_W = -1; +static int hf_iscsi_SCSICommand_Attr = -1; +static int hf_iscsi_SCSICommand_CRN = -1; +static int hf_iscsi_SCSICommand_AddCDB = -1; +static int hf_iscsi_Length03 = -1; +static int hf_iscsi_DataSegmentLength = -1; +static int hf_iscsi_TotalAHSLength = -1; +static int hf_iscsi_LUN = -1; +static int hf_iscsi_InitiatorTaskTag = -1; +static int hf_iscsi_ExpectedDataTransferLength = -1; +static int hf_iscsi_CmdSN = -1; +static int hf_iscsi_ExpStatSN = -1; +static int hf_iscsi_SCSICommand_CDB = -1; +static int hf_iscsi_SCSICommand_CDB0 = -1; +static int hf_iscsi_StatSN = -1; +static int hf_iscsi_ExpCmdSN = -1; +static int hf_iscsi_MaxCmdSN = -1; +static int hf_iscsi_SCSIResponse_o03 = -1; +static int hf_iscsi_SCSIResponse_u03 = -1; +static int hf_iscsi_SCSIResponse_O03 = -1; +static int hf_iscsi_SCSIResponse_U03 = -1; +static int hf_iscsi_SCSIResponse_o = -1; +static int hf_iscsi_SCSIResponse_u = -1; +static int hf_iscsi_SCSIResponse_O = -1; +static int hf_iscsi_SCSIResponse_U = -1; +static int hf_iscsi_SCSIResponse_S = -1; +static int hf_iscsi_CommandStatus03 = -1; +static int hf_iscsi_StatusResponse_is_status = -1; +static int hf_iscsi_StatusResponse_is_response = -1; +static int hf_iscsi_SCSIResponse_SenseLength = -1; +static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1; +static int hf_iscsi_SCSIResponse_BasicResidualCount = -1; +static int hf_iscsi_SCSIData_F = -1; +static int hf_iscsi_SCSIData_P03 = -1; +static int hf_iscsi_SCSIData_S03 = -1; +static int hf_iscsi_SCSIData_O03 = -1; +static int hf_iscsi_SCSIData_U03 = -1; +static int hf_iscsi_SCSIData_S = -1; +static int hf_iscsi_SCSIData_O = -1; +static int hf_iscsi_SCSIData_U = -1; +static int hf_iscsi_TargetTransferTag = -1; +static int hf_iscsi_DataSN = -1; +static int hf_iscsi_BufferOffset = -1; +static int hf_iscsi_SCSIData_ResidualCount = -1; +static int hf_iscsi_VersionMin = -1; +static int hf_iscsi_VersionMax = -1; +static int hf_iscsi_CID = -1; +static int hf_iscsi_ISID = -1; +static int hf_iscsi_TSID = -1; +static int hf_iscsi_InitStatSN = -1; +static int hf_iscsi_InitCmdSN = -1; +static int hf_iscsi_Login_F = -1; +static int hf_iscsi_Login_Status03 = -1; +static int hf_iscsi_Login_Status = -1; +static int hf_iscsi_KeyValue = -1; +static int hf_iscsi_Text_F = -1; +static int hf_iscsi_NOP_P = -1; +static int hf_iscsi_ExpDataSN = -1; +static int hf_iscsi_R2TExpDataSN = -1; +static int hf_iscsi_SCSITask_ReferencedTaskTag = -1; +static int hf_iscsi_SCSITask_Function = -1; +static int hf_iscsi_SCSITask_Response = -1; +static int hf_iscsi_Logout_Reason03 = -1; +static int hf_iscsi_Logout_Reason = -1; +static int hf_iscsi_Logout_Response = -1; +static int hf_iscsi_DesiredDataLength = -1; +static int hf_iscsi_SCSIEvent = -1; +static int hf_iscsi_iSCSIEvent = -1; +static int hf_iscsi_SCSIEvent03 = -1; +static int hf_iscsi_iSCSIEvent03 = -1; +static int hf_iscsi_Parameter1 = -1; +static int hf_iscsi_Parameter2 = -1; +static int hf_iscsi_Reject_Reason = -1; +static int hf_iscsi_Reject_FirstBadByte = -1; +static int hf_iscsi_Reject_Reason03 = -1; +static int hf_iscsi_SNACK_S = -1; +static int hf_iscsi_AddRuns = -1; +static int hf_iscsi_BegRun = -1; +static int hf_iscsi_RunLength = -1; +static int hf_iscsi_AdditionalRuns = -1; + +/* Initialize the subtree pointers */ +static gint ett_iscsi_KeyValues = -1; +static gint ett_iscsi_CDB = -1; + +static const value_string iscsi_opcodes[] = { + {0x00, "NOP Out"}, + {0x40, "NOP Out (Immediate)"}, + {0x80, "NOP Out (Retry)"}, + + {0x01, "SCSI Command"}, + {0x41, "SCSI Command (Immediate)"}, + {0x81, "SCSI Command (Retry)"}, + + {0x02, "SCSI Task Management Command"}, + {0x42, "SCSI Task Management Command (Immediate)"}, + {0x82, "SCSI Task Management Command (Retry)"}, + + {0x03, "Login Command"}, + {0x83, "Login Command (Retry)"}, + + {0x04, "Text Command"}, + {0x44, "Text Command (Immediate)"}, + {0x84, "Text Command (Retry)"}, + + {0x05, "SCSI Write Data"}, + + {0x06, "Logout Command"}, + {0x46, "Logout Command (Immediate)"}, + + {0x10, "SNACK Request (Missing Immediate bit)"}, + {0x50, "SNACK Request"}, + + {0xc0, "NOP In"}, + {0xc1, "SCSI Command Response"}, + {0xc2, "SCSI Task Management Response"}, + {0xc3, "Login Response"}, + {0xc4, "Text Response"}, + {0xc5, "SCSI Read Data"}, + {0xc6, "Logout Response"}, + {0xd0, "Ready To Transfer"}, + {0xd1, "Asynchronous Message"}, + {0xef, "Reject"}, + {0, NULL}, +}; + +static const value_string iscsi_opcodes_03[] = { + {0x00, "NOP Out"}, + {0x01, "SCSI Command"}, + {0x02, "SCSI Task Management Command"}, + {0x03, "Login Command"}, + {0x04, "Text Command"}, + {0x05, "SCSI Write Data"}, + {0x06, "Logout Command"}, + {0x80, "NOP In"}, + {0x81, "SCSI Command Response"}, + {0x82, "SCSI Task Management Response"}, + {0x83, "Login Response"}, + {0x84, "Text Response"}, + {0x85, "SCSI Read Data"}, + {0x86, "Logout Response"}, + {0x90, "Ready To Transfer"}, + {0x91, "Asynchronous Event"}, + {0xef, "Reject"}, + {0, NULL}, +}; + +static const true_false_string iscsi_meaning_X = { + "Retry", + "Not retry" +}; + +static const true_false_string iscsi_meaning_I = { + "Immediate delivery", + "Queued delivery" +}; + +static const true_false_string iscsi_meaning_F = { + "Final PDU in sequence", + "Not final PDU in sequence" +}; + +static const true_false_string iscsi_meaning_P = { + "Poll requested", + "No poll requested" +}; + +static const true_false_string iscsi_meaning_S = { + "Response contains SCSI status", + "Response does not contain SCSI status" +}; + +static const true_false_string iscsi_meaning_R = { + "Data will be read from target", + "No data will be read from target" +}; + +static const true_false_string iscsi_meaning_W = { + "Data will be written to target", + "No data will be written to target" +}; + +static const true_false_string iscsi_meaning_o = { + "Read part of bi-directional command overflowed", + "No overflow of read part of bi-directional command", +}; + +static const true_false_string iscsi_meaning_u = { + "Read part of bi-directional command underflowed", + "No underflow of read part of bi-directional command", +}; + +static const true_false_string iscsi_meaning_O = { + "Residual overflow occurred", + "No residual overflow occurred", +}; + +static const true_false_string iscsi_meaning_U = { + "Residual underflow occurred", + "No residual underflow occurred", +}; + +static const true_false_string iscsi_meaning_scsiresponse_S = { + "Status/Response field contains SCSI status", + "Status/Response field contains iSCSI response", +}; + +static const true_false_string iscsi_meaning_SNACK_S = { + "Status SNACK", + "Data SNACK", +}; + +static const value_string iscsi_scsicommand_taskattrs[] = { + {0, "Untagged"}, + {1, "Simple"}, + {2, "Ordered"}, + {3, "Head of Queue"}, + {4, "ACA"}, + {0, NULL}, +}; + +static const value_string iscsi_scsi_cdb0[] = { + {0x00, "TEST_UNIT_READY"}, + {0x01, "REZERO_UNIT"}, + {0x03, "REQUEST_SENSE"}, + {0x04, "FORMAT_UNIT"}, + {0x05, "READ_BLOCK_LIMITS"}, + {0x07, "REASSIGN_BLOCKS"}, + {0x08, "READ_6"}, + {0x0a, "WRITE_6"}, + {0x0b, "SEEK_6"}, + {0x0f, "READ_REVERSE"}, + {0x10, "WRITE_FILEMARKS"}, + {0x11, "SPACE"}, + {0x12, "INQUIRY"}, + {0x14, "RECOVER_BUFFERED_DATA"}, + {0x15, "MODE_SELECT"}, + {0x16, "RESERVE"}, + {0x17, "RELEASE"}, + {0x18, "COPY"}, + {0x19, "ERASE"}, + {0x1a, "MODE_SENSE"}, + {0x1b, "START_STOP"}, + {0x1c, "RECEIVE_DIAGNOSTIC"}, + {0x1d, "SEND_DIAGNOSTIC"}, + {0x1e, "ALLOW_MEDIUM_REMOVAL"}, + {0x24, "SET_WINDOW"}, + {0x25, "READ_CAPACITY"}, + {0x28, "READ_10"}, + {0x2a, "WRITE_10"}, + {0x2b, "SEEK_10"}, + {0x2e, "WRITE_VERIFY"}, + {0x2f, "VERIFY"}, + {0x30, "SEARCH_HIGH"}, + {0x31, "SEARCH_EQUAL"}, + {0x32, "SEARCH_LOW"}, + {0x33, "SET_LIMITS"}, + {0x34, "PRE_FETCH"}, + {0x34, "READ_POSITION"}, + {0x35, "SYNCHRONIZE_CACHE"}, + {0x36, "LOCK_UNLOCK_CACHE"}, + {0x37, "READ_DEFECT_DATA"}, + {0x38, "MEDIUM_SCAN"}, + {0x39, "COMPARE"}, + {0x3a, "COPY_VERIFY"}, + {0x3b, "WRITE_BUFFER"}, + {0x3c, "READ_BUFFER"}, + {0x3d, "UPDATE_BLOCK"}, + {0x3e, "READ_LONG"}, + {0x3f, "WRITE_LONG"}, + {0x40, "CHANGE_DEFINITION"}, + {0x41, "WRITE_SAME"}, + {0x43, "READ_TOC"}, + {0x4c, "LOG_SELECT"}, + {0x4d, "LOG_SENSE"}, + {0x55, "MODE_SELECT_10"}, + {0x5a, "MODE_SENSE_10"}, + {0xa5, "MOVE_MEDIUM"}, + {0xa8, "READ_12"}, + {0xaa, "WRITE_12"}, + {0xae, "WRITE_VERIFY_12"}, + {0xb0, "SEARCH_HIGH_12"}, + {0xb1, "SEARCH_EQUAL_12"}, + {0xb2, "SEARCH_LOW_12"}, + {0xb8, "READ_ELEMENT_STATUS"}, + {0xb6, "SEND_VOLUME_TAG"}, + {0xea, "WRITE_LONG_2"}, + {0, NULL}, +}; + +static const value_string iscsi_scsi_statuses[] = { + {0x00, "Good"}, + {0x01, "Check condition"}, + {0x02, "Condition good"}, + {0x04, "Busy"}, + {0x08, "Intermediate good"}, + {0x0a, "Intermediate c good"}, + {0x0c, "Reservation conflict"}, + {0x11, "Command terminated"}, + {0x14, "Queue full"}, + {0, NULL}, +}; + +static const value_string iscsi_scsi_responses[] = { + {0x01, "Target failure"}, + {0x02, "Delivery subsystem failure"}, + {0x03, "Unsolicited data rejected"}, + {0x04, "SNACK rejected"}, + {0, NULL}, +}; + +static const value_string iscsi_task_responses[] = { + {0, "Function complete"}, + {1, "Task not in task set"}, + {2, "LUN does not exist"}, + {255, "Function rejected"}, + {0, NULL}, +}; + +static const value_string iscsi_task_functions[] = { + {1, "Abort Task"}, + {2, "Abort Task Set"}, + {3, "Clear ACA"}, + {4, "Clear Task Set"}, + {5, "Logical Unit Reset"}, + {6, "Target Warm Reset"}, + {7, "Target Cold Reset"}, + {0, NULL}, +}; + +static const value_string iscsi_login_status03[] = { + {0, "Accept Login"}, + {1, "Reject Login - unsupported version"}, + {2, "Reject Login - failed authentication"}, + {3, "Reject Login - incompatible parameters"}, + {0, NULL}, +}; + +static const value_string iscsi_login_status[] = { + {0x0000, "Success - Accept login"}, + {0x0001, "Success - Athenticate"}, + {0x0002, "Success - iSCSI target name required"}, + {0x0101, "Redirection - Target moved temporarily"}, + {0x0102, "Redirection - Target moved permanently"}, + {0x0103, "Redirection - Proxy required"}, + {0x0201, "Initiator error - Athentication failed"}, + {0x0202, "Initiator error - Forbidden target"}, + {0x0203, "Initiator error - Target not found"}, + {0x0204, "Initiator error - Target removed"}, + {0x0205, "Initiator error - Target conflict"}, + {0x0206, "Initiator error - Initiator SID error"}, + {0x0207, "Initiator error - Missing parameter"}, + {0x0300, "Target error - Target error"}, + {0x0301, "Target error - Service unavailable"}, + {0x0302, "Target error - Unsupported version"}, + {0, NULL}, +}; + +static const value_string iscsi_logout_reasons03[] = { + {0, "Remove connection - session is closing"}, + {1, "Remove connection - for recovery"}, + {2, "Remove connection - at target's request"}, + {0, NULL}, +}; + +static const value_string iscsi_logout_reasons[] = { + {0, "Session is closing"}, + {1, "Close connections"}, + {2, "Remove connection for recovery"}, + {3, "Remove connection at target's request"}, + {0, NULL}, +}; + +static const value_string iscsi_logout_response[] = { + {0, "Connection closed successfully"}, + {1, "Cleanup failed"}, + {0, NULL}, +}; + +static const value_string iscsi_scsievents03[] = { + {1, "Error condition encountered after command completion"}, + {2, "A newly initialised device is available to the initiator"}, + {3, "All task sets are being reset by another initiator"}, + {5, "Some other type of unit attention condition has occurred"}, + {6, "An asynchronous event has occurred"}, + {0, NULL}, +}; + +static const value_string iscsi_iscsievents03[] = { + {1, "Target is being reset"}, + {2, "Target requests logout"}, + {3, "Target will drop connection"}, + {0, NULL}, +}; + +static const value_string iscsi_reject_reasons03[] = { + {1, "Format error"}, + {2, "Header digest error"}, + {3, "Payload digest error"}, + {0, NULL}, +}; + +static const value_string iscsi_reject_reasons[] = { + {1, "Format error"}, + {2, "Header digest error"}, + {3, "Payload digest error"}, + {4, "Data SNACK reject"}, + {5, "Command retry reject"}, + {15, "Full feature phase command before login"}, + {0, NULL}, +}; + +static int min(int a, int b) { + return (a < b)? a : b; +} + +static gint addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) { + const gint limit = offset + text_len; + while(offset < limit) { + const char *p = tvb_get_ptr(tvb, offset, 1); + int len = strlen(p) + 1; + if((offset + len) >= limit) + len = limit - offset; + proto_tree_add_string_format(tt, hf_iscsi_KeyValue, tvb, offset, len, p, "%s", p); + offset += len; + } + return offset; +} + +static gint dissectCDB(proto_tree *tt, tvbuff_t *tvb, gint offset, gint cdbLen) { + guint8 cdb0 = tvb_get_guint8(tvb, offset); + switch(cdb0) { + case 0x08: /* READ_6 */ +#if 0 + proto_tree_add_uint(tt, hf_iscsi_SCSICommand_CDB0, tvb, offset, 1, cdb0); +#endif + default: + proto_tree_add_bytes(tt, hf_iscsi_SCSICommand_CDB, tvb, offset, cdbLen, tvb_get_ptr(tvb, offset, cdbLen)); + } + return offset + cdbLen; +} + +/* Code to actually dissect the packets */ +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 */ + proto_item *ti; + gint offset = 0; + guint32 data_segment_len; + guint8 opcode; + const char *opcode_str; + guint32 pdu_len; + + /* Make sure we have enough of the packet to check whether it's + iSCSI */ + if (tvb_length_remaining(tvb, offset) < 8) { + /* We don't */ + return FALSE; + } + + opcode = tvb_get_guint8(tvb, offset + 0); + pdu_len = tvb_length_remaining(tvb, 0); + if(enable_03_mode) { + opcode_str = match_strval(opcode, iscsi_opcodes_03); + data_segment_len = tvb_get_ntohl(tvb, offset + 4); + } + else { + 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 || + pdu_len < 48 || + pdu_len > (data_segment_len + 48 + bogus_pdu_max_digest_padding)))) { + return FALSE; + } + + /* Make entries in Protocol column and Info column on summary display */ + if (check_col(pinfo->fd, COL_PROTOCOL)) + col_set_str(pinfo->fd, COL_PROTOCOL, "iSCSI"); + + + if (check_col(pinfo->fd, COL_INFO)) { + const char *scsiCommandName = 0; + + col_add_str(pinfo->fd, COL_INFO, (char *)opcode_str); + + if((opcode & 0xbf) == 0x01 && pdu_len > 32) + scsiCommandName = match_strval(tvb_get_guint8(tvb, offset + 32), + iscsi_scsi_cdb0); + if(scsiCommandName != NULL) + col_append_fstr(pinfo->fd, COL_INFO, " (%s)", scsiCommandName); + } + + /* In the interest of speed, if "tree" is NULL, don't do any + work not necessary to generate protocol tree items. */ + if (tree) { + + /* create display subtree for the protocol */ + ti = proto_tree_add_item(tree, proto_iscsi, tvb, offset, + pdu_len, FALSE); + + if((enable_03_mode && opcode == 0x00) || + (!enable_03_mode && (opcode == 0x00 || + opcode == 0x40 || + opcode == 0x80))) { + /* NOP Out */ + gint b = tvb_get_guint8(tvb, offset + 1); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + } + proto_tree_add_boolean(ti, hf_iscsi_NOP_P, tvb, offset + 1, 1, b); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_bytes(ti, hf_iscsi_LUN, tvb, offset + 8, 8, tvb_get_ptr(tvb, offset + 8, 8)); + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + proto_tree_add_uint(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_ExpDataSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + } + proto_tree_add_uint(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, tvb_get_ntohl(tvb, offset + 40)); + offset += 48; + } + else if((enable_03_mode && opcode == 0x80) || + (!enable_03_mode && opcode == 0xc0)) { + /* NOP In */ + gint b = tvb_get_guint8(tvb, offset + 1); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + } + proto_tree_add_boolean(ti, hf_iscsi_NOP_P, tvb, offset + 1, 1, b); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + proto_tree_add_uint(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + proto_tree_add_uint(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + offset += 48; + } + else if((enable_03_mode && opcode == 0x01) || + (!enable_03_mode && (opcode == 0x01 || + opcode == 0x41 || + opcode == 0x81))) { + /* SCSI Command */ + gint b = tvb_get_guint8(tvb, offset + 1); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_SCSICommand_X03, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b); + proto_tree_add_uint(ti, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b); + proto_tree_add_uint(ti, hf_iscsi_SCSICommand_AddCDB, tvb, offset + 3, 1, tvb_get_guint8(tvb, offset + 3)); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b); + proto_tree_add_uint(ti, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b); + proto_tree_add_uint(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, tvb_get_guint8(tvb, offset + 3)); + proto_tree_add_uint(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, tvb_get_guint8(tvb, offset + 4)); + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_bytes(ti, hf_iscsi_LUN, tvb, offset + 8, 8, tvb_get_ptr(tvb, offset + 8, 8)); + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + proto_tree_add_uint(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + { + guint8 cdb0 = tvb_get_guint8(tvb, offset + 32); + proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_SCSICommand_CDB0, tvb, offset + 32, 1, cdb0); + proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_CDB); + dissectCDB(tt, tvb, offset + 32, 16 + tvb_get_guint8(tvb, offset + 3) * 4); + } + offset += 48; + } + else if((enable_03_mode && opcode == 0x81) || + (!enable_03_mode && opcode == 0xc1)) { + /* SCSI Response */ + gint b = tvb_get_guint8(tvb, offset + 1); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_SCSIResponse_o03, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIResponse_u03, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIResponse_O03, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIResponse_U03, tvb, offset + 1, 1, b); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIResponse_S, tvb, offset + 1, 1, b); + if(b & 0x01) + proto_tree_add_uint(ti, hf_iscsi_StatusResponse_is_status, tvb, offset + 3, 1, tvb_get_guint8(tvb, offset + 3)); + else + proto_tree_add_uint(ti, hf_iscsi_StatusResponse_is_response, tvb, offset + 3, 1, tvb_get_guint8(tvb, offset + 3)); + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_SCSIResponse_BasicResidualCount, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + proto_tree_add_uint(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + proto_tree_add_uint(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_CommandStatus03, tvb, offset + 36, 1, tvb_get_guint8(tvb, offset + 36)); + proto_tree_add_uint(ti, hf_iscsi_SCSIResponse_SenseLength, tvb, offset + 40, 2, tvb_get_ntohs(tvb, offset + 40)); + } + else { + proto_tree_add_uint(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, tvb_get_ntohl(tvb, offset + 36)); + proto_tree_add_uint(ti, hf_iscsi_R2TExpDataSN, tvb, offset + 40, 4, tvb_get_ntohl(tvb, offset + 40)); + } + proto_tree_add_uint(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, tvb_get_ntohl(tvb, offset + 44)); + offset += 48; + } + else if((enable_03_mode && opcode == 0x02) || + (!enable_03_mode && (opcode == 0x02 || + opcode == 0x42 || + opcode == 0x82))) { + /* SCSI Task Command */ + gint b = tvb_get_guint8(tvb, offset + 1); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + } + proto_tree_add_uint(ti, hf_iscsi_SCSITask_Function, tvb, offset + 1, 1, b); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + proto_tree_add_bytes(ti, hf_iscsi_LUN, tvb, offset + 8, 8, tvb_get_ptr(tvb, offset + 8, 8)); + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_SCSITask_ReferencedTaskTag, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + proto_tree_add_uint(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + offset += 48; + } + else if((enable_03_mode && opcode == 0x82) || + (!enable_03_mode && opcode == 0xc2)) { + /* SCSI Task Response */ + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + } + proto_tree_add_bytes(ti, hf_iscsi_LUN, tvb, offset + 8, 8, tvb_get_ptr(tvb, offset + 8, 8)); + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_SCSITask_ReferencedTaskTag, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + proto_tree_add_uint(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + proto_tree_add_uint(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + proto_tree_add_uint(ti, hf_iscsi_SCSITask_Response, tvb, offset + 36, 1, tvb_get_guint8(tvb, offset + 36)); + offset += 48; + } + else if((enable_03_mode && opcode == 0x03) || + (!enable_03_mode && (opcode == 0x03 || + opcode == 0x83))) { + /* Login Command */ + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_Login_F, tvb, offset + 1, 1, tvb_get_guint8(tvb, offset + 1)); + } + proto_tree_add_uint(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, tvb_get_guint8(tvb, offset + 2)); + proto_tree_add_uint(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, tvb_get_guint8(tvb, offset + 3)); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_uint(ti, hf_iscsi_CID, tvb, offset + 8, 2, tvb_get_ntohs(tvb, offset + 8)); + proto_tree_add_uint(ti, hf_iscsi_ISID, tvb, offset + 12, 2, tvb_get_ntohs(tvb, offset + 12)); + proto_tree_add_uint(ti, hf_iscsi_TSID, tvb, offset + 14, 2, tvb_get_ntohs(tvb, offset + 14)); + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_InitCmdSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + } + else { + proto_tree_add_uint(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + } + offset += 48; + if(pdu_len > 48) { + int text_len = min(data_segment_len, pdu_len - 48); + proto_item *tf = proto_tree_add_text(ti, tvb, 48, text_len, "Key/Value Pairs"); + proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues); + offset = addTextKeys(tt, tvb, 48, text_len); + } + } + else if((enable_03_mode && opcode == 0x83) || + (!enable_03_mode && opcode == 0xc3)) { + /* Login Response */ + gint b = tvb_get_guint8(tvb, offset + 1); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + } + proto_tree_add_boolean(ti, hf_iscsi_Login_F, tvb, offset + 1, 1, b); + proto_tree_add_uint(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, tvb_get_guint8(tvb, offset + 2)); + proto_tree_add_uint(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, tvb_get_guint8(tvb, offset + 3)); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_uint(ti, hf_iscsi_ISID, tvb, offset + 12, 2, tvb_get_ntohs(tvb, offset + 12)); + proto_tree_add_uint(ti, hf_iscsi_TSID, tvb, offset + 14, 2, tvb_get_ntohs(tvb, offset + 14)); + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_InitStatSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + proto_tree_add_uint(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Login_Status03, tvb, offset + 36, 1, tvb_get_guint8(tvb, offset + 36)); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Login_Status, tvb, offset + 36, 1, tvb_get_ntohs(tvb, offset + 36)); + } + offset += 48; + if(pdu_len > 48) { + int text_len = min(data_segment_len, pdu_len - 48); + proto_item *tf = proto_tree_add_text(ti, tvb, 48, text_len, "Key/Value Pairs"); + proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues); + offset = addTextKeys(tt, tvb, 48, text_len); + } + } + else if((enable_03_mode && opcode == 0x04) || + (!enable_03_mode && (opcode == 0x04 || + opcode == 0x44 || + opcode == 0x84))) { + /* Text Command */ + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_Text_F, tvb, offset + 1, 1, tvb_get_guint8(tvb, offset + 1)); + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + offset += 48; + if(pdu_len > 48) { + int text_len = min(data_segment_len, pdu_len - 48); + proto_item *tf = proto_tree_add_text(ti, tvb, 48, text_len, "Key/Value Pairs"); + proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues); + offset = addTextKeys(tt, tvb, 48, text_len); + } + } + else if((enable_03_mode && opcode == 0x84) || + (!enable_03_mode && (opcode == 0xc4))) { + /* Text Response */ + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_Text_F, tvb, offset + 1, 1, tvb_get_guint8(tvb, offset + 1)); + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + proto_tree_add_uint(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + offset += 48; + if(pdu_len > 48) { + int text_len = min(data_segment_len, pdu_len - 48); + proto_item *tf = proto_tree_add_text(ti, tvb, 48, text_len, "Key/Value Pairs"); + proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues); + offset = addTextKeys(tt, tvb, 48, text_len); + } + } + else if(opcode == 0x05) { + /* SCSI Data (write) */ + gint b = tvb_get_guint8(tvb, offset + 1); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + } + proto_tree_add_boolean(ti, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_bytes(ti, hf_iscsi_LUN, tvb, offset + 8, 8, tvb_get_ptr(tvb, offset + 8, 8)); + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + proto_tree_add_uint(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + if(!enable_03_mode) + proto_tree_add_uint(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, tvb_get_ntohl(tvb, offset + 36)); + proto_tree_add_uint(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, tvb_get_ntohl(tvb, offset + 40)); + offset += 48; + } + else if((enable_03_mode && opcode == 0x85) || + (!enable_03_mode && opcode == 0xc5)) { + /* SCSI Data (read) */ + gint b = tvb_get_guint8(tvb, offset + 1); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_SCSIData_P03, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIData_S03, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIData_O03, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIData_U03, tvb, offset + 1, 1, b); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b); + proto_tree_add_uint(ti, hf_iscsi_StatusResponse_is_status, tvb, offset + 3, 1, tvb_get_guint8(tvb, offset + 3)); + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + } + proto_tree_add_uint(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + proto_tree_add_uint(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_CommandStatus03, tvb, offset + 36, 1, tvb_get_guint8(tvb, offset + 36)); + } + else { + proto_tree_add_uint(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, tvb_get_ntohl(tvb, offset + 36)); + } + proto_tree_add_uint(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, tvb_get_ntohl(tvb, offset + 40)); + proto_tree_add_uint(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 44, 4, tvb_get_ntohl(tvb, offset + 44)); + offset += 48; + } + else if((enable_03_mode && opcode == 0x06) || + (!enable_03_mode && (opcode == 0x06 || opcode == 0x46))) { + /* Logout Command */ + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_uint(ti, hf_iscsi_CID, tvb, offset + 8, 2, tvb_get_ntohs(tvb, offset + 8)); + if(enable_03_mode) + proto_tree_add_uint(ti, hf_iscsi_Logout_Reason03, tvb, offset + 11, 1, tvb_get_guint8(tvb, offset + 11)); + else + proto_tree_add_uint(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, tvb_get_guint8(tvb, offset + 11)); + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + if(!enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + } + offset += 48; + } + else if((enable_03_mode && opcode == 0x86) || + (!enable_03_mode && opcode == 0xc6)) { + /* Logout Response */ + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + } + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + proto_tree_add_uint(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + proto_tree_add_uint(ti, hf_iscsi_Logout_Response, tvb, offset + 36, 1, tvb_get_guint8(tvb, offset + 36)); + offset += 48; + } + else if((!enable_03_mode && (opcode == 0x10 || opcode == 0x50))) { + /* SNACK Request */ + gint b = tvb_get_guint8(tvb, offset + 1); + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_boolean(ti, hf_iscsi_SNACK_S, tvb, offset + 1, 1, b); + proto_tree_add_boolean(ti, hf_iscsi_AddRuns, tvb, offset + 3, 1, tvb_get_guint8(tvb, offset + 3)); + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + proto_tree_add_uint(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + if(b & 0x01) { + proto_tree_add_uint(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + } + else { + proto_tree_add_uint(ti, hf_iscsi_ExpDataSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + } + proto_tree_add_bytes(ti, hf_iscsi_AdditionalRuns, tvb, offset + 32, 16, tvb_get_ptr(tvb, offset + 32, 16)); + offset += 48; + } + else if((enable_03_mode && opcode == 0x90) || + (!enable_03_mode && opcode == 0xd0)) { + /* R2T */ + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + } + proto_tree_add_uint(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, tvb_get_ntohl(tvb, offset + 16)); + proto_tree_add_uint(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, tvb_get_ntohl(tvb, offset + 20)); + if(!enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + } + proto_tree_add_uint(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + proto_tree_add_uint(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_DesiredDataLength, tvb, offset + 36, 4, tvb_get_ntohl(tvb, offset + 36)); + proto_tree_add_uint(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, tvb_get_ntohl(tvb, offset + 40)); + } + else { + proto_tree_add_uint(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, tvb_get_ntohl(tvb, offset + 36)); + proto_tree_add_uint(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, tvb_get_ntohl(tvb, offset + 40)); + proto_tree_add_uint(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, tvb_get_ntohl(tvb, offset + 44)); + } + offset += 48; + } + else if((enable_03_mode && opcode == 0x91) || + (!enable_03_mode && opcode == 0xd1)) { + /* Asynchronous Message */ + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + } + proto_tree_add_bytes(ti, hf_iscsi_LUN, tvb, offset + 8, 8, tvb_get_ptr(tvb, offset + 8, 8)); + proto_tree_add_uint(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, tvb_get_ntohl(tvb, offset + 24)); + proto_tree_add_uint(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28)); + proto_tree_add_uint(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, tvb_get_ntohl(tvb, offset + 32)); + proto_tree_add_uint(ti, hf_iscsi_SCSIEvent, tvb, offset + 36, 1, tvb_get_guint8(tvb, offset + 36)); + proto_tree_add_uint(ti, hf_iscsi_iSCSIEvent, tvb, offset + 37, 1, tvb_get_guint8(tvb, offset + 37)); + proto_tree_add_uint(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, tvb_get_ntohs(tvb, offset + 38)); + proto_tree_add_uint(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, tvb_get_ntohs(tvb, offset + 40)); + offset += 48; + } + else if(opcode == 0xef) { + /* Reject */ + if(enable_03_mode) { + proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len); + proto_tree_add_uint(ti, hf_iscsi_Reject_Reason03, tvb, offset + 36, 1, tvb_get_guint8(tvb, offset + 36)); + } + else { + proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb, + offset + 0, 1, opcode); + proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len); + proto_tree_add_uint(ti, hf_iscsi_Reject_Reason, tvb, offset + 40, 1, tvb_get_guint8(tvb, offset + 40)); + proto_tree_add_uint(ti, hf_iscsi_Reject_FirstBadByte, tvb, offset + 42, 1, tvb_get_ntohs(tvb, offset + 42)); + } + offset += 48; + } + + if(pdu_len > offset) + proto_tree_add_bytes(ti, hf_iscsi_Payload, tvb, offset, pdu_len - offset, tvb_get_ptr(tvb, offset, pdu_len - offset)); + } + + return TRUE; +} + +/* 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. +*/ + +void +proto_register_iscsi(void) +{ + + /* Setup list of header fields See Section 1.6.1 for details*/ + static hf_register_info hf[] = { + { &hf_iscsi_Payload, + { "Payload", "iscsi.payload", + FT_BYTES, BASE_HEX, NULL, 0, + "Payload" } + }, + { &hf_iscsi_Opcode, + { "Opcode", "iscsi.opcode", + FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0, + "Opcode" } + }, + { &hf_iscsi_Opcode_03, + { "Opcode", "iscsi.opcode", + FT_UINT8, BASE_HEX, VALS(iscsi_opcodes_03), 0, + "Opcode" } + }, +#if 0 + { &hf_iscsi_X, + { "X", "iscsi.x", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80, + "Command Retry" } + }, + { &hf_iscsi_I, + { "I", "iscsi.i", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40, + "Immediate delivery" } + }, +#endif + { &hf_iscsi_SCSICommand_X03, + { "X", "iscsi.scsicommand.x", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80, + "Command Retry" } + }, + { &hf_iscsi_SCSICommand_F, + { "F", "iscsi.scsicommand.f", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80, + "PDU completes command" } + }, + { &hf_iscsi_SCSICommand_R, + { "R", "iscsi.scsicommand.r", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40, + "Command reads from SCSI target" } + }, + { &hf_iscsi_SCSICommand_W, + { "W", "iscsi.scsicommand.r", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20, + "Command writes to SCSI target" } + }, + { &hf_iscsi_SCSICommand_Attr, + { "Attr", "iscsi.scsicommand.attr", + FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07, + "SCSI task attributes" } + }, + { &hf_iscsi_SCSICommand_CRN, + { "CRN", "iscsi.scsicommand.crn", + FT_UINT8, BASE_HEX, NULL, 0, + "SCSI command reference number" } + }, + { &hf_iscsi_SCSICommand_AddCDB, + { "AddCDB", "iscsi.scsicommand.addcdb", + FT_UINT8, BASE_HEX, NULL, 0, + "Additional CDB length (in 4 byte units)" } + }, + { &hf_iscsi_Length03, + { "Length", "iscsi.length", + FT_UINT32, BASE_HEX, NULL, 0, + "Data length (bytes)" } + }, + { &hf_iscsi_DataSegmentLength, + { "DataSegmentLength", "iscsi.datasegmentlength", + FT_UINT32, BASE_HEX, NULL, 0, + "Data segment length (bytes)" } + }, + { &hf_iscsi_TotalAHSLength, + { "TotalAHSLength", "iscsi.totalahslength", + FT_UINT8, BASE_HEX, NULL, 0, + "Total additional header segment length (4 byte words)" } + }, + { &hf_iscsi_LUN, + { "LUN", "iscsi.lun", + FT_BYTES, BASE_HEX, NULL, 0, + "Logical Unit Number" } + }, + { &hf_iscsi_InitiatorTaskTag, + { "InitiatorTaskTag", "iscsi.initiatortasktag", + FT_UINT32, BASE_HEX, NULL, 0, + "Initiator's task tag" } + }, + { &hf_iscsi_ExpectedDataTransferLength, + { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength", + FT_UINT32, BASE_HEX, NULL, 0, + "Expected length of data transfer" } + }, + { &hf_iscsi_CmdSN, + { "CmdSN", "iscsi.cmdsn", + FT_UINT32, BASE_HEX, NULL, 0, + "Sequence number for this command (0 == immediate)" } + }, + { &hf_iscsi_ExpStatSN, + { "ExpStatSN", "iscsi.expstatsn", + FT_UINT32, BASE_HEX, NULL, 0, + "Next expected status sequence number" } + }, + { &hf_iscsi_SCSICommand_CDB, + { "CDB", "iscsi.scsicommand.cdb", + FT_BYTES, BASE_HEX, NULL, 0, + "SCSI CDB" } + }, + { &hf_iscsi_SCSICommand_CDB0, + { "CDB", "iscsi.scsicommand.cdb0", + FT_UINT8, BASE_HEX, VALS(iscsi_scsi_cdb0), 0, + "SCSI CDB[0]" } + }, + { &hf_iscsi_SCSIResponse_BasicResidualCount, + { "BasicResidualCount", "iscsi.scsiresponse.basicresidualcount", + FT_UINT32, BASE_HEX, NULL, 0, + "Residual count" } + }, + { &hf_iscsi_StatSN, + { "StatSN", "iscsi.statsn", + FT_UINT32, BASE_HEX, NULL, 0, + "Status sequence number" } + }, + { &hf_iscsi_ExpCmdSN, + { "ExpCmdSN", "iscsi.expcmdsn", + FT_UINT32, BASE_HEX, NULL, 0, + "Next expected command sequence number" } + }, + { &hf_iscsi_MaxCmdSN, + { "MaxCmdSN", "iscsi.maxcmdsn", + FT_UINT32, BASE_HEX, NULL, 0, + "Maximum acceptable command sequence number" } + }, + { &hf_iscsi_SCSIResponse_o03, + { "o", "iscsi.scsiresponse.o", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x08, + "Bi-directional read residual overflow" } + }, + { &hf_iscsi_SCSIResponse_u03, + { "u", "iscsi.scsiresponse.u", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x04, + "Bi-directional read residual underflow" } + }, + { &hf_iscsi_SCSIResponse_O03, + { "O", "iscsi.scsiresponse.O", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x02, + "Residual overflow" } + }, + { &hf_iscsi_SCSIResponse_U03, + { "U", "iscsi.scsiresponse.U", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x01, + "Residual underflow" } + }, + { &hf_iscsi_SCSIResponse_o, + { "o", "iscsi.scsiresponse.o", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10, + "Bi-directional read residual overflow" } + }, + { &hf_iscsi_SCSIResponse_u, + { "u", "iscsi.scsiresponse.u", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08, + "Bi-directional read residual underflow" } + }, + { &hf_iscsi_SCSIResponse_O, + { "O", "iscsi.scsiresponse.O", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04, + "Residual overflow" } + }, + { &hf_iscsi_SCSIResponse_U, + { "U", "iscsi.scsiresponse.U", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02, + "Residual underflow" } + }, + { &hf_iscsi_SCSIResponse_S, + { "S", "iscsi.scsiresponse.S", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_scsiresponse_S), 0x01, + "Status/Response" } + }, + { &hf_iscsi_CommandStatus03, + { "CommandStatus", "iscsi.commandstatus", + FT_UINT8, BASE_HEX, VALS(iscsi_scsi_statuses), 0, + "SCSI command status value" } + }, + { &hf_iscsi_StatusResponse_is_status, + { "Status/Response", "iscsi.scsiresponse.statusresponse", + FT_UINT8, BASE_HEX, VALS(iscsi_scsi_statuses), 0, + "SCSI command status value" } + }, + { &hf_iscsi_StatusResponse_is_response, + { "Status/Response", "iscsi.scsiresponse.statusresponse", + FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0, + "iSCSI response value" } + }, + { &hf_iscsi_SCSIResponse_SenseLength, + { "SenseLength", "iscsi.scsiresponse.senselength", + FT_UINT16, BASE_HEX, NULL, 0, + "SCSI sense data length" } + }, + { &hf_iscsi_SCSIResponse_BidiReadResidualCount, + { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount", + FT_UINT32, BASE_HEX, NULL, 0, + "Bi-directional read residual count" } + }, + { &hf_iscsi_SCSIData_F, + { "F", "iscsi.scsidata.f", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80, + "Final PDU" } + }, + { &hf_iscsi_SCSIData_P03, + { "P", "iscsi.scsidata.p", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_P), 0x80, + "Poll requested" } + }, + { &hf_iscsi_SCSIData_S03, + { "S", "iscsi.scsidata.s", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), 0x04, + "PDU Contains SCSI command status" } + }, + { &hf_iscsi_SCSIData_O03, + { "O", "iscsi.scsidata.O", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x02, + "Residual overflow" } + }, + { &hf_iscsi_SCSIData_U03, + { "U", "iscsi.scsidata.U", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x01, + "Residual underflow" } + }, + { &hf_iscsi_SCSIData_S, + { "S", "iscsi.scsidata.s", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), 0x01, + "PDU Contains SCSI command status" } + }, + { &hf_iscsi_SCSIData_U, + { "U", "iscsi.scsidata.U", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02, + "Residual underflow" } + }, + { &hf_iscsi_SCSIData_O, + { "O", "iscsi.scsidata.O", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04, + "Residual overflow" } + }, + { &hf_iscsi_TargetTransferTag, + { "TargetTransferTag", "iscsi.targettransfertag", + FT_UINT32, BASE_HEX, NULL, 0, + "Target transfer tag" } + }, + { &hf_iscsi_BufferOffset, + { "BufferOffset", "iscsi.bufferOffset", + FT_UINT32, BASE_HEX, NULL, 0, + "Buffer offset" } + }, + { &hf_iscsi_SCSIData_ResidualCount, + { "ResidualCount", "iscsi.scsidata.readresidualcount", + FT_UINT32, BASE_HEX, NULL, 0, + "Residual count" } + }, + { &hf_iscsi_DataSN, + { "DataSN", "iscsi.datasn", + FT_UINT32, BASE_HEX, NULL, 0, + "Data sequence number" } + }, + { &hf_iscsi_VersionMax, + { "VersionMax", "iscsi.versionmax", + FT_UINT8, BASE_HEX, NULL, 0, + "Maximum supported protocol version" } + }, + { &hf_iscsi_VersionMin, + { "VersionMin", "iscsi.versionmin", + FT_UINT8, BASE_HEX, NULL, 0, + "Minimum supported protocol version" } + }, + { &hf_iscsi_CID, + { "CID", "iscsi.cid", + FT_UINT16, BASE_HEX, NULL, 0, + "Connection identifier" } + }, + { &hf_iscsi_ISID, + { "ISID", "iscsi.isid", + FT_UINT16, BASE_HEX, NULL, 0, + "Initiator part of session identifier" } + }, + { &hf_iscsi_TSID, + { "TSID", "iscsi.tsid", + FT_UINT16, BASE_HEX, NULL, 0, + "Target part of session identifier" } + }, + { &hf_iscsi_InitStatSN, + { "InitStatSN", "iscsi.initstatsn", + FT_UINT32, BASE_HEX, NULL, 0, + "Initial status sequence number" } + }, + { &hf_iscsi_InitCmdSN, + { "InitCmdSN", "iscsi.initcmdsn", + FT_UINT32, BASE_HEX, NULL, 0, + "Initial command sequence number" } + }, + { &hf_iscsi_Login_F, + { "F", "iscsi.login.f", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80, + "Final PDU in login sequence" } + }, + { &hf_iscsi_Login_Status03, + { "Status", "iscsi.login.status", + FT_UINT8, BASE_HEX, VALS(iscsi_login_status03), 0, + "Status" } + }, + { &hf_iscsi_Login_Status, + { "Status", "iscsi.login.status", + FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0, + "Status class and detail" } + }, + { &hf_iscsi_KeyValue, + { "KeyValue", "iscsi.keyvalue", + FT_STRING, 0, NULL, 0, + "Key/value pair" } + }, + { &hf_iscsi_Text_F, + { "F", "iscsi.text.f", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80, + "Final PDU in text sequence" } + }, + { &hf_iscsi_NOP_P, + { "P", "iscsi.nop.p", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_P), 0x80, + "Poll requested" } + }, + { &hf_iscsi_ExpDataSN, + { "ExpCmdSN", "iscsi.expdatasn", + FT_UINT32, BASE_HEX, NULL, 0, + "Next expected data sequence number" } + }, + { &hf_iscsi_R2TExpDataSN, + { "R2TExpCmdSN", "iscsi.r2texpdatasn", + FT_UINT32, BASE_HEX, NULL, 0, + "Next expected R2T data sequence number" } + }, + { &hf_iscsi_SCSITask_Response, + { "Response", "iscsi.scsitask.response", + FT_UINT8, BASE_HEX, VALS(iscsi_task_responses), 0, + "Response" } + }, + { &hf_iscsi_SCSITask_ReferencedTaskTag, + { "InitiatorTaskTag", "iscsi.scsitask.referencedtasktag", + FT_UINT32, BASE_HEX, NULL, 0, + "Task's initiator task tag" } + }, + { &hf_iscsi_SCSITask_Function, + { "Function", "iscsi.scsitask.function", + FT_UINT8, BASE_HEX, VALS(iscsi_task_functions), 0x7F, + "Requested task function" } + }, + { &hf_iscsi_Logout_Reason03, + { "Reason", "iscsi.logout.reason", + FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons03), 0, + "Reason for logout" } + }, + { &hf_iscsi_Logout_Reason, + { "Reason", "iscsi.logout.reason", + FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0, + "Reason for logout" } + }, + { &hf_iscsi_Logout_Response, + { "Response", "iscsi.logout.response", + FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0, + "Logout response" } + }, + { &hf_iscsi_DesiredDataLength, + { "DesiredDataLength", "iscsi.desireddatalength", + FT_UINT32, BASE_HEX, NULL, 0, + "Desired data length (bytes)" } + }, + { &hf_iscsi_SCSIEvent03, + { "SCSIEvent", "iscsi.scsievent", + FT_UINT8, BASE_HEX, VALS(iscsi_scsievents03), 0, + "SCSI event indicator" } + }, + { &hf_iscsi_iSCSIEvent03, + { "iSCSIEvent", "iscsi.iscsievent", + FT_UINT8, BASE_HEX, VALS(iscsi_iscsievents03), 0, + "iSCSI event indicator" } + }, + { &hf_iscsi_Parameter1, + { "Parameter1", "iscsi.parameter1", + FT_UINT16, BASE_HEX, NULL, 0, + "Parameter 1" } + }, + { &hf_iscsi_Parameter2, + { "Parameter2", "iscsi.parameter2", + FT_UINT16, BASE_HEX, NULL, 0, + "Parameter 2" } + }, + { &hf_iscsi_Reject_Reason, + { "Reason", "iscsi.reject.reason", + FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0, + "Reason for command rejection" } + }, + { &hf_iscsi_Reject_FirstBadByte, + { "FirstBadByte", "iscsi.reject.firstbadbyte", + FT_UINT16, BASE_HEX, NULL, 0, + "Offset of first bad byte in PDU when reason is 'format error'" } + }, + { &hf_iscsi_Reject_Reason03, + { "Reason", "iscsi.reject.reason", + FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons03), 0, + "Reason for command rejection" } + }, + { &hf_iscsi_SNACK_S, + { "S", "iscsi.snack.s", + FT_BOOLEAN, 8, TFS(&iscsi_meaning_SNACK_S), 0x01, + "Status not data SNACK requested" } + }, + { &hf_iscsi_AddRuns, + { "AddRuns", "iscsi.snack.addruns", + FT_UINT8, BASE_HEX, NULL, 0, + "Number of additional runs" } + }, + { &hf_iscsi_BegRun, + { "BegRun", "iscsi.snack.begrun", + FT_UINT32, BASE_HEX, NULL, 0, + "First missed DataSN or StatSN" } + }, + { &hf_iscsi_RunLength, + { "RunLength", "iscsi.snack.runlength", + FT_UINT32, BASE_HEX, NULL, 0, + "Number of additional missing status PDUs in this run" } + }, + { &hf_iscsi_AdditionalRuns, + { "AdditionalRuns", "iscsi.snack.additionalruns", + FT_BYTES, BASE_HEX, NULL, 0, + "Additional runs of missing status PDUs" } + }, + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_iscsi_KeyValues, + &ett_iscsi_CDB, + }; + + /* 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 */ + proto_register_field_array(proto_iscsi, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + { + module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL); + + prefs_register_bool_preference(iscsi_module, + "version03compatible", + "Enable 03 compatibility mode", + "When enabled, assume packets conform to the legacy 03 version of the iSCSI specification", + &enable_03_mode); + prefs_register_bool_preference(iscsi_module, + "boguspdufilter", + "Enable bogus pdu filter", + "When enabled, packets that appear bogus are ignored", + &enable_bogosity_filter); + + prefs_register_uint_preference(iscsi_module, + "boguspdumaxdatalen", + "Bogus pdu max data length threshold", + "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, + "boguspdumaxdigestpadding", + "Bogus pdu max digest padding", + "Treat packets whose apparent total digest size is greater than this value as bogus", + 10, + &bogus_pdu_max_digest_padding); + } +} + + +/* 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) +{ + heur_dissector_add("tcp", dissect_iscsi, proto_iscsi); +} |