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