Rename samr_dissect_LOGON_HOURS() to dissect_ndr_nt_LOGON_HOURS() and
[obnox/wireshark/wip.git] / packet-iscsi.c
index fd5e1fe3253971f5993085b72767d5e234a33a30..8b5348de4a9ac600a81afdc65335da548fb1269b 100644 (file)
@@ -2,10 +2,11 @@
  * 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
+ * Conforms to the protocol described in: draft-ietf-ips-iscsi-09.txt
+ * Optionally, may be compiled for compatibility with
+ * draft-ietf-ips-iscsi-08.txt by defining DRAFT08
  *
- * $Id: packet-iscsi.c,v 1.6 2001/06/18 02:17:47 guy Exp $
+ * $Id: packet-iscsi.c,v 1.26 2002/02/13 01:17:58 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 # include "snprintf.h"
 #endif
 
-#include "packet.h"
+#include <epan/packet.h>
 #include "prefs.h"
+#include <epan/conversation.h>
+#include "packet-scsi.h"
 
-static int enable_03_mode = TRUE;
+static gboolean iscsi_desegment = TRUE;
+
+static int demand_good_f_bit = FALSE;
 static int enable_bogosity_filter = TRUE;
-static int bogus_pdu_data_length_threshold = 1024 * 1024;
-static int 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 guint iscsi_port = 3260;
 
 /* Initialize the protocol and registered fields */
 static int proto_iscsi = -1;
-static int hf_iscsi_Payload = -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;
+static int hf_iscsi_write_data = -1;
+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_Opcode_03 = -1;
 static int hf_iscsi_Flags = -1;
-#if 0
+static int hf_iscsi_HeaderDigest = -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;
-static int hf_iscsi_I = -1;
 #endif
-static int hf_iscsi_SCSICommand_X03 = -1;
+static int hf_iscsi_I = -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;
@@ -81,31 +103,19 @@ 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_SCSIResponse_ResidualCount = -1;
+static int hf_iscsi_SCSIResponse_Response = -1;
+static int hf_iscsi_SCSIResponse_Status = -1;
+static int hf_iscsi_SenseLength = -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;
@@ -115,112 +125,148 @@ 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_VersionActive = -1;
 static int hf_iscsi_CID = -1;
 static int hf_iscsi_ISID = -1;
+#ifndef DRAFT08
+static int hf_iscsi_ISIDType = -1;
+static int hf_iscsi_ISIDNamingAuthority = -1;
+static int hf_iscsi_ISIDQualifier = -1;
+#endif
 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;
+#ifndef DRAFT08
+static int hf_iscsi_Login_X = -1;
+#endif
+static int hf_iscsi_Login_T = -1;
+static int hf_iscsi_Login_CSG = -1;
+static int hf_iscsi_Login_NSG = -1;
+static int hf_iscsi_Login_Stage = -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_R2TSN = -1;
+static int hf_iscsi_TaskManagementFunction_ReferencedTaskTag = -1;
+static int hf_iscsi_RefCmdSN = -1;
+static int hf_iscsi_TaskManagementFunction_Function = -1;
+static int hf_iscsi_TaskManagementFunction_Response = -1;
 static int hf_iscsi_Logout_Reason = -1;
 static int hf_iscsi_Logout_Response = -1;
+static int hf_iscsi_Time2Wait = -1;
+static int hf_iscsi_Time2Retain = -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_AsyncEvent = -1;
+static int hf_iscsi_EventVendorCode = -1;
 static int hf_iscsi_Parameter1 = -1;
 static int hf_iscsi_Parameter2 = -1;
+static int hf_iscsi_Parameter3 = -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_snack_type = -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 gint ett_iscsi_Flags = -1;
+#ifndef DRAFT08
+static gint ett_iscsi_ISID = -1;
+#endif
 
-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},
-};
+typedef struct _iscsi_conv_key {
+    guint32 conv_idx;
+    guint32 itt;
+} iscsi_conv_key_t;
 
-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"},
+typedef struct _iscsi_conv_data {
+    guint32 iscsi_dl;
+    guint32 abs_secs;
+    guint32 abs_usecs;
+} iscsi_conv_data_t;
+
+static GHashTable *iscsi_req_hash = NULL;
+static GMemChunk *iscsi_req_keys = NULL;
+static GMemChunk *iscsi_req_vals = NULL;
+static guint32 iscsi_init_count = 25;
+
+#ifdef DRAFT08
+#define X_BIT 0x80
+#endif
+#define I_BIT 0x40
+
+#define OPCODE_MASK 0x3f
+
+#define TARGET_OPCODE_BIT 0x20
+
+#define ISCSI_OPCODE_NOP_OUT                  0x00
+#define ISCSI_OPCODE_SCSI_COMMAND             0x01
+#define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION 0x02
+#define ISCSI_OPCODE_LOGIN_COMMAND            0x03
+#define ISCSI_OPCODE_TEXT_COMMAND             0x04
+#define ISCSI_OPCODE_SCSI_DATA_OUT            0x05
+#define ISCSI_OPCODE_LOGOUT_COMMAND           0x06
+#define ISCSI_OPCODE_SNACK_REQUEST            0x10
+
+#define ISCSI_OPCODE_NOP_IN                            0x20
+#define ISCSI_OPCODE_SCSI_RESPONSE                     0x21
+#define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE 0x22
+#define ISCSI_OPCODE_LOGIN_RESPONSE                    0x23
+#define ISCSI_OPCODE_TEXT_RESPONSE                     0x24
+#define ISCSI_OPCODE_SCSI_DATA_IN                      0x25
+#define ISCSI_OPCODE_LOGOUT_RESPONSE                   0x26
+#define ISCSI_OPCODE_R2T                               0x31
+#define ISCSI_OPCODE_ASYNC_MESSAGE                     0x32
+#define ISCSI_OPCODE_REJECT                            0x3f
+
+#define CSG_SHIFT 2
+#define CSG_MASK  (0x03 << CSG_SHIFT)
+#define NSG_MASK  0x03
+
+#define ISCSI_CSG_SECURITY_NEGOTIATION    (0 << CSG_SHIFT)
+#define ISCSI_CSG_OPERATIONAL_NEGOTIATION (1 << CSG_SHIFT)
+#define ISCSI_CSG_FULL_FEATURE_PHASE      (3 << CSG_SHIFT)
+
+#define ISCSI_SCSI_DATA_FLAG_S 0x01
+#define ISCSI_SCSI_DATA_FLAG_U 0x02
+#define ISCSI_SCSI_DATA_FLAG_O 0x04
+#define ISCSI_SCSI_DATA_FLAG_F 0x80
+
+static const value_string iscsi_opcodes[] = {
+  { ISCSI_OPCODE_NOP_OUT,                           "NOP Out" },
+  { ISCSI_OPCODE_SCSI_COMMAND,                      "SCSI Command" },
+  { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION,          "Task Management Function" },
+  { ISCSI_OPCODE_LOGIN_COMMAND,                     "Login Command" },
+  { ISCSI_OPCODE_TEXT_COMMAND,                      "Text Command" },
+  { ISCSI_OPCODE_SCSI_DATA_OUT,                     "SCSI Data Out" },
+  { ISCSI_OPCODE_LOGOUT_COMMAND,                    "Logout Command" },
+  { ISCSI_OPCODE_SNACK_REQUEST,                     "SNACK Request" },
+
+  { ISCSI_OPCODE_NOP_IN,                            "NOP In" },
+  { ISCSI_OPCODE_SCSI_RESPONSE,                     "SCSI Response" },
+  { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE, "Task Management Function Response" },
+  { ISCSI_OPCODE_LOGIN_RESPONSE,                    "Login Response" },
+  { ISCSI_OPCODE_TEXT_RESPONSE,                     "Text Response" },
+  { ISCSI_OPCODE_SCSI_DATA_IN,                      "SCSI Data In" },
+  { ISCSI_OPCODE_LOGOUT_RESPONSE,                   "Logout Response" },
+  { ISCSI_OPCODE_R2T,                               "Ready To Transfer" },
+  { ISCSI_OPCODE_ASYNC_MESSAGE,                     "Asynchronous Message" },
+  { ISCSI_OPCODE_REJECT,                            "Reject"},
   {0, NULL},
 };
 
+#ifdef DRAFT08
 static const true_false_string iscsi_meaning_X = {
     "Retry",
     "Not retry"
 };
+#else
+static const true_false_string iscsi_meaning_login_X = {
+    "Reinstate failed connection",
+    "New connection"
+};
+#endif
 
 static const true_false_string iscsi_meaning_I = {
     "Immediate delivery",
@@ -232,9 +278,9 @@ static const true_false_string iscsi_meaning_F = {
     "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_T = {
+    "Transit to next login stage",
+    "Stay in current login stage"
 };
 
 static const true_false_string iscsi_meaning_S = {
@@ -272,14 +318,10 @@ static const true_false_string iscsi_meaning_U = {
     "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_scsi_responses[] = {
+    { 0, "Command completed at target" },
+    { 1, "Response does not contain SCSI status"},
+    { 0, NULL }
 };
 
 static const value_string iscsi_scsicommand_taskattrs[] = {
@@ -291,105 +333,19 @@ static const value_string iscsi_scsicommand_taskattrs[] = {
     {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[] = {
+static const value_string iscsi_task_management_responses[] = {
     {0, "Function complete"},
     {1, "Task not in task set"},
     {2, "LUN does not exist"},
+    {3, "Task still allegiant"},
+    {4, "Task failover not supported"},
+    {5, "Task management function not supported"},
+    {6, "Authorisation failed"},
     {255, "Function rejected"},
     {0, NULL},
 };
 
-static const value_string iscsi_task_functions[] = {
+static const value_string iscsi_task_management_functions[] = {
     {1, "Abort Task"},
     {2, "Abort Task Set"},
     {3, "Clear ACA"},
@@ -400,187 +356,470 @@ static const value_string iscsi_task_functions[] = {
     {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"},
+static const value_string iscsi_login_status[] = {
+    {0x0000, "Success"},
+    {0x0101, "Target moved temporarily"},
+    {0x0102, "Target moved permanently"},
+    {0x0200, "Initiator error (miscellaneous error)"},
+    {0x0201, "Athentication failed"},
+    {0x0202, "Authorisation failure"},
+    {0x0203, "Target not found"},
+    {0x0204, "Target removed"},
+    {0x0205, "Unsupported version"},
+    {0x0206, "Too many connections"},
+    {0x0207, "Missing parameter"},
+    {0x0208, "Can't include in session"},
+    {0x0209, "Session type not supported"},
+    {0x0300, "Target error (miscellaneous error)"},
+    {0x0301, "Service unavailable"},
+    {0x0302, "Out of resources"},
     {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"},
+static const value_string iscsi_login_stage[] = {
+    {0, "Security negotiation"},
+    {1, "Operational negotiation"},
+    {3, "Full feature phase"},
     {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"},
+#ifndef DRAFT08
+static const value_string iscsi_isid_type[] = {
+    {0x00, "IEEE OUI"},
+    {0x01, "IANA Enterprise Number"},
+    {0x02, "Random"},
     {0, NULL},
 };
+#endif
 
 static const value_string iscsi_logout_reasons[] = {
-    {0, "Session is closing"},
-    {1, "Close connections"},
+    {0, "Close session"},
+    {1, "Close connection"},
     {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"},
+    {1, "CID not found"},
+    {2, "Connection recovery not supported"},
+    {3, "Cleanup failed for various reasons"},
     {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"},
+static const value_string iscsi_asyncevents[] = {
+    {0, "A SCSI asynchronous event is reported in the sense data"},
+    {1, "Target requests logout"},
+    {2, "Target will/has dropped connection"},
+    {3, "Target will/has dropped all connections"},
     {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_snack_types[] = {
+    {0, "Data/R2T"},
+    {1, "Status"},
+    {0, NULL}
 };
 
-static const value_string iscsi_reject_reasons03[] = {
-    {1, "Format error"},
-    {2, "Header digest error"},
-    {3, "Payload digest error"},
+static const value_string iscsi_reject_reasons[] = {
+    {0x01, "Full feature phase command before login"},
+    {0x02, "Data (payload) digest error"},
+    {0x03, "Data SNACK reject"},
+    {0x04, "Protocol error"},
+    {0x05, "Command not supported in this session type"},
+    {0x06, "Immediate command reject (too many immediate commands)"},
+    {0x07, "Task in progress"},
+    {0x08, "Invalid SNACK"},
+    {0x09, "Bookmark reject (no bookmark for this initiator task tag)"},
+    {0x0a, "Bookmark reject (can't generate bookmark - out of resources)"},
+    {0x0b, "Negotiation reset"},
     {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},
+/*****************************************************************/
+/*                                                               */
+/* CRC LOOKUP TABLE                                              */
+/* ================                                              */
+/* The following CRC lookup table was generated automagically    */
+/* by the Rocksoft^tm Model CRC Algorithm Table Generation       */
+/* Program V1.0 using the following model parameters:            */
+/*                                                               */
+/*    Width   : 4 bytes.                                         */
+/*    Poly    : 0x1EDC6F41L                                      */
+/*    Reverse : TRUE.                                            */
+/*                                                               */
+/* For more information on the Rocksoft^tm Model CRC Algorithm,  */
+/* see the document titled "A Painless Guide to CRC Error        */
+/* Detection Algorithms" by Ross Williams                        */
+/* (ross@guest.adelaide.edu.au.). This document is likely to be  */
+/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".        */
+/*                                                               */
+/*****************************************************************/
+
+static guint32 crc32Table[256] = {
+    0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
+    0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
+    0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
+    0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
+    0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
+    0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
+    0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
+    0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
+    0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
+    0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
+    0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
+    0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
+    0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
+    0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
+    0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
+    0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
+    0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
+    0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
+    0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
+    0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
+    0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
+    0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
+    0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
+    0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
+    0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
+    0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
+    0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
+    0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
+    0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
+    0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
+    0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
+    0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
+    0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
+    0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
+    0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
+    0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
+    0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
+    0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
+    0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
+    0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
+    0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
+    0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
+    0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
+    0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
+    0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
+    0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
+    0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
+    0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
+    0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
+    0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
+    0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
+    0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
+    0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
+    0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
+    0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
+    0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
+    0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
+    0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
+    0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
+    0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
+    0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
+    0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
+    0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
+    0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
 };
 
-static int iscsi_min(int a, int b) {
+#define CRC32C_PRELOAD 0xffffffff
+
+static guint32
+calculateCRC32(const void *buf, int len, guint32 crc) {
+    guint8 *p = (guint8 *)buf;
+    while(len-- > 0)
+        crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+    return crc;
+}
+
+/*
+ * Hash Functions
+ */
+static gint
+iscsi_equal(gconstpointer v, gconstpointer w)
+{
+  iscsi_conv_key_t *v1 = (iscsi_conv_key_t *)v;
+  iscsi_conv_key_t *v2 = (iscsi_conv_key_t *)w;
+
+  return (v1->conv_idx == v2->conv_idx);
+}
+
+static guint
+iscsi_hash (gconstpointer v)
+{
+       iscsi_conv_key_t *key = (iscsi_conv_key_t *)v;
+       guint val;
+
+       val = key->conv_idx;
+
+       return val;
+}
+
+/*
+ * Protocol initialization
+ */
+static void
+iscsi_init_protocol(void)
+{
+    if (iscsi_req_keys)
+        g_mem_chunk_destroy(iscsi_req_keys);
+    if (iscsi_req_vals)
+        g_mem_chunk_destroy(iscsi_req_vals);
+    if (iscsi_req_hash)
+        g_hash_table_destroy(iscsi_req_hash);
+
+    iscsi_req_hash = g_hash_table_new(iscsi_hash, iscsi_equal);
+    iscsi_req_keys = g_mem_chunk_new("iscsi_req_keys",
+                                   sizeof(iscsi_conv_key_t),
+                                   iscsi_init_count * sizeof(iscsi_conv_key_t),
+                                   G_ALLOC_AND_FREE);
+    iscsi_req_vals = g_mem_chunk_new("iscsi_req_vals",
+                                   sizeof(iscsi_conv_data_t),
+                                   iscsi_init_count * sizeof(iscsi_conv_data_t),
+                                   G_ALLOC_AND_FREE);
+}
+
+static int
+iscsi_min(int a, int b) {
     return (a < b)? a : b;
 }
 
-static gint addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
+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)
+       gint len = tvb_strnlen(tvb, offset, limit - offset);
+       if(len == -1)
            len = limit - offset;
-       proto_tree_add_string_format(tt, hf_iscsi_KeyValue, tvb, offset, len, p, "%s", p);
+       else
+           len = len + 1;
+       proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, FALSE);
        offset += len;
     }
     return offset;
 }
 
-/* Code to actually dissect the packets */
-static gboolean
-dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
+static gint
+handleHeaderDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
+    int available_bytes = tvb_length_remaining(tvb, offset);
+    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, should be 0x%08x)", sent, crc);
+               }
+           }
+           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;
+}
 
-    /* Set up structures needed to add the protocol subtree and manage it */
-    proto_item *ti;
-    guint32 data_segment_len;
-    guint8 opcode;
-    guint offset = 0;
-    guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
-    const char *opcode_str = NULL;
-    char *scsi_command_name = NULL;
-    guint32 packet_len = tvb_length_remaining(tvb, offset);
+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, should be 0x%08x)", sent, crc);
+               }
+           }
+           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 offset + dataLen;
+}
 
-    /* quick check to see if the packet is long enough to contain a
-     * whole iSCSI header segment */
-    if (packet_len < 48) {
-       /* no, so give up */
-       return FALSE;
+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);
     }
 
-    opcode = tvb_get_guint8(tvb, offset + 0);
+    return offset;
+}
 
-    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;
+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;
+}
 
-    /* try and distinguish between data and real headers */
-    if(opcode_str == NULL ||
-       (enable_bogosity_filter &&
-       (data_segment_len > bogus_pdu_data_length_threshold ||
-        packet_len > (data_segment_len + 48 + bogus_pdu_max_digest_padding)))) {
-       return FALSE;
-    }
+/* 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 = NULL;
+    char *scsi_command_name = NULL;
+    guint8 scsi_status = 0;
+    guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
+    guint end_offset = offset + tvb_length_remaining(tvb, offset);
+    guint32 del_usecs = 0;
+    conversation_t *conversation = NULL;
+    iscsi_conv_data_t *cdata = NULL;
+    iscsi_conv_key_t ckey, *req_key;
+    scsi_task_id_t task_key;
+    int paddedDataSegmentLength = data_segment_len;
+    if(paddedDataSegmentLength & 3)
+       paddedDataSegmentLength += 4 - (paddedDataSegmentLength & 3);
 
     /* 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->cinfo, COL_PROTOCOL))
+       col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
 
-    if (check_col(pinfo->fd, COL_INFO)) {
+    if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
+       opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
+        scsi_status = tvb_get_guint8 (tvb, offset+3);
+    }
 
-       col_add_str(pinfo->fd, COL_INFO, (char *)opcode_str);
+    if ((opcode == ISCSI_OPCODE_SCSI_RESPONSE) ||
+        (opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
+        (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
+        conversation = find_conversation (&pinfo->src, &pinfo->dst,
+                                          pinfo->ptype, pinfo->srcport,
+                                          pinfo->destport, 0);
+        if (conversation) {
+            ckey.conv_idx = conversation->index;
+            ckey.itt = tvb_get_ntohl (tvb, offset+16);
+            
+            cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_hash,
+                                                              &ckey);
+
+            task_key.conv_id = ckey.conv_idx;
+            task_key.task_id = ckey.itt;
+            pinfo->private_data = &task_key;
+        } else {
+            /* no conversation, meaning we didn't see the request */
+            pinfo->private_data = NULL;
+        }
+        
+        if (cdata) {
+            del_usecs = (pinfo->fd->abs_secs - cdata->abs_secs)* 1000000 +
+                (pinfo->fd->abs_usecs - cdata->abs_usecs);
+        }
+    }
+    else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
+        conversation = find_conversation (&pinfo->src, &pinfo->dst,
+                                          pinfo->ptype, pinfo->srcport,
+                                          pinfo->destport, 0);
+        if (!conversation) {
+            conversation = conversation_new (&pinfo->src, &pinfo->dst,
+                                             pinfo->ptype, pinfo->srcport,
+                                             pinfo->destport, 0);
+        }
+        
+        ckey.conv_idx = conversation->index;
+        ckey.itt = tvb_get_ntohl (tvb, offset+16);
+        
+        cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_hash,
+                                                          &ckey);
+        if (cdata) {
+            /* Since we never free the memory used by an exchange, this maybe a
+             * case of another request using the same exchange as a previous
+             * req. 
+             */
+            cdata->abs_usecs = pinfo->fd->abs_usecs;
+            cdata->abs_secs = pinfo->fd->abs_secs;
+        }
+        else {
+            req_key = g_mem_chunk_alloc (iscsi_req_keys);
+            req_key->conv_idx = conversation->index;
+            req_key->itt = tvb_get_ntohl (tvb, offset+16);
+            
+            cdata = g_mem_chunk_alloc (iscsi_req_vals);
+            cdata->abs_usecs = pinfo->fd->abs_usecs;
+            cdata->abs_secs = pinfo->fd->abs_secs;
+            
+            g_hash_table_insert (iscsi_req_hash, req_key, cdata);
+        }
+
+        /* The SCSI protocol uses this as the key to detect a
+         * SCSI-level conversation. */
+        task_key.conv_id = ckey.conv_idx;
+        task_key.task_id = ckey.itt;
+        pinfo->private_data = &task_key;
+    }
+    else {
+        pinfo->private_data = NULL;
+    }
+    
+    if (check_col(pinfo->cinfo, COL_INFO)) {
 
-       if((opcode & 0xbf) == 0x01) {
-           /* SCSI Command */
-           guint8 cdb0 = tvb_get_guint8(tvb, cdb_offset);
-           scsi_command_name = match_strval(cdb0, iscsi_scsi_cdb0);
-           if(cdb0 == 0x08 || cdb0 == 0x0a) {
-               /* READ_6 and WRITE_6 */
-               guint lba = tvb_get_ntohl(tvb, cdb_offset) & 0x1fffff;
-               guint len = tvb_get_guint8(tvb, cdb_offset + 4);
-               col_append_fstr(pinfo->fd, COL_INFO, " (%s LBA 0x%06x len 0x%02x)", scsi_command_name, lba, len);
+        if (opcode != ISCSI_OPCODE_SCSI_COMMAND) {
+
+            col_append_str(pinfo->cinfo, COL_INFO, (char *)opcode_str);
+
+           if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
+               (opcode == ISCSI_OPCODE_SCSI_DATA_IN &&
+                (tvb_get_guint8(tvb, offset + 1) & ISCSI_SCSI_DATA_FLAG_S))) {
+               col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
+                                val_to_str (scsi_status, scsi_status_val, "0x%x"));
            }
-           else if(cdb0 == 0x28 || cdb0 == 0x2a) {
-               /* READ_10 and WRITE_10 */
-               guint lba = tvb_get_ntohl(tvb, cdb_offset + 2);
-               guint len = tvb_get_ntohs(tvb, cdb_offset + 7);
-               col_append_fstr(pinfo->fd, COL_INFO, " (%s LBA 0x%08x len 0x%04x)", scsi_command_name, lba, len);
+           else if (opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
+               if(end_offset > (offset + 38)) {
+                   guint16 login_status = tvb_get_ntohs(tvb, offset+36);
+                   col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
+                                    val_to_str (login_status, iscsi_login_status, "0x%x"));
+               }
+           }
+           else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
+               guint8 tmf = tvb_get_guint8(tvb, offset + 1);
+               col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
+                                val_to_str (tmf, iscsi_task_management_functions, "0x%x"));
+           }
+           else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
+               guint8 resp = tvb_get_guint8(tvb, offset + 2);
+               col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
+                                val_to_str (resp, iscsi_task_management_responses, "0x%x"));
            }
-           else if(scsi_command_name != NULL)
-               col_append_fstr(pinfo->fd, COL_INFO, " (%s)", scsi_command_name);
-       }
-       else if(enable_03_mode && opcode == 0x81) {
-           /* SCSI Command Response */
-           const char *blurb = match_strval(tvb_get_guint8(tvb, offset + 36), iscsi_scsi_statuses);
-           if(blurb != NULL)
-               col_append_fstr(pinfo->fd, COL_INFO, " (%s)", blurb);
-       }
-       else if(!enable_03_mode && opcode == 0xc1) {
-           /* SCSI Command Response */
-           const char *blurb = NULL;
-           if(tvb_get_guint8(tvb, offset + 1) & 0x01)
-               blurb = match_strval(tvb_get_guint8(tvb, offset + 3), iscsi_scsi_statuses);
-           else
-               blurb = match_strval(tvb_get_guint8(tvb, offset + 3), iscsi_scsi_responses);
-           if(blurb != NULL)
-               col_append_fstr(pinfo->fd, COL_INFO, " (%s)", blurb);
        }
     }
 
@@ -589,419 +828,268 @@ dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
     if (tree) {
 
        /* create display subtree for the protocol */
-       ti = proto_tree_add_protocol_format(tree, proto_iscsi, tvb, offset,
-                                packet_len, "iSCSI (%s)", (char *)opcode_str);
+       ti = proto_tree_add_protocol_format(tree, proto_iscsi, tvb,
+                                           offset, -1, "iSCSI (%s)",
+                                           (char *)opcode_str);
+
+       proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
+                           offset + 0, 1, opcode);
+       if((opcode & TARGET_OPCODE_BIT) == 0) {
+           /* initiator -> target */
+           gint b = tvb_get_guint8(tvb, offset + 0);
+#ifdef DRAFT08
+           if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
+              opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
+              opcode != ISCSI_OPCODE_SNACK_REQUEST)
+               proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
+#endif
+           if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
+              opcode != ISCSI_OPCODE_LOGIN_COMMAND)
+               proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
+       }
 
-       if((enable_03_mode && opcode == 0x00) ||
-          (!enable_03_mode && (opcode == 0x00 ||
-                               opcode == 0x40 ||
-                               opcode == 0x80))) {
+       if(opcode == ISCSI_OPCODE_NOP_OUT) {
            /* NOP Out */
-           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);
-           }
-           {
-               gint b = tvb_get_guint8(tvb, offset + 1);
-               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);
-               proto_tree_add_boolean(tt, 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;
+           proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+           proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
+           offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
        }
-       else if((enable_03_mode && opcode == 0x80) ||
-               (!enable_03_mode && opcode == 0xc0)) {
+       else if(opcode == ISCSI_OPCODE_NOP_IN) {
            /* NOP In */
-           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_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+           proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
+           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 = 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);
                proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
-               proto_tree_add_boolean(tt, 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 */
-           if(enable_03_mode) {
-               proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, 
-                                   offset + 0, 1, opcode);
-               {
-                   gint b = tvb_get_guint8(tvb, offset + 1);
-                   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);
-
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_X03, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
-                   proto_tree_add_uint(tt, 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);
-               {
-                   gint b = tvb_get_guint8(tvb, offset + 1);
-                   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);
-
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
-                   proto_tree_add_uint(tt, 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));
+               
+               proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
+               proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
+               proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
+               proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
+           }
+           proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
+           proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+           proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, 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);
            {
-               /* dissect a little of the CDB for the most common
-                * commands */
-               guint8 cdb0 = tvb_get_guint8(tvb, cdb_offset);
-               gint cdb_len = 16;
-               proto_item *tf;
-               if(enable_03_mode) {
-                   cdb_len += tvb_get_guint8(tvb, offset + 3) * 4;
-               }
-               else {
-                   /* FIXME - extended CDB */
-               }
-               if(scsi_command_name == NULL)
-                   scsi_command_name = match_strval(cdb0, iscsi_scsi_cdb0);
-               if(cdb0 == 0x08 || cdb0 == 0x0a) {
-                   /* READ_6 and WRITE_6 */
-                   guint lba = tvb_get_ntohl(tvb, cdb_offset) & 0x1fffff;
-                   guint len = tvb_get_guint8(tvb, cdb_offset + 4);
-                   tf = proto_tree_add_uint_format(ti, hf_iscsi_SCSICommand_CDB0, tvb, cdb_offset, cdb_len, cdb0, "CDB: %s LBA 0x%06x len 0x%02x", scsi_command_name, lba, len);
+               if(ahsLen > 0) {
+                   /* FIXME - disssect AHS? */
+                   proto_tree_add_item(ti, hf_iscsi_AHS, tvb, offset + 48, ahsLen, FALSE);
                }
-               else if(cdb0 == 0x28 || cdb0 == 0x2a) {
-                   /* READ_10 and WRITE_10 */
-                   guint lba = tvb_get_ntohl(tvb, cdb_offset + 2);
-                   guint len = tvb_get_ntohs(tvb, cdb_offset + 7);
-                   tf = proto_tree_add_uint_format(ti, hf_iscsi_SCSICommand_CDB0, tvb, cdb_offset, cdb_len, cdb0, "CDB: %s LBA 0x%08x len 0x%04x", scsi_command_name, lba, len);
-               }
-               else
-                   tf = proto_tree_add_uint(ti, hf_iscsi_SCSICommand_CDB0, tvb, cdb_offset, cdb_len, cdb0);
-               {
-                   proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_CDB);
-                   proto_tree_add_bytes(tt, hf_iscsi_SCSICommand_CDB, tvb, cdb_offset, cdb_len, tvb_get_ptr(tvb, cdb_offset, cdb_len));
-               }
-               offset = cdb_offset + cdb_len;
+               offset = handleHeaderDigest(ti, tvb, offset, 48 + ahsLen);
            }
+           offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
        }
-       else if((enable_03_mode && opcode == 0x81) ||
-               (!enable_03_mode && opcode == 0xc1)) {
+       else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
            /* SCSI Response */
-           if(enable_03_mode) {
-               proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, 
-                                   offset + 0, 1, opcode);
-               {
-                   gint b = tvb_get_guint8(tvb, offset + 1);
-                   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);
-
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o03, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u03, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O03, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, 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);
-               {
-                   gint b = tvb_get_guint8(tvb, offset + 1);
-                   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);
-
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, 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;
+            if (del_usecs) {
+                if (del_usecs > 1000)
+                    proto_tree_add_text (ti, tvb, offset, 0,
+                                         "Cmd Response Time: %d msecs",
+                                         del_usecs/1000);
+                else
+                    proto_tree_add_text (ti, tvb, offset, 0,
+                                         "Cmd Response Time: %d usecs",
+                                         del_usecs);
+            }
+           {
+               gint b = tvb_get_guint8(tvb, offset + 1);
+               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);
+               
+               proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
+               proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
+               proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
+               proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
+           }
+           proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Response, tvb, offset + 2, 1, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
+           proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 20, 4, FALSE);
+           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);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
+           /* do not update offset here because the data segment is
+            * dissected below */
+           handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
        }
-       else if((enable_03_mode && opcode == 0x02) ||
-               (!enable_03_mode && (opcode == 0x02 ||
-                                    opcode == 0x42 ||
-                                    opcode == 0x82))) {
-           /* SCSI Task 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_uint(ti, hf_iscsi_SCSITask_Function, tvb, offset + 1, 1, tvb_get_guint8(tvb, offset + 1));
-           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(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
+           /* Task Management Function */
+           proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, 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);
+           proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
+           offset = handleHeaderDigest(ti, tvb, 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(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
+           /* Task Management Function Response */
+           proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Response, tvb, offset + 2, 1, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
        }
-       else if((enable_03_mode && opcode == 0x03) ||
-               (!enable_03_mode && (opcode == 0x03 ||
-                                    opcode == 0x83))) {
+       else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
            /* 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);
-               {
-                   gint b = tvb_get_guint8(tvb, offset + 1);
-                   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);
-
-                   proto_tree_add_boolean(tt, 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_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(packet_len > 48) {
-               int text_len = iscsi_min(data_segment_len, packet_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);
+           int digestsActive = 0;
+           {
+               gint b = tvb_get_guint8(tvb, offset + 1);
+#ifdef DRAFT08
+               if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
+                   digestsActive = 1;
+#endif
+#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);
+#endif
+               
+               proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
+#ifndef DRAFT08
+               proto_tree_add_boolean(ti, hf_iscsi_Login_X, tvb, offset + 1, 1, b);
+#endif
+               proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
+               proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
+           }
+           proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
+           proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+#ifdef DRAFT08
+           proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
+#else
+           {
+               proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
+               proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
+               proto_tree_add_item(tt, hf_iscsi_ISIDType, tvb, offset + 8, 1, FALSE);
+               proto_tree_add_item(tt, hf_iscsi_ISIDNamingAuthority, tvb, offset + 9, 3, FALSE);
+               proto_tree_add_item(tt, hf_iscsi_ISIDQualifier, tvb, offset + 12, 2, FALSE);
            }
+#endif
+           proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+#ifndef DRAFT08
+           proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
+#endif
+           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);
+           if(digestsActive)
+               offset = handleHeaderDigest(ti, tvb, offset, 48);
+           else
+               offset += 48;
+           offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
        }
-       else if((enable_03_mode && opcode == 0x83) ||
-               (!enable_03_mode && opcode == 0xc3)) {
+       else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
            /* Login Response */
-           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);
-           }
+           int digestsActive = 0;
            {
                gint b = tvb_get_guint8(tvb, offset + 1);
+#ifdef DRAFT08
+               if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
+                   digestsActive = 1;
+#endif
+#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);
-
-               proto_tree_add_boolean(tt, 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(packet_len > 48) {
-               int text_len = iscsi_min(data_segment_len, packet_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);
+#endif
+               
+               proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
+               proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
+               proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
+           }
+
+           proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_VersionActive, tvb, offset + 3, 1, FALSE);
+           proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+#ifdef DRAFT08
+           proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
+#else
+           {
+               proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
+               proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
+               proto_tree_add_item(tt, hf_iscsi_ISIDType, tvb, offset + 8, 1, FALSE);
+               proto_tree_add_item(tt, hf_iscsi_ISIDNamingAuthority, tvb, offset + 9, 3, FALSE);
+               proto_tree_add_item(tt, hf_iscsi_ISIDQualifier, tvb, offset + 12, 2, FALSE);
            }
+#endif
+           proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           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);
+           proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, FALSE);
+           if(digestsActive)
+               offset = handleHeaderDigest(ti, tvb, offset, 48);
+           else
+               offset += 48;
+           offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
        }
-       else if((enable_03_mode && opcode == 0x04) ||
-               (!enable_03_mode && (opcode == 0x04 ||
-                                    opcode == 0x44 ||
-                                    opcode == 0x84))) {
+       else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
            /* 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);
-               {
-                   gint b = tvb_get_guint8(tvb, offset + 1);
-                   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);
-
-                   proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
-               }
+           {
+               gint b = tvb_get_guint8(tvb, offset + 1);
+               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);
+               
+               proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
                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(packet_len > 48) {
-               int text_len = iscsi_min(data_segment_len, packet_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);
-           }
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
+           offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
        }
-       else if((enable_03_mode && opcode == 0x84) ||
-               (!enable_03_mode && (opcode == 0xc4))) {
+       else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
            /* 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);
-               {
-                   gint b = tvb_get_guint8(tvb, offset + 1);
-                   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);
-
-                   proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
-               }
+           {
+               gint b = tvb_get_guint8(tvb, offset + 1);
+               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);
+               
+               proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
                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(packet_len > 48) {
-               int text_len = iscsi_min(data_segment_len, packet_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);
-           }
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
+           offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
        }
-       else if(opcode == 0x05) {
-           /* SCSI Data (write) */
-           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);
-           }
+       else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
+           /* SCSI Data Out (write) */
            {
                gint b = tvb_get_guint8(tvb, offset + 1);
                proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
@@ -1009,279 +1097,417 @@ dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 
                proto_tree_add_boolean(tt, 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;
+           proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+           proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
+           /* do not update offset here because the data segment is
+            * dissected below */
+           handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
        }
-       else if((enable_03_mode && opcode == 0x85) ||
-               (!enable_03_mode && opcode == 0xc5)) {
-           /* SCSI Data (read) */
-           if(enable_03_mode) {
-               proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, 
-                                   offset + 0, 1, opcode);
-               {
-                   gint b = tvb_get_guint8(tvb, offset + 1);
-                   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);
-
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIData_P03, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S03, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O03, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, 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);
-               {
-                   gint b = tvb_get_guint8(tvb, offset + 1);
-                   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);
-
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
-                   proto_tree_add_boolean(tt, 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(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
+           /* SCSI Data In (read) */
+           {
+               gint b = tvb_get_guint8(tvb, offset + 1);
+               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);
+
+               proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
+               proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
+               proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
+               proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
+           }
+           proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
+           proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 20, 4, FALSE);
+           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);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
+           /* do not update offset here because the data segment is
+            * dissected below */
+           handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
        }
-       else if((enable_03_mode && opcode == 0x06) ||
-               (!enable_03_mode && (opcode == 0x06 || opcode == 0x46))) {
+       else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
            /* 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;
+           proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
+           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_CmdSN, tvb, offset + 24, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
+           offset = handleHeaderDigest(ti, tvb, offset, 48);
        }
-       else if((enable_03_mode && opcode == 0x86) ||
-               (!enable_03_mode && opcode == 0xc6)) {
+       else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
            /* 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;
+           proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           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);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
        }
-       else if((!enable_03_mode && (opcode == 0x10 || opcode == 0x50))) {
-           int S = 0;
+       else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
            /* SNACK Request */
-           proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
-                               offset + 0, 1, opcode);
            {
                gint b = tvb_get_guint8(tvb, offset + 1);
+#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);
+#endif
 
-               proto_tree_add_boolean(tt, hf_iscsi_SNACK_S, tvb, offset + 1, 1, b);
-               S = b & 0x01;
-           }
-           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(S) {
-               proto_tree_add_uint(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, tvb_get_ntohl(tvb, offset + 28));
+               proto_tree_add_item(ti, hf_iscsi_snack_type, tvb, offset + 1, 1, b);
            }
-           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;
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, FALSE);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
        }
-       else if((enable_03_mode && opcode == 0x90) ||
-               (!enable_03_mode && opcode == 0xd0)) {
+       else if(opcode == ISCSI_OPCODE_R2T) {
            /* 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;
+           proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
+           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);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
        }
-       else if((enable_03_mode && opcode == 0x91) || 
-               (!enable_03_mode && opcode == 0xd1)) {
+       else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
            /* 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;
+           proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+           proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
+           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);
+           proto_tree_add_item(ti, hf_iscsi_AsyncEvent, tvb, offset + 36, 1, FALSE);
+           proto_tree_add_item(ti, hf_iscsi_EventVendorCode, tvb, offset + 37, 1, FALSE);
+           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 = handleHeaderDigest(ti, tvb, offset, 48);
        }
-       else if(opcode == 0xef) {
+       else if(opcode == ISCSI_OPCODE_REJECT) {
            /* 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));
+           proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
+           proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
+           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);
+           proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
+           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);
+    }
+#ifdef DRAFT08
+    if((opcode & ~(X_BIT | I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND)
+#else
+    if((opcode & ~I_BIT) == ISCSI_OPCODE_SCSI_COMMAND)
+#endif
+    {
+        /* SCSI Command */
+        dissect_scsi_cdb (tvb, pinfo, tree, cdb_offset, 16);
+    }
+    else if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
+        if (scsi_status == 0x2) {
+            /* A SCSI response with Check Condition contains sense data */
+            /* offset is setup correctly by the iscsi code for response above */
+           if((end_offset - offset) >= 2) {
+               int senseLen = tvb_get_ntohs(tvb, offset);
+               if(ti != NULL)
+                   proto_tree_add_item(ti, hf_iscsi_SenseLength, tvb, offset, 2, FALSE);
+               offset += 2;
+               if(senseLen > 0)
+                   dissect_scsi_snsinfo (tvb, pinfo, tree, offset,
+                                         iscsi_min (senseLen,
+                                                    end_offset-offset));
+           }
+        }
+        else {
+            dissect_scsi_rsp (tvb, pinfo, tree);
+        }
+        if (cdata && tree) {
+            /* destroy the data structures for this SCSI task */
+#if 0            
+            g_mem_chunk_free (iscsi_req_vals, cdata);
+            g_hash_table_remove (iscsi_req_hash, &ckey);
+            pinfo->private_data = NULL;
+#endif             
+        }
+    }
+    else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
+             (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
+        /* offset is setup correctly by the iscsi code for response above */ 
+        dissect_scsi_payload (tvb, pinfo, tree, offset, FALSE,
+                              iscsi_min (data_segment_len, end_offset-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);
+
+    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;
+    }
+
+    /* 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;
+
+       /* mask out any extra bits in the opcode byte */
+       opcode &= OPCODE_MASK;
+
+       opcode_str = match_strval(opcode, iscsi_opcodes);
+       if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION ||
+          opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_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(demand_good_f_bit &&
+                   !(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_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
+                    opcode == ISCSI_OPCODE_R2T ||
+                    opcode == ISCSI_OPCODE_ASYNC_MESSAGE ||
+                    opcode == ISCSI_OPCODE_SNACK_REQUEST ||
+                    opcode == ISCSI_OPCODE_REJECT)) {
+               badPdu = TRUE;
            }
-           offset += 48;
        }
 
-       if(packet_len > offset)
-           proto_tree_add_bytes(ti, hf_iscsi_Payload, tvb, offset, packet_len - offset, tvb_get_ptr(tvb, offset, packet_len - offset));
+       if(badPdu) {
+           return iSCSIPdusDissected > 0;
+       }
+       else {
+           guint32 pduLen = 48;
+           int digestsActive = 1;
+
+           if(opcode == ISCSI_OPCODE_LOGIN_COMMAND ||
+              opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
+#ifdef DRAFT08
+               if((secondPduByte & CSG_MASK) < ISCSI_CSG_OPERATIONAL_NEGOTIATION) {
+                   /* digests are not yet turned on */
+                   digestsActive = 0;
+               }
+#else
+               digestsActive = 0;
+#endif
+           }
+
+           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;
+               }
+           }
+
+           if(check_col(pinfo->cinfo, COL_INFO)) {
+               if(iSCSIPdusDissected == 0)
+                   col_set_str(pinfo->cinfo, COL_INFO, "");
+               else
+                   col_append_str(pinfo->cinfo, COL_INFO, ", ");
+           }
+
+           dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len);
+           if(pduLen > available_bytes)
+               pduLen = available_bytes;
+           offset += pduLen;
+           available_bytes -= pduLen;
+           ++iSCSIPdusDissected;
+       }
     }
 
-    return TRUE;
+    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_Payload,
-         { "Payload", "iscsi.payload",
+       { &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,
+           "Padding to 4 byte boundary", HFILL }
+       },
+       { &hf_iscsi_ping_data,
+         { "PingData", "iscsi.pingdata",
+           FT_BYTES, BASE_HEX, NULL, 0,
+           "Ping Data", HFILL }
+       },
+       { &hf_iscsi_immediate_data,
+         { "ImmediateData", "iscsi.immediatedata",
+           FT_BYTES, BASE_HEX, NULL, 0,
+           "Immediate Data", HFILL }
+       },
+       { &hf_iscsi_write_data,
+         { "WriteData", "iscsi.writedata",
+           FT_BYTES, BASE_HEX, NULL, 0,
+           "Write Data", HFILL }
+       },
+       { &hf_iscsi_read_data,
+         { "ReadData", "iscsi.readdata",
+           FT_BYTES, BASE_HEX, NULL, 0,
+           "Read Data", HFILL }
+       },
+       { &hf_iscsi_error_pdu_data,
+         { "ErrorPDUData", "iscsi.errorpdudata",
+           FT_BYTES, BASE_HEX, NULL, 0,
+           "Error PDU Data", HFILL }
+       },
+       { &hf_iscsi_HeaderDigest,
+         { "HeaderDigest", "iscsi.headerdigest",
            FT_BYTES, BASE_HEX, NULL, 0,
-           "Payload (includes any header digest)", HFILL }
+           "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,          
            "Opcode", HFILL }
        },
-       { &hf_iscsi_Opcode_03,
-         { "Opcode", "iscsi.opcode",
-           FT_UINT8, BASE_HEX, VALS(iscsi_opcodes_03), 0,          
-           "Opcode", HFILL }
-       },
-#if 0
+#ifdef DRAFT08
        { &hf_iscsi_X,
-         { "X", "iscsi.x",
+         { "X", "iscsi.X",
            FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,          
            "Command Retry", HFILL }
        },
+#endif
        { &hf_iscsi_I,
-         { "I", "iscsi.i",
+         { "I", "iscsi.I",
            FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,          
            "Immediate delivery", HFILL }
        },
-#endif
        { &hf_iscsi_Flags,
          { "Flags", "iscsi.flags",
            FT_UINT8, BASE_HEX, NULL, 0,          
            "Opcode specific flags", HFILL }
        },
-       { &hf_iscsi_SCSICommand_X03,
-         { "X", "iscsi.scsicommand.x",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,          
-           "Command Retry", HFILL }
-       },
        { &hf_iscsi_SCSICommand_F,
-         { "F", "iscsi.scsicommand.f",
+         { "F", "iscsi.scsicommand.F",
            FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,          
            "PDU completes command", HFILL }
        },
        { &hf_iscsi_SCSICommand_R,
-         { "R", "iscsi.scsicommand.r",
+         { "R", "iscsi.scsicommand.R",
            FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,          
            "Command reads from SCSI target", HFILL }
        },
        { &hf_iscsi_SCSICommand_W,
-         { "W", "iscsi.scsicommand.r",
+         { "W", "iscsi.scsicommand.W",
            FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,          
            "Command writes to SCSI target", HFILL }
        },
@@ -1300,11 +1526,6 @@ proto_register_iscsi(void)
            FT_UINT8, BASE_HEX, NULL, 0,
            "Additional CDB length (in 4 byte units)", HFILL }
        },
-       { &hf_iscsi_Length03,
-         { "Length", "iscsi.length",
-           FT_UINT32, BASE_HEX, NULL, 0,
-           "Data length (bytes)", HFILL }
-       },
        { &hf_iscsi_DataSegmentLength,
          { "DataSegmentLength", "iscsi.datasegmentlength",
            FT_UINT32, BASE_HEX, NULL, 0,
@@ -1340,18 +1561,8 @@ proto_register_iscsi(void)
            FT_UINT32, BASE_HEX, NULL, 0,
            "Next expected status sequence number", HFILL }
        },
-       { &hf_iscsi_SCSICommand_CDB,
-         { "CDB", "iscsi.scsicommand.cdb",
-           FT_BYTES, BASE_HEX, NULL, 0,
-           "SCSI CDB", HFILL }
-       },
-       { &hf_iscsi_SCSICommand_CDB0,
-         { "CDB", "iscsi.scsicommand.cdb0",
-           FT_UINT8, BASE_HEX, VALS(iscsi_scsi_cdb0), 0,
-           "SCSI CDB[0]", HFILL }
-       },
-       { &hf_iscsi_SCSIResponse_BasicResidualCount,
-         { "BasicResidualCount", "iscsi.scsiresponse.basicresidualcount",
+       { &hf_iscsi_SCSIResponse_ResidualCount,
+         { "ResidualCount", "iscsi.scsiresponse.residualcount",
            FT_UINT32, BASE_HEX, NULL, 0,
            "Residual count", HFILL }
        },
@@ -1370,26 +1581,6 @@ proto_register_iscsi(void)
            FT_UINT32, BASE_HEX, NULL, 0,
            "Maximum acceptable command sequence number", HFILL }
        },
-       { &hf_iscsi_SCSIResponse_o03,
-         { "o", "iscsi.scsiresponse.o",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x08,          
-           "Bi-directional read residual overflow", HFILL }
-       },
-       { &hf_iscsi_SCSIResponse_u03,
-         { "u", "iscsi.scsiresponse.u",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x04,          
-           "Bi-directional read residual underflow", HFILL }
-       },
-       { &hf_iscsi_SCSIResponse_O03,
-         { "O", "iscsi.scsiresponse.O",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x02,          
-           "Residual overflow", HFILL }
-       },
-       { &hf_iscsi_SCSIResponse_U03,
-         { "U", "iscsi.scsiresponse.U",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x01,          
-           "Residual underflow", HFILL }
-       },
        { &hf_iscsi_SCSIResponse_o,
          { "o", "iscsi.scsiresponse.o",
            FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,          
@@ -1410,74 +1601,44 @@ proto_register_iscsi(void)
            FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,          
            "Residual underflow", HFILL }
        },
-       { &hf_iscsi_SCSIResponse_S,
-         { "S", "iscsi.scsiresponse.S",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_scsiresponse_S), 0x01,          
-           "Status/Response", HFILL }
-       },
-       { &hf_iscsi_CommandStatus03,
-         { "CommandStatus", "iscsi.commandstatus",
-           FT_UINT8, BASE_HEX, VALS(iscsi_scsi_statuses), 0,
+       { &hf_iscsi_SCSIResponse_Status,
+         { "Status", "iscsi.scsiresponse.status",
+           FT_UINT8, BASE_HEX, VALS(scsi_status_val), 0,
            "SCSI command status value", HFILL }
        },
-       { &hf_iscsi_StatusResponse_is_status,
-         { "Status/Response", "iscsi.scsiresponse.statusresponse",
-           FT_UINT8, BASE_HEX, VALS(iscsi_scsi_statuses), 0,
-           "SCSI command status value", HFILL }
-       },
-       { &hf_iscsi_StatusResponse_is_response,
-         { "Status/Response", "iscsi.scsiresponse.statusresponse",
+       { &hf_iscsi_SCSIResponse_Response,
+         { "Response", "iscsi.scsiresponse.response",
            FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
-           "iSCSI response value", HFILL }
-       },
-       { &hf_iscsi_SCSIResponse_SenseLength,
-         { "SenseLength", "iscsi.scsiresponse.senselength",
-           FT_UINT16, BASE_HEX, NULL, 0,
-           "SCSI sense data length", HFILL }
+           "SCSI command response value", HFILL }
        },
        { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
          { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
            FT_UINT32, BASE_HEX, NULL, 0,
            "Bi-directional read residual count", HFILL }
        },
+       { &hf_iscsi_SenseLength,
+         { "SenseLength", "iscsi.scsiresponse.senselength",
+           FT_UINT16, BASE_HEX, NULL, 0,
+           "Sense data length", HFILL }
+       },
        { &hf_iscsi_SCSIData_F,
-         { "F", "iscsi.scsidata.f",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,          
+         { "F", "iscsi.scsidata.F",
+           FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), ISCSI_SCSI_DATA_FLAG_F,
            "Final PDU", HFILL }
        },
-       { &hf_iscsi_SCSIData_P03,
-         { "P", "iscsi.scsidata.p",
-           FT_BOOLEAN, 8,  TFS(&iscsi_meaning_P), 0x80,          
-           "Poll requested", HFILL }
-       },
-       { &hf_iscsi_SCSIData_S03,
-         { "S", "iscsi.scsidata.s",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), 0x04,          
-           "PDU Contains SCSI command status", HFILL }
-       },
-       { &hf_iscsi_SCSIData_O03,
-         { "O", "iscsi.scsidata.O",
-           FT_BOOLEAN, 8,  TFS(&iscsi_meaning_O), 0x02,          
-           "Residual overflow", HFILL }
-       },
-       { &hf_iscsi_SCSIData_U03,
-         { "U", "iscsi.scsidata.U",
-           FT_BOOLEAN, 8,  TFS(&iscsi_meaning_U), 0x01,          
-           "Residual underflow", HFILL }
-       },
        { &hf_iscsi_SCSIData_S,
-         { "S", "iscsi.scsidata.s",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), 0x01,          
+         { "S", "iscsi.scsidata.S",
+           FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), ISCSI_SCSI_DATA_FLAG_S,
            "PDU Contains SCSI command status", HFILL }
        },
        { &hf_iscsi_SCSIData_U,
          { "U", "iscsi.scsidata.U",
-           FT_BOOLEAN, 8,  TFS(&iscsi_meaning_U), 0x02,          
+           FT_BOOLEAN, 8,  TFS(&iscsi_meaning_U), ISCSI_SCSI_DATA_FLAG_U,
            "Residual underflow", HFILL }
        },
        { &hf_iscsi_SCSIData_O,
          { "O", "iscsi.scsidata.O",
-           FT_BOOLEAN, 8,  TFS(&iscsi_meaning_O), 0x04,          
+           FT_BOOLEAN, 8,  TFS(&iscsi_meaning_O), ISCSI_SCSI_DATA_FLAG_O,
            "Residual overflow", HFILL }
        },
        { &hf_iscsi_TargetTransferTag,
@@ -1510,16 +1671,44 @@ proto_register_iscsi(void)
            FT_UINT8, BASE_HEX, NULL, 0,
            "Minimum supported protocol version", HFILL }
        },
+       { &hf_iscsi_VersionActive,
+         { "VersionActive", "iscsi.versionactive",
+           FT_UINT8, BASE_HEX, NULL, 0,
+           "Negotiated protocol version", HFILL }
+       },
        { &hf_iscsi_CID,
          { "CID", "iscsi.cid",
            FT_UINT16, BASE_HEX, NULL, 0,
            "Connection identifier", HFILL }
        },
+#ifdef DRAFT08
        { &hf_iscsi_ISID,
          { "ISID", "iscsi.isid",
            FT_UINT16, BASE_HEX, NULL, 0,
            "Initiator part of session identifier", HFILL }
        },
+#else
+       { &hf_iscsi_ISID,
+         { "ISID", "iscsi.isid",
+           FT_BYTES, BASE_HEX, NULL, 0,
+           "Initiator part of session identifier", HFILL }
+       },
+       { &hf_iscsi_ISIDType,
+         { "ISIDType", "iscsi.isid.type",
+           FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0,
+           "Initiator part of session identifier - type", HFILL }
+       },
+       { &hf_iscsi_ISIDNamingAuthority,
+         { "ISIDNamingAuthority", "iscsi.isid.namingauthority",
+           FT_UINT24, BASE_HEX, NULL, 0,
+           "Initiator part of session identifier - naming authority", HFILL }
+       },
+       { &hf_iscsi_ISIDQualifier,
+         { "ISIDQualifier", "iscsi.isid.qualifier",
+           FT_UINT8, BASE_HEX, NULL, 0,
+           "Initiator part of session identifier - qualifier", HFILL }
+       },
+#endif
        { &hf_iscsi_TSID,
          { "TSID", "iscsi.tsid",
            FT_UINT16, BASE_HEX, NULL, 0,
@@ -1535,15 +1724,27 @@ proto_register_iscsi(void)
            FT_UINT32, BASE_HEX, NULL, 0,
            "Initial command sequence number", HFILL }
        },
-       { &hf_iscsi_Login_F,
-         { "F", "iscsi.login.f",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,          
-           "Final PDU in login sequence", HFILL }
+       { &hf_iscsi_Login_T,
+         { "T", "iscsi.login.T",
+           FT_BOOLEAN, 8, TFS(&iscsi_meaning_T), 0x80,          
+           "Transit to next login stage",  HFILL }
        },
-       { &hf_iscsi_Login_Status03,
-         { "Status", "iscsi.login.status",
-           FT_UINT8, BASE_HEX, VALS(iscsi_login_status03), 0,
-           "Status", HFILL }
+#ifndef DRAFT08
+       { &hf_iscsi_Login_X,
+         { "X", "iscsi.login.X",
+           FT_BOOLEAN, 8, TFS(&iscsi_meaning_login_X), 0x40,
+           "Restart Connection",  HFILL }
+       },
+#endif
+       { &hf_iscsi_Login_CSG,
+         { "CSG", "iscsi.login.csg",
+           FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), CSG_MASK,          
+           "Current stage",  HFILL }
+       },
+       { &hf_iscsi_Login_NSG,
+         { "NSG", "iscsi.login.nsg",
+           FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), NSG_MASK,          
+           "Next stage",  HFILL }
        },
        { &hf_iscsi_Login_Status,
          { "Status", "iscsi.login.status",
@@ -1556,44 +1757,39 @@ proto_register_iscsi(void)
            "Key/value pair", HFILL }
        },
        { &hf_iscsi_Text_F,
-         { "F", "iscsi.text.f",
+         { "F", "iscsi.text.F",
            FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,          
            "Final PDU in text sequence", HFILL }
        },
-       { &hf_iscsi_NOP_P,
-         { "P", "iscsi.nop.p",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_P), 0x80,          
-           "Poll requested", HFILL }
-       },
        { &hf_iscsi_ExpDataSN,
-         { "ExpCmdSN", "iscsi.expdatasn",
+         { "ExpDataSN", "iscsi.expdatasn",
            FT_UINT32, BASE_HEX, NULL, 0,
            "Next expected data sequence number", HFILL }
        },
-       { &hf_iscsi_R2TExpDataSN,
-         { "R2TExpCmdSN", "iscsi.r2texpdatasn",
+       { &hf_iscsi_R2TSN,
+         { "R2TSN", "iscsi.r2tsn",
            FT_UINT32, BASE_HEX, NULL, 0,
-           "Next expected R2T data sequence number", HFILL }
+           "R2T PDU Number", HFILL }
        },
-       { &hf_iscsi_SCSITask_Response,
-         { "Response", "iscsi.scsitask.response",
-           FT_UINT8, BASE_HEX, VALS(iscsi_task_responses), 0,
+       { &hf_iscsi_TaskManagementFunction_Response,
+         { "Response", "iscsi.taskmanfun.response",
+           FT_UINT8, BASE_HEX, VALS(iscsi_task_management_responses), 0,
            "Response", HFILL }
        },
-       { &hf_iscsi_SCSITask_ReferencedTaskTag,
-         { "InitiatorTaskTag", "iscsi.scsitask.referencedtasktag",
+       { &hf_iscsi_TaskManagementFunction_ReferencedTaskTag,
+         { "ReferencedTaskTag", "iscsi.taskmanfun.referencedtasktag",
            FT_UINT32, BASE_HEX, NULL, 0,
-           "Task's initiator task tag", HFILL }
+           "Referenced task tag", HFILL }
        },
-       { &hf_iscsi_SCSITask_Function,
-         { "Function", "iscsi.scsitask.function",
-           FT_UINT8, BASE_HEX, VALS(iscsi_task_functions), 0x7F,
-           "Requested task function", HFILL }
+       { &hf_iscsi_RefCmdSN,
+         { "RefCmdSN", "iscsi.refcmdsn",
+           FT_UINT32, BASE_HEX, NULL, 0,
+           "Command sequence number for command to be aborted", HFILL }
        },
-       { &hf_iscsi_Logout_Reason03,
-         { "Reason", "iscsi.logout.reason",
-           FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons03), 0,
-           "Reason for logout", HFILL }
+       { &hf_iscsi_TaskManagementFunction_Function,
+         { "Function", "iscsi.taskmanfun.function",
+           FT_UINT8, BASE_HEX, VALS(iscsi_task_management_functions), 0x7F,
+           "Requested task function", HFILL }
        },
        { &hf_iscsi_Logout_Reason,
          { "Reason", "iscsi.logout.reason",
@@ -1605,20 +1801,30 @@ proto_register_iscsi(void)
            FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
            "Logout response", HFILL }
        },
+       { &hf_iscsi_Time2Wait,
+         { "Time2Wait", "iscsi.time2wait",
+           FT_UINT16, BASE_HEX, NULL, 0,
+           "Time2Wait", HFILL }
+       },
+       { &hf_iscsi_Time2Retain,
+         { "Time2Retain", "iscsi.time2retain",
+           FT_UINT16, BASE_HEX, NULL, 0,
+           "Time2Retain", HFILL }
+       },
        { &hf_iscsi_DesiredDataLength,
          { "DesiredDataLength", "iscsi.desireddatalength",
            FT_UINT32, BASE_HEX, NULL, 0,
            "Desired data length (bytes)", HFILL }
        },
-       { &hf_iscsi_SCSIEvent03,
-         { "SCSIEvent", "iscsi.scsievent",
-           FT_UINT8, BASE_HEX, VALS(iscsi_scsievents03), 0,
-           "SCSI event indicator", HFILL }
+       { &hf_iscsi_AsyncEvent,
+         { "AsyncEvent", "iscsi.asyncevent",
+           FT_UINT8, BASE_HEX, VALS(iscsi_asyncevents), 0,
+           "Async event type", HFILL }
        },
-       { &hf_iscsi_iSCSIEvent03,
-         { "iSCSIEvent", "iscsi.iscsievent",
-           FT_UINT8, BASE_HEX, VALS(iscsi_iscsievents03), 0,
-           "iSCSI event indicator", HFILL }
+       { &hf_iscsi_EventVendorCode,
+         { "EventVendorCode", "iscsi.eventvendorcode",
+           FT_UINT8, BASE_HEX, NULL, 0,
+           "Event vendor code", HFILL }
        },
        { &hf_iscsi_Parameter1,
          { "Parameter1", "iscsi.parameter1",
@@ -1630,30 +1836,20 @@ proto_register_iscsi(void)
            FT_UINT16, BASE_HEX, NULL, 0,
            "Parameter 2", HFILL }
        },
-       { &hf_iscsi_Reject_Reason,
-         { "Reason", "iscsi.reject.reason",
-           FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
-           "Reason for command rejection", HFILL }
-       },
-       { &hf_iscsi_Reject_FirstBadByte,
-         { "FirstBadByte", "iscsi.reject.firstbadbyte",
+       { &hf_iscsi_Parameter3,
+         { "Parameter3", "iscsi.parameter3",
            FT_UINT16, BASE_HEX, NULL, 0,
-           "Offset of first bad byte in PDU when reason is 'format error'", HFILL }
+           "Parameter 3", HFILL }
        },
-       { &hf_iscsi_Reject_Reason03,
+       { &hf_iscsi_Reject_Reason,
          { "Reason", "iscsi.reject.reason",
-           FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons03), 0,
+           FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
            "Reason for command rejection", HFILL }
        },
-       { &hf_iscsi_SNACK_S,
-         { "S", "iscsi.snack.s",
-           FT_BOOLEAN, 8, TFS(&iscsi_meaning_SNACK_S), 0x01,          
-           "Status not data SNACK requested", HFILL }
-       },
-       { &hf_iscsi_AddRuns,
-         { "AddRuns", "iscsi.snack.addruns",
-           FT_UINT8, BASE_HEX, NULL, 0,
-           "Number of additional runs", HFILL }
+       { &hf_iscsi_snack_type,
+         { "S", "iscsi.snack.type",
+           FT_UINT8, BASE_DEC, VALS(iscsi_snack_types), 0x0f,          
+           "Type of SNACK requested", HFILL }
        },
        { &hf_iscsi_BegRun,
          { "BegRun", "iscsi.snack.begrun",
@@ -1665,11 +1861,6 @@ proto_register_iscsi(void)
            FT_UINT32, BASE_HEX, NULL, 0,
            "Number of additional missing status PDUs in this run", HFILL }
        },
-       { &hf_iscsi_AdditionalRuns,
-         { "AdditionalRuns", "iscsi.snack.additionalruns",
-           FT_BYTES, BASE_HEX, NULL, 0,
-           "Additional runs of missing status PDUs", HFILL }
-       },
     };
 
     /* Setup protocol subtree array */
@@ -1677,49 +1868,109 @@ proto_register_iscsi(void)
        &ett_iscsi_KeyValues,
        &ett_iscsi_CDB,
        &ett_iscsi_Flags,
+#ifndef DRAFT08
+       &ett_iscsi_ISID,
+#endif
     };
 
     /* Register the protocol name and description */
-    proto_iscsi = proto_register_protocol("iSCSI", "ISCSI", "iscsi");
+    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));
-
+    register_init_routine (&iscsi_init_protocol);
+    
     {
        module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
 
        prefs_register_bool_preference(iscsi_module,
-                                      "version_03_compatible", 
-                                      "Enable 03 compatibility mode",
-                                      "When enabled, assume packets conform to the legacy 03 version of the iSCSI specification",
-                                      &enable_03_mode);
+                                      "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",
                                       &enable_bogosity_filter);
 
+       prefs_register_bool_preference(iscsi_module,
+                                      "demand_good_f_bit", 
+                                      "Ignore packets with bad F bit",
+                                      "Ignore packets that haven't set the F bit when they should have",
+                                      &demand_good_f_bit);
+
        prefs_register_uint_preference(iscsi_module,
                                       "bogus_pdu_max_data_len", 
                                       "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,
+                                      "iscsi_port", 
+                                      "Target port",
+                                      "Port number of iSCSI target",
+                                      10,
+                                      &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,
-                                      "bogus_pdu_max_digest_padding", 
-                                      "Bogus pdu max digest padding",
-                                      "Treat packets whose apparent total digest size is greater than this value as bogus",
+                                      "header_digest_size", 
+                                      "Header digest size",
+                                      "The size of a header digest (bytes)",
                                       10,
-                                      &bogus_pdu_max_digest_padding);
+                                      &headerDigestSize);
+       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,
+                                      "version_03_compatible");
+       prefs_register_obsolete_preference(iscsi_module,
+                                      "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.
-*/
+/*
+ * 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)
 {