1 /* TODO for the cases where one just can not autodetect whether header digest
2 is used or not we might need a new preference
10 * Routines for iSCSI dissection
11 * Copyright 2001, Eurologic and Mark Burton <markb@ordern.com>
12 * 2004 Request/Response matching and Service Response Time: ronnie sahlberg
16 * Wireshark - Network traffic analyzer
17 * By Gerald Combs <gerald@wireshark.org>
18 * Copyright 1998 Gerald Combs
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version 2
23 * of the License, or (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
45 #include <epan/packet.h>
46 #include <epan/prefs.h>
47 #include <epan/conversation.h>
48 #include "packet-fc.h"
49 #include "packet-scsi.h"
50 #include "epan/nstime.h"
51 #include <epan/emem.h>
53 /* the absolute values of these constants don't matter as long as
54 * latter revisions of the protocol are assigned a larger number */
55 #define ISCSI_PROTOCOL_DRAFT08 1
56 #define ISCSI_PROTOCOL_DRAFT09 2
57 #define ISCSI_PROTOCOL_DRAFT11 3
58 #define ISCSI_PROTOCOL_DRAFT12 4
59 #define ISCSI_PROTOCOL_DRAFT13 5
61 static enum_val_t iscsi_protocol_versions[] = {
62 { "draft-08", "Draft 08", ISCSI_PROTOCOL_DRAFT08 },
63 { "draft-09", "Draft 09", ISCSI_PROTOCOL_DRAFT09 },
64 { "draft-11", "Draft 11", ISCSI_PROTOCOL_DRAFT11 },
65 { "draft-12", "Draft 12", ISCSI_PROTOCOL_DRAFT12 },
66 { "draft-13", "Draft 13", ISCSI_PROTOCOL_DRAFT13 },
70 static const value_string ahs_type_vals[] = {
72 {2, "Expected Bidirection Read Data Length"},
76 static dissector_handle_t iscsi_handle=NULL;
78 static gint iscsi_protocol_version = ISCSI_PROTOCOL_DRAFT13;
80 static gboolean iscsi_desegment = TRUE;
82 static int demand_good_f_bit = FALSE;
83 static int enable_bogosity_filter = TRUE;
84 static guint32 bogus_pdu_data_length_threshold = 256 * 1024;
86 static int enableDataDigests = FALSE;
88 static int dataDigestIsCRC32 = TRUE;
90 static guint dataDigestSize = 4;
92 static guint iscsi_port = 3260;
94 /* Initialize the protocol and registered fields */
95 static int proto_iscsi = -1;
96 static int hf_iscsi_time = -1;
97 static int hf_iscsi_request_frame = -1;
98 static int hf_iscsi_data_in_frame = -1;
99 static int hf_iscsi_data_out_frame = -1;
100 static int hf_iscsi_response_frame = -1;
101 static int hf_iscsi_AHS = -1;
102 static int hf_iscsi_AHS_length = -1;
103 static int hf_iscsi_AHS_type = -1;
104 static int hf_iscsi_AHS_blob = -1;
105 static int hf_iscsi_AHS_read_data_length = -1;
106 static int hf_iscsi_AHS_extended_cdb = -1;
107 static int hf_iscsi_Padding = -1;
108 static int hf_iscsi_ping_data = -1;
109 static int hf_iscsi_immediate_data = -1;
110 static int hf_iscsi_write_data = -1;
111 static int hf_iscsi_read_data = -1;
112 static int hf_iscsi_error_pdu_data = -1;
113 static int hf_iscsi_async_message_data = -1;
114 static int hf_iscsi_vendor_specific_data = -1;
115 static int hf_iscsi_Opcode = -1;
116 static int hf_iscsi_Flags = -1;
117 static int hf_iscsi_HeaderDigest32 = -1;
118 static int hf_iscsi_DataDigest = -1;
119 static int hf_iscsi_DataDigest32 = -1;
121 static int hf_iscsi_X = -1;
123 static int hf_iscsi_I = -1;
124 static int hf_iscsi_SCSICommand_F = -1;
125 static int hf_iscsi_SCSICommand_R = -1;
126 static int hf_iscsi_SCSICommand_W = -1;
127 static int hf_iscsi_SCSICommand_Attr = -1;
128 static int hf_iscsi_SCSICommand_CRN = -1;
129 static int hf_iscsi_SCSICommand_AddCDB = -1;
130 static int hf_iscsi_DataSegmentLength = -1;
131 static int hf_iscsi_TotalAHSLength = -1;
132 static int hf_iscsi_LUN = -1;
133 static int hf_iscsi_InitiatorTaskTag = -1;
134 static int hf_iscsi_ExpectedDataTransferLength = -1;
135 static int hf_iscsi_CmdSN = -1;
136 static int hf_iscsi_ExpStatSN = -1;
137 static int hf_iscsi_StatSN = -1;
138 static int hf_iscsi_ExpCmdSN = -1;
139 static int hf_iscsi_MaxCmdSN = -1;
140 static int hf_iscsi_SCSIResponse_o = -1;
141 static int hf_iscsi_SCSIResponse_u = -1;
142 static int hf_iscsi_SCSIResponse_O = -1;
143 static int hf_iscsi_SCSIResponse_U = -1;
144 static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1;
145 static int hf_iscsi_SCSIResponse_ResidualCount = -1;
146 static int hf_iscsi_SCSIResponse_Response = -1;
147 static int hf_iscsi_SCSIResponse_Status = -1;
148 static int hf_iscsi_SenseLength = -1;
149 static int hf_iscsi_SCSIData_F = -1;
150 static int hf_iscsi_SCSIData_A = -1;
151 static int hf_iscsi_SCSIData_S = -1;
152 static int hf_iscsi_SCSIData_O = -1;
153 static int hf_iscsi_SCSIData_U = -1;
154 static int hf_iscsi_TargetTransferTag = -1;
155 static int hf_iscsi_DataSN = -1;
156 static int hf_iscsi_BufferOffset = -1;
157 static int hf_iscsi_SCSIData_ResidualCount = -1;
158 static int hf_iscsi_VersionMin = -1;
159 static int hf_iscsi_VersionMax = -1;
160 static int hf_iscsi_VersionActive = -1;
161 static int hf_iscsi_CID = -1;
162 static int hf_iscsi_ISID8 = -1;
163 static int hf_iscsi_ISID = -1;
164 /* #if defined(DRAFT09) */
165 static int hf_iscsi_ISID_Type = -1;
166 static int hf_iscsi_ISID_NamingAuthority = -1;
167 static int hf_iscsi_ISID_Qualifier = -1;
168 /* #elif !defined(DRAFT08) */
169 static int hf_iscsi_ISID_t = -1;
170 static int hf_iscsi_ISID_a = -1;
171 static int hf_iscsi_ISID_b = -1;
172 static int hf_iscsi_ISID_c = -1;
173 static int hf_iscsi_ISID_d = -1;
175 static int hf_iscsi_TSID = -1;
176 static int hf_iscsi_TSIH = -1;
177 static int hf_iscsi_InitStatSN = -1;
178 static int hf_iscsi_InitCmdSN = -1;
180 static int hf_iscsi_Login_X = -1;
182 static int hf_iscsi_Login_C = -1;
183 static int hf_iscsi_Login_T = -1;
184 static int hf_iscsi_Login_CSG = -1;
185 static int hf_iscsi_Login_NSG = -1;
186 static int hf_iscsi_Login_Status = -1;
187 static int hf_iscsi_KeyValue = -1;
188 static int hf_iscsi_Text_C = -1;
189 static int hf_iscsi_Text_F = -1;
190 static int hf_iscsi_ExpDataSN = -1;
191 static int hf_iscsi_R2TSN = -1;
192 static int hf_iscsi_TaskManagementFunction_ReferencedTaskTag = -1;
193 static int hf_iscsi_RefCmdSN = -1;
194 static int hf_iscsi_TaskManagementFunction_Function = -1;
195 static int hf_iscsi_TaskManagementFunction_Response = -1;
196 static int hf_iscsi_Logout_Reason = -1;
197 static int hf_iscsi_Logout_Response = -1;
198 static int hf_iscsi_Time2Wait = -1;
199 static int hf_iscsi_Time2Retain = -1;
200 static int hf_iscsi_DesiredDataLength = -1;
201 static int hf_iscsi_AsyncEvent = -1;
202 static int hf_iscsi_EventVendorCode = -1;
203 static int hf_iscsi_Parameter1 = -1;
204 static int hf_iscsi_Parameter2 = -1;
205 static int hf_iscsi_Parameter3 = -1;
206 static int hf_iscsi_Reject_Reason = -1;
207 static int hf_iscsi_snack_type = -1;
208 static int hf_iscsi_BegRun = -1;
209 static int hf_iscsi_RunLength = -1;
211 /* Initialize the subtree pointers */
212 static gint ett_iscsi = -1;
213 static gint ett_iscsi_KeyValues = -1;
214 static gint ett_iscsi_CDB = -1;
215 static gint ett_iscsi_Flags = -1;
216 /* #ifndef DRAFT08 */
217 static gint ett_iscsi_ISID = -1;
220 #define ISCSI_HEADER_DIGEST_AUTO 0
221 #define ISCSI_HEADER_DIGEST_NONE 1
222 #define ISCSI_HEADER_DIGEST_CRC32 2
223 /* this structure contains session wide state for a specific tcp conversation */
224 typedef struct _iscsi_session_t {
225 guint32 header_digest;
226 emem_tree_t *itlq; /* indexed by ITT */
227 emem_tree_t *itl; /* indexed by LUN */
238 #define OPCODE_MASK 0x3f
240 #define TARGET_OPCODE_BIT 0x20
242 #define ISCSI_OPCODE_NOP_OUT 0x00
243 #define ISCSI_OPCODE_SCSI_COMMAND 0x01
244 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION 0x02
245 #define ISCSI_OPCODE_LOGIN_COMMAND 0x03
246 #define ISCSI_OPCODE_TEXT_COMMAND 0x04
247 #define ISCSI_OPCODE_SCSI_DATA_OUT 0x05
248 #define ISCSI_OPCODE_LOGOUT_COMMAND 0x06
249 #define ISCSI_OPCODE_SNACK_REQUEST 0x10
250 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I0 0x1c
251 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I1 0x1d
252 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I2 0x1e
254 #define ISCSI_OPCODE_NOP_IN 0x20
255 #define ISCSI_OPCODE_SCSI_RESPONSE 0x21
256 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE 0x22
257 #define ISCSI_OPCODE_LOGIN_RESPONSE 0x23
258 #define ISCSI_OPCODE_TEXT_RESPONSE 0x24
259 #define ISCSI_OPCODE_SCSI_DATA_IN 0x25
260 #define ISCSI_OPCODE_LOGOUT_RESPONSE 0x26
261 #define ISCSI_OPCODE_R2T 0x31
262 #define ISCSI_OPCODE_ASYNC_MESSAGE 0x32
263 #define ISCSI_OPCODE_REJECT 0x3f
264 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T0 0x3c
265 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T1 0x3d
266 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T2 0x3e
269 #define CSG_MASK (0x03 << CSG_SHIFT)
270 #define NSG_MASK 0x03
272 #define ISCSI_CSG_SECURITY_NEGOTIATION (0 << CSG_SHIFT)
273 #define ISCSI_CSG_OPERATIONAL_NEGOTIATION (1 << CSG_SHIFT)
274 #define ISCSI_CSG_FULL_FEATURE_PHASE (3 << CSG_SHIFT)
276 #define ISCSI_SCSI_DATA_FLAG_S 0x01
277 #define ISCSI_SCSI_DATA_FLAG_U 0x02
278 #define ISCSI_SCSI_DATA_FLAG_O 0x04
279 #define ISCSI_SCSI_DATA_FLAG_A 0x40
280 #define ISCSI_SCSI_DATA_FLAG_F 0x80
282 static const value_string iscsi_opcodes[] = {
283 { ISCSI_OPCODE_NOP_OUT, "NOP Out" },
284 { ISCSI_OPCODE_SCSI_COMMAND, "SCSI Command" },
285 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION, "Task Management Function" },
286 { ISCSI_OPCODE_LOGIN_COMMAND, "Login Command" },
287 { ISCSI_OPCODE_TEXT_COMMAND, "Text Command" },
288 { ISCSI_OPCODE_SCSI_DATA_OUT, "SCSI Data Out" },
289 { ISCSI_OPCODE_LOGOUT_COMMAND, "Logout Command" },
290 { ISCSI_OPCODE_SNACK_REQUEST, "SNACK Request" },
291 { ISCSI_OPCODE_VENDOR_SPECIFIC_I0, "Vendor Specific I0" },
292 { ISCSI_OPCODE_VENDOR_SPECIFIC_I1, "Vendor Specific I1" },
293 { ISCSI_OPCODE_VENDOR_SPECIFIC_I2, "Vendor Specific I2" },
295 { ISCSI_OPCODE_NOP_IN, "NOP In" },
296 { ISCSI_OPCODE_SCSI_RESPONSE, "SCSI Response" },
297 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE, "Task Management Function Response" },
298 { ISCSI_OPCODE_LOGIN_RESPONSE, "Login Response" },
299 { ISCSI_OPCODE_TEXT_RESPONSE, "Text Response" },
300 { ISCSI_OPCODE_SCSI_DATA_IN, "SCSI Data In" },
301 { ISCSI_OPCODE_LOGOUT_RESPONSE, "Logout Response" },
302 { ISCSI_OPCODE_R2T, "Ready To Transfer" },
303 { ISCSI_OPCODE_ASYNC_MESSAGE, "Asynchronous Message" },
304 { ISCSI_OPCODE_REJECT, "Reject"},
305 { ISCSI_OPCODE_VENDOR_SPECIFIC_T0, "Vendor Specific T0" },
306 { ISCSI_OPCODE_VENDOR_SPECIFIC_T1, "Vendor Specific T1" },
307 { ISCSI_OPCODE_VENDOR_SPECIFIC_T2, "Vendor Specific T2" },
312 static const true_false_string iscsi_meaning_X = {
319 static const true_false_string iscsi_meaning_login_X = {
320 "Reinstate failed connection",
325 static const true_false_string iscsi_meaning_I = {
326 "Immediate delivery",
330 static const true_false_string iscsi_meaning_F = {
331 "Final PDU in sequence",
332 "Not final PDU in sequence"
335 static const true_false_string iscsi_meaning_A = {
336 "Acknowledge requested",
337 "Acknowledge not requested"
340 static const true_false_string iscsi_meaning_T = {
341 "Transit to next login stage",
342 "Stay in current login stage"
345 static const true_false_string iscsi_meaning_C = {
346 "Text is incomplete",
350 static const true_false_string iscsi_meaning_S = {
351 "Response contains SCSI status",
352 "Response does not contain SCSI status"
355 static const true_false_string iscsi_meaning_R = {
356 "Data will be read from target",
357 "No data will be read from target"
360 static const true_false_string iscsi_meaning_W = {
361 "Data will be written to target",
362 "No data will be written to target"
365 static const true_false_string iscsi_meaning_o = {
366 "Read part of bi-directional command overflowed",
367 "No overflow of read part of bi-directional command",
370 static const true_false_string iscsi_meaning_u = {
371 "Read part of bi-directional command underflowed",
372 "No underflow of read part of bi-directional command",
375 static const true_false_string iscsi_meaning_O = {
376 "Residual overflow occurred",
377 "No residual overflow occurred",
380 static const true_false_string iscsi_meaning_U = {
381 "Residual underflow occurred",
382 "No residual underflow occurred",
385 static const value_string iscsi_scsi_responses[] = {
386 { 0, "Command completed at target" },
387 { 1, "Response does not contain SCSI status"},
391 static const value_string iscsi_scsicommand_taskattrs[] = {
395 {3, "Head of Queue"},
400 static const value_string iscsi_task_management_responses[] = {
401 {0, "Function complete"},
402 {1, "Task not in task set"},
403 {2, "LUN does not exist"},
404 {3, "Task still allegiant"},
405 {4, "Task failover not supported"},
406 {5, "Task management function not supported"},
407 {6, "Authorisation failed"},
408 {255, "Function rejected"},
412 static const value_string iscsi_task_management_functions[] = {
414 {2, "Abort Task Set"},
416 {4, "Clear Task Set"},
417 {5, "Logical Unit Reset"},
418 {6, "Target Warm Reset"},
419 {7, "Target Cold Reset"},
420 {8, "Target Reassign"},
424 static const value_string iscsi_login_status[] = {
426 {0x0101, "Target moved temporarily"},
427 {0x0102, "Target moved permanently"},
428 {0x0200, "Initiator error (miscellaneous error)"},
429 {0x0201, "Authentication failed"},
430 {0x0202, "Authorisation failure"},
431 {0x0203, "Target not found"},
432 {0x0204, "Target removed"},
433 {0x0205, "Unsupported version"},
434 {0x0206, "Too many connections"},
435 {0x0207, "Missing parameter"},
436 {0x0208, "Can't include in session"},
437 {0x0209, "Session type not supported"},
438 {0x020a, "Session does not exist"},
439 {0x020b, "Invalid request during login"},
440 {0x0300, "Target error (miscellaneous error)"},
441 {0x0301, "Service unavailable"},
442 {0x0302, "Out of resources"},
446 static const value_string iscsi_login_stage[] = {
447 {0, "Security negotiation"},
448 {1, "Operational negotiation"},
449 {3, "Full feature phase"},
453 /* #ifndef DRAFT08 */
454 static const value_string iscsi_isid_type[] = {
456 {0x01, "IANA Enterprise Number"},
462 static const value_string iscsi_logout_reasons[] = {
463 {0, "Close session"},
464 {1, "Close connection"},
465 {2, "Remove connection for recovery"},
469 static const value_string iscsi_logout_response[] = {
470 {0, "Connection closed successfully"},
471 {1, "CID not found"},
472 {2, "Connection recovery not supported"},
473 {3, "Cleanup failed for various reasons"},
477 static const value_string iscsi_asyncevents[] = {
478 {0, "A SCSI asynchronous event is reported in the sense data"},
479 {1, "Target requests logout"},
480 {2, "Target will/has dropped connection"},
481 {3, "Target will/has dropped all connections"},
482 {4, "Target requests parameter negotiation"},
486 static const value_string iscsi_snack_types[] = {
489 /* #ifndef DRAFT08 */
496 static const value_string iscsi_reject_reasons[] = {
498 {0x01, "Full feature phase command before login"},
500 {0x02, "Data (payload) digest error"},
501 {0x03, "Data SNACK reject"},
502 {0x04, "Protocol error"},
503 {0x05, "Command not supported in this session type"},
504 {0x06, "Immediate command reject (too many immediate commands)"},
505 {0x07, "Task in progress"},
506 {0x08, "Invalid Data Ack"},
507 {0x09, "Invalid PDU field"},
508 {0x0a, "Long operation reject"},
509 {0x0b, "Negotiation reset"},
510 {0x0c, "Waiting for logout"},
514 /*****************************************************************/
516 /* CRC LOOKUP TABLE */
517 /* ================ */
518 /* The following CRC lookup table was generated automagically */
519 /* by the Rocksoft^tm Model CRC Algorithm Table Generation */
520 /* Program V1.0 using the following model parameters: */
522 /* Width : 4 bytes. */
523 /* Poly : 0x1EDC6F41L */
524 /* Reverse : TRUE. */
526 /* For more information on the Rocksoft^tm Model CRC Algorithm, */
527 /* see the document titled "A Painless Guide to CRC Error */
528 /* Detection Algorithms" by Ross Williams */
529 /* (ross@guest.adelaide.edu.au.). This document is likely to be */
530 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
532 /*****************************************************************/
534 static guint32 crc32Table[256] = {
535 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
536 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
537 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
538 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
539 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
540 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
541 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
542 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
543 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
544 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
545 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
546 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
547 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
548 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
549 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
550 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
551 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
552 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
553 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
554 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
555 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
556 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
557 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
558 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
559 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
560 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
561 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
562 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
563 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
564 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
565 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
566 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
567 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
568 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
569 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
570 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
571 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
572 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
573 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
574 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
575 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
576 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
577 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
578 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
579 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
580 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
581 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
582 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
583 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
584 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
585 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
586 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
587 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
588 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
589 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
590 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
591 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
592 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
593 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
594 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
595 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
596 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
597 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
598 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
601 #define CRC32C_PRELOAD 0xffffffff
604 * Byte swap fix contributed by Dave Wysochanski <davidw@netapp.com>
606 #define CRC32C_SWAP(crc32c_value) \
607 (((crc32c_value & 0xff000000) >> 24) | \
608 ((crc32c_value & 0x00ff0000) >> 8) | \
609 ((crc32c_value & 0x0000ff00) << 8) | \
610 ((crc32c_value & 0x000000ff) << 24))
613 calculateCRC32(const void *buf, int len, guint32 crc) {
614 const guint8 *p = (const guint8 *)buf;
615 crc = CRC32C_SWAP(crc);
617 crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
618 return CRC32C_SWAP(crc);
625 /* structure and functions to keep track of
626 * COMMAND/DATA_IN/DATA_OUT/RESPONSE matching
628 typedef struct _iscsi_conv_data {
629 guint32 data_in_frame;
630 guint32 data_out_frame;
635 iscsi_min(int a, int b) {
636 return (a < b)? a : b;
640 addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
641 const gint limit = offset + text_len;
642 while(offset < limit) {
643 gint len = tvb_strnlen(tvb, offset, limit - offset);
645 len = limit - offset;
648 proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, FALSE);
655 handleHeaderDigest(iscsi_session_t *iscsi_session, proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
656 int available_bytes = tvb_length_remaining(tvb, offset);
658 switch(iscsi_session->header_digest){
659 case ISCSI_HEADER_DIGEST_CRC32:
660 if(available_bytes >= (headerLen + 4)) {
661 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
662 guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
664 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
666 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);
669 return offset + headerLen + 4;
672 return offset + headerLen;
676 handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) {
677 int available_bytes = tvb_length_remaining(tvb, offset);
678 if(enableDataDigests) {
679 if(dataDigestIsCRC32) {
680 if(available_bytes >= (dataLen + 4)) {
681 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
682 guint32 sent = tvb_get_ntohl(tvb, offset + dataLen);
684 proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Good CRC32)", sent);
687 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);
690 return offset + dataLen + 4;
692 if((unsigned)available_bytes >= (dataLen + dataDigestSize)) {
693 proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, FALSE);
695 return offset + dataLen + dataDigestSize;
697 return offset + dataLen;
701 handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) {
702 if(endOffset > offset) {
703 int dataOffset = offset;
704 int dataLen = iscsi_min(dataSegmentLen, endOffset - offset);
706 proto_tree_add_item(ti, hf_id, tvb, offset, dataLen, FALSE);
709 if(offset < endOffset && (offset & 3) != 0) {
710 int padding = 4 - (offset & 3);
711 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
714 if(dataSegmentLen > 0 && offset < endOffset)
715 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
722 handleDataSegmentAsTextKeys(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) {
723 if(endOffset > offset) {
724 int dataOffset = offset;
725 int textLen = iscsi_min(dataSegmentLen, endOffset - offset);
727 proto_item *tf = proto_tree_add_text(ti, tvb, offset, textLen, "Key/Value Pairs");
728 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
729 offset = addTextKeys(tt, tvb, offset, textLen);
731 if(offset < endOffset && (offset & 3) != 0) {
732 int padding = 4 - (offset & 3);
733 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
736 if(digestsActive && dataSegmentLen > 0 && offset < endOffset)
737 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
742 /* Code to actually dissect the packets */
744 dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 opcode, const char *opcode_str, guint32 data_segment_len, iscsi_session_t *iscsi_session) {
746 guint original_offset = offset;
747 proto_tree *ti = NULL;
748 guint8 scsi_status = 0;
749 gboolean S_bit=FALSE;
750 guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
751 guint end_offset = offset + tvb_length_remaining(tvb, offset);
752 iscsi_conv_data_t *cdata = NULL;
753 int paddedDataSegmentLength = data_segment_len;
755 guint immediate_data_length=0;
756 guint immediate_data_offset=0;
757 itl_nexus_t *itl=NULL;
758 guint ahs_cdb_length=0;
759 guint ahs_cdb_offset=0;
761 if(paddedDataSegmentLength & 3)
762 paddedDataSegmentLength += 4 - (paddedDataSegmentLength & 3);
764 /* Make entries in Protocol column and Info column on summary display */
765 if (check_col(pinfo->cinfo, COL_PROTOCOL))
766 col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
768 /* XXX we need a way to handle replayed iscsi itt here */
769 cdata=(iscsi_conv_data_t *)se_tree_lookup32(iscsi_session->itlq, tvb_get_ntohl(tvb, offset+16));
771 cdata = se_alloc (sizeof(iscsi_conv_data_t));
772 cdata->itlq.lun=0xffff;
773 cdata->itlq.scsi_opcode=0xffff;
774 cdata->itlq.fc_time = pinfo->fd->abs_ts;
775 cdata->itlq.first_exchange_frame=0;
776 cdata->itlq.last_exchange_frame=0;
778 cdata->itlq.alloc_len=0;
779 cdata->itlq.extra_data=NULL;
780 cdata->data_in_frame=0;
781 cdata->data_out_frame=0;
783 se_tree_insert32(iscsi_session->itlq, tvb_get_ntohl(tvb, offset+16), cdata);
786 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
787 opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
788 scsi_status = tvb_get_guint8 (tvb, offset+3);
791 if ((opcode == ISCSI_OPCODE_SCSI_RESPONSE) ||
792 (opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
793 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
794 /* first time we see this packet. check if we can find the request */
796 case ISCSI_OPCODE_SCSI_RESPONSE:
797 cdata->itlq.last_exchange_frame=pinfo->fd->num;
799 case ISCSI_OPCODE_SCSI_DATA_IN:
800 /* a bit ugly but we need to check the S bit here */
801 if(tvb_get_guint8(tvb, offset+1)&ISCSI_SCSI_DATA_FLAG_S){
802 cdata->itlq.last_exchange_frame=pinfo->fd->num;
804 cdata->data_in_frame=pinfo->fd->num;
806 case ISCSI_OPCODE_SCSI_DATA_OUT:
807 cdata->data_out_frame=pinfo->fd->num;
811 } else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
812 /*we need the LUN value for some of the commands so we can pass it
813 across to the SCSI dissector.
814 Not correct but simple and probably accurate enough :
815 If bit 6 of first bit is 0 then just take second byte as the LUN
816 If bit 6 of first bit is 1, then take 6 bits from first byte
817 and all of second byte and pretend it is the lun value
818 people that care can add host specific dissection of vsa later.
820 We need to keep track of this on a per transaction basis since
821 for error recoverylevel 0 and when the A bit is clear in a
822 Data-In PDU, there will not be a LUN field in teh iscsi layer.
824 if(tvb_get_guint8(tvb, offset+8)&0x40){
825 /* volume set addressing */
826 lun=tvb_get_guint8(tvb,offset+8)&0x3f;
828 lun|=tvb_get_guint8(tvb,offset+9);
830 lun=tvb_get_guint8(tvb,offset+9);
834 cdata->itlq.first_exchange_frame=pinfo->fd->num;
836 itl=(itl_nexus_t *)se_tree_lookup32(iscsi_session->itl, lun);
838 itl=se_alloc(sizeof(itl_nexus_t));
840 se_tree_insert32(iscsi_session->itl, lun, itl);
846 itl=(itl_nexus_t *)se_tree_lookup32(iscsi_session->itl, cdata->itlq.lun);
850 if (check_col(pinfo->cinfo, COL_INFO)) {
852 if (opcode != ISCSI_OPCODE_SCSI_COMMAND) {
854 col_append_str(pinfo->cinfo, COL_INFO, opcode_str);
856 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
857 (opcode == ISCSI_OPCODE_SCSI_DATA_IN &&
858 (tvb_get_guint8(tvb, offset + 1) & ISCSI_SCSI_DATA_FLAG_S))) {
859 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
860 val_to_str (scsi_status, scsi_status_val, "0x%x"));
862 else if (opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
863 guint16 login_status = tvb_get_ntohs(tvb, offset+36);
864 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
865 val_to_str (login_status, iscsi_login_status, "0x%x"));
867 else if (opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
869 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
870 logoutReason = tvb_get_guint8(tvb, offset+11);
871 } else if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
872 logoutReason = tvb_get_guint8(tvb, offset+1) & 0x7f;
875 logoutReason = tvb_get_guint8(tvb, offset+23);
877 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
878 val_to_str (logoutReason, iscsi_logout_reasons, "0x%x"));
880 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
881 guint8 tmf = tvb_get_guint8(tvb, offset + 1);
882 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
883 val_to_str (tmf, iscsi_task_management_functions, "0x%x"));
885 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
886 guint8 resp = tvb_get_guint8(tvb, offset + 2);
887 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
888 val_to_str (resp, iscsi_task_management_responses, "0x%x"));
890 else if (opcode == ISCSI_OPCODE_REJECT) {
891 guint8 reason = tvb_get_guint8(tvb, offset + 2);
892 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
893 val_to_str (reason, iscsi_reject_reasons, "0x%x"));
895 else if (opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
896 guint8 asyncEvent = tvb_get_guint8(tvb, offset + 36);
897 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
898 val_to_str (asyncEvent, iscsi_asyncevents, "0x%x"));
903 /* In the interest of speed, if "tree" is NULL, don't do any
904 work not necessary to generate protocol tree items. */
907 /* create display subtree for the protocol */
908 tp = proto_tree_add_protocol_format(tree, proto_iscsi, tvb,
909 offset, -1, "iSCSI (%s)",
911 ti = proto_item_add_subtree(tp, ett_iscsi);
913 proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
914 offset + 0, 1, opcode);
915 if((opcode & TARGET_OPCODE_BIT) == 0) {
916 /* initiator -> target */
917 gint b = tvb_get_guint8(tvb, offset + 0);
918 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
919 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
920 opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
921 opcode != ISCSI_OPCODE_SNACK_REQUEST)
922 proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
924 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
925 opcode != ISCSI_OPCODE_LOGIN_COMMAND &&
926 opcode != ISCSI_OPCODE_SNACK_REQUEST)
927 proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
930 if(opcode == ISCSI_OPCODE_NOP_OUT) {
932 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
933 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
935 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
936 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
937 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
938 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
939 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
940 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
941 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
942 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
943 } else if(opcode == ISCSI_OPCODE_NOP_IN) {
945 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
946 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
948 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
949 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
950 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
951 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
952 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
953 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
954 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
955 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
956 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
957 } else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
959 guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
961 gint b = tvb_get_guint8(tvb, offset + 1);
962 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
963 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
965 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
966 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
967 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
968 proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
970 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
971 proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, FALSE);
973 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
974 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
975 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
976 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
977 proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, FALSE);
978 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
979 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
981 int ahs_offset=offset+48;
982 guint16 ahs_length=0;
985 while(ahs_offset<(offset+48+ahsLen)){
987 ahs_length=tvb_get_ntohs(tvb, ahs_offset);
988 proto_tree_add_item(ti, hf_iscsi_AHS_length, tvb, ahs_offset, 2, FALSE);
991 ahs_type=tvb_get_guint8(tvb, ahs_offset);
992 proto_tree_add_item(ti, hf_iscsi_AHS_type, tvb, ahs_offset, 1, FALSE);
996 case 0x01: /* extended CDB */
998 ahs_cdb_offset=ahs_offset+1;
999 ahs_cdb_length=ahs_length-1;
1000 proto_tree_add_item(ti, hf_iscsi_AHS_extended_cdb, tvb, ahs_cdb_offset, ahs_cdb_length, FALSE);
1001 ahs_offset+=ahs_length;
1003 case 0x02: /* bidirectional read data length */
1004 /* skip reserved byte */
1006 /* read data length */
1007 proto_tree_add_item(ti, hf_iscsi_AHS_read_data_length, tvb, ahs_offset, 4, FALSE);
1011 proto_tree_add_item(ti, hf_iscsi_AHS_blob, tvb, ahs_offset, ahs_length, FALSE);
1012 ahs_offset+=ahs_length;
1015 /* strip off padding bytes */
1016 if(ahs_offset&0x0003){
1017 ahs_offset=(ahs_offset+3)&0xfffc;
1023 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48 + ahsLen);
1025 immediate_data_offset=offset;
1026 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
1027 immediate_data_length=offset-immediate_data_offset;
1028 } else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1031 gint b = tvb_get_guint8(tvb, offset + 1);
1032 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1033 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1035 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
1036 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
1037 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
1038 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
1040 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Response, tvb, offset + 2, 1, FALSE);
1041 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
1042 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1043 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1045 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1046 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1047 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1048 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 20, 4, FALSE);
1050 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1051 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1052 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1053 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1054 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1055 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, FALSE);
1058 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 40, 4, FALSE);
1059 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 44, 4, FALSE);
1061 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1062 /* do not update offset here because the data segment is
1063 * dissected below */
1064 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1065 } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
1066 /* Task Management Function */
1067 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, FALSE);
1068 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1069 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1070 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1072 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1073 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1074 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1075 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1076 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1077 proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
1078 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1079 } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
1080 /* Task Management Function Response */
1081 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Response, tvb, offset + 2, 1, FALSE);
1082 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1083 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1084 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1086 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1087 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1088 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1090 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1091 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1092 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1093 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1094 } else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
1096 int digestsActive = 0;
1098 gint b = tvb_get_guint8(tvb, offset + 1);
1099 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1100 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1104 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1105 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1108 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1109 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1110 proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1112 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1113 proto_tree_add_boolean(ti, hf_iscsi_Login_X, tvb, offset + 1, 1, b);
1115 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
1117 /* NSG is undefined unless T is set */
1119 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
1122 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1123 proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
1124 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1125 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1127 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1128 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1129 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1130 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, FALSE);
1133 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
1134 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1135 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1136 proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, FALSE);
1137 proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, FALSE);
1138 proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, FALSE);
1141 proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, FALSE);
1142 proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, FALSE);
1143 proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, FALSE);
1144 proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, FALSE);
1145 proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, FALSE);
1148 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1149 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1152 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, FALSE);
1154 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1155 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1156 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
1158 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1159 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1161 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1165 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1166 } else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1167 /* Login Response */
1168 int digestsActive = 0;
1170 gint b = tvb_get_guint8(tvb, offset + 1);
1171 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1172 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1176 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1177 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1180 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1181 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1182 proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1184 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
1185 /* NSG is undefined unless T is set */
1187 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
1191 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1192 proto_tree_add_item(ti, hf_iscsi_VersionActive, tvb, offset + 3, 1, FALSE);
1193 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1194 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1196 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1197 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1198 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, FALSE);
1201 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
1202 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1203 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1204 proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, FALSE);
1205 proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, FALSE);
1206 proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, FALSE);
1209 proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, FALSE);
1210 proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, FALSE);
1211 proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, FALSE);
1212 proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, FALSE);
1213 proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, FALSE);
1216 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1217 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1220 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, FALSE);
1222 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1223 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1224 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1225 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1226 proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, FALSE);
1228 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1232 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1233 } else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
1236 gint b = tvb_get_guint8(tvb, offset + 1);
1237 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1238 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1240 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1241 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1242 proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1245 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1246 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1248 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1249 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1250 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1252 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1253 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1254 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1255 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1256 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1257 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1258 } else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
1261 gint b = tvb_get_guint8(tvb, offset + 1);
1262 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1263 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1265 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1266 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1267 proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1270 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1271 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1273 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1274 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1275 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1277 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1278 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1279 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1280 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1281 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1282 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1283 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1284 } else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
1285 /* SCSI Data Out (write) */
1287 gint b = tvb_get_guint8(tvb, offset + 1);
1288 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1289 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1291 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1293 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1294 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1296 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1297 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1298 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1299 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1300 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1301 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1302 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1303 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1304 /* do not update offset here because the data segment is
1305 * dissected below */
1306 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1307 } else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
1308 /* SCSI Data In (read) */
1310 gint b = tvb_get_guint8(tvb, offset + 1);
1311 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1312 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1314 if(b&ISCSI_SCSI_DATA_FLAG_S){
1317 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1318 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1319 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_A, tvb, offset + 1, 1, b);
1321 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
1322 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
1323 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
1326 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
1328 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1329 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1331 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1332 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1333 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1335 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1336 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1337 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 20, 4, FALSE);
1340 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1342 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1343 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1344 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1345 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1346 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1347 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1348 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 44, 4, FALSE);
1350 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1351 /* do not update offset here because the data segment is
1352 * dissected below */
1353 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1354 } else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
1355 /* Logout Command */
1356 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1357 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 1, 1, FALSE);
1359 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1360 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1361 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1363 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1364 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1365 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, FALSE);
1367 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1368 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1369 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
1370 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT13) {
1371 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 23, 1, FALSE);
1374 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1375 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1376 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1377 } else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
1378 /* Logout Response */
1379 proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, FALSE);
1380 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1381 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1382 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1384 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1385 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1386 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1387 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1388 proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, FALSE);
1389 proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, FALSE);
1390 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1391 } else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
1394 gint b = tvb_get_guint8(tvb, offset + 1);
1396 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1397 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1400 proto_tree_add_item(ti, hf_iscsi_snack_type, tvb, offset + 1, 1, b);
1402 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1403 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1404 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1405 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1407 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1408 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1409 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, FALSE);
1410 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, FALSE);
1411 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1412 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1415 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1416 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1417 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 40, 4, FALSE);
1418 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 44, 4, FALSE);
1420 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1421 } else if(opcode == ISCSI_OPCODE_R2T) {
1423 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1424 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1425 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1426 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1428 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1429 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1430 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1431 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1432 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1433 proto_tree_add_item(ti, hf_iscsi_R2TSN, tvb, offset + 36, 4, FALSE);
1434 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1435 proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
1436 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1437 } else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1438 /* Asynchronous Message */
1439 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1440 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1442 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1443 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1444 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1445 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1446 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1447 proto_tree_add_item(ti, hf_iscsi_AsyncEvent, tvb, offset + 36, 1, FALSE);
1448 proto_tree_add_item(ti, hf_iscsi_EventVendorCode, tvb, offset + 37, 1, FALSE);
1449 proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, FALSE);
1450 proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
1451 proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
1452 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1453 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_async_message_data);
1454 } else if(opcode == ISCSI_OPCODE_REJECT) {
1456 proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
1457 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1458 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1460 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1461 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1462 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1463 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1464 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1465 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1466 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_error_pdu_data);
1467 } else if(opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I0 ||
1468 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I1 ||
1469 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I2 ||
1470 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T0 ||
1471 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T1 ||
1472 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T2) {
1473 /* Vendor specific opcodes */
1474 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1475 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1477 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1478 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1479 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_vendor_specific_data);
1484 /* handle request/response matching */
1486 case ISCSI_OPCODE_SCSI_RESPONSE:
1487 if (cdata->itlq.first_exchange_frame){
1488 nstime_t delta_time;
1489 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1490 nstime_delta(&delta_time, &pinfo->fd->abs_ts, &cdata->itlq.fc_time);
1491 proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1493 if (cdata->data_in_frame)
1494 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1495 if (cdata->data_out_frame)
1496 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1498 case ISCSI_OPCODE_SCSI_DATA_IN:
1499 /* if we have phase collaps then we might have the
1500 response embedded in the last DataIn segment */
1502 if (cdata->itlq.first_exchange_frame)
1503 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1504 if (cdata->itlq.last_exchange_frame)
1505 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
1507 if (cdata->itlq.first_exchange_frame){
1508 nstime_t delta_time;
1509 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1510 nstime_delta(&delta_time, &pinfo->fd->abs_ts, &cdata->itlq.fc_time);
1511 proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1514 if (cdata->data_out_frame)
1515 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1517 case ISCSI_OPCODE_SCSI_DATA_OUT:
1518 if (cdata->itlq.first_exchange_frame)
1519 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1520 if (cdata->data_in_frame)
1521 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1522 if (cdata->itlq.last_exchange_frame)
1523 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
1525 case ISCSI_OPCODE_SCSI_COMMAND:
1526 if (cdata->data_in_frame)
1527 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1528 if (cdata->data_out_frame)
1529 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1530 if (cdata->itlq.last_exchange_frame)
1531 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
1537 proto_item_set_len(ti, offset - original_offset);
1539 if((opcode & ((iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08)?
1541 ~I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND) {
1542 tvbuff_t *cdb_tvb, *data_tvb;
1543 int tvb_len, tvb_rlen;
1547 tvb_len=tvb_length_remaining(tvb, cdb_offset);
1548 tvb_rlen=tvb_reported_length_remaining(tvb, cdb_offset);
1549 scsi_opcode=tvb_get_guint8(tvb, cdb_offset);
1550 if(ahs_cdb_length && ahs_cdb_length<1024){
1553 /* We have a variable length CDB where bytes >16 is transported
1556 cdb_buf=ep_alloc(16+ahs_cdb_length);
1557 /* the 16 first bytes of the cdb */
1558 tvb_memcpy(tvb, cdb_buf, cdb_offset, 16);
1559 /* the remainder of the cdb from the ahs */
1560 tvb_memcpy(tvb, cdb_buf+16, ahs_cdb_offset, ahs_cdb_length);
1562 cdb_tvb = tvb_new_real_data(cdb_buf,
1566 tvb_set_child_real_data_tvbuff(tvb, cdb_tvb);
1568 add_new_data_source(pinfo, cdb_tvb, "CDB+AHS");
1576 cdb_tvb=tvb_new_subset(tvb, cdb_offset, tvb_len, tvb_rlen);
1578 dissect_scsi_cdb(cdb_tvb, pinfo, tree, SCSI_DEV_UNKNOWN, &cdata->itlq, itl);
1579 /* we dont want the immediata below to overwrite our CDB info */
1580 if (check_col(pinfo->cinfo, COL_INFO)) {
1581 col_set_fence(pinfo->cinfo, COL_INFO);
1583 /* where there any ImmediateData ? */
1584 if(immediate_data_length){
1585 /* Immediate Data TVB */
1586 tvb_len=tvb_length_remaining(tvb, immediate_data_offset);
1587 if(tvb_len>(int)immediate_data_length)
1588 tvb_len=immediate_data_length;
1589 tvb_rlen=tvb_reported_length_remaining(tvb, immediate_data_offset);
1590 if(tvb_rlen>(int)immediate_data_length)
1591 tvb_rlen=immediate_data_length;
1592 data_tvb=tvb_new_subset(tvb, immediate_data_offset, tvb_len, tvb_rlen);
1593 dissect_scsi_payload (data_tvb, pinfo, tree,
1598 else if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1599 if (scsi_status == 0x2) {
1600 /* A SCSI response with Check Condition contains sense data */
1601 /* offset is setup correctly by the iscsi code for response above */
1602 if((end_offset - offset) >= 2) {
1603 int senseLen = tvb_get_ntohs(tvb, offset);
1605 proto_tree_add_item(ti, hf_iscsi_SenseLength, tvb, offset, 2, FALSE);
1609 int tvb_len, tvb_rlen;
1611 tvb_len=tvb_length_remaining(tvb, offset);
1612 if(tvb_len>senseLen)
1614 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1615 if(tvb_rlen>senseLen)
1617 data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1618 dissect_scsi_snsinfo (data_tvb, pinfo, tree, 0,
1625 dissect_scsi_rsp(tvb, pinfo, tree, &cdata->itlq, itl, scsi_status);
1628 else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
1629 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
1631 int tvb_len, tvb_rlen;
1633 /* offset is setup correctly by the iscsi code for response above */
1634 tvb_len=tvb_length_remaining(tvb, offset);
1635 if(tvb_len>(int)data_segment_len)
1636 tvb_len=data_segment_len;
1637 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1638 if(tvb_rlen>(int)data_segment_len)
1639 tvb_rlen=data_segment_len;
1640 data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1641 dissect_scsi_payload (data_tvb, pinfo, tree,
1642 (opcode==ISCSI_OPCODE_SCSI_DATA_OUT),
1647 dissect_scsi_rsp(tvb, pinfo, tree, &cdata->itlq, itl, scsi_status);
1652 dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean check_port) {
1653 /* Set up structures needed to add the protocol subtree and manage it */
1654 guint iSCSIPdusDissected = 0;
1656 guint32 available_bytes = tvb_length_remaining(tvb, offset);
1657 int digestsActive = 1;
1658 conversation_t *conversation = NULL;
1659 iscsi_session_t *iscsi_session=NULL;
1660 guint8 opcode, tmpbyte;
1662 /* quick check to see if the packet is long enough to contain the
1663 * minimum amount of information we need */
1664 if (available_bytes < 48 ){
1665 /* no, so give up */
1669 opcode = tvb_get_guint8(tvb, offset + 0);
1670 opcode &= OPCODE_MASK;
1672 /* heuristics to verify that the packet looks sane. the heuristics
1673 * are based on the RFC version of iscsi.
1674 * (we should retire support for older iscsi versions in wireshark)
1677 /* opcode must be any of the ones from the standard
1678 * also check the header that it looks "sane"
1679 * all reserved or undefined bits in iscsi must be set to zero.
1682 case ISCSI_OPCODE_NOP_IN:
1683 /* top two bits of byte 0 must be 0 */
1684 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1687 /* byte 1 must be 0x80 */
1688 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1691 /* bytes 2 and 3 must be 0 */
1692 if(tvb_get_guint8(tvb, offset+2)||tvb_get_guint8(tvb, offset+3)){
1696 case ISCSI_OPCODE_NOP_OUT:
1697 /* top bit of byte 0 must be 0 */
1698 if(tvb_get_guint8(tvb, offset+0)&0x80){
1701 /* byte 1 must be 0x80 */
1702 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1705 /* bytes 2 and 3 must be 0 */
1706 if(tvb_get_guint8(tvb, offset+2)||tvb_get_guint8(tvb, offset+3)){
1709 /* assume ITT and TTT must always be non NULL (ok they can be NULL
1710 * from time to time but it usually means we are in the middle
1711 * of a zeroed datablock).
1713 if(!tvb_get_letohl(tvb,offset+16) || !tvb_get_letohl(tvb,offset+20)){
1716 /* all reserved bytes between 32 - 47 must be null */
1717 if(tvb_get_letohl(tvb,offset+32)
1718 || tvb_get_letohl(tvb,offset+36)
1719 || tvb_get_letohl(tvb,offset+40)
1720 || tvb_get_letohl(tvb,offset+44)){
1724 case ISCSI_OPCODE_LOGIN_COMMAND:
1725 /* top two bits in byte 0 must be 0x40 */
1726 if((tvb_get_guint8(tvb, offset+0)&0xc0)!=0x40){
1730 /* exactly one of the T and C bits must be set
1731 * and the two reserved bits in byte 1 must be 0
1733 tmpbyte=tvb_get_guint8(tvb, offset+1);
1734 switch(tmpbyte&0xf0){
1741 /* CSG and NSG must not be 2 */
1742 if(((tmpbyte&0x03)==0x02)
1743 || ((tmpbyte&0xc0)==0x08)){
1746 /* if T bit is set NSG must not be 0 */
1748 if(!(tmpbyte&0x03)){
1752 /* should we test that datasegmentlen is non zero? */
1754 case ISCSI_OPCODE_LOGIN_RESPONSE:
1755 /* top two bits in byte 0 must be 0 */
1756 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1760 /* both the T and C bits can not be set
1761 * and the two reserved bits in byte 1 must be 0
1763 tmpbyte=tvb_get_guint8(tvb, offset+1);
1764 switch(tmpbyte&0xf0){
1772 /* CSG and NSG must not be 2 */
1773 if(((tmpbyte&0x03)==0x02)
1774 || ((tmpbyte&0xc0)==0x08)){
1777 /* if T bit is set NSG must not be 0 */
1779 if(!(tmpbyte&0x03)){
1783 /* the 32bit words at offsets 20, 40, 44 must be zero */
1784 if(tvb_get_letohl(tvb,offset+20)
1785 || tvb_get_letohl(tvb,offset+40)
1786 || tvb_get_letohl(tvb,offset+44)){
1789 /* the two bytes at offset 38 must be zero */
1790 if(tvb_get_letohs(tvb,offset+38)){
1793 /* should we test that datasegmentlen is non zero unless we just
1794 * entered full featured phase?
1797 case ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION:
1798 /* top bit in byte 0 must be 0 */
1799 if(tvb_get_guint8(tvb, offset+0)&0x80){
1802 /* top bit in byte 1 must be set */
1803 tmpbyte=tvb_get_guint8(tvb, offset+1);
1804 if(!(tmpbyte&0x80)){
1807 /* Function must be known */
1808 if(!match_strval(tmpbyte&0x7f, iscsi_task_management_functions)){
1811 /* bytes 2,3 must be null */
1812 if(tvb_get_letohs(tvb,offset+2)){
1815 /* ahs and dsl must be null */
1816 if(tvb_get_letohl(tvb,offset+4)){
1820 case ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE:
1821 /* top two bits in byte 0 must be 0 */
1822 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1825 /* byte 1 must be 0x80 */
1826 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1829 /* response must be 0-6 or 255 */
1830 tmpbyte=tvb_get_guint8(tvb,offset+2);
1831 if(tmpbyte>6 && tmpbyte<255){
1834 /* byte 3 must be 0 */
1835 if(tvb_get_guint8(tvb,offset+3)){
1838 /* ahs and dsl as well as the 32bit words at offsets 8, 12, 20, 36
1839 * 40, 44 must all be 0
1841 if(tvb_get_letohl(tvb,offset+4)
1842 || tvb_get_letohl(tvb,offset+8)
1843 || tvb_get_letohl(tvb,offset+12)
1844 || tvb_get_letohl(tvb,offset+20)
1845 || tvb_get_letohl(tvb,offset+36)
1846 || tvb_get_letohl(tvb,offset+40)
1847 || tvb_get_letohl(tvb,offset+44)){
1851 case ISCSI_OPCODE_LOGOUT_COMMAND:
1852 /* top bit in byte 0 must be 0 */
1853 if(tvb_get_guint8(tvb, offset+0)&0x80){
1856 /* top bit in byte 1 must be set */
1857 tmpbyte=tvb_get_guint8(tvb, offset+1);
1858 if(!(tmpbyte&0x80)){
1861 /* Reason code must be known */
1862 if(!match_strval(tmpbyte&0x7f, iscsi_logout_reasons)){
1865 /* bytes 2,3 must be null */
1866 if(tvb_get_letohs(tvb,offset+2)){
1869 /* ahs and dsl as well as the 32bit words at offsets 8, 12, 32, 36
1870 * 40, 44 must all be 0
1872 if(tvb_get_letohl(tvb,offset+4)
1873 || tvb_get_letohl(tvb,offset+8)
1874 || tvb_get_letohl(tvb,offset+12)
1875 || tvb_get_letohl(tvb,offset+32)
1876 || tvb_get_letohl(tvb,offset+36)
1877 || tvb_get_letohl(tvb,offset+40)
1878 || tvb_get_letohl(tvb,offset+44)){
1882 case ISCSI_OPCODE_SNACK_REQUEST:
1883 /* top two bits in byte 0 must be 0 */
1884 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1887 /* top 4 bits in byte 1 must be 0x80 */
1888 tmpbyte=tvb_get_guint8(tvb, offset+1);
1889 if((tmpbyte&0xf0)!=0x80){
1892 /* type must be known */
1893 if(!match_strval(tmpbyte&0x0f, iscsi_snack_types)){
1896 /* for status/snack and datack itt must be 0xffffffff
1897 * for rdata/snack ttt must not be 0 or 0xffffffff
1899 switch(tmpbyte&0x0f){
1902 if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
1907 if(tvb_get_letohl(tvb,offset+20)==0xffffffff){
1910 if(tvb_get_letohl(tvb,offset+20)==0){
1915 /* bytes 2,3 must be null */
1916 if(tvb_get_letohs(tvb,offset+2)){
1919 /* the 32bit words at offsets 24, 32, 36
1922 if(tvb_get_letohl(tvb,offset+24)
1923 || tvb_get_letohl(tvb,offset+32)
1924 || tvb_get_letohl(tvb,offset+36)){
1929 case ISCSI_OPCODE_R2T:
1930 /* top two bits in byte 0 must be 0 */
1931 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1934 /* byte 1 must be 0x80 */
1935 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1938 /* bytes 2,3 must be null */
1939 if(tvb_get_letohs(tvb,offset+2)){
1942 /* ahs and dsl must be null */
1943 if(tvb_get_letohl(tvb,offset+4)){
1946 /* desired data transfer length must not be null */
1947 if(!tvb_get_letohl(tvb,offset+44)){
1951 case ISCSI_OPCODE_REJECT:
1952 /* top two bits in byte 0 must be 0 */
1953 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1956 /* byte 1 must be 0x80 */
1957 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1960 /* reason must be known */
1961 if(!match_strval(tvb_get_guint8(tvb,offset+2), iscsi_reject_reasons)){
1964 /* byte 3 must be 0 */
1965 if(tvb_get_guint8(tvb, offset+3)){
1968 /* the 32bit words at offsets 8, 12, 20, 40, 44
1971 if(tvb_get_letohl(tvb,offset+8)
1972 || tvb_get_letohl(tvb,offset+12)
1973 || tvb_get_letohl(tvb,offset+20)
1974 || tvb_get_letohl(tvb,offset+40)
1975 || tvb_get_letohl(tvb,offset+44)){
1978 /* the 32bit word at 16 must be 0xffffffff */
1979 if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
1983 case ISCSI_OPCODE_TEXT_COMMAND:
1984 /* top bit in byte 0 must be 0 */
1985 if(tvb_get_guint8(tvb, offset+0)&0x80){
1988 /* one of the F and C bits must be set but not both
1989 * low 6 bits in byte 1 must be 0
1991 switch(tvb_get_guint8(tvb,offset+1)){
1998 /* bytes 2,3 must be null */
1999 if(tvb_get_letohs(tvb,offset+2)){
2002 /* the 32bit words at offsets 32, 36, 40, 44
2005 if(tvb_get_letohl(tvb,offset+32)
2006 || tvb_get_letohl(tvb,offset+36)
2007 || tvb_get_letohl(tvb,offset+40)
2008 || tvb_get_letohl(tvb,offset+44)){
2012 case ISCSI_OPCODE_TEXT_RESPONSE:
2013 /* top two bits in byte 0 must be 0 */
2014 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2017 /* one of the F and C bits must be set but not both
2018 * low 6 bits in byte 1 must be 0
2020 switch(tvb_get_guint8(tvb,offset+1)){
2027 /* bytes 2,3 must be null */
2028 if(tvb_get_letohs(tvb,offset+2)){
2031 /* the 32bit words at offsets 36, 40, 44
2034 if(tvb_get_letohl(tvb,offset+36)
2035 || tvb_get_letohl(tvb,offset+40)
2036 || tvb_get_letohl(tvb,offset+44)){
2040 case ISCSI_OPCODE_SCSI_COMMAND:
2041 /* top bit in byte 0 must be 0 */
2042 if(tvb_get_guint8(tvb, offset+0)&0x80){
2045 /* reserved bits in byte 1 must be 0 */
2046 if(tvb_get_guint8(tvb, offset+1)&0x18){
2049 /* bytes 2,3 must be null */
2050 if(tvb_get_letohs(tvb,offset+2)){
2053 /* expected data transfer length is never >16MByte ? */
2054 if(tvb_get_guint8(tvb,offset+20)){
2058 case ISCSI_OPCODE_SCSI_RESPONSE:
2059 /* top two bits in byte 0 must be 0 */
2060 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2063 /* top bit in byte 1 must be 1 */
2064 tmpbyte=tvb_get_guint8(tvb,offset+1);
2065 if(!(tmpbyte&0x80)){
2068 /* the reserved bits in byte 1 must be 0 */
2072 /* status must be known */
2073 if(!match_strval(tvb_get_guint8(tvb,offset+3), scsi_status_val)){
2076 /* the 32bit words at offsets 8, 12
2079 if(tvb_get_letohl(tvb,offset+8)
2080 || tvb_get_letohl(tvb,offset+12)){
2084 case ISCSI_OPCODE_ASYNC_MESSAGE:
2085 /* top two bits in byte 0 must be 0 */
2086 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2089 /* byte 1 must be 0x80 */
2090 if(tvb_get_guint8(tvb, offset+1)!=0x80){
2093 /* bytes 2,3 must be null */
2094 if(tvb_get_letohs(tvb,offset+2)){
2097 /* the 32bit words at offsets 20, 44
2100 if(tvb_get_letohl(tvb,offset+20)
2101 || tvb_get_letohl(tvb,offset+44)){
2104 /* the 32bit word at 16 must be 0xffffffff */
2105 if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
2109 case ISCSI_OPCODE_LOGOUT_RESPONSE:
2110 /* top two bits in byte 0 must be 0 */
2111 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2114 /* byte 1 must be 0x80 */
2115 if(tvb_get_guint8(tvb, offset+1)!=0x80){
2118 /* response must be known */
2119 if(!match_strval(tvb_get_guint8(tvb,offset+2), iscsi_logout_response)){
2122 /* byte 3 must be 0 */
2123 if(tvb_get_guint8(tvb,offset+3)){
2126 /* ahs and dsl as well as the 32bit words at offsets 8, 12, 20, 36
2129 if(tvb_get_letohl(tvb,offset+4)
2130 || tvb_get_letohl(tvb,offset+8)
2131 || tvb_get_letohl(tvb,offset+12)
2132 || tvb_get_letohl(tvb,offset+20)
2133 || tvb_get_letohl(tvb,offset+36)
2134 || tvb_get_letohl(tvb,offset+44)){
2138 case ISCSI_OPCODE_SCSI_DATA_OUT:
2139 /* top two bits in byte 0 must be 0 */
2140 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2143 /* low 7 bits in byte 1 must be 0 */
2144 if(tvb_get_guint8(tvb,offset+1)&0x7f){
2147 /* bytes 2,3 must be null */
2148 if(tvb_get_letohs(tvb,offset+2)){
2151 /* the 32bit words at offsets 24, 32, 44
2154 if(tvb_get_letohl(tvb,offset+24)
2155 || tvb_get_letohl(tvb,offset+32)
2156 || tvb_get_letohl(tvb,offset+44)){
2160 case ISCSI_OPCODE_SCSI_DATA_IN:
2161 /* top two bits in byte 0 must be 0 */
2162 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2165 /* reserved bits in byte 1 must be 0 */
2166 if(tvb_get_guint8(tvb,offset+1)&0x38){
2169 /* byte 2 must be reserved */
2170 if(tvb_get_guint8(tvb,offset+2)){
2174 case ISCSI_OPCODE_VENDOR_SPECIFIC_I0:
2175 case ISCSI_OPCODE_VENDOR_SPECIFIC_I1:
2176 case ISCSI_OPCODE_VENDOR_SPECIFIC_I2:
2177 case ISCSI_OPCODE_VENDOR_SPECIFIC_T0:
2178 case ISCSI_OPCODE_VENDOR_SPECIFIC_T1:
2179 case ISCSI_OPCODE_VENDOR_SPECIFIC_T2:
2186 /* process multiple iSCSI PDUs per packet */
2187 while(available_bytes >= 48 || (iscsi_desegment && available_bytes >= 8)) {
2188 const char *opcode_str = NULL;
2189 guint32 data_segment_len;
2190 guint32 pduLen = 48;
2191 guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1);
2195 /* mask out any extra bits in the opcode byte */
2196 opcode = tvb_get_guint8(tvb, offset + 0);
2197 opcode &= OPCODE_MASK;
2199 opcode_str = match_strval(opcode, iscsi_opcodes);
2200 if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION ||
2201 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
2202 opcode == ISCSI_OPCODE_R2T ||
2203 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
2204 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
2205 opcode == ISCSI_OPCODE_SNACK_REQUEST)
2206 data_segment_len = 0;
2208 data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
2210 if(opcode_str == NULL) {
2213 else if(check_port && iscsi_port != 0 &&
2214 (((opcode & TARGET_OPCODE_BIT) && pinfo->srcport != iscsi_port) ||
2215 (!(opcode & TARGET_OPCODE_BIT) && pinfo->destport != iscsi_port))) {
2218 else if(enable_bogosity_filter) {
2219 /* try and distinguish between data and real headers */
2220 if(data_segment_len > bogus_pdu_data_length_threshold) {
2223 else if(demand_good_f_bit &&
2224 !(secondPduByte & 0x80) &&
2225 (opcode == ISCSI_OPCODE_NOP_OUT ||
2226 opcode == ISCSI_OPCODE_NOP_IN ||
2227 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
2228 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
2229 opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
2230 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
2231 opcode == ISCSI_OPCODE_R2T ||
2232 opcode == ISCSI_OPCODE_ASYNC_MESSAGE ||
2233 opcode == ISCSI_OPCODE_SNACK_REQUEST ||
2234 opcode == ISCSI_OPCODE_REJECT)) {
2236 } else if(opcode==ISCSI_OPCODE_NOP_OUT) {
2237 /* TransferTag for NOP-Out should either be -1 or
2238 the tag value we want for a response.
2239 Assume 0 means we are just inside a big all zero
2242 if(tvb_get_ntohl(tvb, offset+20)==0){
2249 return iSCSIPdusDissected > 0;
2252 if(opcode == ISCSI_OPCODE_LOGIN_COMMAND ||
2253 opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
2254 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
2255 if((secondPduByte & CSG_MASK) < ISCSI_CSG_OPERATIONAL_NEGOTIATION) {
2256 /* digests are not yet turned on */
2264 if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
2266 ahsLen = tvb_get_guint8(tvb, offset + 4);
2267 pduLen += ahsLen * 4;
2270 pduLen += data_segment_len;
2271 if((pduLen & 3) != 0)
2272 pduLen += 4 - (pduLen & 3);
2275 if(digestsActive && data_segment_len > 0 && enableDataDigests) {
2276 if(dataDigestIsCRC32)
2279 pduLen += dataDigestSize;
2282 /* make sure we have a conversation for this session */
2283 conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
2284 pinfo->ptype, pinfo->srcport,
2285 pinfo->destport, 0);
2286 if (!conversation) {
2287 conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst,
2288 pinfo->ptype, pinfo->srcport,
2289 pinfo->destport, 0);
2291 iscsi_session=conversation_get_proto_data(conversation, proto_iscsi);
2293 iscsi_session=se_alloc(sizeof(iscsi_session_t));
2294 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_AUTO;
2295 iscsi_session->itlq=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "iSCSI ITLQ");
2296 iscsi_session->itl=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "iSCSI ITL");
2297 conversation_add_proto_data(conversation, proto_iscsi, iscsi_session);
2299 /* DataOut PDUs are often mistaken by DCERPC heuristics to be
2300 * that protocol. Now that we know this is iscsi, set a
2301 * dissector for this conversation to block other heuristic
2304 conversation_set_dissector(conversation, iscsi_handle);
2306 /* try to autodetect if header digest is used or not */
2307 if(digestsActive && (available_bytes>=(48+4+ahsLen*4)) && (iscsi_session->header_digest==ISCSI_HEADER_DIGEST_AUTO) ){
2309 /* we have enough data to test if HeaderDigest is enabled */
2310 crc= ~calculateCRC32(tvb_get_ptr(tvb, offset, 48+ahsLen*4), 48+ahsLen*4, CRC32C_PRELOAD);
2311 if(crc==tvb_get_ntohl(tvb,48+ahsLen*4)){
2312 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_CRC32;
2314 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_NONE;
2319 /* Add header digest length to pdulen */
2321 switch(iscsi_session->header_digest){
2322 case ISCSI_HEADER_DIGEST_CRC32:
2325 case ISCSI_HEADER_DIGEST_NONE:
2327 case ISCSI_HEADER_DIGEST_AUTO:
2328 /* oops we didnt know what digest is used yet */
2329 /* here we should use some default */
2332 DISSECTOR_ASSERT_NOT_REACHED();
2337 * Desegmentation check.
2339 if(iscsi_desegment && pinfo->can_desegment) {
2340 if(pduLen > available_bytes) {
2342 * This frame doesn't have all of the data for
2343 * this message, but we can do reassembly on it.
2345 * Tell the TCP dissector where the data for this
2346 * message starts in the data it handed us, and
2347 * how many more bytes we need, and return.
2349 pinfo->desegment_offset = offset;
2350 pinfo->desegment_len = pduLen - available_bytes;
2355 /* This is to help TCP keep track of PDU boundaries
2356 and allows it to find PDUs that are not aligned to
2357 the start of a TCP segments.
2358 Since it also allows TCP to know what is in the middle
2359 of a large PDU, it reduces the probability of a segment
2360 in the middle of a large PDU transfer being misdissected as
2363 if(!pinfo->fd->flags.visited){
2364 if(pduLen>(guint32)tvb_reported_length_remaining(tvb, offset)){
2365 pinfo->want_pdu_tracking=2;
2366 pinfo->bytes_until_next_pdu=pduLen-tvb_reported_length_remaining(tvb, offset);
2370 if(check_col(pinfo->cinfo, COL_INFO)) {
2371 if(iSCSIPdusDissected == 0)
2372 col_set_str(pinfo->cinfo, COL_INFO, "");
2374 col_append_str(pinfo->cinfo, COL_INFO, ", ");
2377 dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len, iscsi_session);
2378 if(pduLen > available_bytes)
2379 pduLen = available_bytes;
2381 available_bytes -= pduLen;
2382 ++iSCSIPdusDissected;
2385 return iSCSIPdusDissected > 0;
2388 /* This is called for those sessions where we have explicitely said
2389 this to be iSCSI using "Decode As..."
2390 In this case we will not check the port number for sanity and just
2391 do as the user said.
2392 We still check that the PDU header looks sane though.
2395 dissect_iscsi_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
2396 return dissect_iscsi(tvb, pinfo, tree, FALSE);
2399 /* This is called through the heuristic handler.
2400 In this case we also want to check that the port matches the preference
2401 setting for iSCSI in order to reduce the number of
2405 dissect_iscsi_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
2406 return dissect_iscsi(tvb, pinfo, tree, TRUE);
2410 /* Register the protocol with Wireshark */
2413 * this format is require because a script is used to build the C
2414 * function that calls all the protocol registration.
2418 proto_register_iscsi(void)
2421 /* Setup list of header fields See Section 1.6.1 for details*/
2422 static hf_register_info hf[] = {
2423 { &hf_iscsi_request_frame,
2424 { "Request in", "iscsi.request_frame",
2425 FT_FRAMENUM, BASE_NONE, NULL, 0,
2426 "The request to this transaction is in this frame", HFILL }},
2429 { "Time from request", "iscsi.time",
2430 FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
2431 "Time between the Command and the Response", HFILL }},
2433 { &hf_iscsi_data_in_frame,
2434 { "Data In in", "iscsi.data_in_frame",
2435 FT_FRAMENUM, BASE_NONE, NULL, 0,
2436 "The Data In for this transaction is in this frame", HFILL }},
2438 { &hf_iscsi_data_out_frame,
2439 { "Data Out in", "iscsi.data_out_frame",
2440 FT_FRAMENUM, BASE_NONE, NULL, 0,
2441 "The Data Out for this transaction is in this frame", HFILL }},
2443 { &hf_iscsi_response_frame,
2444 { "Response in", "iscsi.response_frame",
2445 FT_FRAMENUM, BASE_NONE, NULL, 0,
2446 "The response to this transaction is in this frame", HFILL }},
2449 { "AHS", "iscsi.ahs",
2450 FT_BYTES, BASE_HEX, NULL, 0,
2451 "Additional header segment", HFILL }
2453 { &hf_iscsi_AHS_length,
2454 { "AHS Length", "iscsi.ahs.length",
2455 FT_UINT16, BASE_DEC, NULL, 0,
2456 "Length of Additional header segment", HFILL }
2458 { &hf_iscsi_AHS_read_data_length,
2459 { "Bidirectional Read Data Length", "iscsi.ahs.bidir.length",
2460 FT_UINT32, BASE_DEC, NULL, 0,
2463 { &hf_iscsi_AHS_type,
2464 { "AHS Type", "iscsi.ahs.type",
2465 FT_UINT8, BASE_DEC, VALS(ahs_type_vals), 0,
2466 "Type of Additional header segment", HFILL }
2468 { &hf_iscsi_AHS_extended_cdb,
2469 { "AHS Extended CDB", "iscsi.ahs.extended_cdb",
2470 FT_BYTES, BASE_HEX, NULL, 0,
2473 { &hf_iscsi_AHS_blob,
2474 { "Unknown AHS blob", "iscsi.ahs.unknown_blob",
2475 FT_BYTES, BASE_HEX, NULL, 0,
2478 { &hf_iscsi_Padding,
2479 { "Padding", "iscsi.padding",
2480 FT_BYTES, BASE_HEX, NULL, 0,
2481 "Padding to 4 byte boundary", HFILL }
2483 { &hf_iscsi_ping_data,
2484 { "PingData", "iscsi.pingdata",
2485 FT_BYTES, BASE_HEX, NULL, 0,
2486 "Ping Data", HFILL }
2488 { &hf_iscsi_immediate_data,
2489 { "ImmediateData", "iscsi.immediatedata",
2490 FT_BYTES, BASE_HEX, NULL, 0,
2491 "Immediate Data", HFILL }
2493 { &hf_iscsi_write_data,
2494 { "WriteData", "iscsi.writedata",
2495 FT_BYTES, BASE_HEX, NULL, 0,
2496 "Write Data", HFILL }
2498 { &hf_iscsi_read_data,
2499 { "ReadData", "iscsi.readdata",
2500 FT_BYTES, BASE_HEX, NULL, 0,
2501 "Read Data", HFILL }
2503 { &hf_iscsi_error_pdu_data,
2504 { "ErrorPDUData", "iscsi.errorpdudata",
2505 FT_BYTES, BASE_HEX, NULL, 0,
2506 "Error PDU Data", HFILL }
2508 { &hf_iscsi_async_message_data,
2509 { "AsyncMessageData", "iscsi.asyncmessagedata",
2510 FT_BYTES, BASE_HEX, NULL, 0,
2511 "Async Message Data", HFILL }
2513 { &hf_iscsi_vendor_specific_data,
2514 { "VendorSpecificData", "iscsi.vendorspecificdata",
2515 FT_BYTES, BASE_HEX, NULL, 0,
2516 "Vendor Specific Data", HFILL }
2518 { &hf_iscsi_HeaderDigest32,
2519 { "HeaderDigest", "iscsi.headerdigest32",
2520 FT_UINT32, BASE_HEX, NULL, 0,
2521 "Header Digest", HFILL }
2523 { &hf_iscsi_DataDigest,
2524 { "DataDigest", "iscsi.datadigest",
2525 FT_BYTES, BASE_HEX, NULL, 0,
2526 "Data Digest", HFILL }
2528 { &hf_iscsi_DataDigest32,
2529 { "DataDigest", "iscsi.datadigest32",
2530 FT_UINT32, BASE_HEX, NULL, 0,
2531 "Data Digest", HFILL }
2534 { "Opcode", "iscsi.opcode",
2535 FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
2538 /* #ifdef DRAFT08 */
2541 FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,
2542 "Command Retry", HFILL }
2547 FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,
2548 "Immediate delivery", HFILL }
2551 { "Flags", "iscsi.flags",
2552 FT_UINT8, BASE_HEX, NULL, 0,
2553 "Opcode specific flags", HFILL }
2555 { &hf_iscsi_SCSICommand_F,
2556 { "F", "iscsi.scsicommand.F",
2557 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
2558 "PDU completes command", HFILL }
2560 { &hf_iscsi_SCSICommand_R,
2561 { "R", "iscsi.scsicommand.R",
2562 FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,
2563 "Command reads from SCSI target", HFILL }
2565 { &hf_iscsi_SCSICommand_W,
2566 { "W", "iscsi.scsicommand.W",
2567 FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,
2568 "Command writes to SCSI target", HFILL }
2570 { &hf_iscsi_SCSICommand_Attr,
2571 { "Attr", "iscsi.scsicommand.attr",
2572 FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07,
2573 "SCSI task attributes", HFILL }
2575 { &hf_iscsi_SCSICommand_CRN,
2576 { "CRN", "iscsi.scsicommand.crn",
2577 FT_UINT8, BASE_HEX, NULL, 0,
2578 "SCSI command reference number", HFILL }
2580 { &hf_iscsi_SCSICommand_AddCDB,
2581 { "AddCDB", "iscsi.scsicommand.addcdb",
2582 FT_UINT8, BASE_HEX, NULL, 0,
2583 "Additional CDB length (in 4 byte units)", HFILL }
2585 { &hf_iscsi_DataSegmentLength,
2586 { "DataSegmentLength", "iscsi.datasegmentlength",
2587 FT_UINT32, BASE_HEX, NULL, 0,
2588 "Data segment length (bytes)", HFILL }
2590 { &hf_iscsi_TotalAHSLength,
2591 { "TotalAHSLength", "iscsi.totalahslength",
2592 FT_UINT8, BASE_HEX, NULL, 0,
2593 "Total additional header segment length (4 byte words)", HFILL }
2596 { "LUN", "iscsi.lun",
2597 FT_BYTES, BASE_HEX, NULL, 0,
2598 "Logical Unit Number", HFILL }
2600 { &hf_iscsi_InitiatorTaskTag,
2601 { "InitiatorTaskTag", "iscsi.initiatortasktag",
2602 FT_UINT32, BASE_HEX, NULL, 0,
2603 "Initiator's task tag", HFILL }
2605 { &hf_iscsi_ExpectedDataTransferLength,
2606 { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength",
2607 FT_UINT32, BASE_HEX, NULL, 0,
2608 "Expected length of data transfer", HFILL }
2611 { "CmdSN", "iscsi.cmdsn",
2612 FT_UINT32, BASE_HEX, NULL, 0,
2613 "Sequence number for this command", HFILL }
2615 { &hf_iscsi_ExpStatSN,
2616 { "ExpStatSN", "iscsi.expstatsn",
2617 FT_UINT32, BASE_HEX, NULL, 0,
2618 "Next expected status sequence number", HFILL }
2620 { &hf_iscsi_SCSIResponse_ResidualCount,
2621 { "ResidualCount", "iscsi.scsiresponse.residualcount",
2622 FT_UINT32, BASE_HEX, NULL, 0,
2623 "Residual count", HFILL }
2626 { "StatSN", "iscsi.statsn",
2627 FT_UINT32, BASE_HEX, NULL, 0,
2628 "Status sequence number", HFILL }
2630 { &hf_iscsi_ExpCmdSN,
2631 { "ExpCmdSN", "iscsi.expcmdsn",
2632 FT_UINT32, BASE_HEX, NULL, 0,
2633 "Next expected command sequence number", HFILL }
2635 { &hf_iscsi_MaxCmdSN,
2636 { "MaxCmdSN", "iscsi.maxcmdsn",
2637 FT_UINT32, BASE_HEX, NULL, 0,
2638 "Maximum acceptable command sequence number", HFILL }
2640 { &hf_iscsi_SCSIResponse_o,
2641 { "o", "iscsi.scsiresponse.o",
2642 FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,
2643 "Bi-directional read residual overflow", HFILL }
2645 { &hf_iscsi_SCSIResponse_u,
2646 { "u", "iscsi.scsiresponse.u",
2647 FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08,
2648 "Bi-directional read residual underflow", HFILL }
2650 { &hf_iscsi_SCSIResponse_O,
2651 { "O", "iscsi.scsiresponse.O",
2652 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
2653 "Residual overflow", HFILL }
2655 { &hf_iscsi_SCSIResponse_U,
2656 { "U", "iscsi.scsiresponse.U",
2657 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
2658 "Residual underflow", HFILL }
2660 { &hf_iscsi_SCSIResponse_Status,
2661 { "Status", "iscsi.scsiresponse.status",
2662 FT_UINT8, BASE_HEX, VALS(scsi_status_val), 0,
2663 "SCSI command status value", HFILL }
2665 { &hf_iscsi_SCSIResponse_Response,
2666 { "Response", "iscsi.scsiresponse.response",
2667 FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
2668 "SCSI command response value", HFILL }
2670 { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
2671 { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
2672 FT_UINT32, BASE_HEX, NULL, 0,
2673 "Bi-directional read residual count", HFILL }
2675 { &hf_iscsi_SenseLength,
2676 { "SenseLength", "iscsi.scsiresponse.senselength",
2677 FT_UINT16, BASE_HEX, NULL, 0,
2678 "Sense data length", HFILL }
2680 { &hf_iscsi_SCSIData_F,
2681 { "F", "iscsi.scsidata.F",
2682 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), ISCSI_SCSI_DATA_FLAG_F,
2683 "Final PDU", HFILL }
2685 { &hf_iscsi_SCSIData_A,
2686 { "A", "iscsi.scsidata.A",
2687 FT_BOOLEAN, 8, TFS(&iscsi_meaning_A), ISCSI_SCSI_DATA_FLAG_A,
2688 "Acknowledge Requested", HFILL }
2690 { &hf_iscsi_SCSIData_S,
2691 { "S", "iscsi.scsidata.S",
2692 FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), ISCSI_SCSI_DATA_FLAG_S,
2693 "PDU Contains SCSI command status", HFILL }
2695 { &hf_iscsi_SCSIData_U,
2696 { "U", "iscsi.scsidata.U",
2697 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), ISCSI_SCSI_DATA_FLAG_U,
2698 "Residual underflow", HFILL }
2700 { &hf_iscsi_SCSIData_O,
2701 { "O", "iscsi.scsidata.O",
2702 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), ISCSI_SCSI_DATA_FLAG_O,
2703 "Residual overflow", HFILL }
2705 { &hf_iscsi_TargetTransferTag,
2706 { "TargetTransferTag", "iscsi.targettransfertag",
2707 FT_UINT32, BASE_HEX, NULL, 0,
2708 "Target transfer tag", HFILL }
2710 { &hf_iscsi_BufferOffset,
2711 { "BufferOffset", "iscsi.bufferOffset",
2712 FT_UINT32, BASE_HEX, NULL, 0,
2713 "Buffer offset", HFILL }
2715 { &hf_iscsi_SCSIData_ResidualCount,
2716 { "ResidualCount", "iscsi.scsidata.readresidualcount",
2717 FT_UINT32, BASE_HEX, NULL, 0,
2718 "Residual count", HFILL }
2721 { "DataSN", "iscsi.datasn",
2722 FT_UINT32, BASE_HEX, NULL, 0,
2723 "Data sequence number", HFILL }
2725 { &hf_iscsi_VersionMax,
2726 { "VersionMax", "iscsi.versionmax",
2727 FT_UINT8, BASE_HEX, NULL, 0,
2728 "Maximum supported protocol version", HFILL }
2730 { &hf_iscsi_VersionMin,
2731 { "VersionMin", "iscsi.versionmin",
2732 FT_UINT8, BASE_HEX, NULL, 0,
2733 "Minimum supported protocol version", HFILL }
2735 { &hf_iscsi_VersionActive,
2736 { "VersionActive", "iscsi.versionactive",
2737 FT_UINT8, BASE_HEX, NULL, 0,
2738 "Negotiated protocol version", HFILL }
2741 { "CID", "iscsi.cid",
2742 FT_UINT16, BASE_HEX, NULL, 0,
2743 "Connection identifier", HFILL }
2745 /* #ifdef DRAFT08 */
2747 { "ISID", "iscsi.isid",
2748 FT_UINT16, BASE_HEX, NULL, 0,
2749 "Initiator part of session identifier", HFILL }
2753 { "ISID", "iscsi.isid",
2754 FT_BYTES, BASE_HEX, NULL, 0,
2755 "Initiator part of session identifier", HFILL }
2757 /* #ifdef DRAFT09 */
2758 { &hf_iscsi_ISID_Type,
2759 { "ISID_Type", "iscsi.isid.type",
2760 FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0,
2761 "Initiator part of session identifier - type", HFILL }
2763 { &hf_iscsi_ISID_NamingAuthority,
2764 { "ISID_NamingAuthority", "iscsi.isid.namingauthority",
2765 FT_UINT24, BASE_HEX, NULL, 0,
2766 "Initiator part of session identifier - naming authority", HFILL }
2768 { &hf_iscsi_ISID_Qualifier,
2769 { "ISID_Qualifier", "iscsi.isid.qualifier",
2770 FT_UINT8, BASE_HEX, NULL, 0,
2771 "Initiator part of session identifier - qualifier", HFILL }
2775 { "ISID_t", "iscsi.isid.t",
2776 FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0xc0,
2777 "Initiator part of session identifier - t", HFILL }
2780 { "ISID_a", "iscsi.isid.a",
2781 FT_UINT8, BASE_HEX, NULL, 0x3f,
2782 "Initiator part of session identifier - a", HFILL }
2785 { "ISID_b", "iscsi.isid.b",
2786 FT_UINT16, BASE_HEX, NULL, 0,
2787 "Initiator part of session identifier - b", HFILL }
2790 { "ISID_c", "iscsi.isid.c",
2791 FT_UINT8, BASE_HEX, NULL, 0,
2792 "Initiator part of session identifier - c", HFILL }
2795 { "ISID_d", "iscsi.isid.d",
2796 FT_UINT16, BASE_HEX, NULL, 0,
2797 "Initiator part of session identifier - d", HFILL }
2802 { "TSID", "iscsi.tsid",
2803 FT_UINT16, BASE_HEX, NULL, 0,
2804 "Target part of session identifier", HFILL }
2807 { "TSIH", "iscsi.tsih",
2808 FT_UINT16, BASE_HEX, NULL, 0,
2809 "Target session identifying handle", HFILL }
2811 { &hf_iscsi_InitStatSN,
2812 { "InitStatSN", "iscsi.initstatsn",
2813 FT_UINT32, BASE_HEX, NULL, 0,
2814 "Initial status sequence number", HFILL }
2816 { &hf_iscsi_InitCmdSN,
2817 { "InitCmdSN", "iscsi.initcmdsn",
2818 FT_UINT32, BASE_HEX, NULL, 0,
2819 "Initial command sequence number", HFILL }
2821 { &hf_iscsi_Login_T,
2822 { "T", "iscsi.login.T",
2823 FT_BOOLEAN, 8, TFS(&iscsi_meaning_T), 0x80,
2824 "Transit to next login stage", HFILL }
2826 { &hf_iscsi_Login_C,
2827 { "C", "iscsi.login.C",
2828 FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2829 "Text incomplete", HFILL }
2831 /* #ifdef DRAFT09 */
2832 { &hf_iscsi_Login_X,
2833 { "X", "iscsi.login.X",
2834 FT_BOOLEAN, 8, TFS(&iscsi_meaning_login_X), 0x40,
2835 "Restart Connection", HFILL }
2838 { &hf_iscsi_Login_CSG,
2839 { "CSG", "iscsi.login.csg",
2840 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), CSG_MASK,
2841 "Current stage", HFILL }
2843 { &hf_iscsi_Login_NSG,
2844 { "NSG", "iscsi.login.nsg",
2845 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), NSG_MASK,
2846 "Next stage", HFILL }
2848 { &hf_iscsi_Login_Status,
2849 { "Status", "iscsi.login.status",
2850 FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0,
2851 "Status class and detail", HFILL }
2853 { &hf_iscsi_KeyValue,
2854 { "KeyValue", "iscsi.keyvalue",
2855 FT_STRING, 0, NULL, 0,
2856 "Key/value pair", HFILL }
2859 { "F", "iscsi.text.F",
2860 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
2861 "Final PDU in text sequence", HFILL }
2864 { "C", "iscsi.text.C",
2865 FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2866 "Text incomplete", HFILL }
2868 { &hf_iscsi_ExpDataSN,
2869 { "ExpDataSN", "iscsi.expdatasn",
2870 FT_UINT32, BASE_HEX, NULL, 0,
2871 "Next expected data sequence number", HFILL }
2874 { "R2TSN", "iscsi.r2tsn",
2875 FT_UINT32, BASE_HEX, NULL, 0,
2876 "R2T PDU Number", HFILL }
2878 { &hf_iscsi_TaskManagementFunction_Response,
2879 { "Response", "iscsi.taskmanfun.response",
2880 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_responses), 0,
2883 { &hf_iscsi_TaskManagementFunction_ReferencedTaskTag,
2884 { "ReferencedTaskTag", "iscsi.taskmanfun.referencedtasktag",
2885 FT_UINT32, BASE_HEX, NULL, 0,
2886 "Referenced task tag", HFILL }
2888 { &hf_iscsi_RefCmdSN,
2889 { "RefCmdSN", "iscsi.refcmdsn",
2890 FT_UINT32, BASE_HEX, NULL, 0,
2891 "Command sequence number for command to be aborted", HFILL }
2893 { &hf_iscsi_TaskManagementFunction_Function,
2894 { "Function", "iscsi.taskmanfun.function",
2895 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_functions), 0x7F,
2896 "Requested task function", HFILL }
2898 { &hf_iscsi_Logout_Reason,
2899 { "Reason", "iscsi.logout.reason",
2900 FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0x7F,
2901 "Reason for logout", HFILL }
2903 { &hf_iscsi_Logout_Response,
2904 { "Response", "iscsi.logout.response",
2905 FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
2906 "Logout response", HFILL }
2908 { &hf_iscsi_Time2Wait,
2909 { "Time2Wait", "iscsi.time2wait",
2910 FT_UINT16, BASE_HEX, NULL, 0,
2911 "Time2Wait", HFILL }
2913 { &hf_iscsi_Time2Retain,
2914 { "Time2Retain", "iscsi.time2retain",
2915 FT_UINT16, BASE_HEX, NULL, 0,
2916 "Time2Retain", HFILL }
2918 { &hf_iscsi_DesiredDataLength,
2919 { "DesiredDataLength", "iscsi.desireddatalength",
2920 FT_UINT32, BASE_HEX, NULL, 0,
2921 "Desired data length (bytes)", HFILL }
2923 { &hf_iscsi_AsyncEvent,
2924 { "AsyncEvent", "iscsi.asyncevent",
2925 FT_UINT8, BASE_HEX, VALS(iscsi_asyncevents), 0,
2926 "Async event type", HFILL }
2928 { &hf_iscsi_EventVendorCode,
2929 { "EventVendorCode", "iscsi.eventvendorcode",
2930 FT_UINT8, BASE_HEX, NULL, 0,
2931 "Event vendor code", HFILL }
2933 { &hf_iscsi_Parameter1,
2934 { "Parameter1", "iscsi.parameter1",
2935 FT_UINT16, BASE_HEX, NULL, 0,
2936 "Parameter 1", HFILL }
2938 { &hf_iscsi_Parameter2,
2939 { "Parameter2", "iscsi.parameter2",
2940 FT_UINT16, BASE_HEX, NULL, 0,
2941 "Parameter 2", HFILL }
2943 { &hf_iscsi_Parameter3,
2944 { "Parameter3", "iscsi.parameter3",
2945 FT_UINT16, BASE_HEX, NULL, 0,
2946 "Parameter 3", HFILL }
2948 { &hf_iscsi_Reject_Reason,
2949 { "Reason", "iscsi.reject.reason",
2950 FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
2951 "Reason for command rejection", HFILL }
2953 { &hf_iscsi_snack_type,
2954 { "S", "iscsi.snack.type",
2955 FT_UINT8, BASE_DEC, VALS(iscsi_snack_types), 0x0f,
2956 "Type of SNACK requested", HFILL }
2959 { "BegRun", "iscsi.snack.begrun",
2960 FT_UINT32, BASE_HEX, NULL, 0,
2961 "First missed DataSN or StatSN", HFILL }
2963 { &hf_iscsi_RunLength,
2964 { "RunLength", "iscsi.snack.runlength",
2965 FT_UINT32, BASE_HEX, NULL, 0,
2966 "Number of additional missing status PDUs in this run", HFILL }
2970 /* Setup protocol subtree array */
2971 static gint *ett[] = {
2973 &ett_iscsi_KeyValues,
2976 /* #ifndef DRAFT08 */
2981 /* Register the protocol name and description */
2982 proto_iscsi = proto_register_protocol("iSCSI", "iSCSI", "iscsi");
2984 /* Required function calls to register the header fields and
2986 proto_register_field_array(proto_iscsi, hf, array_length(hf));
2987 proto_register_subtree_array(ett, array_length(ett));
2990 module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
2992 prefs_register_enum_preference(iscsi_module,
2995 "The iSCSI protocol version",
2996 &iscsi_protocol_version,
2997 iscsi_protocol_versions,
3000 prefs_register_bool_preference(iscsi_module,
3001 "desegment_iscsi_messages",
3002 "Reassemble iSCSI messages\nspanning multiple TCP segments",
3003 "Whether the iSCSI dissector should reassemble messages spanning multiple TCP segments."
3004 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
3007 prefs_register_bool_preference(iscsi_module,
3009 "Enable bogus pdu filter",
3010 "When enabled, packets that appear bogus are ignored",
3011 &enable_bogosity_filter);
3013 prefs_register_bool_preference(iscsi_module,
3014 "demand_good_f_bit",
3015 "Ignore packets with bad F bit",
3016 "Ignore packets that haven't set the F bit when they should have",
3017 &demand_good_f_bit);
3019 prefs_register_uint_preference(iscsi_module,
3020 "bogus_pdu_max_data_len",
3021 "Bogus pdu max data length threshold",
3022 "Treat packets whose data segment length is greater than this value as bogus",
3024 &bogus_pdu_data_length_threshold);
3027 prefs_register_uint_preference(iscsi_module,
3030 "Port number of iSCSI target",
3034 prefs_register_bool_preference(iscsi_module,
3035 "enable_data_digests",
3036 "Enable data digests",
3037 "When enabled, pdus are assumed to contain a data digest",
3038 &enableDataDigests);
3040 prefs_register_bool_preference(iscsi_module,
3041 "data_digest_is_crc32c",
3042 "Data digest is CRC32C",
3043 "When enabled, data digests are assumed to be CRC32C",
3044 &dataDigestIsCRC32);
3046 prefs_register_uint_preference(iscsi_module,
3049 "The size of a data digest (bytes)",
3053 /* Preference supported in older versions.
3054 Register them as obsolete. */
3055 prefs_register_obsolete_preference(iscsi_module,
3056 "version_03_compatible");
3057 prefs_register_obsolete_preference(iscsi_module,
3058 "bogus_pdu_max_digest_padding");
3059 prefs_register_obsolete_preference(iscsi_module,
3060 "header_digest_is_crc32c");
3061 prefs_register_obsolete_preference(iscsi_module,
3062 "header_digest_size");
3063 prefs_register_obsolete_preference(iscsi_module,
3064 "enable_header_digests");
3070 * If this dissector uses sub-dissector registration add a
3071 * registration routine.
3075 * This format is required because a script is used to find these
3076 * routines and create the code that calls these routines.
3079 proto_reg_handoff_iscsi(void)
3081 heur_dissector_add("tcp", dissect_iscsi_heur, proto_iscsi);
3083 iscsi_handle = new_create_dissector_handle(dissect_iscsi_handle, proto_iscsi);
3084 dissector_add_handle("tcp.port", iscsi_handle);