2 * Routines for iSCSI dissection
3 * Copyright 2001, Eurologic and Mark Burton <markb@ordern.com>
4 * 2004 Request/Response matching and Service Response Time: ronnie sahlberg
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 #include <epan/packet.h>
39 #include <epan/conversation.h>
40 #include "packet-scsi.h"
41 #include "epan/nstime.h"
43 /* the absolute values of these constants don't matter as long as
44 * latter revisions of the protocol are assigned a larger number */
45 #define ISCSI_PROTOCOL_DRAFT08 1
46 #define ISCSI_PROTOCOL_DRAFT09 2
47 #define ISCSI_PROTOCOL_DRAFT11 3
48 #define ISCSI_PROTOCOL_DRAFT12 4
49 #define ISCSI_PROTOCOL_DRAFT13 5
51 static enum_val_t iscsi_protocol_versions[] = {
52 { "draft-08", "Draft 08", ISCSI_PROTOCOL_DRAFT08 },
53 { "draft-09", "Draft 09", ISCSI_PROTOCOL_DRAFT09 },
54 { "draft-11", "Draft 11", ISCSI_PROTOCOL_DRAFT11 },
55 { "draft-12", "Draft 12", ISCSI_PROTOCOL_DRAFT12 },
56 { "draft-13", "Draft 13", ISCSI_PROTOCOL_DRAFT13 },
60 static gint iscsi_protocol_version = ISCSI_PROTOCOL_DRAFT13;
62 static gboolean iscsi_desegment = TRUE;
64 static int demand_good_f_bit = FALSE;
65 static int enable_bogosity_filter = TRUE;
66 static guint32 bogus_pdu_data_length_threshold = 256 * 1024;
68 static int enableDataDigests = FALSE;
70 static int dataDigestIsCRC32 = TRUE;
72 static int dataDigestSize = 4;
74 static guint iscsi_port = 3260;
76 /* Initialize the protocol and registered fields */
77 static int proto_iscsi = -1;
78 static int hf_iscsi_time = -1;
79 static int hf_iscsi_request_frame = -1;
80 static int hf_iscsi_data_in_frame = -1;
81 static int hf_iscsi_data_out_frame = -1;
82 static int hf_iscsi_response_frame = -1;
83 static int hf_iscsi_AHS = -1;
84 static int hf_iscsi_Padding = -1;
85 static int hf_iscsi_ping_data = -1;
86 static int hf_iscsi_immediate_data = -1;
87 static int hf_iscsi_write_data = -1;
88 static int hf_iscsi_read_data = -1;
89 static int hf_iscsi_error_pdu_data = -1;
90 static int hf_iscsi_async_message_data = -1;
91 static int hf_iscsi_vendor_specific_data = -1;
92 static int hf_iscsi_Opcode = -1;
93 static int hf_iscsi_Flags = -1;
94 static int hf_iscsi_HeaderDigest32 = -1;
95 static int hf_iscsi_DataDigest = -1;
96 static int hf_iscsi_DataDigest32 = -1;
98 static int hf_iscsi_X = -1;
100 static int hf_iscsi_I = -1;
101 static int hf_iscsi_SCSICommand_F = -1;
102 static int hf_iscsi_SCSICommand_R = -1;
103 static int hf_iscsi_SCSICommand_W = -1;
104 static int hf_iscsi_SCSICommand_Attr = -1;
105 static int hf_iscsi_SCSICommand_CRN = -1;
106 static int hf_iscsi_SCSICommand_AddCDB = -1;
107 static int hf_iscsi_DataSegmentLength = -1;
108 static int hf_iscsi_TotalAHSLength = -1;
109 static int hf_iscsi_LUN = -1;
110 static int hf_iscsi_InitiatorTaskTag = -1;
111 static int hf_iscsi_ExpectedDataTransferLength = -1;
112 static int hf_iscsi_CmdSN = -1;
113 static int hf_iscsi_ExpStatSN = -1;
114 static int hf_iscsi_StatSN = -1;
115 static int hf_iscsi_ExpCmdSN = -1;
116 static int hf_iscsi_MaxCmdSN = -1;
117 static int hf_iscsi_SCSIResponse_o = -1;
118 static int hf_iscsi_SCSIResponse_u = -1;
119 static int hf_iscsi_SCSIResponse_O = -1;
120 static int hf_iscsi_SCSIResponse_U = -1;
121 static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1;
122 static int hf_iscsi_SCSIResponse_ResidualCount = -1;
123 static int hf_iscsi_SCSIResponse_Response = -1;
124 static int hf_iscsi_SCSIResponse_Status = -1;
125 static int hf_iscsi_SenseLength = -1;
126 static int hf_iscsi_SCSIData_F = -1;
127 static int hf_iscsi_SCSIData_A = -1;
128 static int hf_iscsi_SCSIData_S = -1;
129 static int hf_iscsi_SCSIData_O = -1;
130 static int hf_iscsi_SCSIData_U = -1;
131 static int hf_iscsi_TargetTransferTag = -1;
132 static int hf_iscsi_DataSN = -1;
133 static int hf_iscsi_BufferOffset = -1;
134 static int hf_iscsi_SCSIData_ResidualCount = -1;
135 static int hf_iscsi_VersionMin = -1;
136 static int hf_iscsi_VersionMax = -1;
137 static int hf_iscsi_VersionActive = -1;
138 static int hf_iscsi_CID = -1;
139 static int hf_iscsi_ISID8 = -1;
140 static int hf_iscsi_ISID = -1;
141 /* #if defined(DRAFT09) */
142 static int hf_iscsi_ISID_Type = -1;
143 static int hf_iscsi_ISID_NamingAuthority = -1;
144 static int hf_iscsi_ISID_Qualifier = -1;
145 /* #elif !defined(DRAFT08) */
146 static int hf_iscsi_ISID_t = -1;
147 static int hf_iscsi_ISID_a = -1;
148 static int hf_iscsi_ISID_b = -1;
149 static int hf_iscsi_ISID_c = -1;
150 static int hf_iscsi_ISID_d = -1;
152 static int hf_iscsi_TSID = -1;
153 static int hf_iscsi_TSIH = -1;
154 static int hf_iscsi_InitStatSN = -1;
155 static int hf_iscsi_InitCmdSN = -1;
157 static int hf_iscsi_Login_X = -1;
159 static int hf_iscsi_Login_C = -1;
160 static int hf_iscsi_Login_T = -1;
161 static int hf_iscsi_Login_CSG = -1;
162 static int hf_iscsi_Login_NSG = -1;
163 static int hf_iscsi_Login_Status = -1;
164 static int hf_iscsi_KeyValue = -1;
165 static int hf_iscsi_Text_C = -1;
166 static int hf_iscsi_Text_F = -1;
167 static int hf_iscsi_ExpDataSN = -1;
168 static int hf_iscsi_R2TSN = -1;
169 static int hf_iscsi_TaskManagementFunction_ReferencedTaskTag = -1;
170 static int hf_iscsi_RefCmdSN = -1;
171 static int hf_iscsi_TaskManagementFunction_Function = -1;
172 static int hf_iscsi_TaskManagementFunction_Response = -1;
173 static int hf_iscsi_Logout_Reason = -1;
174 static int hf_iscsi_Logout_Response = -1;
175 static int hf_iscsi_Time2Wait = -1;
176 static int hf_iscsi_Time2Retain = -1;
177 static int hf_iscsi_DesiredDataLength = -1;
178 static int hf_iscsi_AsyncEvent = -1;
179 static int hf_iscsi_EventVendorCode = -1;
180 static int hf_iscsi_Parameter1 = -1;
181 static int hf_iscsi_Parameter2 = -1;
182 static int hf_iscsi_Parameter3 = -1;
183 static int hf_iscsi_Reject_Reason = -1;
184 static int hf_iscsi_snack_type = -1;
185 static int hf_iscsi_BegRun = -1;
186 static int hf_iscsi_RunLength = -1;
188 /* Initialize the subtree pointers */
189 static gint ett_iscsi = -1;
190 static gint ett_iscsi_KeyValues = -1;
191 static gint ett_iscsi_CDB = -1;
192 static gint ett_iscsi_Flags = -1;
193 /* #ifndef DRAFT08 */
194 static gint ett_iscsi_ISID = -1;
197 #define ISCSI_HEADER_DIGEST_AUTO 0
198 #define ISCSI_HEADER_DIGEST_NONE 1
199 #define ISCSI_HEADER_DIGEST_CRC32 2
200 /* this structure contains session wide state for all iscsi sessions */
201 typedef struct _iscsi_session_t {
202 guint32 conv_idx; /* unique ID for conversation */
203 guint32 header_digest;
205 static GHashTable *iscsi_session_table = NULL;
206 static GMemChunk *iscsi_sessions = NULL;
208 iscsi_session_equal(gconstpointer v, gconstpointer w)
210 const iscsi_session_t *v1 = (const iscsi_session_t *)v;
211 const iscsi_session_t *v2 = (const iscsi_session_t *)w;
213 return (v1->conv_idx == v2->conv_idx);
217 iscsi_session_hash (gconstpointer v)
219 const iscsi_session_t *key = (const iscsi_session_t *)v;
221 return key->conv_idx;
232 #define OPCODE_MASK 0x3f
234 #define TARGET_OPCODE_BIT 0x20
236 #define ISCSI_OPCODE_NOP_OUT 0x00
237 #define ISCSI_OPCODE_SCSI_COMMAND 0x01
238 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION 0x02
239 #define ISCSI_OPCODE_LOGIN_COMMAND 0x03
240 #define ISCSI_OPCODE_TEXT_COMMAND 0x04
241 #define ISCSI_OPCODE_SCSI_DATA_OUT 0x05
242 #define ISCSI_OPCODE_LOGOUT_COMMAND 0x06
243 #define ISCSI_OPCODE_SNACK_REQUEST 0x10
244 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I0 0x1c
245 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I1 0x1d
246 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I2 0x1e
248 #define ISCSI_OPCODE_NOP_IN 0x20
249 #define ISCSI_OPCODE_SCSI_RESPONSE 0x21
250 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE 0x22
251 #define ISCSI_OPCODE_LOGIN_RESPONSE 0x23
252 #define ISCSI_OPCODE_TEXT_RESPONSE 0x24
253 #define ISCSI_OPCODE_SCSI_DATA_IN 0x25
254 #define ISCSI_OPCODE_LOGOUT_RESPONSE 0x26
255 #define ISCSI_OPCODE_R2T 0x31
256 #define ISCSI_OPCODE_ASYNC_MESSAGE 0x32
257 #define ISCSI_OPCODE_REJECT 0x3f
258 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T0 0x3c
259 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T1 0x3d
260 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T2 0x3e
263 #define CSG_MASK (0x03 << CSG_SHIFT)
264 #define NSG_MASK 0x03
266 #define ISCSI_CSG_SECURITY_NEGOTIATION (0 << CSG_SHIFT)
267 #define ISCSI_CSG_OPERATIONAL_NEGOTIATION (1 << CSG_SHIFT)
268 #define ISCSI_CSG_FULL_FEATURE_PHASE (3 << CSG_SHIFT)
270 #define ISCSI_SCSI_DATA_FLAG_S 0x01
271 #define ISCSI_SCSI_DATA_FLAG_U 0x02
272 #define ISCSI_SCSI_DATA_FLAG_O 0x04
273 #define ISCSI_SCSI_DATA_FLAG_A 0x40
274 #define ISCSI_SCSI_DATA_FLAG_F 0x80
276 static const value_string iscsi_opcodes[] = {
277 { ISCSI_OPCODE_NOP_OUT, "NOP Out" },
278 { ISCSI_OPCODE_SCSI_COMMAND, "SCSI Command" },
279 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION, "Task Management Function" },
280 { ISCSI_OPCODE_LOGIN_COMMAND, "Login Command" },
281 { ISCSI_OPCODE_TEXT_COMMAND, "Text Command" },
282 { ISCSI_OPCODE_SCSI_DATA_OUT, "SCSI Data Out" },
283 { ISCSI_OPCODE_LOGOUT_COMMAND, "Logout Command" },
284 { ISCSI_OPCODE_SNACK_REQUEST, "SNACK Request" },
285 { ISCSI_OPCODE_VENDOR_SPECIFIC_I0, "Vendor Specific I0" },
286 { ISCSI_OPCODE_VENDOR_SPECIFIC_I1, "Vendor Specific I1" },
287 { ISCSI_OPCODE_VENDOR_SPECIFIC_I2, "Vendor Specific I2" },
289 { ISCSI_OPCODE_NOP_IN, "NOP In" },
290 { ISCSI_OPCODE_SCSI_RESPONSE, "SCSI Response" },
291 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE, "Task Management Function Response" },
292 { ISCSI_OPCODE_LOGIN_RESPONSE, "Login Response" },
293 { ISCSI_OPCODE_TEXT_RESPONSE, "Text Response" },
294 { ISCSI_OPCODE_SCSI_DATA_IN, "SCSI Data In" },
295 { ISCSI_OPCODE_LOGOUT_RESPONSE, "Logout Response" },
296 { ISCSI_OPCODE_R2T, "Ready To Transfer" },
297 { ISCSI_OPCODE_ASYNC_MESSAGE, "Asynchronous Message" },
298 { ISCSI_OPCODE_REJECT, "Reject"},
299 { ISCSI_OPCODE_VENDOR_SPECIFIC_T0, "Vendor Specific T0" },
300 { ISCSI_OPCODE_VENDOR_SPECIFIC_T1, "Vendor Specific T1" },
301 { ISCSI_OPCODE_VENDOR_SPECIFIC_T2, "Vendor Specific T2" },
306 static const true_false_string iscsi_meaning_X = {
313 static const true_false_string iscsi_meaning_login_X = {
314 "Reinstate failed connection",
319 static const true_false_string iscsi_meaning_I = {
320 "Immediate delivery",
324 static const true_false_string iscsi_meaning_F = {
325 "Final PDU in sequence",
326 "Not final PDU in sequence"
329 static const true_false_string iscsi_meaning_A = {
330 "Acknowledge requested",
331 "Acknowledge not requested"
334 static const true_false_string iscsi_meaning_T = {
335 "Transit to next login stage",
336 "Stay in current login stage"
339 static const true_false_string iscsi_meaning_C = {
340 "Text is incomplete",
344 static const true_false_string iscsi_meaning_S = {
345 "Response contains SCSI status",
346 "Response does not contain SCSI status"
349 static const true_false_string iscsi_meaning_R = {
350 "Data will be read from target",
351 "No data will be read from target"
354 static const true_false_string iscsi_meaning_W = {
355 "Data will be written to target",
356 "No data will be written to target"
359 static const true_false_string iscsi_meaning_o = {
360 "Read part of bi-directional command overflowed",
361 "No overflow of read part of bi-directional command",
364 static const true_false_string iscsi_meaning_u = {
365 "Read part of bi-directional command underflowed",
366 "No underflow of read part of bi-directional command",
369 static const true_false_string iscsi_meaning_O = {
370 "Residual overflow occurred",
371 "No residual overflow occurred",
374 static const true_false_string iscsi_meaning_U = {
375 "Residual underflow occurred",
376 "No residual underflow occurred",
379 static const value_string iscsi_scsi_responses[] = {
380 { 0, "Command completed at target" },
381 { 1, "Response does not contain SCSI status"},
385 static const value_string iscsi_scsicommand_taskattrs[] = {
389 {3, "Head of Queue"},
394 static const value_string iscsi_task_management_responses[] = {
395 {0, "Function complete"},
396 {1, "Task not in task set"},
397 {2, "LUN does not exist"},
398 {3, "Task still allegiant"},
399 {4, "Task failover not supported"},
400 {5, "Task management function not supported"},
401 {6, "Authorisation failed"},
402 {255, "Function rejected"},
406 static const value_string iscsi_task_management_functions[] = {
408 {2, "Abort Task Set"},
410 {4, "Clear Task Set"},
411 {5, "Logical Unit Reset"},
412 {6, "Target Warm Reset"},
413 {7, "Target Cold Reset"},
417 static const value_string iscsi_login_status[] = {
419 {0x0101, "Target moved temporarily"},
420 {0x0102, "Target moved permanently"},
421 {0x0200, "Initiator error (miscellaneous error)"},
422 {0x0201, "Authentication failed"},
423 {0x0202, "Authorisation failure"},
424 {0x0203, "Target not found"},
425 {0x0204, "Target removed"},
426 {0x0205, "Unsupported version"},
427 {0x0206, "Too many connections"},
428 {0x0207, "Missing parameter"},
429 {0x0208, "Can't include in session"},
430 {0x0209, "Session type not supported"},
431 {0x020a, "Session does not exist"},
432 {0x020b, "Invalid request during login"},
433 {0x0300, "Target error (miscellaneous error)"},
434 {0x0301, "Service unavailable"},
435 {0x0302, "Out of resources"},
439 static const value_string iscsi_login_stage[] = {
440 {0, "Security negotiation"},
441 {1, "Operational negotiation"},
442 {3, "Full feature phase"},
446 /* #ifndef DRAFT08 */
447 static const value_string iscsi_isid_type[] = {
449 {0x01, "IANA Enterprise Number"},
455 static const value_string iscsi_logout_reasons[] = {
456 {0, "Close session"},
457 {1, "Close connection"},
458 {2, "Remove connection for recovery"},
462 static const value_string iscsi_logout_response[] = {
463 {0, "Connection closed successfully"},
464 {1, "CID not found"},
465 {2, "Connection recovery not supported"},
466 {3, "Cleanup failed for various reasons"},
470 static const value_string iscsi_asyncevents[] = {
471 {0, "A SCSI asynchronous event is reported in the sense data"},
472 {1, "Target requests logout"},
473 {2, "Target will/has dropped connection"},
474 {3, "Target will/has dropped all connections"},
475 {4, "Target requests parameter negotiation"},
479 static const value_string iscsi_snack_types[] = {
482 /* #ifndef DRAFT08 */
489 static const value_string iscsi_reject_reasons[] = {
491 {0x01, "Full feature phase command before login"},
493 {0x02, "Data (payload) digest error"},
494 {0x03, "Data SNACK reject"},
495 {0x04, "Protocol error"},
496 {0x05, "Command not supported in this session type"},
497 {0x06, "Immediate command reject (too many immediate commands)"},
498 {0x07, "Task in progress"},
499 {0x08, "Invalid Data Ack"},
500 {0x09, "Invalid PDU field"},
501 {0x0a, "Long operation reject"},
502 {0x0b, "Negotiation reset"},
503 {0x0c, "Waiting for logout"},
507 /*****************************************************************/
509 /* CRC LOOKUP TABLE */
510 /* ================ */
511 /* The following CRC lookup table was generated automagically */
512 /* by the Rocksoft^tm Model CRC Algorithm Table Generation */
513 /* Program V1.0 using the following model parameters: */
515 /* Width : 4 bytes. */
516 /* Poly : 0x1EDC6F41L */
517 /* Reverse : TRUE. */
519 /* For more information on the Rocksoft^tm Model CRC Algorithm, */
520 /* see the document titled "A Painless Guide to CRC Error */
521 /* Detection Algorithms" by Ross Williams */
522 /* (ross@guest.adelaide.edu.au.). This document is likely to be */
523 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
525 /*****************************************************************/
527 static guint32 crc32Table[256] = {
528 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
529 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
530 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
531 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
532 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
533 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
534 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
535 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
536 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
537 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
538 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
539 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
540 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
541 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
542 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
543 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
544 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
545 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
546 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
547 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
548 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
549 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
550 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
551 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
552 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
553 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
554 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
555 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
556 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
557 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
558 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
559 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
560 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
561 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
562 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
563 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
564 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
565 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
566 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
567 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
568 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
569 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
570 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
571 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
572 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
573 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
574 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
575 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
576 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
577 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
578 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
579 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
580 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
581 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
582 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
583 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
584 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
585 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
586 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
587 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
588 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
589 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
590 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
591 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
594 #define CRC32C_PRELOAD 0xffffffff
597 * Byte swap fix contributed by Dave Wysochanski <davidw@netapp.com>
599 #define CRC32C_SWAP(crc32c_value) \
600 (((crc32c_value & 0xff000000) >> 24) | \
601 ((crc32c_value & 0x00ff0000) >> 8) | \
602 ((crc32c_value & 0x0000ff00) << 8) | \
603 ((crc32c_value & 0x000000ff) << 24))
606 calculateCRC32(const void *buf, int len, guint32 crc) {
607 const guint8 *p = (const guint8 *)buf;
608 crc = CRC32C_SWAP(crc);
610 crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
611 return CRC32C_SWAP(crc);
618 /* structure and functions to keep track of
619 * COMMAND/DATA_IN/DATA_OUT/RESPONSE matching
621 typedef struct _iscsi_conv_data {
624 guint32 request_frame;
625 guint32 data_in_frame;
626 guint32 data_out_frame;
627 guint32 response_frame;
631 static GHashTable *iscsi_req_unmatched = NULL;
632 static GHashTable *iscsi_req_matched = NULL;
633 static GMemChunk *iscsi_req_vals = NULL;
634 static guint32 iscsi_init_count = 200;
637 iscsi_equal_unmatched(gconstpointer v, gconstpointer w)
639 const iscsi_conv_data_t *v1 = (const iscsi_conv_data_t *)v;
640 const iscsi_conv_data_t *v2 = (const iscsi_conv_data_t *)w;
642 return (v1->conv_idx == v2->conv_idx)&&(v1->itt == v2->itt);
646 iscsi_hash_unmatched (gconstpointer v)
648 const iscsi_conv_data_t *key = (const iscsi_conv_data_t *)v;
651 val = key->conv_idx + key->itt;
657 iscsi_equal_matched(gconstpointer v, gconstpointer w)
659 const iscsi_conv_data_t *v1 = (const iscsi_conv_data_t *)v;
660 const iscsi_conv_data_t *v2 = (const iscsi_conv_data_t *)w;
664 if (v1->request_frame && (v1->request_frame==v2->request_frame))
666 if (v1->data_in_frame && (v1->data_in_frame==v2->data_in_frame))
668 if (v1->data_out_frame && (v1->data_out_frame==v2->data_out_frame))
670 if (v1->response_frame && (v1->response_frame==v2->response_frame))
673 return check_frame&&(v1->conv_idx == v2->conv_idx)&&(v1->itt == v2->itt);
677 iscsi_hash_matched (gconstpointer v)
679 const iscsi_conv_data_t *key = (const iscsi_conv_data_t *)v;
682 val = key->conv_idx + key->itt;
693 * Protocol initialization
696 iscsi_init_protocol(void)
698 if (iscsi_sessions) {
699 g_mem_chunk_destroy(iscsi_sessions);
702 if (iscsi_req_vals) {
703 g_mem_chunk_destroy(iscsi_req_vals);
706 if (iscsi_req_unmatched) {
707 g_hash_table_destroy(iscsi_req_unmatched);
708 iscsi_req_unmatched=NULL;
710 if (iscsi_req_matched) {
711 g_hash_table_destroy(iscsi_req_matched);
712 iscsi_req_matched=NULL;
714 if (iscsi_session_table) {
715 g_hash_table_destroy(iscsi_session_table);
716 iscsi_session_table=NULL;
719 iscsi_req_unmatched = g_hash_table_new(iscsi_hash_unmatched, iscsi_equal_unmatched);
720 iscsi_req_matched = g_hash_table_new(iscsi_hash_matched, iscsi_equal_matched);
721 iscsi_session_table = g_hash_table_new(iscsi_session_hash, iscsi_session_equal);
722 iscsi_req_vals = g_mem_chunk_new("iscsi_req_vals",
723 sizeof(iscsi_conv_data_t),
724 iscsi_init_count * sizeof(iscsi_conv_data_t),
726 iscsi_sessions = g_mem_chunk_new("iscsi_sessions",
727 sizeof(iscsi_session_t),
728 iscsi_init_count * sizeof(iscsi_session_t),
733 iscsi_min(int a, int b) {
734 return (a < b)? a : b;
738 addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
739 const gint limit = offset + text_len;
740 while(offset < limit) {
741 gint len = tvb_strnlen(tvb, offset, limit - offset);
743 len = limit - offset;
746 proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, FALSE);
753 handleHeaderDigest(iscsi_session_t *iscsi_session, proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
754 int available_bytes = tvb_length_remaining(tvb, offset);
756 switch(iscsi_session->header_digest){
757 case ISCSI_HEADER_DIGEST_CRC32:
758 if(available_bytes >= (headerLen + 4)) {
759 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
760 guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
762 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
764 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);
765 printf("bad digest\n");
768 return offset + headerLen + 4;
771 return offset + headerLen;
775 handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) {
776 int available_bytes = tvb_length_remaining(tvb, offset);
777 if(enableDataDigests) {
778 if(dataDigestIsCRC32) {
779 if(available_bytes >= (dataLen + 4)) {
780 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
781 guint32 sent = tvb_get_ntohl(tvb, offset + dataLen);
783 proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Good CRC32)", sent);
786 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);
789 return offset + dataLen + 4;
791 if(available_bytes >= (dataLen + dataDigestSize)) {
792 proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, FALSE);
794 return offset + dataLen + dataDigestSize;
796 return offset + dataLen;
800 handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) {
801 if(endOffset > offset) {
802 int dataOffset = offset;
803 int dataLen = iscsi_min(dataSegmentLen, endOffset - offset);
805 proto_tree_add_item(ti, hf_id, tvb, offset, dataLen, FALSE);
808 if(offset < endOffset && (offset & 3) != 0) {
809 int padding = 4 - (offset & 3);
810 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
813 if(dataSegmentLen > 0 && offset < endOffset)
814 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
821 handleDataSegmentAsTextKeys(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) {
822 if(endOffset > offset) {
823 int dataOffset = offset;
824 int textLen = iscsi_min(dataSegmentLen, endOffset - offset);
826 proto_item *tf = proto_tree_add_text(ti, tvb, offset, textLen, "Key/Value Pairs");
827 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
828 offset = addTextKeys(tt, tvb, offset, textLen);
830 if(offset < endOffset && (offset & 3) != 0) {
831 int padding = 4 - (offset & 3);
832 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
835 if(digestsActive && dataSegmentLen > 0 && offset < endOffset)
836 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
841 /* Code to actually dissect the packets */
843 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) {
845 guint original_offset = offset;
846 proto_tree *ti = NULL;
847 guint8 scsi_status = 0;
848 gboolean S_bit=FALSE;
849 guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
850 guint end_offset = offset + tvb_length_remaining(tvb, offset);
851 iscsi_conv_data_t *cdata = NULL;
852 scsi_task_id_t task_key;
853 int paddedDataSegmentLength = data_segment_len;
854 if(paddedDataSegmentLength & 3)
855 paddedDataSegmentLength += 4 - (paddedDataSegmentLength & 3);
857 /* Make entries in Protocol column and Info column on summary display */
858 if (check_col(pinfo->cinfo, COL_PROTOCOL))
859 col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
861 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
862 opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
863 scsi_status = tvb_get_guint8 (tvb, offset+3);
866 if ((opcode == ISCSI_OPCODE_SCSI_RESPONSE) ||
867 (opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
868 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
869 if (!pinfo->fd->flags.visited){
870 iscsi_conv_data_t ckey;
871 ckey.conv_idx = iscsi_session->conv_idx;
872 ckey.itt = tvb_get_ntohl (tvb, offset+16);
874 /* first time we see this packet. check if we can find the request */
875 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_unmatched, &ckey);
877 if (cdata->data_in_frame+cdata->data_out_frame+cdata->response_frame==0){
878 /* this is the first response to the request, add it to the matched table */
879 g_hash_table_insert (iscsi_req_matched, cdata, cdata);
882 case ISCSI_OPCODE_SCSI_RESPONSE:
883 cdata->response_frame=pinfo->fd->num;
885 case ISCSI_OPCODE_SCSI_DATA_IN:
886 /* a bit ugly but we need to check the S bit here */
887 if(tvb_get_guint8(tvb, offset+1)&ISCSI_SCSI_DATA_FLAG_S){
888 cdata->response_frame=pinfo->fd->num;
890 cdata->data_in_frame=pinfo->fd->num;
892 case ISCSI_OPCODE_SCSI_DATA_OUT:
893 cdata->data_out_frame=pinfo->fd->num;
898 iscsi_conv_data_t ckey;
899 ckey.conv_idx = iscsi_session->conv_idx;
900 ckey.itt = tvb_get_ntohl (tvb, offset+16);
901 ckey.request_frame=0;
902 ckey.data_in_frame=0;
903 ckey.data_out_frame=0;
904 ckey.response_frame=0;
906 case ISCSI_OPCODE_SCSI_RESPONSE:
907 ckey.response_frame=pinfo->fd->num;
909 case ISCSI_OPCODE_SCSI_DATA_IN:
910 ckey.data_in_frame=pinfo->fd->num;
912 case ISCSI_OPCODE_SCSI_DATA_OUT:
913 ckey.data_out_frame=pinfo->fd->num;
917 /* we have seen this one before, pick it up from the matched table */
918 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_matched, &ckey);
922 task_key.conv_id = cdata->conv_idx;
923 task_key.task_id = cdata->itt;
924 pinfo->private_data = &task_key;
926 pinfo->private_data = NULL;
929 } else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
930 if (!pinfo->fd->flags.visited){
931 iscsi_conv_data_t ckey;
933 /* first time we see this packet. */
934 /*check if we have seen this request before and delete it in that case */
935 ckey.conv_idx = iscsi_session->conv_idx;
936 ckey.itt = tvb_get_ntohl (tvb, offset+16);
937 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_unmatched, &ckey);
939 g_hash_table_remove(iscsi_req_unmatched, &ckey);
942 /* add this new transaction to the unmatched table */
943 cdata = g_mem_chunk_alloc (iscsi_req_vals);
944 cdata->conv_idx = iscsi_session->conv_idx;
945 cdata->itt = tvb_get_ntohl (tvb, offset+16);
946 cdata->request_frame=pinfo->fd->num;
947 cdata->data_in_frame=0;
948 cdata->data_out_frame=0;
949 cdata->response_frame=0;
950 cdata->req_time.nsecs = pinfo->fd->abs_usecs*1000;
951 cdata->req_time.secs = pinfo->fd->abs_secs;
953 g_hash_table_insert (iscsi_req_unmatched, cdata, cdata);
955 iscsi_conv_data_t ckey;
956 ckey.conv_idx = iscsi_session->conv_idx;
957 ckey.itt = tvb_get_ntohl (tvb, offset+16);
958 ckey.request_frame=pinfo->fd->num;
959 ckey.data_in_frame=0;
960 ckey.data_out_frame=0;
961 ckey.response_frame=0;
963 /* we have seen this one before, pick it up from the matched table */
964 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_matched, &ckey);
969 /* The SCSI protocol uses this as the key to detect a
970 * SCSI-level conversation. */
971 task_key.conv_id = cdata->conv_idx;
972 task_key.task_id = cdata->itt;
973 pinfo->private_data = &task_key;
975 pinfo->private_data=NULL;
979 pinfo->private_data = NULL;
982 if (check_col(pinfo->cinfo, COL_INFO)) {
984 if (opcode != ISCSI_OPCODE_SCSI_COMMAND) {
986 col_append_str(pinfo->cinfo, COL_INFO, opcode_str);
988 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
989 (opcode == ISCSI_OPCODE_SCSI_DATA_IN &&
990 (tvb_get_guint8(tvb, offset + 1) & ISCSI_SCSI_DATA_FLAG_S))) {
991 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
992 val_to_str (scsi_status, scsi_status_val, "0x%x"));
994 else if (opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
995 guint16 login_status = tvb_get_ntohs(tvb, offset+36);
996 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
997 val_to_str (login_status, iscsi_login_status, "0x%x"));
999 else if (opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
1000 guint8 logoutReason;
1001 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1002 logoutReason = tvb_get_guint8(tvb, offset+11);
1003 } else if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1004 logoutReason = tvb_get_guint8(tvb, offset+1) & 0x7f;
1007 logoutReason = tvb_get_guint8(tvb, offset+23);
1009 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
1010 val_to_str (logoutReason, iscsi_logout_reasons, "0x%x"));
1012 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
1013 guint8 tmf = tvb_get_guint8(tvb, offset + 1);
1014 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
1015 val_to_str (tmf, iscsi_task_management_functions, "0x%x"));
1017 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
1018 guint8 resp = tvb_get_guint8(tvb, offset + 2);
1019 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
1020 val_to_str (resp, iscsi_task_management_responses, "0x%x"));
1022 else if (opcode == ISCSI_OPCODE_REJECT) {
1023 guint8 reason = tvb_get_guint8(tvb, offset + 2);
1024 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
1025 val_to_str (reason, iscsi_reject_reasons, "0x%x"));
1027 else if (opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1028 guint8 asyncEvent = tvb_get_guint8(tvb, offset + 36);
1029 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
1030 val_to_str (asyncEvent, iscsi_asyncevents, "0x%x"));
1035 /* In the interest of speed, if "tree" is NULL, don't do any
1036 work not necessary to generate protocol tree items. */
1039 /* create display subtree for the protocol */
1040 tp = proto_tree_add_protocol_format(tree, proto_iscsi, tvb,
1041 offset, -1, "iSCSI (%s)",
1043 ti = proto_item_add_subtree(tp, ett_iscsi);
1045 proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
1046 offset + 0, 1, opcode);
1047 if((opcode & TARGET_OPCODE_BIT) == 0) {
1048 /* initiator -> target */
1049 gint b = tvb_get_guint8(tvb, offset + 0);
1050 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1051 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
1052 opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
1053 opcode != ISCSI_OPCODE_SNACK_REQUEST)
1054 proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
1056 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
1057 opcode != ISCSI_OPCODE_LOGIN_COMMAND &&
1058 opcode != ISCSI_OPCODE_SNACK_REQUEST)
1059 proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
1063 if(opcode == ISCSI_OPCODE_NOP_OUT) {
1065 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1066 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1068 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1069 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1070 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1071 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1072 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1073 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1074 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1075 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
1076 } else if(opcode == ISCSI_OPCODE_NOP_IN) {
1078 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1079 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1081 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1082 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1083 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1084 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1085 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1086 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1087 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1088 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1089 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
1090 } else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
1092 guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
1094 gint b = tvb_get_guint8(tvb, offset + 1);
1095 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1096 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1098 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
1099 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
1100 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
1101 proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
1103 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1104 proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, FALSE);
1106 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1107 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1108 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1109 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1110 proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, FALSE);
1111 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1112 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1115 /* FIXME - disssect AHS? */
1116 proto_tree_add_item(ti, hf_iscsi_AHS, tvb, offset + 48, ahsLen, FALSE);
1118 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48 + ahsLen);
1120 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
1121 } else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1124 gint b = tvb_get_guint8(tvb, offset + 1);
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);
1128 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
1129 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
1130 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
1131 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
1133 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Response, tvb, offset + 2, 1, FALSE);
1134 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
1135 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1136 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1138 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1139 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1140 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1141 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 20, 4, FALSE);
1143 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1144 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1145 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1146 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1147 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1148 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, FALSE);
1151 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 40, 4, FALSE);
1152 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 44, 4, FALSE);
1154 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1155 /* do not update offset here because the data segment is
1156 * dissected below */
1157 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1158 } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
1159 /* Task Management Function */
1160 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, FALSE);
1161 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1162 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1163 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1165 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1166 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1167 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1168 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1169 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1170 proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
1171 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1172 } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
1173 /* Task Management Function Response */
1174 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Response, tvb, offset + 2, 1, FALSE);
1175 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1176 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1177 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1179 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1180 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1181 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1183 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1184 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1185 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1186 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1187 } else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
1189 int digestsActive = 0;
1191 gint b = tvb_get_guint8(tvb, offset + 1);
1192 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1193 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1197 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1198 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1201 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1202 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1203 proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1205 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1206 proto_tree_add_boolean(ti, hf_iscsi_Login_X, tvb, offset + 1, 1, b);
1208 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
1210 /* NSG is undefined unless T is set */
1212 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
1215 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1216 proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
1217 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1218 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1220 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1221 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1222 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1223 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, FALSE);
1226 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
1227 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1228 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1229 proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, FALSE);
1230 proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, FALSE);
1231 proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, FALSE);
1234 proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, FALSE);
1235 proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, FALSE);
1236 proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, FALSE);
1237 proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, FALSE);
1238 proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, FALSE);
1241 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1242 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1245 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, FALSE);
1247 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1248 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1249 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
1251 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1252 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1254 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1258 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1259 } else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1260 /* Login Response */
1261 int digestsActive = 0;
1263 gint b = tvb_get_guint8(tvb, offset + 1);
1264 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1265 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1269 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1270 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1273 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1274 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1275 proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1277 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
1278 /* NSG is undefined unless T is set */
1280 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
1284 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1285 proto_tree_add_item(ti, hf_iscsi_VersionActive, tvb, offset + 3, 1, FALSE);
1286 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1287 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1289 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1290 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1291 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, FALSE);
1294 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
1295 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1296 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1297 proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, FALSE);
1298 proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, FALSE);
1299 proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, FALSE);
1302 proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, FALSE);
1303 proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, FALSE);
1304 proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, FALSE);
1305 proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, FALSE);
1306 proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, FALSE);
1309 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1310 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1313 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, FALSE);
1315 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1316 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1317 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1318 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1319 proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, FALSE);
1321 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1325 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1326 } else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
1329 gint b = tvb_get_guint8(tvb, offset + 1);
1330 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1331 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1333 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1334 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1335 proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1338 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1339 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1341 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1342 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1343 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1345 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1346 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1347 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1348 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1349 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1350 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1351 } else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
1354 gint b = tvb_get_guint8(tvb, offset + 1);
1355 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1356 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1358 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1359 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1360 proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1363 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1364 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1366 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1367 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1368 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1370 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1371 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1372 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1373 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1374 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1375 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1376 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1377 } else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
1378 /* SCSI Data Out (write) */
1380 gint b = tvb_get_guint8(tvb, offset + 1);
1381 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1382 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1384 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1386 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1387 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1389 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1390 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1391 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1392 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1393 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1394 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1395 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1396 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1397 /* do not update offset here because the data segment is
1398 * dissected below */
1399 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1400 } else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
1401 /* SCSI Data In (read) */
1403 gint b = tvb_get_guint8(tvb, offset + 1);
1404 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1405 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1407 if(b&ISCSI_SCSI_DATA_FLAG_S){
1410 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1411 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1412 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_A, tvb, offset + 1, 1, b);
1414 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
1415 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
1416 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
1418 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
1419 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1420 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1422 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1423 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1424 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1426 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1427 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1428 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 20, 4, FALSE);
1431 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1433 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1434 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1435 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1436 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1437 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1438 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1439 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 44, 4, FALSE);
1441 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1442 /* do not update offset here because the data segment is
1443 * dissected below */
1444 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1445 } else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
1446 /* Logout Command */
1447 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1448 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 1, 1, FALSE);
1450 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1451 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1452 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1454 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1455 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1456 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, FALSE);
1458 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1459 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1460 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
1461 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT13) {
1462 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 23, 1, FALSE);
1465 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1466 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1467 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1468 } else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
1469 /* Logout Response */
1470 proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, FALSE);
1471 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1472 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1473 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1475 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1476 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1477 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1478 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1479 proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, FALSE);
1480 proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, FALSE);
1481 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1482 } else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
1485 gint b = tvb_get_guint8(tvb, offset + 1);
1487 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1488 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1491 proto_tree_add_item(ti, hf_iscsi_snack_type, tvb, offset + 1, 1, b);
1493 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1494 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1495 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1496 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1498 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1499 if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1500 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, FALSE);
1501 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, FALSE);
1502 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1503 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1506 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1507 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1508 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 40, 4, FALSE);
1509 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 44, 4, FALSE);
1511 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1512 } else if(opcode == ISCSI_OPCODE_R2T) {
1514 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1515 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1516 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1517 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1519 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1520 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1521 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1522 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1523 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1524 proto_tree_add_item(ti, hf_iscsi_R2TSN, tvb, offset + 36, 4, FALSE);
1525 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1526 proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
1527 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1528 } else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1529 /* Asynchronous Message */
1530 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1531 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1533 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1534 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1535 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1536 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1537 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1538 proto_tree_add_item(ti, hf_iscsi_AsyncEvent, tvb, offset + 36, 1, FALSE);
1539 proto_tree_add_item(ti, hf_iscsi_EventVendorCode, tvb, offset + 37, 1, FALSE);
1540 proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, FALSE);
1541 proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
1542 proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
1543 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1544 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_async_message_data);
1545 } else if(opcode == ISCSI_OPCODE_REJECT) {
1547 proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
1548 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1549 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1551 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1552 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1553 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1554 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1555 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1556 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1557 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_error_pdu_data);
1558 } else if(opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I0 ||
1559 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I1 ||
1560 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I2 ||
1561 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T0 ||
1562 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T1 ||
1563 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T2) {
1564 /* Vendor specific opcodes */
1565 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1566 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1568 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1569 offset = handleHeaderDigest(iscsi_session, ti, tvb, offset, 48);
1570 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_vendor_specific_data);
1575 /* handle request/response matching */
1578 case ISCSI_OPCODE_SCSI_RESPONSE:
1579 if (cdata->request_frame){
1580 nstime_t delta_time;
1581 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
1582 delta_time.secs = pinfo->fd->abs_secs - cdata->req_time.secs;
1583 delta_time.nsecs = pinfo->fd->abs_usecs*1000 - cdata->req_time.nsecs;
1584 if (delta_time.nsecs<0){
1585 delta_time.nsecs+=1000000000;
1588 proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1591 if (cdata->data_in_frame)
1592 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1593 if (cdata->data_out_frame)
1594 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1596 case ISCSI_OPCODE_SCSI_DATA_IN:
1597 /* if we have phase collaps then we might have the
1598 response embedded in the last DataIn segment */
1600 if (cdata->request_frame)
1601 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
1602 if (cdata->response_frame)
1603 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->response_frame);
1605 if (cdata->request_frame){
1606 nstime_t delta_time;
1607 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
1608 delta_time.secs = pinfo->fd->abs_secs - cdata->req_time.secs;
1609 delta_time.nsecs = pinfo->fd->abs_usecs*1000 - cdata->req_time.nsecs;
1610 if (delta_time.nsecs<0){
1611 delta_time.nsecs+=1000000000;
1614 proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1618 if (cdata->data_out_frame)
1619 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1621 case ISCSI_OPCODE_SCSI_DATA_OUT:
1622 if (cdata->request_frame)
1623 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
1624 if (cdata->data_in_frame)
1625 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1626 if (cdata->response_frame)
1627 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->response_frame);
1629 case ISCSI_OPCODE_SCSI_COMMAND:
1630 if (cdata->data_in_frame)
1631 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1632 if (cdata->data_out_frame)
1633 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1634 if (cdata->response_frame)
1635 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->response_frame);
1642 proto_item_set_len(ti, offset - original_offset);
1644 if((opcode & ((iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08)?
1646 ~I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND) {
1648 dissect_scsi_cdb (tvb, pinfo, tree, cdb_offset, 16, SCSI_DEV_UNKNOWN);
1650 else if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1651 if (scsi_status == 0x2) {
1652 /* A SCSI response with Check Condition contains sense data */
1653 /* offset is setup correctly by the iscsi code for response above */
1654 if((end_offset - offset) >= 2) {
1655 int senseLen = tvb_get_ntohs(tvb, offset);
1657 proto_tree_add_item(ti, hf_iscsi_SenseLength, tvb, offset, 2, FALSE);
1660 dissect_scsi_snsinfo (tvb, pinfo, tree, offset,
1661 iscsi_min (senseLen,
1662 end_offset-offset));
1666 dissect_scsi_rsp (tvb, pinfo, tree);
1669 else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
1670 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
1671 /* offset is setup correctly by the iscsi code for response above */
1672 dissect_scsi_payload (tvb, pinfo, tree, offset, FALSE,
1673 iscsi_min (data_segment_len, end_offset-offset));
1678 dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean check_port) {
1679 /* Set up structures needed to add the protocol subtree and manage it */
1680 guint iSCSIPdusDissected = 0;
1682 guint32 available_bytes = tvb_length_remaining(tvb, offset);
1683 guint32 pduLen = 48;
1684 int digestsActive = 1;
1685 conversation_t *conversation = NULL;
1686 iscsi_session_t *iscsi_session=NULL;
1688 /* quick check to see if the packet is long enough to contain the
1689 * minimum amount of information we need */
1690 if (available_bytes < 48 && (!iscsi_desegment || available_bytes < 8)) {
1691 /* no, so give up */
1695 /* process multiple iSCSI PDUs per packet */
1696 while(available_bytes >= 48 || (iscsi_desegment && available_bytes >= 8)) {
1697 const char *opcode_str = NULL;
1698 guint32 data_segment_len;
1699 guint8 opcode = tvb_get_guint8(tvb, offset + 0);
1700 guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1);
1703 /* mask out any extra bits in the opcode byte */
1704 opcode &= OPCODE_MASK;
1706 opcode_str = match_strval(opcode, iscsi_opcodes);
1707 if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION ||
1708 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
1709 opcode == ISCSI_OPCODE_R2T ||
1710 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
1711 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
1712 opcode == ISCSI_OPCODE_SNACK_REQUEST)
1713 data_segment_len = 0;
1715 data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
1717 if(opcode_str == NULL) {
1720 else if(check_port && iscsi_port != 0 &&
1721 (((opcode & TARGET_OPCODE_BIT) && pinfo->srcport != iscsi_port) ||
1722 (!(opcode & TARGET_OPCODE_BIT) && pinfo->destport != iscsi_port))) {
1725 else if(enable_bogosity_filter) {
1726 /* try and distinguish between data and real headers */
1727 if(data_segment_len > bogus_pdu_data_length_threshold) {
1730 else if(demand_good_f_bit &&
1731 !(secondPduByte & 0x80) &&
1732 (opcode == ISCSI_OPCODE_NOP_OUT ||
1733 opcode == ISCSI_OPCODE_NOP_IN ||
1734 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
1735 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
1736 opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
1737 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
1738 opcode == ISCSI_OPCODE_R2T ||
1739 opcode == ISCSI_OPCODE_ASYNC_MESSAGE ||
1740 opcode == ISCSI_OPCODE_SNACK_REQUEST ||
1741 opcode == ISCSI_OPCODE_REJECT)) {
1743 } else if(opcode==ISCSI_OPCODE_NOP_OUT) {
1744 /* TransferTag for NOP-Out should either be -1 or
1745 the tag value we want for a response.
1746 Assume 0 means we are just inside a big all zero
1749 if(tvb_get_ntohl(tvb, offset+20)==0){
1756 return iSCSIPdusDissected > 0;
1759 if(opcode == ISCSI_OPCODE_LOGIN_COMMAND ||
1760 opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1761 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1762 if((secondPduByte & CSG_MASK) < ISCSI_CSG_OPERATIONAL_NEGOTIATION) {
1763 /* digests are not yet turned on */
1771 if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
1773 pduLen += tvb_get_guint8(tvb, offset + 4) * 4;
1776 pduLen += data_segment_len;
1777 if((pduLen & 3) != 0)
1778 pduLen += 4 - (pduLen & 3);
1784 if(digestsActive && data_segment_len > 0 && enableDataDigests) {
1785 if(dataDigestIsCRC32)
1788 pduLen += dataDigestSize;
1791 /* make sure we have a conversation for this session */
1792 conversation = find_conversation (&pinfo->src, &pinfo->dst,
1793 pinfo->ptype, pinfo->srcport,
1794 pinfo->destport, 0);
1795 if (!conversation) {
1796 conversation = conversation_new (&pinfo->src, &pinfo->dst,
1797 pinfo->ptype, pinfo->srcport,
1798 pinfo->destport, 0);
1799 iscsi_session=g_mem_chunk_alloc(iscsi_sessions);
1800 iscsi_session->conv_idx=conversation->index;
1801 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_AUTO;
1802 g_hash_table_insert(iscsi_session_table, iscsi_session, iscsi_session);
1805 iscsi_session_t key;
1806 key.conv_idx=conversation->index;
1807 /* this should never return NULL */
1808 iscsi_session = (iscsi_session_t *)g_hash_table_lookup (iscsi_session_table, &key);
1810 iscsi_session=g_mem_chunk_alloc(iscsi_sessions);
1811 iscsi_session->conv_idx=conversation->index;
1812 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_AUTO;
1813 g_hash_table_insert(iscsi_session_table, iscsi_session, iscsi_session);
1816 /* try to autodetect if header digest is used or not */
1817 if(digestsActive && (available_bytes>=52) && (iscsi_session->header_digest==ISCSI_HEADER_DIGEST_AUTO) ){
1819 /* we have enough data to test if HeaderDigest is enabled */
1820 crc= ~calculateCRC32(tvb_get_ptr(tvb, offset, 48), 48, CRC32C_PRELOAD);
1821 if(crc==tvb_get_ntohl(tvb,48)){
1822 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_CRC32;
1824 iscsi_session->header_digest=ISCSI_HEADER_DIGEST_NONE;
1830 * Desegmentation check.
1832 if(iscsi_desegment && pinfo->can_desegment) {
1833 if(pduLen > available_bytes) {
1835 * This frame doesn't have all of the data for
1836 * this message, but we can do reassembly on it.
1838 * Tell the TCP dissector where the data for this
1839 * message starts in the data it handed us, and
1840 * how many more bytes we need, and return.
1842 pinfo->desegment_offset = offset;
1843 pinfo->desegment_len = pduLen - available_bytes;
1848 /* This is to help TCP keep track of PDU boundaries
1849 and allows it to find PDUs that are not aligned to
1850 the start of a TCP segments.
1851 Since it also allows TCP to know what is in the middle
1852 of a large PDU, it reduces the probability of a segment
1853 in the middle of a large PDU transfer being misdissected as
1856 if(!pinfo->fd->flags.visited){
1857 if(pduLen>(guint32)tvb_reported_length_remaining(tvb, offset)){
1858 pinfo->want_pdu_tracking=2;
1859 pinfo->bytes_until_next_pdu=pduLen-tvb_reported_length_remaining(tvb, offset);
1863 if(check_col(pinfo->cinfo, COL_INFO)) {
1864 if(iSCSIPdusDissected == 0)
1865 col_set_str(pinfo->cinfo, COL_INFO, "");
1867 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1870 dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len, iscsi_session);
1871 if(pduLen > available_bytes)
1872 pduLen = available_bytes;
1874 available_bytes -= pduLen;
1875 ++iSCSIPdusDissected;
1878 return iSCSIPdusDissected > 0;
1881 /* This is called for those sessions where we have explicitely said
1882 this to be iSCSI using "Decode As..."
1883 In this case we will not check the port number for sanity and just
1884 do as the user said.
1887 dissect_iscsi_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1888 dissect_iscsi(tvb, pinfo, tree, FALSE);
1891 /* This is called through the heuristic handler.
1892 In this case we also want to check that the port matches the preference
1893 setting for iSCSI in order to reduce the number of
1897 dissect_iscsi_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1898 return dissect_iscsi(tvb, pinfo, tree, TRUE);
1902 /* Register the protocol with Ethereal */
1905 * this format is require because a script is used to build the C
1906 * function that calls all the protocol registration.
1910 proto_register_iscsi(void)
1913 /* Setup list of header fields See Section 1.6.1 for details*/
1914 static hf_register_info hf[] = {
1915 { &hf_iscsi_request_frame,
1916 { "Request in", "iscsi.request_frame",
1917 FT_FRAMENUM, BASE_NONE, NULL, 0,
1918 "The request to this transaction is in this frame", HFILL }},
1921 { "Time from request", "iscsi.time",
1922 FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
1923 "Time between the Command and the Response", HFILL }},
1925 { &hf_iscsi_data_in_frame,
1926 { "Data In in", "iscsi.data_in_frame",
1927 FT_FRAMENUM, BASE_NONE, NULL, 0,
1928 "The Data In for this transaction is in this frame", HFILL }},
1930 { &hf_iscsi_data_out_frame,
1931 { "Data Out in", "iscsi.data_out_frame",
1932 FT_FRAMENUM, BASE_NONE, NULL, 0,
1933 "The Data Out for this transaction is in this frame", HFILL }},
1935 { &hf_iscsi_response_frame,
1936 { "Response in", "iscsi.response_frame",
1937 FT_FRAMENUM, BASE_NONE, NULL, 0,
1938 "The response to this transaction is in this frame", HFILL }},
1941 { "AHS", "iscsi.ahs",
1942 FT_BYTES, BASE_HEX, NULL, 0,
1943 "Additional header segment", HFILL }
1945 { &hf_iscsi_Padding,
1946 { "Padding", "iscsi.padding",
1947 FT_BYTES, BASE_HEX, NULL, 0,
1948 "Padding to 4 byte boundary", HFILL }
1950 { &hf_iscsi_ping_data,
1951 { "PingData", "iscsi.pingdata",
1952 FT_BYTES, BASE_HEX, NULL, 0,
1953 "Ping Data", HFILL }
1955 { &hf_iscsi_immediate_data,
1956 { "ImmediateData", "iscsi.immediatedata",
1957 FT_BYTES, BASE_HEX, NULL, 0,
1958 "Immediate Data", HFILL }
1960 { &hf_iscsi_write_data,
1961 { "WriteData", "iscsi.writedata",
1962 FT_BYTES, BASE_HEX, NULL, 0,
1963 "Write Data", HFILL }
1965 { &hf_iscsi_read_data,
1966 { "ReadData", "iscsi.readdata",
1967 FT_BYTES, BASE_HEX, NULL, 0,
1968 "Read Data", HFILL }
1970 { &hf_iscsi_error_pdu_data,
1971 { "ErrorPDUData", "iscsi.errorpdudata",
1972 FT_BYTES, BASE_HEX, NULL, 0,
1973 "Error PDU Data", HFILL }
1975 { &hf_iscsi_async_message_data,
1976 { "AsyncMessageData", "iscsi.asyncmessagedata",
1977 FT_BYTES, BASE_HEX, NULL, 0,
1978 "Async Message Data", HFILL }
1980 { &hf_iscsi_vendor_specific_data,
1981 { "VendorSpecificData", "iscsi.vendorspecificdata",
1982 FT_BYTES, BASE_HEX, NULL, 0,
1983 "Vendor Specific Data", HFILL }
1985 { &hf_iscsi_HeaderDigest32,
1986 { "HeaderDigest", "iscsi.headerdigest32",
1987 FT_UINT32, BASE_HEX, NULL, 0,
1988 "Header Digest", HFILL }
1990 { &hf_iscsi_DataDigest,
1991 { "DataDigest", "iscsi.datadigest",
1992 FT_BYTES, BASE_HEX, NULL, 0,
1993 "Data Digest", HFILL }
1995 { &hf_iscsi_DataDigest32,
1996 { "DataDigest", "iscsi.datadigest32",
1997 FT_UINT32, BASE_HEX, NULL, 0,
1998 "Data Digest", HFILL }
2001 { "Opcode", "iscsi.opcode",
2002 FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
2005 /* #ifdef DRAFT08 */
2008 FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,
2009 "Command Retry", HFILL }
2014 FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,
2015 "Immediate delivery", HFILL }
2018 { "Flags", "iscsi.flags",
2019 FT_UINT8, BASE_HEX, NULL, 0,
2020 "Opcode specific flags", HFILL }
2022 { &hf_iscsi_SCSICommand_F,
2023 { "F", "iscsi.scsicommand.F",
2024 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
2025 "PDU completes command", HFILL }
2027 { &hf_iscsi_SCSICommand_R,
2028 { "R", "iscsi.scsicommand.R",
2029 FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,
2030 "Command reads from SCSI target", HFILL }
2032 { &hf_iscsi_SCSICommand_W,
2033 { "W", "iscsi.scsicommand.W",
2034 FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,
2035 "Command writes to SCSI target", HFILL }
2037 { &hf_iscsi_SCSICommand_Attr,
2038 { "Attr", "iscsi.scsicommand.attr",
2039 FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07,
2040 "SCSI task attributes", HFILL }
2042 { &hf_iscsi_SCSICommand_CRN,
2043 { "CRN", "iscsi.scsicommand.crn",
2044 FT_UINT8, BASE_HEX, NULL, 0,
2045 "SCSI command reference number", HFILL }
2047 { &hf_iscsi_SCSICommand_AddCDB,
2048 { "AddCDB", "iscsi.scsicommand.addcdb",
2049 FT_UINT8, BASE_HEX, NULL, 0,
2050 "Additional CDB length (in 4 byte units)", HFILL }
2052 { &hf_iscsi_DataSegmentLength,
2053 { "DataSegmentLength", "iscsi.datasegmentlength",
2054 FT_UINT32, BASE_HEX, NULL, 0,
2055 "Data segment length (bytes)", HFILL }
2057 { &hf_iscsi_TotalAHSLength,
2058 { "TotalAHSLength", "iscsi.totalahslength",
2059 FT_UINT8, BASE_HEX, NULL, 0,
2060 "Total additional header segment length (4 byte words)", HFILL }
2063 { "LUN", "iscsi.lun",
2064 FT_BYTES, BASE_HEX, NULL, 0,
2065 "Logical Unit Number", HFILL }
2067 { &hf_iscsi_InitiatorTaskTag,
2068 { "InitiatorTaskTag", "iscsi.initiatortasktag",
2069 FT_UINT32, BASE_HEX, NULL, 0,
2070 "Initiator's task tag", HFILL }
2072 { &hf_iscsi_ExpectedDataTransferLength,
2073 { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength",
2074 FT_UINT32, BASE_HEX, NULL, 0,
2075 "Expected length of data transfer", HFILL }
2078 { "CmdSN", "iscsi.cmdsn",
2079 FT_UINT32, BASE_HEX, NULL, 0,
2080 "Sequence number for this command", HFILL }
2082 { &hf_iscsi_ExpStatSN,
2083 { "ExpStatSN", "iscsi.expstatsn",
2084 FT_UINT32, BASE_HEX, NULL, 0,
2085 "Next expected status sequence number", HFILL }
2087 { &hf_iscsi_SCSIResponse_ResidualCount,
2088 { "ResidualCount", "iscsi.scsiresponse.residualcount",
2089 FT_UINT32, BASE_HEX, NULL, 0,
2090 "Residual count", HFILL }
2093 { "StatSN", "iscsi.statsn",
2094 FT_UINT32, BASE_HEX, NULL, 0,
2095 "Status sequence number", HFILL }
2097 { &hf_iscsi_ExpCmdSN,
2098 { "ExpCmdSN", "iscsi.expcmdsn",
2099 FT_UINT32, BASE_HEX, NULL, 0,
2100 "Next expected command sequence number", HFILL }
2102 { &hf_iscsi_MaxCmdSN,
2103 { "MaxCmdSN", "iscsi.maxcmdsn",
2104 FT_UINT32, BASE_HEX, NULL, 0,
2105 "Maximum acceptable command sequence number", HFILL }
2107 { &hf_iscsi_SCSIResponse_o,
2108 { "o", "iscsi.scsiresponse.o",
2109 FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,
2110 "Bi-directional read residual overflow", HFILL }
2112 { &hf_iscsi_SCSIResponse_u,
2113 { "u", "iscsi.scsiresponse.u",
2114 FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08,
2115 "Bi-directional read residual underflow", HFILL }
2117 { &hf_iscsi_SCSIResponse_O,
2118 { "O", "iscsi.scsiresponse.O",
2119 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
2120 "Residual overflow", HFILL }
2122 { &hf_iscsi_SCSIResponse_U,
2123 { "U", "iscsi.scsiresponse.U",
2124 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
2125 "Residual underflow", HFILL }
2127 { &hf_iscsi_SCSIResponse_Status,
2128 { "Status", "iscsi.scsiresponse.status",
2129 FT_UINT8, BASE_HEX, VALS(scsi_status_val), 0,
2130 "SCSI command status value", HFILL }
2132 { &hf_iscsi_SCSIResponse_Response,
2133 { "Response", "iscsi.scsiresponse.response",
2134 FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
2135 "SCSI command response value", HFILL }
2137 { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
2138 { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
2139 FT_UINT32, BASE_HEX, NULL, 0,
2140 "Bi-directional read residual count", HFILL }
2142 { &hf_iscsi_SenseLength,
2143 { "SenseLength", "iscsi.scsiresponse.senselength",
2144 FT_UINT16, BASE_HEX, NULL, 0,
2145 "Sense data length", HFILL }
2147 { &hf_iscsi_SCSIData_F,
2148 { "F", "iscsi.scsidata.F",
2149 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), ISCSI_SCSI_DATA_FLAG_F,
2150 "Final PDU", HFILL }
2152 { &hf_iscsi_SCSIData_A,
2153 { "A", "iscsi.scsidata.A",
2154 FT_BOOLEAN, 8, TFS(&iscsi_meaning_A), ISCSI_SCSI_DATA_FLAG_A,
2155 "Acknowledge Requested", HFILL }
2157 { &hf_iscsi_SCSIData_S,
2158 { "S", "iscsi.scsidata.S",
2159 FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), ISCSI_SCSI_DATA_FLAG_S,
2160 "PDU Contains SCSI command status", HFILL }
2162 { &hf_iscsi_SCSIData_U,
2163 { "U", "iscsi.scsidata.U",
2164 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), ISCSI_SCSI_DATA_FLAG_U,
2165 "Residual underflow", HFILL }
2167 { &hf_iscsi_SCSIData_O,
2168 { "O", "iscsi.scsidata.O",
2169 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), ISCSI_SCSI_DATA_FLAG_O,
2170 "Residual overflow", HFILL }
2172 { &hf_iscsi_TargetTransferTag,
2173 { "TargetTransferTag", "iscsi.targettransfertag",
2174 FT_UINT32, BASE_HEX, NULL, 0,
2175 "Target transfer tag", HFILL }
2177 { &hf_iscsi_BufferOffset,
2178 { "BufferOffset", "iscsi.bufferOffset",
2179 FT_UINT32, BASE_HEX, NULL, 0,
2180 "Buffer offset", HFILL }
2182 { &hf_iscsi_SCSIData_ResidualCount,
2183 { "ResidualCount", "iscsi.scsidata.readresidualcount",
2184 FT_UINT32, BASE_HEX, NULL, 0,
2185 "Residual count", HFILL }
2188 { "DataSN", "iscsi.datasn",
2189 FT_UINT32, BASE_HEX, NULL, 0,
2190 "Data sequence number", HFILL }
2192 { &hf_iscsi_VersionMax,
2193 { "VersionMax", "iscsi.versionmax",
2194 FT_UINT8, BASE_HEX, NULL, 0,
2195 "Maximum supported protocol version", HFILL }
2197 { &hf_iscsi_VersionMin,
2198 { "VersionMin", "iscsi.versionmin",
2199 FT_UINT8, BASE_HEX, NULL, 0,
2200 "Minimum supported protocol version", HFILL }
2202 { &hf_iscsi_VersionActive,
2203 { "VersionActive", "iscsi.versionactive",
2204 FT_UINT8, BASE_HEX, NULL, 0,
2205 "Negotiated protocol version", HFILL }
2208 { "CID", "iscsi.cid",
2209 FT_UINT16, BASE_HEX, NULL, 0,
2210 "Connection identifier", HFILL }
2212 /* #ifdef DRAFT08 */
2214 { "ISID", "iscsi.isid",
2215 FT_UINT16, BASE_HEX, NULL, 0,
2216 "Initiator part of session identifier", HFILL }
2220 { "ISID", "iscsi.isid",
2221 FT_BYTES, BASE_HEX, NULL, 0,
2222 "Initiator part of session identifier", HFILL }
2224 /* #ifdef DRAFT09 */
2225 { &hf_iscsi_ISID_Type,
2226 { "ISID_Type", "iscsi.isid.type",
2227 FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0,
2228 "Initiator part of session identifier - type", HFILL }
2230 { &hf_iscsi_ISID_NamingAuthority,
2231 { "ISID_NamingAuthority", "iscsi.isid.namingauthority",
2232 FT_UINT24, BASE_HEX, NULL, 0,
2233 "Initiator part of session identifier - naming authority", HFILL }
2235 { &hf_iscsi_ISID_Qualifier,
2236 { "ISID_Qualifier", "iscsi.isid.qualifier",
2237 FT_UINT8, BASE_HEX, NULL, 0,
2238 "Initiator part of session identifier - qualifier", HFILL }
2242 { "ISID_t", "iscsi.isid.t",
2243 FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0xc0,
2244 "Initiator part of session identifier - t", HFILL }
2247 { "ISID_a", "iscsi.isid.a",
2248 FT_UINT8, BASE_HEX, NULL, 0x3f,
2249 "Initiator part of session identifier - a", HFILL }
2252 { "ISID_b", "iscsi.isid.b",
2253 FT_UINT16, BASE_HEX, NULL, 0,
2254 "Initiator part of session identifier - b", HFILL }
2257 { "ISID_c", "iscsi.isid.c",
2258 FT_UINT8, BASE_HEX, NULL, 0,
2259 "Initiator part of session identifier - c", HFILL }
2262 { "ISID_d", "iscsi.isid.d",
2263 FT_UINT16, BASE_HEX, NULL, 0,
2264 "Initiator part of session identifier - d", HFILL }
2269 { "TSID", "iscsi.tsid",
2270 FT_UINT16, BASE_HEX, NULL, 0,
2271 "Target part of session identifier", HFILL }
2274 { "TSIH", "iscsi.tsih",
2275 FT_UINT16, BASE_HEX, NULL, 0,
2276 "Target session identifying handle", HFILL }
2278 { &hf_iscsi_InitStatSN,
2279 { "InitStatSN", "iscsi.initstatsn",
2280 FT_UINT32, BASE_HEX, NULL, 0,
2281 "Initial status sequence number", HFILL }
2283 { &hf_iscsi_InitCmdSN,
2284 { "InitCmdSN", "iscsi.initcmdsn",
2285 FT_UINT32, BASE_HEX, NULL, 0,
2286 "Initial command sequence number", HFILL }
2288 { &hf_iscsi_Login_T,
2289 { "T", "iscsi.login.T",
2290 FT_BOOLEAN, 8, TFS(&iscsi_meaning_T), 0x80,
2291 "Transit to next login stage", HFILL }
2293 { &hf_iscsi_Login_C,
2294 { "C", "iscsi.login.C",
2295 FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2296 "Text incomplete", HFILL }
2298 /* #ifdef DRAFT09 */
2299 { &hf_iscsi_Login_X,
2300 { "X", "iscsi.login.X",
2301 FT_BOOLEAN, 8, TFS(&iscsi_meaning_login_X), 0x40,
2302 "Restart Connection", HFILL }
2305 { &hf_iscsi_Login_CSG,
2306 { "CSG", "iscsi.login.csg",
2307 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), CSG_MASK,
2308 "Current stage", HFILL }
2310 { &hf_iscsi_Login_NSG,
2311 { "NSG", "iscsi.login.nsg",
2312 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), NSG_MASK,
2313 "Next stage", HFILL }
2315 { &hf_iscsi_Login_Status,
2316 { "Status", "iscsi.login.status",
2317 FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0,
2318 "Status class and detail", HFILL }
2320 { &hf_iscsi_KeyValue,
2321 { "KeyValue", "iscsi.keyvalue",
2322 FT_STRING, 0, NULL, 0,
2323 "Key/value pair", HFILL }
2326 { "F", "iscsi.text.F",
2327 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
2328 "Final PDU in text sequence", HFILL }
2331 { "C", "iscsi.text.C",
2332 FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2333 "Text incomplete", HFILL }
2335 { &hf_iscsi_ExpDataSN,
2336 { "ExpDataSN", "iscsi.expdatasn",
2337 FT_UINT32, BASE_HEX, NULL, 0,
2338 "Next expected data sequence number", HFILL }
2341 { "R2TSN", "iscsi.r2tsn",
2342 FT_UINT32, BASE_HEX, NULL, 0,
2343 "R2T PDU Number", HFILL }
2345 { &hf_iscsi_TaskManagementFunction_Response,
2346 { "Response", "iscsi.taskmanfun.response",
2347 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_responses), 0,
2350 { &hf_iscsi_TaskManagementFunction_ReferencedTaskTag,
2351 { "ReferencedTaskTag", "iscsi.taskmanfun.referencedtasktag",
2352 FT_UINT32, BASE_HEX, NULL, 0,
2353 "Referenced task tag", HFILL }
2355 { &hf_iscsi_RefCmdSN,
2356 { "RefCmdSN", "iscsi.refcmdsn",
2357 FT_UINT32, BASE_HEX, NULL, 0,
2358 "Command sequence number for command to be aborted", HFILL }
2360 { &hf_iscsi_TaskManagementFunction_Function,
2361 { "Function", "iscsi.taskmanfun.function",
2362 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_functions), 0x7F,
2363 "Requested task function", HFILL }
2365 { &hf_iscsi_Logout_Reason,
2366 { "Reason", "iscsi.logout.reason",
2367 FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0x7F,
2368 "Reason for logout", HFILL }
2370 { &hf_iscsi_Logout_Response,
2371 { "Response", "iscsi.logout.response",
2372 FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
2373 "Logout response", HFILL }
2375 { &hf_iscsi_Time2Wait,
2376 { "Time2Wait", "iscsi.time2wait",
2377 FT_UINT16, BASE_HEX, NULL, 0,
2378 "Time2Wait", HFILL }
2380 { &hf_iscsi_Time2Retain,
2381 { "Time2Retain", "iscsi.time2retain",
2382 FT_UINT16, BASE_HEX, NULL, 0,
2383 "Time2Retain", HFILL }
2385 { &hf_iscsi_DesiredDataLength,
2386 { "DesiredDataLength", "iscsi.desireddatalength",
2387 FT_UINT32, BASE_HEX, NULL, 0,
2388 "Desired data length (bytes)", HFILL }
2390 { &hf_iscsi_AsyncEvent,
2391 { "AsyncEvent", "iscsi.asyncevent",
2392 FT_UINT8, BASE_HEX, VALS(iscsi_asyncevents), 0,
2393 "Async event type", HFILL }
2395 { &hf_iscsi_EventVendorCode,
2396 { "EventVendorCode", "iscsi.eventvendorcode",
2397 FT_UINT8, BASE_HEX, NULL, 0,
2398 "Event vendor code", HFILL }
2400 { &hf_iscsi_Parameter1,
2401 { "Parameter1", "iscsi.parameter1",
2402 FT_UINT16, BASE_HEX, NULL, 0,
2403 "Parameter 1", HFILL }
2405 { &hf_iscsi_Parameter2,
2406 { "Parameter2", "iscsi.parameter2",
2407 FT_UINT16, BASE_HEX, NULL, 0,
2408 "Parameter 2", HFILL }
2410 { &hf_iscsi_Parameter3,
2411 { "Parameter3", "iscsi.parameter3",
2412 FT_UINT16, BASE_HEX, NULL, 0,
2413 "Parameter 3", HFILL }
2415 { &hf_iscsi_Reject_Reason,
2416 { "Reason", "iscsi.reject.reason",
2417 FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
2418 "Reason for command rejection", HFILL }
2420 { &hf_iscsi_snack_type,
2421 { "S", "iscsi.snack.type",
2422 FT_UINT8, BASE_DEC, VALS(iscsi_snack_types), 0x0f,
2423 "Type of SNACK requested", HFILL }
2426 { "BegRun", "iscsi.snack.begrun",
2427 FT_UINT32, BASE_HEX, NULL, 0,
2428 "First missed DataSN or StatSN", HFILL }
2430 { &hf_iscsi_RunLength,
2431 { "RunLength", "iscsi.snack.runlength",
2432 FT_UINT32, BASE_HEX, NULL, 0,
2433 "Number of additional missing status PDUs in this run", HFILL }
2437 /* Setup protocol subtree array */
2438 static gint *ett[] = {
2440 &ett_iscsi_KeyValues,
2443 /* #ifndef DRAFT08 */
2448 /* Register the protocol name and description */
2449 proto_iscsi = proto_register_protocol("iSCSI", "iSCSI", "iscsi");
2451 /* Required function calls to register the header fields and
2453 proto_register_field_array(proto_iscsi, hf, array_length(hf));
2454 proto_register_subtree_array(ett, array_length(ett));
2455 register_init_routine (&iscsi_init_protocol);
2458 module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
2460 prefs_register_enum_preference(iscsi_module,
2463 "The iSCSI protocol version",
2464 &iscsi_protocol_version,
2465 iscsi_protocol_versions,
2468 prefs_register_bool_preference(iscsi_module,
2469 "desegment_iscsi_messages",
2470 "Reassemble iSCSI messages\nspanning multiple TCP segments",
2471 "Whether the iSCSI dissector should reassemble messages spanning multiple TCP segments."
2472 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2475 prefs_register_bool_preference(iscsi_module,
2477 "Enable bogus pdu filter",
2478 "When enabled, packets that appear bogus are ignored",
2479 &enable_bogosity_filter);
2481 prefs_register_bool_preference(iscsi_module,
2482 "demand_good_f_bit",
2483 "Ignore packets with bad F bit",
2484 "Ignore packets that haven't set the F bit when they should have",
2485 &demand_good_f_bit);
2487 prefs_register_uint_preference(iscsi_module,
2488 "bogus_pdu_max_data_len",
2489 "Bogus pdu max data length threshold",
2490 "Treat packets whose data segment length is greater than this value as bogus",
2492 &bogus_pdu_data_length_threshold);
2495 prefs_register_uint_preference(iscsi_module,
2498 "Port number of iSCSI target",
2502 prefs_register_bool_preference(iscsi_module,
2503 "enable_data_digests",
2504 "Enable data digests",
2505 "When enabled, pdus are assumed to contain a data digest",
2506 &enableDataDigests);
2508 prefs_register_bool_preference(iscsi_module,
2509 "data_digest_is_crc32c",
2510 "Data digest is CRC32C",
2511 "When enabled, data digests are assumed to be CRC32C",
2512 &dataDigestIsCRC32);
2514 prefs_register_uint_preference(iscsi_module,
2517 "The size of a data digest (bytes)",
2521 /* Preference supported in older versions.
2522 Register them as obsolete. */
2523 prefs_register_obsolete_preference(iscsi_module,
2524 "version_03_compatible");
2525 prefs_register_obsolete_preference(iscsi_module,
2526 "bogus_pdu_max_digest_padding");
2532 * If this dissector uses sub-dissector registration add a
2533 * registration routine.
2537 * This format is required because a script is used to find these
2538 * routines and create the code that calls these routines.
2541 proto_reg_handoff_iscsi(void)
2543 dissector_handle_t iscsi_handle;
2545 heur_dissector_add("tcp", dissect_iscsi_heur, proto_iscsi);
2547 iscsi_handle = create_dissector_handle(dissect_iscsi_handle, proto_iscsi);
2548 dissector_add_handle("tcp.port", iscsi_handle);