Remove all $Id$ from top of file
[metze/wireshark/wip.git] / epan / dissectors / packet-scsi.h
index 0e0b1b4d0b2a7cd6f36002b1710c046e0a9b307d..7d059426dffdd2934a37babd07de40eca6d995dd 100644 (file)
@@ -1,10 +1,8 @@
 /* packet-scsi.h
  * Author: Dinesh G Dutt (ddutt@cisco.com)
  *
- * $Id$
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 2002 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 #ifndef __PACKET_SCSI_H_
 #define __PACKET_SCSI_H_
 
+#include <epan/exceptions.h>
+
+/* Structure containing itl nexus data :
+ * The itlq nexus is a structure containing data specific
+ * for a initiator target lun combination.
+ */
+typedef struct _itl_nexus_t {
+#define SCSI_CMDSET_DEFAULT    0x80
+#define SCSI_CMDSET_MASK       0x7f
+    guint8 cmdset;         /* This is a bitfield.
+                           * The MSB (0x80) represents whether
+                           * 0: the commandset is known from a INQ PDU
+                           * 1: is using the "default" from preferences.
+                           * The lower 7 bits represent the commandset used
+                           * for decoding commands on this itl nexus.
+                           * The field is initialized to 0xff == unknown.
+                           */
+    conversation_t *conversation;
+} itl_nexus_t;
+
+/* Structure containing itlq nexus data :
+ * The itlq nexus is a structure containing data specific
+ * for a initiator target lun queue/commandid combination.
+ */
+typedef struct _itlq_nexus_t {
+    guint32 first_exchange_frame;
+    guint32 last_exchange_frame;
+    guint16 lun;         /* initialized to 0xffff == unknown */
+    guint16 scsi_opcode; /* initialized to 0xffff == unknown */
+    guint16 flags;
+
+#define SCSI_DATA_READ 0x0001
+#define SCSI_DATA_WRITE        0x0002
+    guint16 task_flags; /* Flags set by the transport for this
+                        * scsi task.
+                        *
+                        * If there is no data being transferred both flags
+                        * are 0 and both data lengths below are undefined.
+                        *
+                        * If one of the flags are set the amount of
+                        * data being transferred is held in data_length
+                        * and bidir_data_length is undefined.
+                        *
+                        * If both flags are set (a bidirectional transfer)
+                        * data_length specifies the amount of DATA-OUT and
+                        * bidir_data_length specifies the amount of DATA-IN
+                        */
+    guint32 data_length;
+    guint32 bidir_data_length;
+
+    guint32 alloc_len; /* we need to track alloc_len between the CDB and
+                        * the DATA pdus for some opcodes.
+                        */
+    nstime_t fc_time;
+
+
+    void *extra_data;     /* extra data that that is task specific */
+} itlq_nexus_t;
+
+
+#define SCSI_PDU_TYPE_CDB       1
+#define SCSI_PDU_TYPE_DATA      2
+#define SCSI_PDU_TYPE_RSP       4
+#define SCSI_PDU_TYPE_SNS       5
+typedef struct _scsi_task_data {
+    int type;
+    itlq_nexus_t *itlq;
+    itl_nexus_t *itl;
+} scsi_task_data_t;
+
+
+/* list of commands for each commandset */
+typedef void (*scsi_dissector_t)(tvbuff_t *tvb, packet_info *pinfo,
+               proto_tree *tree, guint offset,
+               gboolean isreq, gboolean iscdb,
+                guint32 payload_len, scsi_task_data_t *cdata);
+
+typedef struct _scsi_cdb_table_t {
+       scsi_dissector_t        func;
+} scsi_cdb_table_t;
+
+
+/* SPC Commands */
+#define SCSI_SPC_ACCESS_CONTROL_IN       0x86
+#define SCSI_SPC_ACCESS_CONTROL_OUT      0x87
+#define SCSI_SPC_CHANGE_DEFINITION       0x40
+#define SCSI_SPC_COMPARE                 0x39
+#define SCSI_SPC_COPY                    0x18
+#define SCSI_SPC_COPY_AND_VERIFY         0x3A
+#define SCSI_SPC_INQUIRY                 0x12
+#define SCSI_SPC_EXTCOPY                 0x83
+#define SCSI_SPC_RECVCOPY               0x84
+#define SCSI_SPC_LOGSELECT               0x4C
+#define SCSI_SPC_LOGSENSE                0x4D
+#define SCSI_SPC_MODESELECT6             0x15
+#define SCSI_SPC_MODESELECT10            0x55
+#define SCSI_SPC_MODESENSE6              0x1A
+#define SCSI_SPC_MODESENSE10             0x5A
+#define SCSI_SPC_PERSRESVIN              0x5E
+#define SCSI_SPC_PERSRESVOUT             0x5F
+#define SCSI_SPC_PREVMEDREMOVAL          0x1E
+#define SCSI_SPC_READBUFFER              0x3C
+#define SCSI_SPC_RCVCOPYRESULTS          0x84
+#define SCSI_SPC_RCVDIAGRESULTS          0x1C
+#define SCSI_SPC_RELEASE6                0x17
+#define SCSI_SPC_RELEASE10               0x57
+#define SCSI_SPC_MGMT_PROTOCOL_IN        0xA3
+#define SCSI_SPC_REPORTLUNS              0xA0
+#define SCSI_SPC_REQSENSE                0x03
+#define SCSI_SPC_RESERVE6                0x16
+#define SCSI_SPC_RESERVE10               0x56
+#define SCSI_SPC_SENDDIAG                0x1D
+#define SCSI_SPC_SETDEVICEID             0xA4
+#define SCSI_SPC_TESTUNITRDY             0x00
+#define SCSI_SPC_WRITEBUFFER             0x3B
+#define SCSI_SPC_VARLENCDB               0x7F
+
+void dissect_spc_inquiry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint32 payload_len, scsi_task_data_t *cdata);
+void dissect_spc_logselect(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_logsense(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_mgmt_protocol_in(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_modeselect6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len, scsi_task_data_t *cdata);
+void dissect_spc_modesense6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len, scsi_task_data_t *cdata);
+void dissect_spc_modeselect10(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len, scsi_task_data_t *cdata);
+void dissect_spc_modesense10(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len, scsi_task_data_t *cdata);
+void dissect_spc_persistentreservein(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len, scsi_task_data_t *cdata);
+void dissect_spc_persistentreserveout(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_reportluns(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_testunitready (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_requestsense (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_preventallowmediaremoval (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_writebuffer (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb _U_, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_reserve6 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_release6 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_reserve10 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_release10 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_senddiagnostic (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_extcopy (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+void dissect_spc_recvcopy (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset, gboolean isreq, gboolean iscdb, guint payload_len _U_, scsi_task_data_t *cdata _U_);
+
+
+
+
+
+
 extern const value_string scsi_status_val[];
 
 /*
@@ -63,21 +206,109 @@ extern const value_string scsi_status_val[];
  * FCP/iSCSI
  */
 void dissect_scsi_cdb (tvbuff_t *, packet_info *, proto_tree *,
-                       gint, guint16, itl_nexus_t *);
+                       gint, itlq_nexus_t *, itl_nexus_t *);
 void dissect_scsi_rsp (tvbuff_t *, packet_info *, proto_tree *, itlq_nexus_t *, itl_nexus_t *, guint8);
 void dissect_scsi_payload (tvbuff_t *, packet_info *, proto_tree *,
-                           gboolean, guint16, itl_nexus_t *);
-void dissect_scsi_snsinfo (tvbuff_t *, packet_info *, proto_tree *, guint, guint, guint16);
+                           gboolean, itlq_nexus_t *, itl_nexus_t *,
+                           guint32 relative_offset);
+void dissect_scsi_snsinfo (tvbuff_t *, packet_info *, proto_tree *, guint, guint, itlq_nexus_t *, itl_nexus_t *);
 
-/*
- * Private data to be supplied to those functions via "pinfo->private_data";
- * the structure contains a 32-bit conversation ID and a 32-bit task
- * ID, where the former identifies a conversation between initiator and
- * target and the latter identifies a SCSI task within that conversation.
+void dissect_scsi_lun(proto_tree *, tvbuff_t *, guint);
+
+extern const int *cdb_control_fields[6];
+extern gint ett_scsi_control;
+extern int hf_scsi_control;
+extern int hf_scsi_alloclen16;
+
+/* service actions */
+#define SHORT_FORM_BLOCK_ID        0x00
+#define SHORT_FORM_VENDOR_SPECIFIC 0x01
+#define LONG_FORM                  0x06
+#define EXTENDED_FORM              0x08
+#define SERVICE_READ_CAPACITY16           0x10
+#define SERVICE_READ_LONG16       0x11
+#define SERVICE_GET_LBA_STATUS     0x12
+
+extern const value_string service_action_vals[];
+extern const value_string scsi_devid_codeset_val[];
+extern const value_string scsi_devid_idtype_val[];
+extern value_string_ext scsi_asc_val_ext;
+
+/* 0xA3 MGMT PROTOCOL IN service actions */
+#define MPI_MANAGEMENT_PROTOCOL_IN           0x10
+#define MPI_REPORT_SUPPORTED_OPERATION_CODES 0x0C
+
+/* These two defines are used to handle cases where data coming back from
+ * the device is truncated due to a too short allocation_length specified
+ * in the command CDB.
+ * This is semi-common in SCSI and it would be wrong to mark these packets
+ * as [malformed packets].
+ * These macros will reset the reported length to what the data pdu specified
+ * and if a ReportedBoundsError is generated we will instead throw
+ * ScsiBoundsError
+ *
+ * Please see dissect_spc_inquiry() for an example how to use these
+ * macros.
+ */
+#define TRY_SCSI_CDB_ALLOC_LEN(pinfo, tvb, offset, length)             \
+    {                                                                  \
+       volatile gboolean short_packet;                                 \
+       tvbuff_t *new_tvb;                                              \
+       guint32 end_data_offset=0;                                      \
+                                                                       \
+       short_packet=pinfo->fd->cap_len<pinfo->fd->pkt_len;             \
+       new_tvb=tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), length);\
+       tvb=new_tvb;                                                    \
+       offset=0;                                                       \
+       TRY {
+
+#define END_TRY_SCSI_CDB_ALLOC_LEN                                     \
+                   if(end_data_offset){                                \
+                       /* just verify we can read all the bytes we were\
+                        * supposed to.                                 \
+                        */                                             \
+                       tvb_get_guint8(tvb,end_data_offset);            \
+               }                                                       \
+           } /* TRY */                                                 \
+       CATCH(BoundsError) {                                            \
+               if(short_packet){                                       \
+                       /* this was a short packet */                   \
+                       RETHROW;                                        \
+               } else {                                                \
+                       /* We probably tried to dissect beyond the end  \
+                        * of the alloc len reported in the data        \
+                        * pdu. This is not an error so dont flag it as \
+                        * one                                          \
+                        * it is the alloc_len in the CDB that is the   \
+                        * important one                                \
+                        */                                             \
+               }                                                       \
+           }                                                           \
+       CATCH(ReportedBoundsError) {                                    \
+               if(short_packet){                                       \
+                       /* this was a short packet */                   \
+                       RETHROW;                                        \
+               } else {                                                \
+                       /* this packet was not really short but limited \
+                        * due to a short SCSI allocation length        \
+                        */                                             \
+                       THROW(ScsiBoundsError);                         \
+               }                                                       \
+           }                                                           \
+       ENDTRY;                                                         \
+    }
+
+/* If the data pdu contains an alloc_len as well, this macro can be set
+ * to registe this offset for the TRY section above.
+ * At the end of the TRY section we will, if set, verify that the data
+ * pdu contained all bytes that was specified in the data alloc len.
+ *
+ * This macro does currently not do anything but we might enhance it in
+ * the future. There is no harm in teaching the dissector about how long
+ * the data pdu is supposed to be according to alloc_len in the data pdu
  */
-typedef struct {
-       guint32 conv_id;
-       guint32 task_id;
-} scsi_task_id_t;
+#define SET_SCSI_DATA_END(offset)                                      \
+       end_data_offset=offset;
+
 
 #endif