2 * Author: Dinesh G Dutt (ddutt@cisco.com)
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 2002 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #ifndef __PACKET_SCSI_H_
26 #define __PACKET_SCSI_H_
28 #include "ws_symbol_export.h"
30 #include <epan/exceptions.h>
32 /* Structure containing itl nexus data :
33 * The itlq nexus is a structure containing data specific
34 * for a initiator target lun combination.
36 typedef struct _itl_nexus_t
{
37 #define SCSI_CMDSET_DEFAULT 0x80
38 #define SCSI_CMDSET_MASK 0x7f
39 guint8 cmdset
; /* This is a bitfield.
40 * The MSB (0x80) represents whether
41 * 0: the commandset is known from a INQ PDU
42 * 1: is using the "default" from preferences.
43 * The lower 7 bits represent the commandset used
44 * for decoding commands on this itl nexus.
45 * The field is initialized to 0xff == unknown.
47 conversation_t
*conversation
;
50 /* Structure containing itlq nexus data :
51 * The itlq nexus is a structure containing data specific
52 * for a initiator target lun queue/commandid combination.
54 typedef struct _itlq_nexus_t
{
55 guint32 first_exchange_frame
;
56 guint32 last_exchange_frame
;
57 guint16 lun
; /* initialized to 0xffff == unknown */
58 guint16 scsi_opcode
; /* initialized to 0xffff == unknown */
61 #define SCSI_DATA_READ 0x0001
62 #define SCSI_DATA_WRITE 0x0002
63 guint16 task_flags
; /* Flags set by the transport for this
66 * If there is no data being transferred both flags
67 * are 0 and both data lengths below are undefined.
69 * If one of the flags are set the amount of
70 * data being transferred is held in data_length
71 * and bidir_data_length is undefined.
73 * If both flags are set (a bidirectional transfer)
74 * data_length specifies the amount of DATA-OUT and
75 * bidir_data_length specifies the amount of DATA-IN
78 guint32 bidir_data_length
;
80 guint32 alloc_len
; /* we need to track alloc_len between the CDB and
81 * the DATA pdus for some opcodes.
86 void *extra_data
; /* extra data that that is task specific */
90 #define SCSI_PDU_TYPE_CDB 1
91 #define SCSI_PDU_TYPE_DATA 2
92 #define SCSI_PDU_TYPE_RSP 4
93 #define SCSI_PDU_TYPE_SNS 5
94 typedef struct _scsi_task_data
{
101 /* list of commands for each commandset */
102 typedef void (*scsi_dissector_t
)(tvbuff_t
*tvb
, packet_info
*pinfo
,
103 proto_tree
*tree
, guint offset
,
104 gboolean isreq
, gboolean iscdb
,
105 guint32 payload_len
, scsi_task_data_t
*cdata
);
107 typedef struct _scsi_cdb_table_t
{
108 scsi_dissector_t func
;
113 #define SCSI_SPC_ACCESS_CONTROL_IN 0x86
114 #define SCSI_SPC_ACCESS_CONTROL_OUT 0x87
115 #define SCSI_SPC_CHANGE_DEFINITION 0x40
116 #define SCSI_SPC_COMPARE 0x39
117 #define SCSI_SPC_COPY 0x18
118 #define SCSI_SPC_COPY_AND_VERIFY 0x3A
119 #define SCSI_SPC_INQUIRY 0x12
120 #define SCSI_SPC_EXTCOPY 0x83
121 #define SCSI_SPC_LOGSELECT 0x4C
122 #define SCSI_SPC_LOGSENSE 0x4D
123 #define SCSI_SPC_MODESELECT6 0x15
124 #define SCSI_SPC_MODESELECT10 0x55
125 #define SCSI_SPC_MODESENSE6 0x1A
126 #define SCSI_SPC_MODESENSE10 0x5A
127 #define SCSI_SPC_PERSRESVIN 0x5E
128 #define SCSI_SPC_PERSRESVOUT 0x5F
129 #define SCSI_SPC_PREVMEDREMOVAL 0x1E
130 #define SCSI_SPC_READBUFFER 0x3C
131 #define SCSI_SPC_RCVCOPYRESULTS 0x84
132 #define SCSI_SPC_RCVDIAGRESULTS 0x1C
133 #define SCSI_SPC_RELEASE6 0x17
134 #define SCSI_SPC_RELEASE10 0x57
135 #define SCSI_SPC_MGMT_PROTOCOL_IN 0xA3
136 #define SCSI_SPC_REPORTLUNS 0xA0
137 #define SCSI_SPC_REQSENSE 0x03
138 #define SCSI_SPC_RESERVE6 0x16
139 #define SCSI_SPC_RESERVE10 0x56
140 #define SCSI_SPC_SENDDIAG 0x1D
141 #define SCSI_SPC_SETDEVICEID 0xA4
142 #define SCSI_SPC_TESTUNITRDY 0x00
143 #define SCSI_SPC_WRITEBUFFER 0x3B
144 #define SCSI_SPC_VARLENCDB 0x7F
146 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
);
147 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_
);
148 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_
);
149 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_
);
150 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
);
151 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
);
152 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
);
153 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
);
154 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
);
155 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_
);
156 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_
);
157 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_
);
158 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_
);
159 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_
);
160 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_
);
161 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_
);
162 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_
);
163 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_
);
164 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_
);
165 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_
);
166 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_
);
172 extern const value_string scsi_status_val
[];
177 * These can be supplied to the dissection routines if the caller happens
178 * to know the device type (e.g., NDMP assumes that a "jukebox" is a
179 * media changer, SCSI_DEV_SMC, and a "tape" is a sequential access device,
182 * If the caller doesn't know the device type, it supplies SCSI_DEV_UNKNOWN.
184 #define SCSI_DEV_UNKNOWN -1
185 #define SCSI_DEV_SBC 0x0
186 #define SCSI_DEV_SSC 0x1
187 #define SCSI_DEV_PRNT 0x2
188 #define SCSI_DEV_PROC 0x3
189 #define SCSI_DEV_WORM 0x4
190 #define SCSI_DEV_CDROM 0x5
191 #define SCSI_DEV_SCAN 0x6
192 #define SCSI_DEV_OPTMEM 0x7
193 #define SCSI_DEV_SMC 0x8
194 #define SCSI_DEV_COMM 0x9
195 #define SCSI_DEV_RAID 0xC
196 #define SCSI_DEV_SES 0xD
197 #define SCSI_DEV_RBC 0xE
198 #define SCSI_DEV_OCRW 0xF
199 #define SCSI_DEV_OSD 0x11
200 #define SCSI_DEV_ADC 0x12
201 #define SCSI_DEV_NOLUN 0x1F
203 #define SCSI_DEV_BITS 0x1F /* the lower 5 bits indicate device type */
204 #define SCSI_MS_PCODE_BITS 0x3F /* Page code bits in Mode Sense */
206 /* Function Decls; functions invoked by SAM-2 transport protocols such as
209 void dissect_scsi_cdb (tvbuff_t
*, packet_info
*, proto_tree
*,
210 gint
, itlq_nexus_t
*, itl_nexus_t
*);
211 void dissect_scsi_rsp (tvbuff_t
*, packet_info
*, proto_tree
*, itlq_nexus_t
*, itl_nexus_t
*, guint8
);
212 void dissect_scsi_payload (tvbuff_t
*, packet_info
*, proto_tree
*,
213 gboolean
, itlq_nexus_t
*, itl_nexus_t
*,
214 guint32 relative_offset
);
215 void dissect_scsi_snsinfo (tvbuff_t
*, packet_info
*, proto_tree
*, guint
, guint
, itlq_nexus_t
*, itl_nexus_t
*);
217 void dissect_scsi_lun(proto_tree
*, tvbuff_t
*, guint
);
219 WS_DLL_PUBLIC
const value_string scsi_mmc_vals
[];
221 extern const int *cdb_control_fields
[6];
222 extern gint ett_scsi_control
;
223 extern int hf_scsi_control
;
224 extern int hf_scsi_alloclen16
;
226 /* service actions */
227 #define SHORT_FORM_BLOCK_ID 0x00
228 #define SHORT_FORM_VENDOR_SPECIFIC 0x01
229 #define LONG_FORM 0x06
230 #define EXTENDED_FORM 0x08
231 #define SERVICE_READ_CAPACITY16 0x10
232 #define SERVICE_READ_LONG16 0x11
233 #define SERVICE_GET_LBA_STATUS 0x12
235 extern const value_string service_action_vals
[];
236 extern const value_string scsi_devid_codeset_val
[];
237 extern const value_string scsi_devid_idtype_val
[];
238 extern value_string_ext scsi_asc_val_ext
;
240 /* 0xA3 MGMT PROTOCOL IN service actions */
241 #define MPI_MANAGEMENT_PROTOCOL_IN 0x10
242 #define MPI_REPORT_SUPPORTED_OPERATION_CODES 0x0C
244 /* These two defines are used to handle cases where data coming back from
245 * the device is truncated due to a too short allocation_length specified
246 * in the command CDB.
247 * This is semi-common in SCSI and it would be wrong to mark these packets
248 * as [malformed packets].
249 * These macros will reset the reported length to what the data pdu specified
250 * and if a ReportedBoundsError is generated we will instead throw
253 * Please see dissect_spc_inquiry() for an example how to use these
256 #define TRY_SCSI_CDB_ALLOC_LEN(pinfo, tvb, offset, length) \
258 volatile gboolean short_packet; \
260 guint32 end_data_offset=0; \
262 short_packet=pinfo->fd->cap_len<pinfo->fd->pkt_len; \
263 new_tvb=tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), length);\
268 #define END_TRY_SCSI_CDB_ALLOC_LEN \
269 if(end_data_offset){ \
270 /* just verify we can read all the bytes we were\
273 tvb_get_guint8(tvb,end_data_offset); \
276 CATCH(BoundsError) { \
278 /* this was a short packet */ \
281 /* We probably tried to dissect beyond the end \
282 * of the alloc len reported in the data \
283 * pdu. This is not an error so dont flag it as \
285 * it is the alloc_len in the CDB that is the \
290 CATCH(ReportedBoundsError) { \
292 /* this was a short packet */ \
295 /* this packet was not really short but limited \
296 * due to a short SCSI allocation length \
298 THROW(ScsiBoundsError); \
304 /* If the data pdu contains an alloc_len as well, this macro can be set
305 * to registe this offset for the TRY section above.
306 * At the end of the TRY section we will, if set, verify that the data
307 * pdu contained all bytes that was specified in the data alloc len.
309 * This macro does currently not do anything but we might enhance it in
310 * the future. There is no harm in teaching the dissector about how long
311 * the data pdu is supposed to be according to alloc_len in the data pdu
313 #define SET_SCSI_DATA_END(offset) \
314 end_data_offset=offset;