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 dissector_handle_t iscsi_handle=NULL;
72 static gint iscsi_protocol_version = ISCSI_PROTOCOL_DRAFT13;
74 static gboolean iscsi_desegment = TRUE;
76 static int demand_good_f_bit = FALSE;
77 static int enable_bogosity_filter = TRUE;
78 static guint32 bogus_pdu_data_length_threshold = 256 * 1024;
80 static int enableDataDigests = FALSE;
82 static int dataDigestIsCRC32 = TRUE;
84 static guint dataDigestSize = 4;
86 static guint iscsi_port = 3260;
88 /* Initialize the protocol and registered fields */
89 static int proto_iscsi = -1;
90 static int hf_iscsi_time = -1;
91 static int hf_iscsi_request_frame = -1;
92 static int hf_iscsi_data_in_frame = -1;
93 static int hf_iscsi_data_out_frame = -1;
94 static int hf_iscsi_response_frame = -1;
95 static int hf_iscsi_AHS = -1;
96 static int hf_iscsi_Padding = -1;
97 static int hf_iscsi_ping_data = -1;
98 static int hf_iscsi_immediate_data = -1;
99 static int hf_iscsi_write_data = -1;
100 static int hf_iscsi_read_data = -1;
101 static int hf_iscsi_error_pdu_data = -1;
102 static int hf_iscsi_async_message_data = -1;
103 static int hf_iscsi_vendor_specific_data = -1;
104 static int hf_iscsi_Opcode = -1;
105 static int hf_iscsi_Flags = -1;
106 static int hf_iscsi_HeaderDigest32 = -1;
107 static int hf_iscsi_DataDigest = -1;
108 static int hf_iscsi_DataDigest32 = -1;
110 static int hf_iscsi_X = -1;
112 static int hf_iscsi_I = -1;
113 static int hf_iscsi_SCSICommand_F = -1;
114 static int hf_iscsi_SCSICommand_R = -1;
115 static int hf_iscsi_SCSICommand_W = -1;
116 static int hf_iscsi_SCSICommand_Attr = -1;
117 static int hf_iscsi_SCSICommand_CRN = -1;
118 static int hf_iscsi_SCSICommand_AddCDB = -1;
119 static int hf_iscsi_DataSegmentLength = -1;
120 static int hf_iscsi_TotalAHSLength = -1;
121 static int hf_iscsi_LUN = -1;
122 static int hf_iscsi_InitiatorTaskTag = -1;
123 static int hf_iscsi_ExpectedDataTransferLength = -1;
124 static int hf_iscsi_CmdSN = -1;
125 static int hf_iscsi_ExpStatSN = -1;
126 static int hf_iscsi_StatSN = -1;
127 static int hf_iscsi_ExpCmdSN = -1;
128 static int hf_iscsi_MaxCmdSN = -1;
129 static int hf_iscsi_SCSIResponse_o = -1;
130 static int hf_iscsi_SCSIResponse_u = -1;
131 static int hf_iscsi_SCSIResponse_O = -1;
132 static int hf_iscsi_SCSIResponse_U = -1;
133 static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1;
134 static int hf_iscsi_SCSIResponse_ResidualCount = -1;
135 static int hf_iscsi_SCSIResponse_Response = -1;
136 static int hf_iscsi_SCSIResponse_Status = -1;
137 static int hf_iscsi_SenseLength = -1;
138 static int hf_iscsi_SCSIData_F = -1;
139 static int hf_iscsi_SCSIData_A = -1;
140 static int hf_iscsi_SCSIData_S = -1;
141 static int hf_iscsi_SCSIData_O = -1;
142 static int hf_iscsi_SCSIData_U = -1;
143 static int hf_iscsi_TargetTransferTag = -1;
144 static int hf_iscsi_DataSN = -1;
145 static int hf_iscsi_BufferOffset = -1;
146 static int hf_iscsi_SCSIData_ResidualCount = -1;
147 static int hf_iscsi_VersionMin = -1;
148 static int hf_iscsi_VersionMax = -1;
149 static int hf_iscsi_VersionActive = -1;
150 static int hf_iscsi_CID = -1;
151 static int hf_iscsi_ISID8 = -1;
152 static int hf_iscsi_ISID = -1;
153 /* #if defined(DRAFT09) */
154 static int hf_iscsi_ISID_Type = -1;
155 static int hf_iscsi_ISID_NamingAuthority = -1;
156 static int hf_iscsi_ISID_Qualifier = -1;
157 /* #elif !defined(DRAFT08) */
158 static int hf_iscsi_ISID_t = -1;
159 static int hf_iscsi_ISID_a = -1;
160 static int hf_iscsi_ISID_b = -1;
161 static int hf_iscsi_ISID_c = -1;
162 static int hf_iscsi_ISID_d = -1;
164 static int hf_iscsi_TSID = -1;
165 static int hf_iscsi_TSIH = -1;
166 static int hf_iscsi_InitStatSN = -1;
167 static int hf_iscsi_InitCmdSN = -1;
169 static int hf_iscsi_Login_X = -1;
171 static int hf_iscsi_Login_C = -1;
172 static int hf_iscsi_Login_T = -1;
173 static int hf_iscsi_Login_CSG = -1;
174 static int hf_iscsi_Login_NSG = -1;
175 static int hf_iscsi_Login_Status = -1;
176 static int hf_iscsi_KeyValue = -1;
177 static int hf_iscsi_Text_C = -1;
178 static int hf_iscsi_Text_F = -1;
179 static int hf_iscsi_ExpDataSN = -1;
180 static int hf_iscsi_R2TSN = -1;
181 static int hf_iscsi_TaskManagementFunction_ReferencedTaskTag = -1;
182 static int hf_iscsi_RefCmdSN = -1;
183 static int hf_iscsi_TaskManagementFunction_Function = -1;
184 static int hf_iscsi_TaskManagementFunction_Response = -1;
185 static int hf_iscsi_Logout_Reason = -1;
186 static int hf_iscsi_Logout_Response = -1;
187 static int hf_iscsi_Time2Wait = -1;
188 static int hf_iscsi_Time2Retain = -1;
189 static int hf_iscsi_DesiredDataLength = -1;
190 static int hf_iscsi_AsyncEvent = -1;
191 static int hf_iscsi_EventVendorCode = -1;
192 static int hf_iscsi_Parameter1 = -1;
193 static int hf_iscsi_Parameter2 = -1;
194 static int hf_iscsi_Parameter3 = -1;
195 static int hf_iscsi_Reject_Reason = -1;
196 static int hf_iscsi_snack_type = -1;
197 static int hf_iscsi_BegRun = -1;
198 static int hf_iscsi_RunLength = -1;
200 /* Initialize the subtree pointers */
201 static gint ett_iscsi = -1;
202 static gint ett_iscsi_KeyValues = -1;
203 static gint ett_iscsi_CDB = -1;
204 static gint ett_iscsi_Flags = -1;
205 /* #ifndef DRAFT08 */
206 static gint ett_iscsi_ISID = -1;
209 #define ISCSI_HEADER_DIGEST_AUTO 0
210 #define ISCSI_HEADER_DIGEST_NONE 1
211 #define ISCSI_HEADER_DIGEST_CRC32 2
212 /* this structure contains session wide state for a specific tcp conversation */
213 typedef struct _iscsi_session_t {
214 guint32 header_digest;
215 emem_tree_t *itlq; /* indexed by ITT */
216 emem_tree_t *itl; /* indexed by LUN */
227 #define OPCODE_MASK 0x3f
229 #define TARGET_OPCODE_BIT 0x20
231 #define ISCSI_OPCODE_NOP_OUT 0x00
232 #define ISCSI_OPCODE_SCSI_COMMAND 0x01
233 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION 0x02
234 #define ISCSI_OPCODE_LOGIN_COMMAND 0x03
235 #define ISCSI_OPCODE_TEXT_COMMAND 0x04
236 #define ISCSI_OPCODE_SCSI_DATA_OUT 0x05
237 #define ISCSI_OPCODE_LOGOUT_COMMAND 0x06
238 #define ISCSI_OPCODE_SNACK_REQUEST 0x10
239 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I0 0x1c
240 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I1 0x1d
241 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I2 0x1e
243 #define ISCSI_OPCODE_NOP_IN 0x20
244 #define ISCSI_OPCODE_SCSI_RESPONSE 0x21
245 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE 0x22
246 #define ISCSI_OPCODE_LOGIN_RESPONSE 0x23
247 #define ISCSI_OPCODE_TEXT_RESPONSE 0x24
248 #define ISCSI_OPCODE_SCSI_DATA_IN 0x25
249 #define ISCSI_OPCODE_LOGOUT_RESPONSE 0x26
250 #define ISCSI_OPCODE_R2T 0x31
251 #define ISCSI_OPCODE_ASYNC_MESSAGE 0x32
252 #define ISCSI_OPCODE_REJECT 0x3f
253 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T0 0x3c
254 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T1 0x3d
255 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T2 0x3e
258 #define CSG_MASK (0x03 << CSG_SHIFT)
259 #define NSG_MASK 0x03
261 #define ISCSI_CSG_SECURITY_NEGOTIATION (0 << CSG_SHIFT)
262 #define ISCSI_CSG_OPERATIONAL_NEGOTIATION (1 << CSG_SHIFT)
263 #define ISCSI_CSG_FULL_FEATURE_PHASE (3 << CSG_SHIFT)
265 #define ISCSI_SCSI_DATA_FLAG_S 0x01
266 #define ISCSI_SCSI_DATA_FLAG_U 0x02
267 #define ISCSI_SCSI_DATA_FLAG_O 0x04
268 #define ISCSI_SCSI_DATA_FLAG_A 0x40
269 #define ISCSI_SCSI_DATA_FLAG_F 0x80
271 static const value_string iscsi_opcodes[] = {
272 { ISCSI_OPCODE_NOP_OUT, "NOP Out" },
273 { ISCSI_OPCODE_SCSI_COMMAND, "SCSI Command" },
274 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION, "Task Management Function" },
275 { ISCSI_OPCODE_LOGIN_COMMAND, "Login Command" },
276 { ISCSI_OPCODE_TEXT_COMMAND, "Text Command" },
277 { ISCSI_OPCODE_SCSI_DATA_OUT, "SCSI Data Out" },
278 { ISCSI_OPCODE_LOGOUT_COMMAND, "Logout Command" },
279 { ISCSI_OPCODE_SNACK_REQUEST, "SNACK Request" },
280 { ISCSI_OPCODE_VENDOR_SPECIFIC_I0, "Vendor Specific I0" },
281 { ISCSI_OPCODE_VENDOR_SPECIFIC_I1, "Vendor Specific I1" },
282 { ISCSI_OPCODE_VENDOR_SPECIFIC_I2, "Vendor Specific I2" },
284 { ISCSI_OPCODE_NOP_IN, "NOP In" },
285 { ISCSI_OPCODE_SCSI_RESPONSE, "SCSI Response" },
286 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE, "Task Management Function Response" },
287 { ISCSI_OPCODE_LOGIN_RESPONSE, "Login Response" },
288 { ISCSI_OPCODE_TEXT_RESPONSE, "Text Response" },
289 { ISCSI_OPCODE_SCSI_DATA_IN, "SCSI Data In" },
290 { ISCSI_OPCODE_LOGOUT_RESPONSE, "Logout Response" },
291 { ISCSI_OPCODE_R2T, "Ready To Transfer" },
292 { ISCSI_OPCODE_ASYNC_MESSAGE, "Asynchronous Message" },
293 { ISCSI_OPCODE_REJECT, "Reject"},
294 { ISCSI_OPCODE_VENDOR_SPECIFIC_T0, "Vendor Specific T0" },
295 { ISCSI_OPCODE_VENDOR_SPECIFIC_T1, "Vendor Specific T1" },
296 { ISCSI_OPCODE_VENDOR_SPECIFIC_T2, "Vendor Specific T2" },
301 static const true_false_string iscsi_meaning_X = {
308 static const true_false_string iscsi_meaning_login_X = {
309 "Reinstate failed connection",
314 static const true_false_string iscsi_meaning_I = {
315 "Immediate delivery",
319 static const true_false_string iscsi_meaning_F = {
320 "Final PDU in sequence",
321 "Not final PDU in sequence"
324 static const true_false_string iscsi_meaning_A = {
325 "Acknowledge requested",
326 "Acknowledge not requested"
329 static const true_false_string iscsi_meaning_T = {
330 "Transit to next login stage",
331 "Stay in current login stage"
334 static const true_false_string iscsi_meaning_C = {
335 "Text is incomplete",
339 static const true_false_string iscsi_meaning_S = {
340 "Response contains SCSI status",
341 "Response does not contain SCSI status"
344 static const true_false_string iscsi_meaning_R = {
345 "Data will be read from target",
346 "No data will be read from target"
349 static const true_false_string iscsi_meaning_W = {
350 "Data will be written to target",
351 "No data will be written to target"
354 static const true_false_string iscsi_meaning_o = {
355 "Read part of bi-directional command overflowed",
356 "No overflow of read part of bi-directional command",
359 static const true_false_string iscsi_meaning_u = {
360 "Read part of bi-directional command underflowed",
361 "No underflow of read part of bi-directional command",
364 static const true_false_string iscsi_meaning_O = {
365 "Residual overflow occurred",
366 "No residual overflow occurred",
369 static const true_false_string iscsi_meaning_U = {
370 "Residual underflow occurred",
371 "No residual underflow occurred",
374 static const value_string iscsi_scsi_responses[] = {
375 { 0, "Command completed at target" },
376 { 1, "Response does not contain SCSI status"},
380 static const value_string iscsi_scsicommand_taskattrs[] = {
384 {3, "Head of Queue"},
389 static const value_string iscsi_task_management_responses[] = {
390 {0, "Function complete"},
391 {1, "Task not in task set"},
392 {2, "LUN does not exist"},
393 {3, "Task still allegiant"},
394 {4, "Task failover not supported"},
395 {5, "Task management function not supported"},
396 {6, "Authorisation failed"},
397 {255, "Function rejected"},
401 static const value_string iscsi_task_management_functions[] = {
403 {2, "Abort Task Set"},
405 {4, "Clear Task Set"},
406 {5, "Logical Unit Reset"},
407 {6, "Target Warm Reset"},
408 {7, "Target Cold Reset"},
409 {8, "Target Reassign"},
413 static const value_string iscsi_login_status[] = {
415 {0x0101, "Target moved temporarily"},
416 {0x0102, "Target moved permanently"},
417 {0x0200, "Initiator error (miscellaneous error)"},
418 {0x0201, "Authentication failed"},
419 {0x0202, "Authorisation failure"},
420 {0x0203, "Target not found"},
421 {0x0204, "Target removed"},
422 {0x0205, "Unsupported version"},
423 {0x0206, "Too many connections"},
424 {0x0207, "Missing parameter"},
425 {0x0208, "Can't include in session"},
426 {0x0209, "Session type not supported"},
427 {0x020a, "Session does not exist"},
428 {0x020b, "Invalid request during login"},
429 {0x0300, "Target error (miscellaneous error)"},
430 {0x0301, "Service unavailable"},
431 {0x0302, "Out of resources"},
435 static const value_string iscsi_login_stage[] = {
436 {0, "Security negotiation"},
437 {1, "Operational negotiation"},
438 {3, "Full feature phase"},
442 /* #ifndef DRAFT08 */
443 static const value_string iscsi_isid_type[] = {
445 {0x01, "IANA Enterprise Number"},
451 static const value_string iscsi_logout_reasons[] = {
452 {0, "Close session"},
453 {1, "Close connection"},
454 {2, "Remove connection for recovery"},
458 static const value_string iscsi_logout_response[] = {
459 {0, "Connection closed successfully"},
460 {1, "CID not found"},
461 {2, "Connection recovery not supported"},
462 {3, "Cleanup failed for various reasons"},
466 static const value_string iscsi_asyncevents[] = {
467 {0, "A SCSI asynchronous event is reported in the sense data"},
468 {1, "Target requests logout"},
469 {2, "Target will/has dropped connection"},
470 {3, "Target will/has dropped all connections"},
471 {4, "Target requests parameter negotiation"},
475 static const value_string iscsi_snack_types[] = {
478 /* #ifndef DRAFT08 */
485 static const value_string iscsi_reject_reasons[] = {
487 {0x01, "Full feature phase command before login"},
489 {0x02, "Data (payload) digest error"},
490 {0x03, "Data SNACK reject"},
491 {0x04, "Protocol error"},
492 {0x05, "Command not supported in this session type"},
493 {0x06, "Immediate command reject (too many immediate commands)"},
494 {0x07, "Task in progress"},
495 {0x08, "Invalid Data Ack"},
496 {0x09, "Invalid PDU field"},
497 {0x0a, "Long operation reject"},
498 {0x0b, "Negotiation reset"},
499 {0x0c, "Waiting for logout"},
503 /*****************************************************************/
505 /* CRC LOOKUP TABLE */
506 /* ================ */
507 /* The following CRC lookup table was generated automagically */
508 /* by the Rocksoft^tm Model CRC Algorithm Table Generation */
509 /* Program V1.0 using the following model parameters: */
511 /* Width : 4 bytes. */
512 /* Poly : 0x1EDC6F41L */
513 /* Reverse : TRUE. */
515 /* For more information on the Rocksoft^tm Model CRC Algorithm, */
516 /* see the document titled "A Painless Guide to CRC Error */
517 /* Detection Algorithms" by Ross Williams */
518 /* (ross@guest.adelaide.edu.au.). This document is likely to be */
519 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
521 /*****************************************************************/
523 static guint32 crc32Table[256] = {
524 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
525 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
526 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
527 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
528 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
529 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
530 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
531 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
532 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
533 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
534 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
535 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
536 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
537 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
538 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
539 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
540 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
541 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
542 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
543 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
544 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
545 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
546 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
547 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
548 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
549 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
550 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
551 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
552 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
553 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
554 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
555 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
556 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
557 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
558 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
559 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
560 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
561 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
562 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
563 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
564 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
565 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
566 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
567 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
568 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
569 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
570 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
571 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
572 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
573 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
574 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
575 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
576 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
577 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
578 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
579 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
580 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
581 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
582 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
583 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
584 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
585 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
586 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
587 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
590 #define CRC32C_PRELOAD 0xffffffff
593 * Byte swap fix contributed by Dave Wysochanski <davidw@netapp.com>
595 #define CRC32C_SWAP(crc32c_value) \
596 (((crc32c_value & 0xff000000) >> 24) | \
597 ((crc32c_value & 0x00ff0000) >> 8) | \
598 ((crc32c_value & 0x0000ff00) << 8) | \
599 ((crc32c_value & 0x000000ff) << 24))
602 calculateCRC32(const void *buf, int len, guint32 crc) {
603 const guint8 *p = (const guint8 *)buf;
604 crc = CRC32C_SWAP(crc);
606 crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
607 return CRC32C_SWAP(crc);
614 /* structure and functions to keep track of
615 * COMMAND/DATA_IN/DATA_OUT/RESPONSE matching
617 typedef struct _iscsi_conv_data {
618 guint32 data_in_frame;
619 guint32 data_out_frame;
624 iscsi_min(int a, int b) {
625 return (a < b)? a : b;
629 addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
630 const gint limit = offset + text_len;
631 while(offset < limit) {
632 gint len = tvb_strnlen(tvb, offset, limit - offset);
634 len = limit - offset;
637 proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, FALSE);
644 handleHeaderDigest(iscsi_session_t *iscsi_session, proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
645 int available_bytes = tvb_length_remaining(tvb, offset);
647 switch(iscsi_session->header_digest){
648 case ISCSI_HEADER_DIGEST_CRC32:
649 if(available_bytes >= (headerLen + 4)) {
650 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
651 guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
653 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
655 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);
658 return offset + headerLen + 4;
661 return offset + headerLen;
665 handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) {
666 int available_bytes = tvb_length_remaining(tvb, offset);
667 if(enableDataDigests) {
668 if(dataDigestIsCRC32) {
669 if(available_bytes >= (dataLen + 4)) {
670 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
671 guint32 sent = tvb_get_ntohl(tvb, offset + dataLen);
673 proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Good CRC32)", sent);
676 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);
679 return offset + dataLen + 4;
681 if((unsigned)available_bytes >= (dataLen + dataDigestSize)) {
682 proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, FALSE);
684 return offset + dataLen + dataDigestSize;
686 return offset + dataLen;
690 handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) {
691 if(endOffset > offset) {
692 int dataOffset = offset;
693 int dataLen = iscsi_min(dataSegmentLen, endOffset - offset);
695 proto_tree_add_item(ti, hf_id, tvb, offset, dataLen, FALSE);
698 if(offset < endOffset && (offset & 3) != 0) {
699 int padding = 4 - (offset & 3);
700 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
703 if(dataSegmentLen > 0 && offset < endOffset)
704 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
711 handleDataSegmentAsTextKeys(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) {
712 if(endOffset > offset) {
713 int dataOffset = offset;
714 int textLen = iscsi_min(dataSegmentLen, endOffset - offset);
716 proto_item *tf = proto_tree_add_text(ti, tvb, offset, textLen, "Key/Value Pairs");
717 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
718 offset = addTextKeys(tt, tvb, offset, textLen);
720 if(offset < endOffset && (offset & 3) != 0) {
721 int padding = 4 - (offset & 3);
722 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
725 if(digestsActive && dataSegmentLen > 0 && offset < endOffset)
726 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
731 /* Code to actually dissect the packets */
733 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) {
735 guint original_offset = offset;
736 proto_tree *ti = NULL;
737 guint8 scsi_status = 0;
738 gboolean S_bit=FALSE;
739 guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
740 guint end_offset = offset + tvb_length_remaining(tvb, offset);
741 iscsi_conv_data_t *cdata = NULL;
742 int paddedDataSegmentLength = data_segment_len;
744 guint immediate_data_length=0;
745 guint immediate_data_offset=0;
746 itl_nexus_t *itl=NULL;
748 if(paddedDataSegmentLength & 3)
749 paddedDataSegmentLength += 4 - (paddedDataSegmentLength & 3);
751 /* Make entries in Protocol column and Info column on summary display */
752 if (check_col(pinfo->cinfo, COL_PROTOCOL))
753 col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
755 /* XXX we need a way to handle replayed iscsi itt here */
756 cdata=(iscsi_conv_data_t *)se_tree_lookup32(iscsi_session->itlq, tvb_get_ntohl(tvb, offset+16));
758 cdata = se_alloc (sizeof(iscsi_conv_data_t));
759 cdata->itlq.lun=0xffff;
760 cdata->itlq.scsi_opcode=0xffff;
761 cdata->itlq.fc_time = pinfo->fd->abs_ts;
762 cdata->itlq.first_exchange_frame=0;
763 cdata->itlq.last_exchange_frame=0;
765 cdata->itlq.alloc_len=0;
766 cdata->itlq.extra_data=NULL;
767 cdata->data_in_frame=0;
768 cdata->data_out_frame=0;
770 se_tree_insert32(iscsi_session->itlq, tvb_get_ntohl(tvb, offset+16), cdata);
773 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
774 opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
775 scsi_status = tvb_get_guint8 (tvb, offset+3);
778 if ((opcode == ISCSI_OPCODE_SCSI_RESPONSE) ||
779 (opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
780 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
781 /* first time we see this packet. check if we can find the request */
783 case ISCSI_OPCODE_SCSI_RESPONSE:
784 cdata->itlq.last_exchange_frame=pinfo->fd->num;
786 case ISCSI_OPCODE_SCSI_DATA_IN:
787 /* a bit ugly but we need to check the S bit here */
788 if(tvb_get_guint8(tvb, offset+1)&ISCSI_SCSI_DATA_FLAG_S){
789 cdata->itlq.last_exchange_frame=pinfo->fd->num;
791 cdata->data_in_frame=pinfo->fd->num;
793 case ISCSI_OPCODE_SCSI_DATA_OUT:
794 cdata->data_out_frame=pinfo->fd->num;
798 } else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
799 /*we need the LUN value for some of the commands so we can pass it
800 across to the SCSI dissector.
801 Not correct but simple and probably accurate enough :
802 If bit 6 of first bit is 0 then just take second byte as the LUN
803 If bit 6 of first bit is 1, then take 6 bits from first byte
804 and all of second byte and pretend it is the lun value
805 people that care can add host specific dissection of vsa later.
807 We need to keep track of this on a per transaction basis since
808 for error recoverylevel 0 and when the A bit is clear in a
809 Data-In PDU, there will not be a LUN field in teh iscsi layer.
811 if(tvb_get_guint8(tvb, offset+8)&0x40){
812 /* volume set addressing */
813 lun=tvb_get_guint8(tvb,offset+8)&0x3f;
815 lun|=tvb_get_guint8(tvb,offset+9);
817 lun=tvb_get_guint8(tvb,offset+9);
821 cdata->itlq.first_exchange_frame=pinfo->fd->num;
823 itl=(itl_nexus_t *)se_tree_lookup32(iscsi_session->itl, lun);
825 itl=se_alloc(sizeof(itl_nexus_t));
827 se_tree_insert32(iscsi_session->itl, lun, itl);
833 itl=(itl_nexus_t *)se_tree_lookup32(iscsi_session->itl, cdata->itlq.lun);
837 if (check_col(pinfo->cinfo, COL_INFO)) {
839 if (opcode != ISCSI_OPCODE_SCSI_COMMAND) {
841 col_append_str(pinfo->cinfo, COL_INFO, opcode_str);
843 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
844 (opcode == ISCSI_OPCODE_SCSI_DATA_IN &&
845 (tvb_get_guint8(tvb, offset + 1) & ISCSI_SCSI_DATA_FLAG_S))) {
846 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
847 val_to_str (scsi_status, scsi_status_val, "0x%x"));
849 else if (opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
850 guint16 login_status = tvb_get_ntohs(tvb, offset+36);
851 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
852 val_to_str (login_status, iscsi_login_status, "0x%x"));
854 else if (opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
856 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
857 logoutReason = tvb_get_guint8(tvb, offset+11);
858 } else if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
859 logoutReason = tvb_get_guint8(tvb, offset+1) & 0x7f;
862 logoutReason = tvb_get_guint8(tvb, offset+23);
864 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
865 val_to_str (logoutReason, iscsi_logout_reasons, "0x%x"));
867 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
868 guint8 tmf = tvb_get_guint8(tvb, offset + 1);
869 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
870 val_to_str (tmf, iscsi_task_management_functions, "0x%x"));
872 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
873 guint8 resp = tvb_get_guint8(tvb, offset + 2);
874 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
875 val_to_str (resp, iscsi_task_management_responses, "0x%x"));
877 else if (opcode == ISCSI_OPCODE_REJECT) {
878 guint8 reason = tvb_get_guint8(tvb, offset + 2);
879 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
880 val_to_str (reason, iscsi_reject_reasons, "0x%x"));
882 else if (opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
883 guint8 asyncEvent = tvb_get_guint8(tvb, offset + 36);
884 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
885 val_to_str (asyncEvent, iscsi_asyncevents, "0x%x"));
890 /* In the interest of speed, if "tree" is NULL, don't do any
891 work not necessary to generate protocol tree items. */
894 /* create display subtree for the protocol */
895 tp = proto_tree_add_protocol_format(tree, proto_iscsi, tvb,
896 offset, -1, "iSCSI (%s)",
898 ti = proto_item_add_subtree(tp, ett_iscsi);
900 proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
901 offset + 0, 1, opcode);
902 if((opcode & TARGET_OPCODE_BIT) == 0) {
903 /* initiator -> target */
904 gint b = tvb_get_guint8(tvb, offset + 0);
905 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
906 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
907 opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
908 opcode != ISCSI_OPCODE_SNACK_REQUEST)
909 proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
911 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
912 opcode != ISCSI_OPCODE_LOGIN_COMMAND &&
913 opcode != ISCSI_OPCODE_SNACK_REQUEST)
914 proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
917 if(opcode == ISCSI_OPCODE_NOP_OUT) {
919 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
920 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
922 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
923 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
924 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
925 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
926 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
927 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
928 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
929 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
930 } else if(opcode == ISCSI_OPCODE_NOP_IN) {
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_StatSN, tvb, offset + 24, 4, FALSE);
940 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
941 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
942 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
943 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
944 } else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
946 guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
948 gint b = tvb_get_guint8(tvb, offset + 1);
949 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
950 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
952 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
953 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
954 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
955 proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
957 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
958 proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, FALSE);
960 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
961 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
962 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
963 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
964 proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, FALSE);
965 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
966 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
969 /* FIXME - disssect AHS? */
970 proto_tree_add_item(ti, hf_iscsi_AHS, tvb, offset + 48, ahsLen, FALSE);
972 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48 + ahsLen);
974 immediate_data_offset=offset;
975 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
976 immediate_data_length=offset-immediate_data_offset;
977 } else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
980 gint b = tvb_get_guint8(tvb, offset + 1);
981 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
982 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
984 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
985 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
986 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
987 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
989 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Response, tvb, offset + 2, 1, FALSE);
990 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
991 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
992 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
994 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
995 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
996 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
997 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 20, 4, FALSE);
999 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1000 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1001 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1002 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1003 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1004 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, FALSE);
1007 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 40, 4, FALSE);
1008 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 44, 4, FALSE);
1010 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1011 /* do not update offset here because the data segment is
1012 * dissected below */
1013 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1014 } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
1015 /* Task Management Function */
1016 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, FALSE);
1017 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1018 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1019 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1021 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1022 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1023 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1024 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1025 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1026 proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
1027 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1028 } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
1029 /* Task Management Function Response */
1030 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Response, tvb, offset + 2, 1, FALSE);
1031 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1032 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1033 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1035 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1036 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1037 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1039 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1040 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1041 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1042 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1043 } else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
1045 int digestsActive = 0;
1047 gint b = tvb_get_guint8(tvb, offset + 1);
1048 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1049 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1053 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1054 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1057 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1058 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1059 proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1061 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1062 proto_tree_add_boolean(ti, hf_iscsi_Login_X, tvb, offset + 1, 1, b);
1064 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
1066 /* NSG is undefined unless T is set */
1068 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
1071 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1072 proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
1073 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1074 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1076 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1077 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1078 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1079 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, FALSE);
1082 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
1083 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1084 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1085 proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, FALSE);
1086 proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, FALSE);
1087 proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, FALSE);
1090 proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, FALSE);
1091 proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, FALSE);
1092 proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, FALSE);
1093 proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, FALSE);
1094 proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, FALSE);
1097 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1098 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1101 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, FALSE);
1103 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1104 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1105 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
1107 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1108 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1110 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1114 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1115 } else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1116 /* Login Response */
1117 int digestsActive = 0;
1119 gint b = tvb_get_guint8(tvb, offset + 1);
1120 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1121 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1125 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1126 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1129 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1130 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1131 proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1133 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
1134 /* NSG is undefined unless T is set */
1136 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
1140 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1141 proto_tree_add_item(ti, hf_iscsi_VersionActive, tvb, offset + 3, 1, FALSE);
1142 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1143 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1145 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1146 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1147 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, FALSE);
1150 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
1151 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1152 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1153 proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, FALSE);
1154 proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, FALSE);
1155 proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, FALSE);
1158 proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, FALSE);
1159 proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, FALSE);
1160 proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, FALSE);
1161 proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, FALSE);
1162 proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, FALSE);
1165 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1166 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1169 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, FALSE);
1171 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1172 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1173 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1174 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1175 proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, FALSE);
1177 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1181 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1182 } else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
1185 gint b = tvb_get_guint8(tvb, offset + 1);
1186 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1187 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1189 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1190 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1191 proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1194 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1195 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1197 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1198 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1199 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1201 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1202 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1203 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1204 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1205 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1206 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1207 } else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
1210 gint b = tvb_get_guint8(tvb, offset + 1);
1211 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1212 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1214 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1215 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1216 proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1219 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1220 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1222 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1223 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1224 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1226 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1227 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1228 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1229 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1230 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1231 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1232 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1233 } else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
1234 /* SCSI Data Out (write) */
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_SCSIData_F, tvb, offset + 1, 1, b);
1242 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1243 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1245 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1246 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1247 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1248 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1249 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1250 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1251 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1252 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1253 /* do not update offset here because the data segment is
1254 * dissected below */
1255 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1256 } else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
1257 /* SCSI Data In (read) */
1259 gint b = tvb_get_guint8(tvb, offset + 1);
1260 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1261 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1263 if(b&ISCSI_SCSI_DATA_FLAG_S){
1266 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1267 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1268 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_A, tvb, offset + 1, 1, b);
1270 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
1271 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
1272 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
1275 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
1277 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1278 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1280 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1281 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1282 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1284 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1285 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1286 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 20, 4, FALSE);
1289 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1291 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1292 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1293 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1294 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1295 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1296 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1297 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 44, 4, FALSE);
1299 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1300 /* do not update offset here because the data segment is
1301 * dissected below */
1302 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1303 } else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
1304 /* Logout Command */
1305 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1306 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 1, 1, FALSE);
1308 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1309 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1310 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1312 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1313 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1314 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, FALSE);
1316 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1317 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1318 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
1319 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT13) {
1320 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 23, 1, FALSE);
1323 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1324 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1325 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1326 } else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
1327 /* Logout Response */
1328 proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, FALSE);
1329 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1330 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);
1333 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1334 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1335 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1336 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1337 proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, FALSE);
1338 proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, FALSE);
1339 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1340 } else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
1343 gint b = tvb_get_guint8(tvb, offset + 1);
1345 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1346 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1349 proto_tree_add_item(ti, hf_iscsi_snack_type, tvb, offset + 1, 1, b);
1351 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1352 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1353 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1354 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1356 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1357 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1358 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, FALSE);
1359 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, FALSE);
1360 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1361 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1364 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1365 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1366 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 40, 4, FALSE);
1367 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 44, 4, FALSE);
1369 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1370 } else if(opcode == ISCSI_OPCODE_R2T) {
1372 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1373 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1374 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1375 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1377 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1378 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1379 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1380 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1381 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1382 proto_tree_add_item(ti, hf_iscsi_R2TSN, tvb, offset + 36, 4, FALSE);
1383 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1384 proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
1385 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1386 } else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1387 /* Asynchronous Message */
1388 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1389 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1391 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1392 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1393 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1394 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1395 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1396 proto_tree_add_item(ti, hf_iscsi_AsyncEvent, tvb, offset + 36, 1, FALSE);
1397 proto_tree_add_item(ti, hf_iscsi_EventVendorCode, tvb, offset + 37, 1, FALSE);
1398 proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, FALSE);
1399 proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
1400 proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
1401 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1402 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_async_message_data);
1403 } else if(opcode == ISCSI_OPCODE_REJECT) {
1405 proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
1406 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1407 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1409 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1410 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1411 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1412 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1413 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1414 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1415 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_error_pdu_data);
1416 } else if(opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I0 ||
1417 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I1 ||
1418 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I2 ||
1419 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T0 ||
1420 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T1 ||
1421 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T2) {
1422 /* Vendor specific opcodes */
1423 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1424 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1426 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1427 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1428 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_vendor_specific_data);
1433 /* handle request/response matching */
1435 case ISCSI_OPCODE_SCSI_RESPONSE:
1436 if (cdata->itlq.first_exchange_frame){
1437 nstime_t delta_time;
1438 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1439 nstime_delta(&delta_time, &pinfo->fd->abs_ts, &cdata->itlq.fc_time);
1440 proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1442 if (cdata->data_in_frame)
1443 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1444 if (cdata->data_out_frame)
1445 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1447 case ISCSI_OPCODE_SCSI_DATA_IN:
1448 /* if we have phase collaps then we might have the
1449 response embedded in the last DataIn segment */
1451 if (cdata->itlq.first_exchange_frame)
1452 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1453 if (cdata->itlq.last_exchange_frame)
1454 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
1456 if (cdata->itlq.first_exchange_frame){
1457 nstime_t delta_time;
1458 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1459 nstime_delta(&delta_time, &pinfo->fd->abs_ts, &cdata->itlq.fc_time);
1460 proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1463 if (cdata->data_out_frame)
1464 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1466 case ISCSI_OPCODE_SCSI_DATA_OUT:
1467 if (cdata->itlq.first_exchange_frame)
1468 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->itlq.first_exchange_frame);
1469 if (cdata->data_in_frame)
1470 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1471 if (cdata->itlq.last_exchange_frame)
1472 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
1474 case ISCSI_OPCODE_SCSI_COMMAND:
1475 if (cdata->data_in_frame)
1476 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1477 if (cdata->data_out_frame)
1478 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1479 if (cdata->itlq.last_exchange_frame)
1480 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->itlq.last_exchange_frame);
1486 proto_item_set_len(ti, offset - original_offset);
1488 if((opcode & ((iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08)?
1490 ~I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND) {
1491 tvbuff_t *cdb_tvb, *data_tvb;
1492 int tvb_len, tvb_rlen;
1496 tvb_len=tvb_length_remaining(tvb, cdb_offset);
1497 tvb_rlen=tvb_reported_length_remaining(tvb, cdb_offset);
1498 scsi_opcode=tvb_get_guint8(tvb, cdb_offset);
1499 /* cdb 0x7f is variable length so dont clamp the cdb tvb */
1500 if(scsi_opcode!=0x7f){
1508 cdb_tvb=tvb_new_subset(tvb, cdb_offset, tvb_len, tvb_rlen);
1509 dissect_scsi_cdb(cdb_tvb, pinfo, tree, SCSI_DEV_UNKNOWN, &cdata->itlq, itl);
1510 /* we dont want the immediata below to overwrite our CDB info */
1511 if (check_col(pinfo->cinfo, COL_INFO)) {
1512 col_set_fence(pinfo->cinfo, COL_INFO);
1514 /* where there any ImmediateData ? */
1515 if(immediate_data_length){
1516 /* Immediate Data TVB */
1517 tvb_len=tvb_length_remaining(tvb, immediate_data_offset);
1518 if(tvb_len>(int)immediate_data_length)
1519 tvb_len=immediate_data_length;
1520 tvb_rlen=tvb_reported_length_remaining(tvb, immediate_data_offset);
1521 if(tvb_rlen>(int)immediate_data_length)
1522 tvb_rlen=immediate_data_length;
1523 data_tvb=tvb_new_subset(tvb, immediate_data_offset, tvb_len, tvb_rlen);
1524 dissect_scsi_payload (data_tvb, pinfo, tree,
1529 else if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1530 if (scsi_status == 0x2) {
1531 /* A SCSI response with Check Condition contains sense data */
1532 /* offset is setup correctly by the iscsi code for response above */
1533 if((end_offset - offset) >= 2) {
1534 int senseLen = tvb_get_ntohs(tvb, offset);
1536 proto_tree_add_item(ti, hf_iscsi_SenseLength, tvb, offset, 2, FALSE);
1540 int tvb_len, tvb_rlen;
1542 tvb_len=tvb_length_remaining(tvb, offset);
1543 if(tvb_len>senseLen)
1545 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1546 if(tvb_rlen>senseLen)
1548 data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1549 dissect_scsi_snsinfo (data_tvb, pinfo, tree, 0,
1556 dissect_scsi_rsp(tvb, pinfo, tree, &cdata->itlq, itl, scsi_status);
1559 else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
1560 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
1562 int tvb_len, tvb_rlen;
1564 /* offset is setup correctly by the iscsi code for response above */
1565 tvb_len=tvb_length_remaining(tvb, offset);
1566 if(tvb_len>(int)data_segment_len)
1567 tvb_len=data_segment_len;
1568 tvb_rlen=tvb_reported_length_remaining(tvb, offset);
1569 if(tvb_rlen>(int)data_segment_len)
1570 tvb_rlen=data_segment_len;
1571 data_tvb=tvb_new_subset(tvb, offset, tvb_len, tvb_rlen);
1572 dissect_scsi_payload (data_tvb, pinfo, tree,
1573 (opcode==ISCSI_OPCODE_SCSI_DATA_OUT),
1578 dissect_scsi_rsp(tvb, pinfo, tree, &cdata->itlq, itl, scsi_status);
1583 dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean check_port) {
1584 /* Set up structures needed to add the protocol subtree and manage it */
1585 guint iSCSIPdusDissected = 0;
1587 guint32 available_bytes = tvb_length_remaining(tvb, offset);
1588 int digestsActive = 1;
1589 conversation_t *conversation = NULL;
1590 iscsi_session_t *iscsi_session=NULL;
1591 guint8 opcode, tmpbyte;
1593 /* quick check to see if the packet is long enough to contain the
1594 * minimum amount of information we need */
1595 if (available_bytes < 48 ){
1596 /* no, so give up */
1600 opcode = tvb_get_guint8(tvb, offset + 0);
1601 opcode &= OPCODE_MASK;
1603 /* heuristics to verify that the packet looks sane. the heuristics
1604 * are based on the RFC version of iscsi.
1605 * (we should retire support for older iscsi versions in wireshark)
1608 /* opcode must be any of the ones from the standard
1609 * also check the header that it looks "sane"
1610 * all reserved or undefined bits in iscsi must be set to zero.
1613 case ISCSI_OPCODE_NOP_IN:
1614 /* top two bits of byte 0 must be 0 */
1615 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1618 /* byte 1 must be 0x80 */
1619 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1622 /* bytes 2 and 3 must be 0 */
1623 if(tvb_get_guint8(tvb, offset+2)||tvb_get_guint8(tvb, offset+3)){
1627 case ISCSI_OPCODE_NOP_OUT:
1628 /* top bit of byte 0 must be 0 */
1629 if(tvb_get_guint8(tvb, offset+0)&0x80){
1632 /* byte 1 must be 0x80 */
1633 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1636 /* bytes 2 and 3 must be 0 */
1637 if(tvb_get_guint8(tvb, offset+2)||tvb_get_guint8(tvb, offset+3)){
1640 /* assume ITT and TTT must always be non NULL (ok they can be NULL
1641 * from time to time but it usually means we are in the middle
1642 * of a zeroed datablock).
1644 if(!tvb_get_letohl(tvb,offset+16) || !tvb_get_letohl(tvb,offset+20)){
1647 /* all reserved bytes between 32 - 47 must be null */
1648 if(tvb_get_letohl(tvb,offset+32)
1649 || tvb_get_letohl(tvb,offset+36)
1650 || tvb_get_letohl(tvb,offset+40)
1651 || tvb_get_letohl(tvb,offset+44)){
1655 case ISCSI_OPCODE_LOGIN_COMMAND:
1656 /* top two bits in byte 0 must be 0x40 */
1657 if((tvb_get_guint8(tvb, offset+0)&0xc0)!=0x40){
1661 /* exactly one of the T and C bits must be set
1662 * and the two reserved bits in byte 1 must be 0
1664 tmpbyte=tvb_get_guint8(tvb, offset+1);
1665 switch(tmpbyte&0xf0){
1672 /* CSG and NSG must not be 2 */
1673 if(((tmpbyte&0x03)==0x02)
1674 || ((tmpbyte&0xc0)==0x08)){
1677 /* if T bit is set NSG must not be 0 */
1679 if(!(tmpbyte&0x03)){
1683 /* should we test that datasegmentlen is non zero? */
1685 case ISCSI_OPCODE_LOGIN_RESPONSE:
1686 /* top two bits in byte 0 must be 0 */
1687 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1691 /* both the T and C bits can not be set
1692 * and the two reserved bits in byte 1 must be 0
1694 tmpbyte=tvb_get_guint8(tvb, offset+1);
1695 switch(tmpbyte&0xf0){
1703 /* CSG and NSG must not be 2 */
1704 if(((tmpbyte&0x03)==0x02)
1705 || ((tmpbyte&0xc0)==0x08)){
1708 /* if T bit is set NSG must not be 0 */
1710 if(!(tmpbyte&0x03)){
1714 /* the 32bit words at offsets 20, 40, 44 must be zero */
1715 if(tvb_get_letohl(tvb,offset+20)
1716 || tvb_get_letohl(tvb,offset+40)
1717 || tvb_get_letohl(tvb,offset+44)){
1720 /* the two bytes at offset 38 must be zero */
1721 if(tvb_get_letohs(tvb,offset+38)){
1724 /* should we test that datasegmentlen is non zero unless we just
1725 * entered full featured phase?
1728 case ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION:
1729 /* top bit in byte 0 must be 0 */
1730 if(tvb_get_guint8(tvb, offset+0)&0x80){
1733 /* top bit in byte 1 must be set */
1734 tmpbyte=tvb_get_guint8(tvb, offset+1);
1735 if(!(tmpbyte&0x80)){
1738 /* Function must be known */
1739 if(!match_strval(tmpbyte&0x7f, iscsi_task_management_functions)){
1742 /* bytes 2,3 must be null */
1743 if(tvb_get_letohs(tvb,offset+2)){
1746 /* ahs and dsl must be null */
1747 if(tvb_get_letohl(tvb,offset+4)){
1751 case ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE:
1752 /* top two bits in byte 0 must be 0 */
1753 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1756 /* byte 1 must be 0x80 */
1757 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1760 /* response must be 0-6 or 255 */
1761 tmpbyte=tvb_get_guint8(tvb,offset+2);
1762 if(tmpbyte>6 && tmpbyte<255){
1765 /* byte 3 must be 0 */
1766 if(tvb_get_guint8(tvb,offset+3)){
1769 /* ahs and dsl as well as the 32bit words at offsets 8, 12, 20, 36
1770 * 40, 44 must all be 0
1772 if(tvb_get_letohl(tvb,offset+4)
1773 || tvb_get_letohl(tvb,offset+8)
1774 || tvb_get_letohl(tvb,offset+12)
1775 || tvb_get_letohl(tvb,offset+20)
1776 || tvb_get_letohl(tvb,offset+36)
1777 || tvb_get_letohl(tvb,offset+40)
1778 || tvb_get_letohl(tvb,offset+44)){
1782 case ISCSI_OPCODE_LOGOUT_COMMAND:
1783 /* top bit in byte 0 must be 0 */
1784 if(tvb_get_guint8(tvb, offset+0)&0x80){
1787 /* top bit in byte 1 must be set */
1788 tmpbyte=tvb_get_guint8(tvb, offset+1);
1789 if(!(tmpbyte&0x80)){
1792 /* Reason code must be known */
1793 if(!match_strval(tmpbyte&0x7f, iscsi_logout_reasons)){
1796 /* bytes 2,3 must be null */
1797 if(tvb_get_letohs(tvb,offset+2)){
1800 /* ahs and dsl as well as the 32bit words at offsets 8, 12, 32, 36
1801 * 40, 44 must all be 0
1803 if(tvb_get_letohl(tvb,offset+4)
1804 || tvb_get_letohl(tvb,offset+8)
1805 || tvb_get_letohl(tvb,offset+12)
1806 || tvb_get_letohl(tvb,offset+32)
1807 || tvb_get_letohl(tvb,offset+36)
1808 || tvb_get_letohl(tvb,offset+40)
1809 || tvb_get_letohl(tvb,offset+44)){
1813 case ISCSI_OPCODE_SNACK_REQUEST:
1814 /* top two bits in byte 0 must be 0 */
1815 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1818 /* top 4 bits in byte 1 must be 0x80 */
1819 tmpbyte=tvb_get_guint8(tvb, offset+1);
1820 if((tmpbyte&0xf0)!=0x80){
1823 /* type must be known */
1824 if(!match_strval(tmpbyte&0x0f, iscsi_snack_types)){
1827 /* for status/snack and datack itt must be 0xffffffff
1828 * for rdata/snack ttt must not be 0 or 0xffffffff
1830 switch(tmpbyte&0x0f){
1833 if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
1838 if(tvb_get_letohl(tvb,offset+20)==0xffffffff){
1841 if(tvb_get_letohl(tvb,offset+20)==0){
1846 /* bytes 2,3 must be null */
1847 if(tvb_get_letohs(tvb,offset+2)){
1850 /* the 32bit words at offsets 24, 32, 36
1853 if(tvb_get_letohl(tvb,offset+24)
1854 || tvb_get_letohl(tvb,offset+32)
1855 || tvb_get_letohl(tvb,offset+36)){
1860 case ISCSI_OPCODE_R2T:
1861 /* top two bits in byte 0 must be 0 */
1862 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1865 /* byte 1 must be 0x80 */
1866 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1869 /* bytes 2,3 must be null */
1870 if(tvb_get_letohs(tvb,offset+2)){
1873 /* ahs and dsl must be null */
1874 if(tvb_get_letohl(tvb,offset+4)){
1877 /* desired data transfer length must not be null */
1878 if(!tvb_get_letohl(tvb,offset+44)){
1882 case ISCSI_OPCODE_REJECT:
1883 /* top two bits in byte 0 must be 0 */
1884 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1887 /* byte 1 must be 0x80 */
1888 if(tvb_get_guint8(tvb, offset+1)!=0x80){
1891 /* reason must be known */
1892 if(!match_strval(tvb_get_guint8(tvb,offset+2), iscsi_reject_reasons)){
1895 /* byte 3 must be 0 */
1896 if(tvb_get_guint8(tvb, offset+3)){
1899 /* the 32bit words at offsets 8, 12, 20, 40, 44
1902 if(tvb_get_letohl(tvb,offset+8)
1903 || tvb_get_letohl(tvb,offset+12)
1904 || tvb_get_letohl(tvb,offset+20)
1905 || tvb_get_letohl(tvb,offset+40)
1906 || tvb_get_letohl(tvb,offset+44)){
1909 /* the 32bit word at 16 must be 0xffffffff */
1910 if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
1914 case ISCSI_OPCODE_TEXT_COMMAND:
1915 /* top bit in byte 0 must be 0 */
1916 if(tvb_get_guint8(tvb, offset+0)&0x80){
1919 /* one of the F and C bits must be set but not both
1920 * low 6 bits in byte 1 must be 0
1922 switch(tvb_get_guint8(tvb,offset+1)){
1929 /* bytes 2,3 must be null */
1930 if(tvb_get_letohs(tvb,offset+2)){
1933 /* the 32bit words at offsets 32, 36, 40, 44
1936 if(tvb_get_letohl(tvb,offset+32)
1937 || tvb_get_letohl(tvb,offset+36)
1938 || tvb_get_letohl(tvb,offset+40)
1939 || tvb_get_letohl(tvb,offset+44)){
1943 case ISCSI_OPCODE_TEXT_RESPONSE:
1944 /* top two bits in byte 0 must be 0 */
1945 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1948 /* one of the F and C bits must be set but not both
1949 * low 6 bits in byte 1 must be 0
1951 switch(tvb_get_guint8(tvb,offset+1)){
1958 /* bytes 2,3 must be null */
1959 if(tvb_get_letohs(tvb,offset+2)){
1962 /* the 32bit words at offsets 36, 40, 44
1965 if(tvb_get_letohl(tvb,offset+36)
1966 || tvb_get_letohl(tvb,offset+40)
1967 || tvb_get_letohl(tvb,offset+44)){
1971 case ISCSI_OPCODE_SCSI_COMMAND:
1972 /* top bit in byte 0 must be 0 */
1973 if(tvb_get_guint8(tvb, offset+0)&0x80){
1976 /* reserved bits in byte 1 must be 0 */
1977 if(tvb_get_guint8(tvb, offset+1)&0x18){
1980 /* bytes 2,3 must be null */
1981 if(tvb_get_letohs(tvb,offset+2)){
1984 /* expected data transfer length is never >16MByte ? */
1985 if(tvb_get_guint8(tvb,offset+20)){
1989 case ISCSI_OPCODE_SCSI_RESPONSE:
1990 /* top two bits in byte 0 must be 0 */
1991 if(tvb_get_guint8(tvb, offset+0)&0xc0){
1994 /* top bit in byte 1 must be 1 */
1995 tmpbyte=tvb_get_guint8(tvb,offset+1);
1996 if(!(tmpbyte&0x80)){
1999 /* the reserved bits in byte 1 must be 0 */
2003 /* status must be known */
2004 if(!match_strval(tvb_get_guint8(tvb,offset+3), scsi_status_val)){
2007 /* the 32bit words at offsets 8, 12
2010 if(tvb_get_letohl(tvb,offset+8)
2011 || tvb_get_letohl(tvb,offset+12)){
2015 case ISCSI_OPCODE_ASYNC_MESSAGE:
2016 /* top two bits in byte 0 must be 0 */
2017 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2020 /* byte 1 must be 0x80 */
2021 if(tvb_get_guint8(tvb, offset+1)!=0x80){
2024 /* bytes 2,3 must be null */
2025 if(tvb_get_letohs(tvb,offset+2)){
2028 /* the 32bit words at offsets 20, 44
2031 if(tvb_get_letohl(tvb,offset+20)
2032 || tvb_get_letohl(tvb,offset+44)){
2035 /* the 32bit word at 16 must be 0xffffffff */
2036 if(tvb_get_letohl(tvb,offset+16)!=0xffffffff){
2040 case ISCSI_OPCODE_LOGOUT_RESPONSE:
2041 /* top two bits in byte 0 must be 0 */
2042 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2045 /* byte 1 must be 0x80 */
2046 if(tvb_get_guint8(tvb, offset+1)!=0x80){
2049 /* response must be known */
2050 if(!match_strval(tvb_get_guint8(tvb,offset+2), iscsi_logout_response)){
2053 /* byte 3 must be 0 */
2054 if(tvb_get_guint8(tvb,offset+3)){
2057 /* ahs and dsl as well as the 32bit words at offsets 8, 12, 20, 36
2060 if(tvb_get_letohl(tvb,offset+4)
2061 || tvb_get_letohl(tvb,offset+8)
2062 || tvb_get_letohl(tvb,offset+12)
2063 || tvb_get_letohl(tvb,offset+20)
2064 || tvb_get_letohl(tvb,offset+36)
2065 || tvb_get_letohl(tvb,offset+44)){
2069 case ISCSI_OPCODE_SCSI_DATA_OUT:
2070 /* top two bits in byte 0 must be 0 */
2071 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2074 /* low 7 bits in byte 1 must be 0 */
2075 if(tvb_get_guint8(tvb,offset+1)&0x7f){
2078 /* bytes 2,3 must be null */
2079 if(tvb_get_letohs(tvb,offset+2)){
2082 /* the 32bit words at offsets 24, 32, 44
2085 if(tvb_get_letohl(tvb,offset+24)
2086 || tvb_get_letohl(tvb,offset+32)
2087 || tvb_get_letohl(tvb,offset+44)){
2091 case ISCSI_OPCODE_SCSI_DATA_IN:
2092 /* top two bits in byte 0 must be 0 */
2093 if(tvb_get_guint8(tvb, offset+0)&0xc0){
2096 /* reserved bits in byte 1 must be 0 */
2097 if(tvb_get_guint8(tvb,offset+1)&0x38){
2100 /* byte 2 must be reserved */
2101 if(tvb_get_guint8(tvb,offset+2)){
2105 case ISCSI_OPCODE_VENDOR_SPECIFIC_I0:
2106 case ISCSI_OPCODE_VENDOR_SPECIFIC_I1:
2107 case ISCSI_OPCODE_VENDOR_SPECIFIC_I2:
2108 case ISCSI_OPCODE_VENDOR_SPECIFIC_T0:
2109 case ISCSI_OPCODE_VENDOR_SPECIFIC_T1:
2110 case ISCSI_OPCODE_VENDOR_SPECIFIC_T2:
2117 /* process multiple iSCSI PDUs per packet */
2118 while(available_bytes >= 48 || (iscsi_desegment && available_bytes >= 8)) {
2119 const char *opcode_str = NULL;
2120 guint32 data_segment_len;
2121 guint32 pduLen = 48;
2122 guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1);
2125 /* mask out any extra bits in the opcode byte */
2126 opcode = tvb_get_guint8(tvb, offset + 0);
2127 opcode &= OPCODE_MASK;
2129 opcode_str = match_strval(opcode, iscsi_opcodes);
2130 if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION ||
2131 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
2132 opcode == ISCSI_OPCODE_R2T ||
2133 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
2134 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
2135 opcode == ISCSI_OPCODE_SNACK_REQUEST)
2136 data_segment_len = 0;
2138 data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
2140 if(opcode_str == NULL) {
2143 else if(check_port && iscsi_port != 0 &&
2144 (((opcode & TARGET_OPCODE_BIT) && pinfo->srcport != iscsi_port) ||
2145 (!(opcode & TARGET_OPCODE_BIT) && pinfo->destport != iscsi_port))) {
2148 else if(enable_bogosity_filter) {
2149 /* try and distinguish between data and real headers */
2150 if(data_segment_len > bogus_pdu_data_length_threshold) {
2153 else if(demand_good_f_bit &&
2154 !(secondPduByte & 0x80) &&
2155 (opcode == ISCSI_OPCODE_NOP_OUT ||
2156 opcode == ISCSI_OPCODE_NOP_IN ||
2157 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
2158 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
2159 opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
2160 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
2161 opcode == ISCSI_OPCODE_R2T ||
2162 opcode == ISCSI_OPCODE_ASYNC_MESSAGE ||
2163 opcode == ISCSI_OPCODE_SNACK_REQUEST ||
2164 opcode == ISCSI_OPCODE_REJECT)) {
2166 } else if(opcode==ISCSI_OPCODE_NOP_OUT) {
2167 /* TransferTag for NOP-Out should either be -1 or
2168 the tag value we want for a response.
2169 Assume 0 means we are just inside a big all zero
2172 if(tvb_get_ntohl(tvb, offset+20)==0){
2179 return iSCSIPdusDissected > 0;
2182 if(opcode == ISCSI_OPCODE_LOGIN_COMMAND ||
2183 opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
2184 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
2185 if((secondPduByte & CSG_MASK) < ISCSI_CSG_OPERATIONAL_NEGOTIATION) {
2186 /* digests are not yet turned on */
2194 if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
2196 pduLen += tvb_get_guint8(tvb, offset + 4) * 4;
2199 pduLen += data_segment_len;
2200 if((pduLen & 3) != 0)
2201 pduLen += 4 - (pduLen & 3);
2204 if(digestsActive && data_segment_len > 0 && enableDataDigests) {
2205 if(dataDigestIsCRC32)
2208 pduLen += dataDigestSize;
2211 /* make sure we have a conversation for this session */
2212 conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
2213 pinfo->ptype, pinfo->srcport,
2214 pinfo->destport, 0);
2215 if (!conversation) {
2216 conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst,
2217 pinfo->ptype, pinfo->srcport,
2218 pinfo->destport, 0);
2220 iscsi_session=conversation_get_proto_data(conversation, proto_iscsi);
2222 iscsi_session=se_alloc(sizeof(iscsi_session_t));
2223 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_AUTO;
2224 iscsi_session->itlq=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "iSCSI ITLQ");
2225 iscsi_session->itl=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "iSCSI ITL");
2226 conversation_add_proto_data(conversation, proto_iscsi, iscsi_session);
2228 /* DataOut PDUs are often mistaken by DCERPC heuristics to be
2229 * that protocol. Now that we know this is iscsi, set a
2230 * dissector for this conversation to block other heuristic
2233 conversation_set_dissector(conversation, iscsi_handle);
2235 /* try to autodetect if header digest is used or not */
2236 if(digestsActive && (available_bytes>=52) && (iscsi_session->header_digest==ISCSI_HEADER_DIGEST_AUTO) ){
2238 /* we have enough data to test if HeaderDigest is enabled */
2239 crc= ~calculateCRC32(tvb_get_ptr(tvb, offset, 48), 48, CRC32C_PRELOAD);
2240 if(crc==tvb_get_ntohl(tvb,48)){
2241 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_CRC32;
2243 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_NONE;
2248 /* Add header digest length to pdulen */
2250 switch(iscsi_session->header_digest){
2251 case ISCSI_HEADER_DIGEST_CRC32:
2254 case ISCSI_HEADER_DIGEST_NONE:
2256 case ISCSI_HEADER_DIGEST_AUTO:
2257 /* oops we didnt know what digest is used yet */
2258 /* here we should use some default */
2261 DISSECTOR_ASSERT_NOT_REACHED();
2266 * Desegmentation check.
2268 if(iscsi_desegment && pinfo->can_desegment) {
2269 if(pduLen > available_bytes) {
2271 * This frame doesn't have all of the data for
2272 * this message, but we can do reassembly on it.
2274 * Tell the TCP dissector where the data for this
2275 * message starts in the data it handed us, and
2276 * how many more bytes we need, and return.
2278 pinfo->desegment_offset = offset;
2279 pinfo->desegment_len = pduLen - available_bytes;
2284 /* This is to help TCP keep track of PDU boundaries
2285 and allows it to find PDUs that are not aligned to
2286 the start of a TCP segments.
2287 Since it also allows TCP to know what is in the middle
2288 of a large PDU, it reduces the probability of a segment
2289 in the middle of a large PDU transfer being misdissected as
2292 if(!pinfo->fd->flags.visited){
2293 if(pduLen>(guint32)tvb_reported_length_remaining(tvb, offset)){
2294 pinfo->want_pdu_tracking=2;
2295 pinfo->bytes_until_next_pdu=pduLen-tvb_reported_length_remaining(tvb, offset);
2299 if(check_col(pinfo->cinfo, COL_INFO)) {
2300 if(iSCSIPdusDissected == 0)
2301 col_set_str(pinfo->cinfo, COL_INFO, "");
2303 col_append_str(pinfo->cinfo, COL_INFO, ", ");
2306 dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len, iscsi_session);
2307 if(pduLen > available_bytes)
2308 pduLen = available_bytes;
2310 available_bytes -= pduLen;
2311 ++iSCSIPdusDissected;
2314 return iSCSIPdusDissected > 0;
2317 /* This is called for those sessions where we have explicitely said
2318 this to be iSCSI using "Decode As..."
2319 In this case we will not check the port number for sanity and just
2320 do as the user said.
2321 We still check that the PDU header looks sane though.
2324 dissect_iscsi_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
2325 return dissect_iscsi(tvb, pinfo, tree, FALSE);
2328 /* This is called through the heuristic handler.
2329 In this case we also want to check that the port matches the preference
2330 setting for iSCSI in order to reduce the number of
2334 dissect_iscsi_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
2335 return dissect_iscsi(tvb, pinfo, tree, TRUE);
2339 /* Register the protocol with Wireshark */
2342 * this format is require because a script is used to build the C
2343 * function that calls all the protocol registration.
2347 proto_register_iscsi(void)
2350 /* Setup list of header fields See Section 1.6.1 for details*/
2351 static hf_register_info hf[] = {
2352 { &hf_iscsi_request_frame,
2353 { "Request in", "iscsi.request_frame",
2354 FT_FRAMENUM, BASE_NONE, NULL, 0,
2355 "The request to this transaction is in this frame", HFILL }},
2358 { "Time from request", "iscsi.time",
2359 FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
2360 "Time between the Command and the Response", HFILL }},
2362 { &hf_iscsi_data_in_frame,
2363 { "Data In in", "iscsi.data_in_frame",
2364 FT_FRAMENUM, BASE_NONE, NULL, 0,
2365 "The Data In for this transaction is in this frame", HFILL }},
2367 { &hf_iscsi_data_out_frame,
2368 { "Data Out in", "iscsi.data_out_frame",
2369 FT_FRAMENUM, BASE_NONE, NULL, 0,
2370 "The Data Out for this transaction is in this frame", HFILL }},
2372 { &hf_iscsi_response_frame,
2373 { "Response in", "iscsi.response_frame",
2374 FT_FRAMENUM, BASE_NONE, NULL, 0,
2375 "The response to this transaction is in this frame", HFILL }},
2378 { "AHS", "iscsi.ahs",
2379 FT_BYTES, BASE_HEX, NULL, 0,
2380 "Additional header segment", HFILL }
2382 { &hf_iscsi_Padding,
2383 { "Padding", "iscsi.padding",
2384 FT_BYTES, BASE_HEX, NULL, 0,
2385 "Padding to 4 byte boundary", HFILL }
2387 { &hf_iscsi_ping_data,
2388 { "PingData", "iscsi.pingdata",
2389 FT_BYTES, BASE_HEX, NULL, 0,
2390 "Ping Data", HFILL }
2392 { &hf_iscsi_immediate_data,
2393 { "ImmediateData", "iscsi.immediatedata",
2394 FT_BYTES, BASE_HEX, NULL, 0,
2395 "Immediate Data", HFILL }
2397 { &hf_iscsi_write_data,
2398 { "WriteData", "iscsi.writedata",
2399 FT_BYTES, BASE_HEX, NULL, 0,
2400 "Write Data", HFILL }
2402 { &hf_iscsi_read_data,
2403 { "ReadData", "iscsi.readdata",
2404 FT_BYTES, BASE_HEX, NULL, 0,
2405 "Read Data", HFILL }
2407 { &hf_iscsi_error_pdu_data,
2408 { "ErrorPDUData", "iscsi.errorpdudata",
2409 FT_BYTES, BASE_HEX, NULL, 0,
2410 "Error PDU Data", HFILL }
2412 { &hf_iscsi_async_message_data,
2413 { "AsyncMessageData", "iscsi.asyncmessagedata",
2414 FT_BYTES, BASE_HEX, NULL, 0,
2415 "Async Message Data", HFILL }
2417 { &hf_iscsi_vendor_specific_data,
2418 { "VendorSpecificData", "iscsi.vendorspecificdata",
2419 FT_BYTES, BASE_HEX, NULL, 0,
2420 "Vendor Specific Data", HFILL }
2422 { &hf_iscsi_HeaderDigest32,
2423 { "HeaderDigest", "iscsi.headerdigest32",
2424 FT_UINT32, BASE_HEX, NULL, 0,
2425 "Header Digest", HFILL }
2427 { &hf_iscsi_DataDigest,
2428 { "DataDigest", "iscsi.datadigest",
2429 FT_BYTES, BASE_HEX, NULL, 0,
2430 "Data Digest", HFILL }
2432 { &hf_iscsi_DataDigest32,
2433 { "DataDigest", "iscsi.datadigest32",
2434 FT_UINT32, BASE_HEX, NULL, 0,
2435 "Data Digest", HFILL }
2438 { "Opcode", "iscsi.opcode",
2439 FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
2442 /* #ifdef DRAFT08 */
2445 FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,
2446 "Command Retry", HFILL }
2451 FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,
2452 "Immediate delivery", HFILL }
2455 { "Flags", "iscsi.flags",
2456 FT_UINT8, BASE_HEX, NULL, 0,
2457 "Opcode specific flags", HFILL }
2459 { &hf_iscsi_SCSICommand_F,
2460 { "F", "iscsi.scsicommand.F",
2461 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
2462 "PDU completes command", HFILL }
2464 { &hf_iscsi_SCSICommand_R,
2465 { "R", "iscsi.scsicommand.R",
2466 FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,
2467 "Command reads from SCSI target", HFILL }
2469 { &hf_iscsi_SCSICommand_W,
2470 { "W", "iscsi.scsicommand.W",
2471 FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,
2472 "Command writes to SCSI target", HFILL }
2474 { &hf_iscsi_SCSICommand_Attr,
2475 { "Attr", "iscsi.scsicommand.attr",
2476 FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07,
2477 "SCSI task attributes", HFILL }
2479 { &hf_iscsi_SCSICommand_CRN,
2480 { "CRN", "iscsi.scsicommand.crn",
2481 FT_UINT8, BASE_HEX, NULL, 0,
2482 "SCSI command reference number", HFILL }
2484 { &hf_iscsi_SCSICommand_AddCDB,
2485 { "AddCDB", "iscsi.scsicommand.addcdb",
2486 FT_UINT8, BASE_HEX, NULL, 0,
2487 "Additional CDB length (in 4 byte units)", HFILL }
2489 { &hf_iscsi_DataSegmentLength,
2490 { "DataSegmentLength", "iscsi.datasegmentlength",
2491 FT_UINT32, BASE_HEX, NULL, 0,
2492 "Data segment length (bytes)", HFILL }
2494 { &hf_iscsi_TotalAHSLength,
2495 { "TotalAHSLength", "iscsi.totalahslength",
2496 FT_UINT8, BASE_HEX, NULL, 0,
2497 "Total additional header segment length (4 byte words)", HFILL }
2500 { "LUN", "iscsi.lun",
2501 FT_BYTES, BASE_HEX, NULL, 0,
2502 "Logical Unit Number", HFILL }
2504 { &hf_iscsi_InitiatorTaskTag,
2505 { "InitiatorTaskTag", "iscsi.initiatortasktag",
2506 FT_UINT32, BASE_HEX, NULL, 0,
2507 "Initiator's task tag", HFILL }
2509 { &hf_iscsi_ExpectedDataTransferLength,
2510 { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength",
2511 FT_UINT32, BASE_HEX, NULL, 0,
2512 "Expected length of data transfer", HFILL }
2515 { "CmdSN", "iscsi.cmdsn",
2516 FT_UINT32, BASE_HEX, NULL, 0,
2517 "Sequence number for this command", HFILL }
2519 { &hf_iscsi_ExpStatSN,
2520 { "ExpStatSN", "iscsi.expstatsn",
2521 FT_UINT32, BASE_HEX, NULL, 0,
2522 "Next expected status sequence number", HFILL }
2524 { &hf_iscsi_SCSIResponse_ResidualCount,
2525 { "ResidualCount", "iscsi.scsiresponse.residualcount",
2526 FT_UINT32, BASE_HEX, NULL, 0,
2527 "Residual count", HFILL }
2530 { "StatSN", "iscsi.statsn",
2531 FT_UINT32, BASE_HEX, NULL, 0,
2532 "Status sequence number", HFILL }
2534 { &hf_iscsi_ExpCmdSN,
2535 { "ExpCmdSN", "iscsi.expcmdsn",
2536 FT_UINT32, BASE_HEX, NULL, 0,
2537 "Next expected command sequence number", HFILL }
2539 { &hf_iscsi_MaxCmdSN,
2540 { "MaxCmdSN", "iscsi.maxcmdsn",
2541 FT_UINT32, BASE_HEX, NULL, 0,
2542 "Maximum acceptable command sequence number", HFILL }
2544 { &hf_iscsi_SCSIResponse_o,
2545 { "o", "iscsi.scsiresponse.o",
2546 FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,
2547 "Bi-directional read residual overflow", HFILL }
2549 { &hf_iscsi_SCSIResponse_u,
2550 { "u", "iscsi.scsiresponse.u",
2551 FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08,
2552 "Bi-directional read residual underflow", HFILL }
2554 { &hf_iscsi_SCSIResponse_O,
2555 { "O", "iscsi.scsiresponse.O",
2556 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
2557 "Residual overflow", HFILL }
2559 { &hf_iscsi_SCSIResponse_U,
2560 { "U", "iscsi.scsiresponse.U",
2561 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
2562 "Residual underflow", HFILL }
2564 { &hf_iscsi_SCSIResponse_Status,
2565 { "Status", "iscsi.scsiresponse.status",
2566 FT_UINT8, BASE_HEX, VALS(scsi_status_val), 0,
2567 "SCSI command status value", HFILL }
2569 { &hf_iscsi_SCSIResponse_Response,
2570 { "Response", "iscsi.scsiresponse.response",
2571 FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
2572 "SCSI command response value", HFILL }
2574 { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
2575 { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
2576 FT_UINT32, BASE_HEX, NULL, 0,
2577 "Bi-directional read residual count", HFILL }
2579 { &hf_iscsi_SenseLength,
2580 { "SenseLength", "iscsi.scsiresponse.senselength",
2581 FT_UINT16, BASE_HEX, NULL, 0,
2582 "Sense data length", HFILL }
2584 { &hf_iscsi_SCSIData_F,
2585 { "F", "iscsi.scsidata.F",
2586 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), ISCSI_SCSI_DATA_FLAG_F,
2587 "Final PDU", HFILL }
2589 { &hf_iscsi_SCSIData_A,
2590 { "A", "iscsi.scsidata.A",
2591 FT_BOOLEAN, 8, TFS(&iscsi_meaning_A), ISCSI_SCSI_DATA_FLAG_A,
2592 "Acknowledge Requested", HFILL }
2594 { &hf_iscsi_SCSIData_S,
2595 { "S", "iscsi.scsidata.S",
2596 FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), ISCSI_SCSI_DATA_FLAG_S,
2597 "PDU Contains SCSI command status", HFILL }
2599 { &hf_iscsi_SCSIData_U,
2600 { "U", "iscsi.scsidata.U",
2601 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), ISCSI_SCSI_DATA_FLAG_U,
2602 "Residual underflow", HFILL }
2604 { &hf_iscsi_SCSIData_O,
2605 { "O", "iscsi.scsidata.O",
2606 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), ISCSI_SCSI_DATA_FLAG_O,
2607 "Residual overflow", HFILL }
2609 { &hf_iscsi_TargetTransferTag,
2610 { "TargetTransferTag", "iscsi.targettransfertag",
2611 FT_UINT32, BASE_HEX, NULL, 0,
2612 "Target transfer tag", HFILL }
2614 { &hf_iscsi_BufferOffset,
2615 { "BufferOffset", "iscsi.bufferOffset",
2616 FT_UINT32, BASE_HEX, NULL, 0,
2617 "Buffer offset", HFILL }
2619 { &hf_iscsi_SCSIData_ResidualCount,
2620 { "ResidualCount", "iscsi.scsidata.readresidualcount",
2621 FT_UINT32, BASE_HEX, NULL, 0,
2622 "Residual count", HFILL }
2625 { "DataSN", "iscsi.datasn",
2626 FT_UINT32, BASE_HEX, NULL, 0,
2627 "Data sequence number", HFILL }
2629 { &hf_iscsi_VersionMax,
2630 { "VersionMax", "iscsi.versionmax",
2631 FT_UINT8, BASE_HEX, NULL, 0,
2632 "Maximum supported protocol version", HFILL }
2634 { &hf_iscsi_VersionMin,
2635 { "VersionMin", "iscsi.versionmin",
2636 FT_UINT8, BASE_HEX, NULL, 0,
2637 "Minimum supported protocol version", HFILL }
2639 { &hf_iscsi_VersionActive,
2640 { "VersionActive", "iscsi.versionactive",
2641 FT_UINT8, BASE_HEX, NULL, 0,
2642 "Negotiated protocol version", HFILL }
2645 { "CID", "iscsi.cid",
2646 FT_UINT16, BASE_HEX, NULL, 0,
2647 "Connection identifier", HFILL }
2649 /* #ifdef DRAFT08 */
2651 { "ISID", "iscsi.isid",
2652 FT_UINT16, BASE_HEX, NULL, 0,
2653 "Initiator part of session identifier", HFILL }
2657 { "ISID", "iscsi.isid",
2658 FT_BYTES, BASE_HEX, NULL, 0,
2659 "Initiator part of session identifier", HFILL }
2661 /* #ifdef DRAFT09 */
2662 { &hf_iscsi_ISID_Type,
2663 { "ISID_Type", "iscsi.isid.type",
2664 FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0,
2665 "Initiator part of session identifier - type", HFILL }
2667 { &hf_iscsi_ISID_NamingAuthority,
2668 { "ISID_NamingAuthority", "iscsi.isid.namingauthority",
2669 FT_UINT24, BASE_HEX, NULL, 0,
2670 "Initiator part of session identifier - naming authority", HFILL }
2672 { &hf_iscsi_ISID_Qualifier,
2673 { "ISID_Qualifier", "iscsi.isid.qualifier",
2674 FT_UINT8, BASE_HEX, NULL, 0,
2675 "Initiator part of session identifier - qualifier", HFILL }
2679 { "ISID_t", "iscsi.isid.t",
2680 FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0xc0,
2681 "Initiator part of session identifier - t", HFILL }
2684 { "ISID_a", "iscsi.isid.a",
2685 FT_UINT8, BASE_HEX, NULL, 0x3f,
2686 "Initiator part of session identifier - a", HFILL }
2689 { "ISID_b", "iscsi.isid.b",
2690 FT_UINT16, BASE_HEX, NULL, 0,
2691 "Initiator part of session identifier - b", HFILL }
2694 { "ISID_c", "iscsi.isid.c",
2695 FT_UINT8, BASE_HEX, NULL, 0,
2696 "Initiator part of session identifier - c", HFILL }
2699 { "ISID_d", "iscsi.isid.d",
2700 FT_UINT16, BASE_HEX, NULL, 0,
2701 "Initiator part of session identifier - d", HFILL }
2706 { "TSID", "iscsi.tsid",
2707 FT_UINT16, BASE_HEX, NULL, 0,
2708 "Target part of session identifier", HFILL }
2711 { "TSIH", "iscsi.tsih",
2712 FT_UINT16, BASE_HEX, NULL, 0,
2713 "Target session identifying handle", HFILL }
2715 { &hf_iscsi_InitStatSN,
2716 { "InitStatSN", "iscsi.initstatsn",
2717 FT_UINT32, BASE_HEX, NULL, 0,
2718 "Initial status sequence number", HFILL }
2720 { &hf_iscsi_InitCmdSN,
2721 { "InitCmdSN", "iscsi.initcmdsn",
2722 FT_UINT32, BASE_HEX, NULL, 0,
2723 "Initial command sequence number", HFILL }
2725 { &hf_iscsi_Login_T,
2726 { "T", "iscsi.login.T",
2727 FT_BOOLEAN, 8, TFS(&iscsi_meaning_T), 0x80,
2728 "Transit to next login stage", HFILL }
2730 { &hf_iscsi_Login_C,
2731 { "C", "iscsi.login.C",
2732 FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2733 "Text incomplete", HFILL }
2735 /* #ifdef DRAFT09 */
2736 { &hf_iscsi_Login_X,
2737 { "X", "iscsi.login.X",
2738 FT_BOOLEAN, 8, TFS(&iscsi_meaning_login_X), 0x40,
2739 "Restart Connection", HFILL }
2742 { &hf_iscsi_Login_CSG,
2743 { "CSG", "iscsi.login.csg",
2744 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), CSG_MASK,
2745 "Current stage", HFILL }
2747 { &hf_iscsi_Login_NSG,
2748 { "NSG", "iscsi.login.nsg",
2749 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), NSG_MASK,
2750 "Next stage", HFILL }
2752 { &hf_iscsi_Login_Status,
2753 { "Status", "iscsi.login.status",
2754 FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0,
2755 "Status class and detail", HFILL }
2757 { &hf_iscsi_KeyValue,
2758 { "KeyValue", "iscsi.keyvalue",
2759 FT_STRING, 0, NULL, 0,
2760 "Key/value pair", HFILL }
2763 { "F", "iscsi.text.F",
2764 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
2765 "Final PDU in text sequence", HFILL }
2768 { "C", "iscsi.text.C",
2769 FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2770 "Text incomplete", HFILL }
2772 { &hf_iscsi_ExpDataSN,
2773 { "ExpDataSN", "iscsi.expdatasn",
2774 FT_UINT32, BASE_HEX, NULL, 0,
2775 "Next expected data sequence number", HFILL }
2778 { "R2TSN", "iscsi.r2tsn",
2779 FT_UINT32, BASE_HEX, NULL, 0,
2780 "R2T PDU Number", HFILL }
2782 { &hf_iscsi_TaskManagementFunction_Response,
2783 { "Response", "iscsi.taskmanfun.response",
2784 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_responses), 0,
2787 { &hf_iscsi_TaskManagementFunction_ReferencedTaskTag,
2788 { "ReferencedTaskTag", "iscsi.taskmanfun.referencedtasktag",
2789 FT_UINT32, BASE_HEX, NULL, 0,
2790 "Referenced task tag", HFILL }
2792 { &hf_iscsi_RefCmdSN,
2793 { "RefCmdSN", "iscsi.refcmdsn",
2794 FT_UINT32, BASE_HEX, NULL, 0,
2795 "Command sequence number for command to be aborted", HFILL }
2797 { &hf_iscsi_TaskManagementFunction_Function,
2798 { "Function", "iscsi.taskmanfun.function",
2799 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_functions), 0x7F,
2800 "Requested task function", HFILL }
2802 { &hf_iscsi_Logout_Reason,
2803 { "Reason", "iscsi.logout.reason",
2804 FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0x7F,
2805 "Reason for logout", HFILL }
2807 { &hf_iscsi_Logout_Response,
2808 { "Response", "iscsi.logout.response",
2809 FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
2810 "Logout response", HFILL }
2812 { &hf_iscsi_Time2Wait,
2813 { "Time2Wait", "iscsi.time2wait",
2814 FT_UINT16, BASE_HEX, NULL, 0,
2815 "Time2Wait", HFILL }
2817 { &hf_iscsi_Time2Retain,
2818 { "Time2Retain", "iscsi.time2retain",
2819 FT_UINT16, BASE_HEX, NULL, 0,
2820 "Time2Retain", HFILL }
2822 { &hf_iscsi_DesiredDataLength,
2823 { "DesiredDataLength", "iscsi.desireddatalength",
2824 FT_UINT32, BASE_HEX, NULL, 0,
2825 "Desired data length (bytes)", HFILL }
2827 { &hf_iscsi_AsyncEvent,
2828 { "AsyncEvent", "iscsi.asyncevent",
2829 FT_UINT8, BASE_HEX, VALS(iscsi_asyncevents), 0,
2830 "Async event type", HFILL }
2832 { &hf_iscsi_EventVendorCode,
2833 { "EventVendorCode", "iscsi.eventvendorcode",
2834 FT_UINT8, BASE_HEX, NULL, 0,
2835 "Event vendor code", HFILL }
2837 { &hf_iscsi_Parameter1,
2838 { "Parameter1", "iscsi.parameter1",
2839 FT_UINT16, BASE_HEX, NULL, 0,
2840 "Parameter 1", HFILL }
2842 { &hf_iscsi_Parameter2,
2843 { "Parameter2", "iscsi.parameter2",
2844 FT_UINT16, BASE_HEX, NULL, 0,
2845 "Parameter 2", HFILL }
2847 { &hf_iscsi_Parameter3,
2848 { "Parameter3", "iscsi.parameter3",
2849 FT_UINT16, BASE_HEX, NULL, 0,
2850 "Parameter 3", HFILL }
2852 { &hf_iscsi_Reject_Reason,
2853 { "Reason", "iscsi.reject.reason",
2854 FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
2855 "Reason for command rejection", HFILL }
2857 { &hf_iscsi_snack_type,
2858 { "S", "iscsi.snack.type",
2859 FT_UINT8, BASE_DEC, VALS(iscsi_snack_types), 0x0f,
2860 "Type of SNACK requested", HFILL }
2863 { "BegRun", "iscsi.snack.begrun",
2864 FT_UINT32, BASE_HEX, NULL, 0,
2865 "First missed DataSN or StatSN", HFILL }
2867 { &hf_iscsi_RunLength,
2868 { "RunLength", "iscsi.snack.runlength",
2869 FT_UINT32, BASE_HEX, NULL, 0,
2870 "Number of additional missing status PDUs in this run", HFILL }
2874 /* Setup protocol subtree array */
2875 static gint *ett[] = {
2877 &ett_iscsi_KeyValues,
2880 /* #ifndef DRAFT08 */
2885 /* Register the protocol name and description */
2886 proto_iscsi = proto_register_protocol("iSCSI", "iSCSI", "iscsi");
2888 /* Required function calls to register the header fields and
2890 proto_register_field_array(proto_iscsi, hf, array_length(hf));
2891 proto_register_subtree_array(ett, array_length(ett));
2894 module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
2896 prefs_register_enum_preference(iscsi_module,
2899 "The iSCSI protocol version",
2900 &iscsi_protocol_version,
2901 iscsi_protocol_versions,
2904 prefs_register_bool_preference(iscsi_module,
2905 "desegment_iscsi_messages",
2906 "Reassemble iSCSI messages\nspanning multiple TCP segments",
2907 "Whether the iSCSI dissector should reassemble messages spanning multiple TCP segments."
2908 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2911 prefs_register_bool_preference(iscsi_module,
2913 "Enable bogus pdu filter",
2914 "When enabled, packets that appear bogus are ignored",
2915 &enable_bogosity_filter);
2917 prefs_register_bool_preference(iscsi_module,
2918 "demand_good_f_bit",
2919 "Ignore packets with bad F bit",
2920 "Ignore packets that haven't set the F bit when they should have",
2921 &demand_good_f_bit);
2923 prefs_register_uint_preference(iscsi_module,
2924 "bogus_pdu_max_data_len",
2925 "Bogus pdu max data length threshold",
2926 "Treat packets whose data segment length is greater than this value as bogus",
2928 &bogus_pdu_data_length_threshold);
2931 prefs_register_uint_preference(iscsi_module,
2934 "Port number of iSCSI target",
2938 prefs_register_bool_preference(iscsi_module,
2939 "enable_data_digests",
2940 "Enable data digests",
2941 "When enabled, pdus are assumed to contain a data digest",
2942 &enableDataDigests);
2944 prefs_register_bool_preference(iscsi_module,
2945 "data_digest_is_crc32c",
2946 "Data digest is CRC32C",
2947 "When enabled, data digests are assumed to be CRC32C",
2948 &dataDigestIsCRC32);
2950 prefs_register_uint_preference(iscsi_module,
2953 "The size of a data digest (bytes)",
2957 /* Preference supported in older versions.
2958 Register them as obsolete. */
2959 prefs_register_obsolete_preference(iscsi_module,
2960 "version_03_compatible");
2961 prefs_register_obsolete_preference(iscsi_module,
2962 "bogus_pdu_max_digest_padding");
2963 prefs_register_obsolete_preference(iscsi_module,
2964 "header_digest_is_crc32c");
2965 prefs_register_obsolete_preference(iscsi_module,
2966 "header_digest_size");
2967 prefs_register_obsolete_preference(iscsi_module,
2968 "enable_header_digests");
2974 * If this dissector uses sub-dissector registration add a
2975 * registration routine.
2979 * This format is required because a script is used to find these
2980 * routines and create the code that calls these routines.
2983 proto_reg_handoff_iscsi(void)
2985 heur_dissector_add("tcp", dissect_iscsi_heur, proto_iscsi);
2987 iscsi_handle = new_create_dissector_handle(dissect_iscsi_handle, proto_iscsi);
2988 dissector_add_handle("tcp.port", iscsi_handle);