1 /* packet-scsi.h
2  * Author: Dinesh G Dutt (ddutt@cisco.com)
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 2002 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #ifndef __PACKET_SCSI_H_
12 #define __PACKET_SCSI_H_
13 
14 #include <epan/exceptions.h>
15 #include <epan/srt_table.h>
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif /* __cplusplus */
20 
21 /* Structure containing itl nexus data :
22  * The itlq nexus is a structure containing data specific
23  * for a initiator target lun combination.
24  */
25 typedef struct _itl_nexus_t {
26 #define SCSI_CMDSET_DEFAULT	0x80
27 #define SCSI_CMDSET_MASK	0x7f
28     guint8 cmdset;         /* This is a bitfield.
29 			    * The MSB (0x80) represents whether
30 			    * 0: the commandset is known from a INQ PDU
31 			    * 1: is using the "default" from preferences.
32 			    * The lower 7 bits represent the commandset used
33 			    * for decoding commands on this itl nexus.
34 			    * The field is initialized to 0xff == unknown.
35 			    */
36     conversation_t *conversation;
37 } itl_nexus_t;
38 
39 /* Structure containing itlq nexus data :
40  * The itlq nexus is a structure containing data specific
41  * for a initiator target lun queue/commandid combination.
42  */
43 typedef struct _itlq_nexus_t {
44     guint32 first_exchange_frame;
45     guint32 last_exchange_frame;
46     guint16 lun;         /* initialized to 0xffff == unknown */
47     guint16 scsi_opcode; /* initialized to 0xffff == unknown */
48     guint16 flags;
49 
50 #define SCSI_DATA_READ	0x0001
51 #define SCSI_DATA_WRITE	0x0002
52     guint16 task_flags; /* Flags set by the transport for this
53 			 * scsi task.
54 			 *
55 			 * If there is no data being transferred both flags
56 			 * are 0 and both data lengths below are undefined.
57 			 *
58 			 * If one of the flags are set the amount of
59 			 * data being transferred is held in data_length
60 			 * and bidir_data_length is undefined.
61 			 *
62 			 * If both flags are set (a bidirectional transfer)
63 			 * data_length specifies the amount of DATA-OUT and
64 			 * bidir_data_length specifies the amount of DATA-IN
65 			 */
66     guint32 data_length;
67     guint32 bidir_data_length;
68 
69     guint32 alloc_len;	/* we need to track alloc_len between the CDB and
70 			 * the DATA pdus for some opcodes.
71 			 */
72     nstime_t fc_time;
73 
74 
75     void *extra_data;     /* extra data that that is task specific */
76 } itlq_nexus_t;
77 
78 
79 #define SCSI_PDU_TYPE_CDB       1
80 #define SCSI_PDU_TYPE_DATA      2
81 #define SCSI_PDU_TYPE_RSP       4
82 #define SCSI_PDU_TYPE_SNS       5
83 typedef struct _scsi_task_data {
84     int type;
85     itlq_nexus_t *itlq;
86     itl_nexus_t *itl;
87 } scsi_task_data_t;
88 
89 
90 /* list of commands for each commandset */
91 typedef void (*scsi_dissector_t)(tvbuff_t *tvb, packet_info *pinfo,
92 		proto_tree *tree, guint offset,
93 		gboolean isreq, gboolean iscdb,
94                 guint32 payload_len, scsi_task_data_t *cdata);
95 
96 typedef struct _scsi_cdb_table_t {
97 	scsi_dissector_t	func;
98 } scsi_cdb_table_t;
99 
100 
101 /* SPC Commands */
102 #define SCSI_SPC_ACCESS_CONTROL_IN       0x86
103 #define SCSI_SPC_ACCESS_CONTROL_OUT      0x87
104 #define SCSI_SPC_CHANGE_DEFINITION       0x40
105 #define SCSI_SPC_COMPARE                 0x39
106 #define SCSI_SPC_COPY                    0x18
107 #define SCSI_SPC_COPY_AND_VERIFY         0x3A
108 #define SCSI_SPC_INQUIRY                 0x12
109 #define SCSI_SPC_EXTCOPY                 0x83
110 #define SCSI_SPC_RECVCOPY		 0x84
111 #define SCSI_SPC_LOGSELECT               0x4C
112 #define SCSI_SPC_LOGSENSE                0x4D
113 #define SCSI_SPC_MODESELECT6             0x15
114 #define SCSI_SPC_MODESELECT10            0x55
115 #define SCSI_SPC_MODESENSE6              0x1A
116 #define SCSI_SPC_MODESENSE10             0x5A
117 #define SCSI_SPC_PERSRESVIN              0x5E
118 #define SCSI_SPC_PERSRESVOUT             0x5F
119 #define SCSI_SPC_PREVMEDREMOVAL          0x1E
120 #define SCSI_SPC_READBUFFER              0x3C
121 #define SCSI_SPC_RCVDIAGRESULTS          0x1C
122 #define SCSI_SPC_RELEASE6                0x17
123 #define SCSI_SPC_RELEASE10               0x57
124 #define SCSI_SPC_MGMT_PROTOCOL_IN        0xA3
125 #define SCSI_SPC_REPORTLUNS              0xA0
126 #define SCSI_SPC_REQSENSE                0x03
127 #define SCSI_SPC_RESERVE6                0x16
128 #define SCSI_SPC_RESERVE10               0x56
129 #define SCSI_SPC_SENDDIAG                0x1D
130 #define SCSI_SPC_SETDEVICEID             0xA4
131 #define SCSI_SPC_TESTUNITRDY             0x00
132 #define SCSI_SPC_WRITEBUFFER             0x3B
133 #define SCSI_SPC_VARLENCDB               0x7F
134 
135 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);
136 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_);
137 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_);
138 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_);
139 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);
140 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);
141 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);
142 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);
143 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);
144 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_);
145 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_);
146 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_);
147 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_);
148 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_);
149 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_);
150 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_);
151 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_);
152 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_);
153 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_);
154 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_);
155 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_);
156 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_);
157 
158 
159 
160 
161 
162 
163 extern const value_string scsi_status_val[];
164 
165 /*
166  * SCSI Device Types.
167  *
168  * These can be supplied to the dissection routines if the caller happens
169  * to know the device type (e.g., NDMP assumes that a "jukebox" is a
170  * media changer, SCSI_DEV_SMC, and a "tape" is a sequential access device,
171  * SCSI_DEV_SSC).
172  *
173  * If the caller doesn't know the device type, it supplies SCSI_DEV_UNKNOWN.
174  */
175 #define SCSI_DEV_UNKNOWN   -1
176 #define SCSI_DEV_SBC       0x0
177 #define SCSI_DEV_SSC       0x1
178 #define SCSI_DEV_PRNT      0x2
179 #define SCSI_DEV_PROC      0x3
180 #define SCSI_DEV_WORM      0x4
181 #define SCSI_DEV_CDROM     0x5
182 #define SCSI_DEV_SCAN      0x6
183 #define SCSI_DEV_OPTMEM    0x7
184 #define SCSI_DEV_SMC       0x8
185 #define SCSI_DEV_COMM      0x9
186 #define SCSI_DEV_RAID      0xC
187 #define SCSI_DEV_SES       0xD
188 #define SCSI_DEV_RBC       0xE
189 #define SCSI_DEV_OCRW      0xF
190 #define SCSI_DEV_OSD       0x11
191 #define SCSI_DEV_ADC       0x12
192 #define SCSI_DEV_NOLUN     0x1F
193 
194 #define SCSI_DEV_BITS      0x1F /* the lower 5 bits indicate device type */
195 #define SCSI_MS_PCODE_BITS 0x3F /* Page code bits in Mode Sense */
196 
197 /* Function Decls; functions invoked by SAM-2 transport protocols such as
198  * FCP/iSCSI
199  */
200 void dissect_scsi_cdb (tvbuff_t *, packet_info *, proto_tree *,
201                        gint, itlq_nexus_t *, itl_nexus_t *);
202 void dissect_scsi_rsp (tvbuff_t *, packet_info *, proto_tree *, itlq_nexus_t *, itl_nexus_t *, guint8);
203 void dissect_scsi_payload (tvbuff_t *, packet_info *, proto_tree *,
204                            gboolean, itlq_nexus_t *, itl_nexus_t *,
205                            guint32 relative_offset);
206 void dissect_scsi_snsinfo (tvbuff_t *, packet_info *, proto_tree *, guint, guint, itlq_nexus_t *, itl_nexus_t *);
207 
208 void dissect_scsi_lun(proto_tree *, tvbuff_t *, guint);
209 
210 extern int * const cdb_control_fields[6];
211 extern gint ett_scsi_control;
212 extern int hf_scsi_control;
213 extern int hf_scsi_alloclen16;
214 
215 /* service actions */
216 #define SHORT_FORM_BLOCK_ID        0x00
217 #define SHORT_FORM_VENDOR_SPECIFIC 0x01
218 #define LONG_FORM                  0x06
219 #define EXTENDED_FORM              0x08
220 #define SERVICE_READ_CAPACITY16	   0x10
221 #define SERVICE_READ_LONG16	   0x11
222 #define SERVICE_WRITE_LONG16	   0x11
223 #define SERVICE_GET_LBA_STATUS     0x12
224 #define SERVICE_REPORT_REFERRALS   0x13
225 
226 extern const value_string service_action_vals[];
227 extern const value_string scsi_devid_codeset_val[];
228 extern const value_string scsi_devid_idtype_val[];
229 extern value_string_ext scsi_asc_val_ext;
230 
231 /* 0xA3 MGMT PROTOCOL IN service actions */
232 #define MPI_MANAGEMENT_PROTOCOL_IN           0x10
233 #define MPI_REPORT_SUPPORTED_OPERATION_CODES 0x0C
234 
235 /* These two defines are used to handle cases where data coming back from
236  * the device is truncated due to a too short allocation_length specified
237  * in the command CDB.
238  * This is semi-common in SCSI and it would be wrong to mark these packets
239  * as [malformed packets].
240  * These macros will reset the reported length to what the data pdu specified
241  * and if a ContainedBoundsError or ReportedBoundsError is generated we will
242  * instead throw ScsiBoundsError
243  *
244  * Please see dissect_spc_inquiry() for an example how to use these
245  * macros.
246  *
247  * Note that try_tvb & try_offset are initialized to be  used in the code
248  *  bounded by TRY_SCSI_ALLOC_LEN and END_TRY_SCSI_CDB_ALLOC_LEN
249  */
250 
251 #define TRY_SCSI_CDB_ALLOC_LEN(length_arg)				\
252     {									\
253 	tvbuff_t *try_tvb;						\
254 	volatile guint try_offset;                                      \
255 	guint32   try_end_data_offset=0;				\
256 									\
257 	try_tvb=tvb_new_subset_length(tvb_a, offset_a, length_arg);	\
258 	try_offset=0;							\
259 	TRY {
260 
261 #define END_TRY_SCSI_CDB_ALLOC_LEN 					\
262 		if(try_end_data_offset){				\
263 			/* just verify we can read all the bytes we were\
264 			 * supposed to.					\
265 			 */						\
266 			tvb_get_guint8(try_tvb,try_end_data_offset);	\
267 		}							\
268 	} /* TRY */							\
269 	CATCH(BoundsError) {						\
270 		/* this was a short packet */				\
271 		RETHROW;						\
272 	}								\
273 	CATCH(ContainedBoundsError) {					\
274 		/* We probably tried to dissect beyond the end		\
275 		 * of the alloc len reported in the data		\
276 		 * pdu. This is not an error so don't flag it		\
277 		 * as one						\
278 		 * it is the alloc_len in the CDB that is the		\
279 		 * important one					\
280 		 */							\
281 	}								\
282 	CATCH(ReportedBoundsError) {					\
283 		/* this packet was not really short but limited		\
284 		 * due to a short SCSI allocation length		\
285 		 */							\
286 		THROW(ScsiBoundsError);					\
287 	}								\
288 	ENDTRY;								\
289     }
290 
291 /* If the data pdu contains an alloc_len as well, this macro can be set
292  * to registe this offset for the TRY section above.
293  * At the end of the TRY section we will, if set, verify that the data
294  * pdu contained all bytes that was specified in the data alloc len.
295  *
296  * This macro does currently not do anything but we might enhance it in
297  * the future. There is no harm in teaching the dissector about how long
298  * the data pdu is supposed to be according to alloc_len in the data pdu
299  */
300 #define SET_SCSI_DATA_END(offset_arg)		\
301 	try_end_data_offset=offset_arg;
302 
303 
304 WS_DLL_PUBLIC guint scsistat_param(register_srt_t* srt, const char* opt_arg, char** err);
305 
306 #ifdef __cplusplus
307 }
308 #endif /* __cplusplus */
309 
310 #endif
311 
312 /*
313  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
314  *
315  * Local variables:
316  * c-basic-offset: 8
317  * tab-width: 8
318  * indent-tabs-mode: t
319  * End:
320  *
321  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
322  * :indentSize=8:tabSize=8:noTabs=false:
323  */
324