Prevent the word "desegmentation" at the GUI, but use reassembling at that places...
[obnox/wireshark/wip.git] / epan / dissectors / packet-iscsi.c
1 /* packet-iscsi.c
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
5  *
6  * $Id$
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <glib.h>
36
37 #include <epan/packet.h>
38 #include "prefs.h"
39 #include <epan/conversation.h>
40 #include "packet-scsi.h"
41 #include "epan/nstime.h"
42
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
50
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 },
57     { NULL, NULL, 0 }
58 };
59
60 static gint iscsi_protocol_version = ISCSI_PROTOCOL_DRAFT13;
61
62 static gboolean iscsi_desegment = TRUE;
63
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;
67
68 static int enableDataDigests = FALSE;
69 static int enableHeaderDigests = FALSE;
70
71 static int dataDigestIsCRC32 = TRUE;
72 static int headerDigestIsCRC32 = TRUE;
73
74 static int dataDigestSize = 4;
75 static int headerDigestSize = 4;
76
77 static guint iscsi_port = 3260;
78
79 /* Initialize the protocol and registered fields */
80 static int proto_iscsi = -1;
81 static int hf_iscsi_time = -1;
82 static int hf_iscsi_request_frame = -1;
83 static int hf_iscsi_data_in_frame = -1;
84 static int hf_iscsi_data_out_frame = -1;
85 static int hf_iscsi_response_frame = -1;
86 static int hf_iscsi_AHS = -1;
87 static int hf_iscsi_Padding = -1;
88 static int hf_iscsi_ping_data = -1;
89 static int hf_iscsi_immediate_data = -1;
90 static int hf_iscsi_write_data = -1;
91 static int hf_iscsi_read_data = -1;
92 static int hf_iscsi_error_pdu_data = -1;
93 static int hf_iscsi_async_message_data = -1;
94 static int hf_iscsi_vendor_specific_data = -1;
95 static int hf_iscsi_Opcode = -1;
96 static int hf_iscsi_Flags = -1;
97 static int hf_iscsi_HeaderDigest = -1;
98 static int hf_iscsi_HeaderDigest32 = -1;
99 static int hf_iscsi_DataDigest = -1;
100 static int hf_iscsi_DataDigest32 = -1;
101 /* #ifdef DRAFT08 */
102 static int hf_iscsi_X = -1;
103 /* #endif */
104 static int hf_iscsi_I = -1;
105 static int hf_iscsi_SCSICommand_F = -1;
106 static int hf_iscsi_SCSICommand_R = -1;
107 static int hf_iscsi_SCSICommand_W = -1;
108 static int hf_iscsi_SCSICommand_Attr = -1;
109 static int hf_iscsi_SCSICommand_CRN = -1;
110 static int hf_iscsi_SCSICommand_AddCDB = -1;
111 static int hf_iscsi_DataSegmentLength = -1;
112 static int hf_iscsi_TotalAHSLength = -1;
113 static int hf_iscsi_LUN = -1;
114 static int hf_iscsi_InitiatorTaskTag = -1;
115 static int hf_iscsi_ExpectedDataTransferLength = -1;
116 static int hf_iscsi_CmdSN = -1;
117 static int hf_iscsi_ExpStatSN = -1;
118 static int hf_iscsi_StatSN = -1;
119 static int hf_iscsi_ExpCmdSN = -1;
120 static int hf_iscsi_MaxCmdSN = -1;
121 static int hf_iscsi_SCSIResponse_o = -1;
122 static int hf_iscsi_SCSIResponse_u = -1;
123 static int hf_iscsi_SCSIResponse_O = -1;
124 static int hf_iscsi_SCSIResponse_U = -1;
125 static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1;
126 static int hf_iscsi_SCSIResponse_ResidualCount = -1;
127 static int hf_iscsi_SCSIResponse_Response = -1;
128 static int hf_iscsi_SCSIResponse_Status = -1;
129 static int hf_iscsi_SenseLength = -1;
130 static int hf_iscsi_SCSIData_F = -1;
131 static int hf_iscsi_SCSIData_A = -1;
132 static int hf_iscsi_SCSIData_S = -1;
133 static int hf_iscsi_SCSIData_O = -1;
134 static int hf_iscsi_SCSIData_U = -1;
135 static int hf_iscsi_TargetTransferTag = -1;
136 static int hf_iscsi_DataSN = -1;
137 static int hf_iscsi_BufferOffset = -1;
138 static int hf_iscsi_SCSIData_ResidualCount = -1;
139 static int hf_iscsi_VersionMin = -1;
140 static int hf_iscsi_VersionMax = -1;
141 static int hf_iscsi_VersionActive = -1;
142 static int hf_iscsi_CID = -1;
143 static int hf_iscsi_ISID8 = -1;
144 static int hf_iscsi_ISID = -1;
145 /* #if defined(DRAFT09) */
146 static int hf_iscsi_ISID_Type = -1;
147 static int hf_iscsi_ISID_NamingAuthority = -1;
148 static int hf_iscsi_ISID_Qualifier = -1;
149 /* #elif !defined(DRAFT08) */
150 static int hf_iscsi_ISID_t = -1;
151 static int hf_iscsi_ISID_a = -1;
152 static int hf_iscsi_ISID_b = -1;
153 static int hf_iscsi_ISID_c = -1;
154 static int hf_iscsi_ISID_d = -1;
155 /* #endif */
156 static int hf_iscsi_TSID = -1;
157 static int hf_iscsi_TSIH = -1;
158 static int hf_iscsi_InitStatSN = -1;
159 static int hf_iscsi_InitCmdSN = -1;
160 /* #ifdef DRAFT09 */
161 static int hf_iscsi_Login_X = -1;
162 /* #endif */
163 static int hf_iscsi_Login_C = -1;
164 static int hf_iscsi_Login_T = -1;
165 static int hf_iscsi_Login_CSG = -1;
166 static int hf_iscsi_Login_NSG = -1;
167 static int hf_iscsi_Login_Status = -1;
168 static int hf_iscsi_KeyValue = -1;
169 static int hf_iscsi_Text_C = -1;
170 static int hf_iscsi_Text_F = -1;
171 static int hf_iscsi_ExpDataSN = -1;
172 static int hf_iscsi_R2TSN = -1;
173 static int hf_iscsi_TaskManagementFunction_ReferencedTaskTag = -1;
174 static int hf_iscsi_RefCmdSN = -1;
175 static int hf_iscsi_TaskManagementFunction_Function = -1;
176 static int hf_iscsi_TaskManagementFunction_Response = -1;
177 static int hf_iscsi_Logout_Reason = -1;
178 static int hf_iscsi_Logout_Response = -1;
179 static int hf_iscsi_Time2Wait = -1;
180 static int hf_iscsi_Time2Retain = -1;
181 static int hf_iscsi_DesiredDataLength = -1;
182 static int hf_iscsi_AsyncEvent = -1;
183 static int hf_iscsi_EventVendorCode = -1;
184 static int hf_iscsi_Parameter1 = -1;
185 static int hf_iscsi_Parameter2 = -1;
186 static int hf_iscsi_Parameter3 = -1;
187 static int hf_iscsi_Reject_Reason = -1;
188 static int hf_iscsi_snack_type = -1;
189 static int hf_iscsi_BegRun = -1;
190 static int hf_iscsi_RunLength = -1;
191
192 /* Initialize the subtree pointers */
193 static gint ett_iscsi = -1;
194 static gint ett_iscsi_KeyValues = -1;
195 static gint ett_iscsi_CDB = -1;
196 static gint ett_iscsi_Flags = -1;
197 /* #ifndef DRAFT08 */
198 static gint ett_iscsi_ISID = -1;
199 /* #endif */
200
201
202 /* #ifdef DRAFT08 */
203 #define X_BIT 0x80
204 /* #endif */
205
206 #define I_BIT 0x40
207
208 #define OPCODE_MASK 0x3f
209
210 #define TARGET_OPCODE_BIT 0x20
211
212 #define ISCSI_OPCODE_NOP_OUT                  0x00
213 #define ISCSI_OPCODE_SCSI_COMMAND             0x01
214 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION 0x02
215 #define ISCSI_OPCODE_LOGIN_COMMAND            0x03
216 #define ISCSI_OPCODE_TEXT_COMMAND             0x04
217 #define ISCSI_OPCODE_SCSI_DATA_OUT            0x05
218 #define ISCSI_OPCODE_LOGOUT_COMMAND           0x06
219 #define ISCSI_OPCODE_SNACK_REQUEST            0x10
220 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I0       0x1c
221 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I1       0x1d
222 #define ISCSI_OPCODE_VENDOR_SPECIFIC_I2       0x1e
223
224 #define ISCSI_OPCODE_NOP_IN                            0x20
225 #define ISCSI_OPCODE_SCSI_RESPONSE                     0x21
226 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE 0x22
227 #define ISCSI_OPCODE_LOGIN_RESPONSE                    0x23
228 #define ISCSI_OPCODE_TEXT_RESPONSE                     0x24
229 #define ISCSI_OPCODE_SCSI_DATA_IN                      0x25
230 #define ISCSI_OPCODE_LOGOUT_RESPONSE                   0x26
231 #define ISCSI_OPCODE_R2T                               0x31
232 #define ISCSI_OPCODE_ASYNC_MESSAGE                     0x32
233 #define ISCSI_OPCODE_REJECT                            0x3f
234 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T0                0x3c
235 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T1                0x3d
236 #define ISCSI_OPCODE_VENDOR_SPECIFIC_T2                0x3e
237
238 #define CSG_SHIFT 2
239 #define CSG_MASK  (0x03 << CSG_SHIFT)
240 #define NSG_MASK  0x03
241
242 #define ISCSI_CSG_SECURITY_NEGOTIATION    (0 << CSG_SHIFT)
243 #define ISCSI_CSG_OPERATIONAL_NEGOTIATION (1 << CSG_SHIFT)
244 #define ISCSI_CSG_FULL_FEATURE_PHASE      (3 << CSG_SHIFT)
245
246 #define ISCSI_SCSI_DATA_FLAG_S 0x01
247 #define ISCSI_SCSI_DATA_FLAG_U 0x02
248 #define ISCSI_SCSI_DATA_FLAG_O 0x04
249 #define ISCSI_SCSI_DATA_FLAG_A 0x40
250 #define ISCSI_SCSI_DATA_FLAG_F 0x80
251
252 static const value_string iscsi_opcodes[] = {
253   { ISCSI_OPCODE_NOP_OUT,                           "NOP Out" },
254   { ISCSI_OPCODE_SCSI_COMMAND,                      "SCSI Command" },
255   { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION,          "Task Management Function" },
256   { ISCSI_OPCODE_LOGIN_COMMAND,                     "Login Command" },
257   { ISCSI_OPCODE_TEXT_COMMAND,                      "Text Command" },
258   { ISCSI_OPCODE_SCSI_DATA_OUT,                     "SCSI Data Out" },
259   { ISCSI_OPCODE_LOGOUT_COMMAND,                    "Logout Command" },
260   { ISCSI_OPCODE_SNACK_REQUEST,                     "SNACK Request" },
261   { ISCSI_OPCODE_VENDOR_SPECIFIC_I0,                "Vendor Specific I0" },
262   { ISCSI_OPCODE_VENDOR_SPECIFIC_I1,                "Vendor Specific I1" },
263   { ISCSI_OPCODE_VENDOR_SPECIFIC_I2,                "Vendor Specific I2" },
264
265   { ISCSI_OPCODE_NOP_IN,                            "NOP In" },
266   { ISCSI_OPCODE_SCSI_RESPONSE,                     "SCSI Response" },
267   { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE, "Task Management Function Response" },
268   { ISCSI_OPCODE_LOGIN_RESPONSE,                    "Login Response" },
269   { ISCSI_OPCODE_TEXT_RESPONSE,                     "Text Response" },
270   { ISCSI_OPCODE_SCSI_DATA_IN,                      "SCSI Data In" },
271   { ISCSI_OPCODE_LOGOUT_RESPONSE,                   "Logout Response" },
272   { ISCSI_OPCODE_R2T,                               "Ready To Transfer" },
273   { ISCSI_OPCODE_ASYNC_MESSAGE,                     "Asynchronous Message" },
274   { ISCSI_OPCODE_REJECT,                            "Reject"},
275   { ISCSI_OPCODE_VENDOR_SPECIFIC_T0,                "Vendor Specific T0" },
276   { ISCSI_OPCODE_VENDOR_SPECIFIC_T1,                "Vendor Specific T1" },
277   { ISCSI_OPCODE_VENDOR_SPECIFIC_T2,                "Vendor Specific T2" },
278   {0, NULL},
279 };
280
281 /* #ifdef DRAFT08 */
282 static const true_false_string iscsi_meaning_X = {
283     "Retry",
284     "Not retry"
285 };
286 /* #endif */
287
288 /* #ifdef DRAFT09 */
289 static const true_false_string iscsi_meaning_login_X = {
290     "Reinstate failed connection",
291     "New connection"
292 };
293 /* #endif */
294
295 static const true_false_string iscsi_meaning_I = {
296     "Immediate delivery",
297     "Queued delivery"
298 };
299
300 static const true_false_string iscsi_meaning_F = {
301     "Final PDU in sequence",
302     "Not final PDU in sequence"
303 };
304
305 static const true_false_string iscsi_meaning_A = {
306     "Acknowledge requested",
307     "Acknowledge not requested"
308 };
309
310 static const true_false_string iscsi_meaning_T = {
311     "Transit to next login stage",
312     "Stay in current login stage"
313 };
314
315 static const true_false_string iscsi_meaning_C = {
316     "Text is incomplete",
317     "Text is complete"
318 };
319
320 static const true_false_string iscsi_meaning_S = {
321     "Response contains SCSI status",
322     "Response does not contain SCSI status"
323 };
324
325 static const true_false_string iscsi_meaning_R = {
326     "Data will be read from target",
327     "No data will be read from target"
328 };
329
330 static const true_false_string iscsi_meaning_W = {
331     "Data will be written to target",
332     "No data will be written to target"
333 };
334
335 static const true_false_string iscsi_meaning_o = {
336     "Read part of bi-directional command overflowed",
337     "No overflow of read part of bi-directional command",
338 };
339
340 static const true_false_string iscsi_meaning_u = {
341     "Read part of bi-directional command underflowed",
342     "No underflow of read part of bi-directional command",
343 };
344
345 static const true_false_string iscsi_meaning_O = {
346     "Residual overflow occurred",
347     "No residual overflow occurred",
348 };
349
350 static const true_false_string iscsi_meaning_U = {
351     "Residual underflow occurred",
352     "No residual underflow occurred",
353 };
354
355 static const value_string iscsi_scsi_responses[] = {
356     { 0, "Command completed at target" },
357     { 1, "Response does not contain SCSI status"},
358     { 0, NULL }
359 };
360
361 static const value_string iscsi_scsicommand_taskattrs[] = {
362     {0, "Untagged"},
363     {1, "Simple"},
364     {2, "Ordered"},
365     {3, "Head of Queue"},
366     {4, "ACA"},
367     {0, NULL},
368 };
369
370 static const value_string iscsi_task_management_responses[] = {
371     {0, "Function complete"},
372     {1, "Task not in task set"},
373     {2, "LUN does not exist"},
374     {3, "Task still allegiant"},
375     {4, "Task failover not supported"},
376     {5, "Task management function not supported"},
377     {6, "Authorisation failed"},
378     {255, "Function rejected"},
379     {0, NULL},
380 };
381
382 static const value_string iscsi_task_management_functions[] = {
383     {1, "Abort Task"},
384     {2, "Abort Task Set"},
385     {3, "Clear ACA"},
386     {4, "Clear Task Set"},
387     {5, "Logical Unit Reset"},
388     {6, "Target Warm Reset"},
389     {7, "Target Cold Reset"},
390     {0, NULL},
391 };
392
393 static const value_string iscsi_login_status[] = {
394     {0x0000, "Success"},
395     {0x0101, "Target moved temporarily"},
396     {0x0102, "Target moved permanently"},
397     {0x0200, "Initiator error (miscellaneous error)"},
398     {0x0201, "Authentication failed"},
399     {0x0202, "Authorisation failure"},
400     {0x0203, "Target not found"},
401     {0x0204, "Target removed"},
402     {0x0205, "Unsupported version"},
403     {0x0206, "Too many connections"},
404     {0x0207, "Missing parameter"},
405     {0x0208, "Can't include in session"},
406     {0x0209, "Session type not supported"},
407     {0x020a, "Session does not exist"},
408     {0x020b, "Invalid request during login"},
409     {0x0300, "Target error (miscellaneous error)"},
410     {0x0301, "Service unavailable"},
411     {0x0302, "Out of resources"},
412     {0, NULL},
413 };
414
415 static const value_string iscsi_login_stage[] = {
416     {0, "Security negotiation"},
417     {1, "Operational negotiation"},
418     {3, "Full feature phase"},
419     {0, NULL},
420 };
421
422 /* #ifndef DRAFT08 */
423 static const value_string iscsi_isid_type[] = {
424     {0x00, "IEEE OUI"},
425     {0x01, "IANA Enterprise Number"},
426     {0x02, "Random"},
427     {0, NULL},
428 };
429 /* #endif */
430
431 static const value_string iscsi_logout_reasons[] = {
432     {0, "Close session"},
433     {1, "Close connection"},
434     {2, "Remove connection for recovery"},
435     {0, NULL},
436 };
437
438 static const value_string iscsi_logout_response[] = {
439     {0, "Connection closed successfully"},
440     {1, "CID not found"},
441     {2, "Connection recovery not supported"},
442     {3, "Cleanup failed for various reasons"},
443     {0, NULL},
444 };
445
446 static const value_string iscsi_asyncevents[] = {
447     {0, "A SCSI asynchronous event is reported in the sense data"},
448     {1, "Target requests logout"},
449     {2, "Target will/has dropped connection"},
450     {3, "Target will/has dropped all connections"},
451     {4, "Target requests parameter negotiation"},
452     {0, NULL},
453 };
454
455 static const value_string iscsi_snack_types[] = {
456     {0, "Data/R2T"},
457     {1, "Status"},
458 /* #ifndef DRAFT08 */
459     {2, "Data ACK"},
460 /* #endif */
461     {3, "R-Data"},
462     {0, NULL}
463 };
464
465 static const value_string iscsi_reject_reasons[] = {
466 /* #ifdef DRAFT08 */
467     {0x01, "Full feature phase command before login"},
468 /* #endif */
469     {0x02, "Data (payload) digest error"},
470     {0x03, "Data SNACK reject"},
471     {0x04, "Protocol error"},
472     {0x05, "Command not supported in this session type"},
473     {0x06, "Immediate command reject (too many immediate commands)"},
474     {0x07, "Task in progress"},
475     {0x08, "Invalid Data Ack"},
476     {0x09, "Invalid PDU field"},
477     {0x0a, "Long operation reject"},
478     {0x0b, "Negotiation reset"},
479     {0x0c, "Waiting for logout"},
480     {0, NULL},
481 };
482
483 /*****************************************************************/
484 /*                                                               */
485 /* CRC LOOKUP TABLE                                              */
486 /* ================                                              */
487 /* The following CRC lookup table was generated automagically    */
488 /* by the Rocksoft^tm Model CRC Algorithm Table Generation       */
489 /* Program V1.0 using the following model parameters:            */
490 /*                                                               */
491 /*    Width   : 4 bytes.                                         */
492 /*    Poly    : 0x1EDC6F41L                                      */
493 /*    Reverse : TRUE.                                            */
494 /*                                                               */
495 /* For more information on the Rocksoft^tm Model CRC Algorithm,  */
496 /* see the document titled "A Painless Guide to CRC Error        */
497 /* Detection Algorithms" by Ross Williams                        */
498 /* (ross@guest.adelaide.edu.au.). This document is likely to be  */
499 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".        */
500 /*                                                               */
501 /*****************************************************************/
502
503 static guint32 crc32Table[256] = {
504     0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
505     0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
506     0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
507     0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
508     0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
509     0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
510     0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
511     0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
512     0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
513     0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
514     0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
515     0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
516     0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
517     0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
518     0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
519     0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
520     0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
521     0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
522     0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
523     0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
524     0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
525     0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
526     0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
527     0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
528     0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
529     0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
530     0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
531     0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
532     0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
533     0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
534     0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
535     0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
536     0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
537     0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
538     0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
539     0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
540     0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
541     0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
542     0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
543     0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
544     0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
545     0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
546     0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
547     0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
548     0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
549     0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
550     0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
551     0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
552     0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
553     0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
554     0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
555     0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
556     0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
557     0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
558     0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
559     0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
560     0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
561     0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
562     0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
563     0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
564     0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
565     0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
566     0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
567     0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
568 };
569
570 #define CRC32C_PRELOAD 0xffffffff
571
572 /* 
573  * Byte swap fix contributed by Dave Wysochanski <davidw@netapp.com>
574  */
575 #define CRC32C_SWAP(crc32c_value) \
576                 (((crc32c_value & 0xff000000) >> 24) | \
577                 ((crc32c_value & 0x00ff0000) >>  8) | \
578                 ((crc32c_value & 0x0000ff00) <<  8) | \
579                 ((crc32c_value & 0x000000ff) << 24))
580
581 static guint32
582 calculateCRC32(const void *buf, int len, guint32 crc) {
583     const guint8 *p = (const guint8 *)buf;
584     crc = CRC32C_SWAP(crc);
585     while(len-- > 0)
586         crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
587     return CRC32C_SWAP(crc);
588 }
589
590
591
592
593
594 /* structure and functions to keep track of 
595  * COMMAND/DATA_IN/DATA_OUT/RESPONSE matching 
596  */
597 typedef struct _iscsi_conv_data {
598     guint32 conv_idx;
599     guint32 itt;
600     guint32 request_frame;
601     guint32 data_in_frame;
602     guint32 data_out_frame;
603     guint32 response_frame;
604     guint32 iscsi_dl;
605     nstime_t req_time;
606 } iscsi_conv_data_t;
607 static GHashTable *iscsi_req_unmatched = NULL;
608 static GHashTable *iscsi_req_matched = NULL;
609 static GMemChunk *iscsi_req_vals = NULL;
610 static guint32 iscsi_init_count = 200;
611
612 static gint
613 iscsi_equal_unmatched(gconstpointer v, gconstpointer w)
614 {
615   const iscsi_conv_data_t *v1 = (const iscsi_conv_data_t *)v;
616   const iscsi_conv_data_t *v2 = (const iscsi_conv_data_t *)w;
617
618   return (v1->conv_idx == v2->conv_idx)&&(v1->itt == v2->itt);
619 }
620
621 static guint
622 iscsi_hash_unmatched (gconstpointer v)
623 {
624         const iscsi_conv_data_t *key = (const iscsi_conv_data_t *)v;
625         guint val;
626
627         val = key->conv_idx + key->itt;
628
629         return val;
630 }
631
632 static gint
633 iscsi_equal_matched(gconstpointer v, gconstpointer w)
634 {
635   const iscsi_conv_data_t *v1 = (const iscsi_conv_data_t *)v;
636   const iscsi_conv_data_t *v2 = (const iscsi_conv_data_t *)w;
637   int check_frame;
638
639   check_frame=0;
640   if (v1->request_frame && (v1->request_frame==v2->request_frame))
641       check_frame=1;
642   if (v1->data_in_frame && (v1->data_in_frame==v2->data_in_frame))
643       check_frame=1;
644   if (v1->data_out_frame && (v1->data_out_frame==v2->data_out_frame))
645       check_frame=1;
646   if (v1->response_frame && (v1->response_frame==v2->response_frame))
647       check_frame=1;
648
649   return check_frame&&(v1->conv_idx == v2->conv_idx)&&(v1->itt == v2->itt);
650 }
651
652 static guint
653 iscsi_hash_matched (gconstpointer v)
654 {
655         const iscsi_conv_data_t *key = (const iscsi_conv_data_t *)v;
656         guint val;
657
658         val = key->conv_idx + key->itt;
659
660         return val;
661 }
662
663
664
665
666
667
668 /*
669  * Protocol initialization
670  */
671 static void
672 iscsi_init_protocol(void)
673 {
674     if (iscsi_req_vals)
675         g_mem_chunk_destroy(iscsi_req_vals);
676     if (iscsi_req_unmatched)
677         g_hash_table_destroy(iscsi_req_unmatched);
678     if (iscsi_req_matched)
679         g_hash_table_destroy(iscsi_req_matched);
680
681     iscsi_req_unmatched = g_hash_table_new(iscsi_hash_unmatched, iscsi_equal_unmatched);
682     iscsi_req_matched = g_hash_table_new(iscsi_hash_matched, iscsi_equal_matched);
683     iscsi_req_vals = g_mem_chunk_new("iscsi_req_vals",
684                                    sizeof(iscsi_conv_data_t),
685                                    iscsi_init_count * sizeof(iscsi_conv_data_t),
686                                    G_ALLOC_AND_FREE);
687 }
688
689 static int
690 iscsi_min(int a, int b) {
691     return (a < b)? a : b;
692 }
693
694 static gint
695 addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
696     const gint limit = offset + text_len;
697     while(offset < limit) {
698         gint len = tvb_strnlen(tvb, offset, limit - offset);
699         if(len == -1)
700             len = limit - offset;
701         else
702             len = len + 1;
703         proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, FALSE);
704         offset += len;
705     }
706     return offset;
707 }
708
709 static gint
710 handleHeaderDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
711     int available_bytes = tvb_length_remaining(tvb, offset);
712     if(enableHeaderDigests) {
713         if(headerDigestIsCRC32) {
714             if(available_bytes >= (headerLen + 4)) {
715                 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
716                 guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
717                 if(crc == sent) {
718                     proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
719                 }
720                 else {
721                     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);
722                 }
723             }
724             return offset + headerLen + 4;
725         }
726         if(available_bytes >= (headerLen + headerDigestSize)) {
727             proto_tree_add_item(ti, hf_iscsi_HeaderDigest, tvb, offset + headerLen, headerDigestSize, FALSE);
728         }
729         return offset + headerLen + headerDigestSize;
730     }
731     return offset + headerLen;
732 }
733
734 static gint
735 handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) {
736     int available_bytes = tvb_length_remaining(tvb, offset);
737     if(enableDataDigests) {
738         if(dataDigestIsCRC32) {
739             if(available_bytes >= (dataLen + 4)) {
740                 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
741                 guint32 sent = tvb_get_ntohl(tvb, offset + dataLen);
742                 if(crc == sent) {
743                     proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Good CRC32)", sent);
744                 }
745                 else {
746                     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);
747                 }
748             }
749             return offset + dataLen + 4;
750         }
751         if(available_bytes >= (dataLen + dataDigestSize)) {
752             proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, FALSE);
753         }
754         return offset + dataLen + dataDigestSize;
755     }
756     return offset + dataLen;
757 }
758
759 static int
760 handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) {
761     if(endOffset > offset) {
762         int dataOffset = offset;
763         int dataLen = iscsi_min(dataSegmentLen, endOffset - offset);
764         if(dataLen > 0) {
765             proto_tree_add_item(ti, hf_id, tvb, offset, dataLen, FALSE);
766             offset += dataLen;
767         }
768         if(offset < endOffset && (offset & 3) != 0) {
769             int padding = 4 - (offset & 3);
770             proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
771             offset += padding;
772         }
773         if(dataSegmentLen > 0 && offset < endOffset)
774             offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
775     }
776
777     return offset;
778 }
779
780 static int
781 handleDataSegmentAsTextKeys(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) {
782     if(endOffset > offset) {
783         int dataOffset = offset;
784         int textLen = iscsi_min(dataSegmentLen, endOffset - offset);
785         if(textLen > 0) {
786             proto_item *tf = proto_tree_add_text(ti, tvb, offset, textLen, "Key/Value Pairs");
787             proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
788             offset = addTextKeys(tt, tvb, offset, textLen);
789         }
790         if(offset < endOffset && (offset & 3) != 0) {
791             int padding = 4 - (offset & 3);
792             proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
793             offset += padding;
794         }
795         if(digestsActive && dataSegmentLen > 0 && offset < endOffset)
796             offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
797     }
798     return offset;
799 }
800
801 /* Code to actually dissect the packets */
802 static void
803 dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 opcode, const char *opcode_str, guint32 data_segment_len) {
804
805     guint original_offset = offset;
806     proto_tree *ti = NULL;
807     guint8 scsi_status = 0;
808     gboolean S_bit=FALSE;
809     guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
810     guint end_offset = offset + tvb_length_remaining(tvb, offset);
811     conversation_t *conversation = NULL;
812     iscsi_conv_data_t *cdata = NULL;
813     scsi_task_id_t task_key;
814     int paddedDataSegmentLength = data_segment_len;
815     if(paddedDataSegmentLength & 3)
816         paddedDataSegmentLength += 4 - (paddedDataSegmentLength & 3);
817
818     /* Make entries in Protocol column and Info column on summary display */
819     if (check_col(pinfo->cinfo, COL_PROTOCOL))
820         col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
821
822     if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
823         opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
824         scsi_status = tvb_get_guint8 (tvb, offset+3);
825     }
826
827     if ((opcode == ISCSI_OPCODE_SCSI_RESPONSE) ||
828         (opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
829         (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
830         conversation = find_conversation (&pinfo->src, &pinfo->dst,
831                                           pinfo->ptype, pinfo->srcport,
832                                           pinfo->destport, 0);
833         if (conversation) {
834             if (!pinfo->fd->flags.visited){
835                 iscsi_conv_data_t ckey;
836                 ckey.conv_idx = conversation->index;
837                 ckey.itt = tvb_get_ntohl (tvb, offset+16);
838
839                 /* first time we see this packet. check if we can find the request */
840                 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_unmatched, &ckey);
841                 if (cdata){
842                     if (cdata->data_in_frame+cdata->data_out_frame+cdata->response_frame==0){
843                         /* this is the first response to the request, add it to the matched table */
844                         g_hash_table_insert (iscsi_req_matched, cdata, cdata);
845                     }
846                     switch(opcode){
847                     case ISCSI_OPCODE_SCSI_RESPONSE:
848                         cdata->response_frame=pinfo->fd->num;
849                         break;
850                     case ISCSI_OPCODE_SCSI_DATA_IN:
851                         /* a bit ugly but we need to check the S bit here */
852                         if(tvb_get_guint8(tvb, offset+1)&ISCSI_SCSI_DATA_FLAG_S){
853                             cdata->response_frame=pinfo->fd->num;
854                         }
855                         cdata->data_in_frame=pinfo->fd->num;
856                         break;
857                     case ISCSI_OPCODE_SCSI_DATA_OUT:
858                         cdata->data_out_frame=pinfo->fd->num;
859                         break;
860                     }
861                 }
862             } else {
863                 iscsi_conv_data_t ckey;
864                 ckey.conv_idx = conversation->index;
865                 ckey.itt = tvb_get_ntohl (tvb, offset+16);
866                 ckey.request_frame=0;
867                 ckey.data_in_frame=0;
868                 ckey.data_out_frame=0;
869                 ckey.response_frame=0;
870                 switch(opcode){
871                 case ISCSI_OPCODE_SCSI_RESPONSE:
872                     ckey.response_frame=pinfo->fd->num;
873                     break;
874                 case ISCSI_OPCODE_SCSI_DATA_IN:
875                     ckey.data_in_frame=pinfo->fd->num;
876                     break;
877                 case ISCSI_OPCODE_SCSI_DATA_OUT:
878                     ckey.data_out_frame=pinfo->fd->num;
879                     break;
880                 }
881
882                 /* we have seen this one before,   pick it up from the matched table */
883                 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_matched, &ckey);
884             }
885
886             if (cdata){
887                 task_key.conv_id = cdata->conv_idx;
888                 task_key.task_id = cdata->itt;
889                 pinfo->private_data = &task_key;
890             } else {
891                 pinfo->private_data = NULL;
892             }
893         } else {
894             /* no conversation, meaning we didn't see the request */
895             pinfo->private_data = NULL;
896         }
897
898     } else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
899         conversation = find_conversation (&pinfo->src, &pinfo->dst,
900                                           pinfo->ptype, pinfo->srcport,
901                                           pinfo->destport, 0);
902         if (!conversation) {
903             conversation = conversation_new (&pinfo->src, &pinfo->dst,
904                                              pinfo->ptype, pinfo->srcport,
905                                              pinfo->destport, 0);
906         }
907
908         if (!pinfo->fd->flags.visited){
909             iscsi_conv_data_t ckey;
910
911             /* first time we see this packet. */
912             /*check if we have seen this request before and delete it in that case */
913             ckey.conv_idx = conversation->index;
914             ckey.itt = tvb_get_ntohl (tvb, offset+16);
915             cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_unmatched, &ckey);
916             if (cdata){
917                 g_hash_table_remove(iscsi_req_unmatched, &ckey);
918             }
919
920             /* add this new transaction to the unmatched table */
921             cdata = g_mem_chunk_alloc (iscsi_req_vals);
922             cdata->conv_idx = conversation->index;
923             cdata->itt = tvb_get_ntohl (tvb, offset+16);
924             cdata->request_frame=pinfo->fd->num;
925             cdata->data_in_frame=0;
926             cdata->data_out_frame=0;
927             cdata->response_frame=0;
928             cdata->req_time.nsecs = pinfo->fd->abs_usecs*1000;
929             cdata->req_time.secs = pinfo->fd->abs_secs;
930
931             g_hash_table_insert (iscsi_req_unmatched, cdata, cdata);
932         } else {
933                 iscsi_conv_data_t ckey;
934                 ckey.conv_idx = conversation->index;
935                 ckey.itt = tvb_get_ntohl (tvb, offset+16);
936                 ckey.request_frame=pinfo->fd->num;
937                 ckey.data_in_frame=0;
938                 ckey.data_out_frame=0;
939                 ckey.response_frame=0;
940
941                 /* we have seen this one before,   pick it up from the matched table */
942                 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_matched, &ckey);
943         }
944
945
946         if (cdata){
947             /* The SCSI protocol uses this as the key to detect a
948              * SCSI-level conversation. */
949             task_key.conv_id = cdata->conv_idx;
950             task_key.task_id = cdata->itt;
951             pinfo->private_data = &task_key;
952         } else {
953             pinfo->private_data=NULL;
954         }
955     }
956     else {
957         pinfo->private_data = NULL;
958     }
959
960     if (check_col(pinfo->cinfo, COL_INFO)) {
961
962         if (opcode != ISCSI_OPCODE_SCSI_COMMAND) {
963
964             col_append_str(pinfo->cinfo, COL_INFO, opcode_str);
965
966             if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
967                 (opcode == ISCSI_OPCODE_SCSI_DATA_IN &&
968                  (tvb_get_guint8(tvb, offset + 1) & ISCSI_SCSI_DATA_FLAG_S))) {
969                 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
970                                  val_to_str (scsi_status, scsi_status_val, "0x%x"));
971             }
972             else if (opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
973                 guint16 login_status = tvb_get_ntohs(tvb, offset+36);
974                 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
975                                  val_to_str (login_status, iscsi_login_status, "0x%x"));
976             }
977             else if (opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
978                 guint8 logoutReason;
979                 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
980                     logoutReason = tvb_get_guint8(tvb, offset+11);
981                 } else if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
982                     logoutReason = tvb_get_guint8(tvb, offset+1) & 0x7f;
983                 }
984                 else {
985                     logoutReason = tvb_get_guint8(tvb, offset+23);
986                 }
987                 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
988                                  val_to_str (logoutReason, iscsi_logout_reasons, "0x%x"));
989             }
990             else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
991                 guint8 tmf = tvb_get_guint8(tvb, offset + 1);
992                 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
993                                  val_to_str (tmf, iscsi_task_management_functions, "0x%x"));
994             }
995             else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
996                 guint8 resp = tvb_get_guint8(tvb, offset + 2);
997                 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
998                                  val_to_str (resp, iscsi_task_management_responses, "0x%x"));
999             }
1000             else if (opcode == ISCSI_OPCODE_REJECT) {
1001                 guint8 reason = tvb_get_guint8(tvb, offset + 2);
1002                 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
1003                                  val_to_str (reason, iscsi_reject_reasons, "0x%x"));
1004             }
1005             else if (opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1006                 guint8 asyncEvent = tvb_get_guint8(tvb, offset + 36);
1007                 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
1008                                  val_to_str (asyncEvent, iscsi_asyncevents, "0x%x"));
1009             }
1010         }
1011     }
1012
1013     /* In the interest of speed, if "tree" is NULL, don't do any
1014        work not necessary to generate protocol tree items. */
1015     if (tree) {
1016         proto_item *tp;
1017         /* create display subtree for the protocol */
1018         tp = proto_tree_add_protocol_format(tree, proto_iscsi, tvb,
1019                                             offset, -1, "iSCSI (%s)",
1020                                             opcode_str);
1021         ti = proto_item_add_subtree(tp, ett_iscsi);
1022     }
1023     proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
1024                             offset + 0, 1, opcode);
1025     if((opcode & TARGET_OPCODE_BIT) == 0) {
1026             /* initiator -> target */
1027             gint b = tvb_get_guint8(tvb, offset + 0);
1028         if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1029                 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
1030                    opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
1031                    opcode != ISCSI_OPCODE_SNACK_REQUEST)
1032                     proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
1033         }
1034             if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
1035                opcode != ISCSI_OPCODE_LOGIN_COMMAND &&
1036                opcode != ISCSI_OPCODE_SNACK_REQUEST)
1037                 proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
1038     }
1039
1040
1041     if(opcode == ISCSI_OPCODE_NOP_OUT) {
1042             /* NOP Out */
1043             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1044                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1045             }
1046             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1047             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1048             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1049             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1050             proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1051             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1052             offset = handleHeaderDigest(ti, tvb, offset, 48);
1053             offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
1054     } else if(opcode == ISCSI_OPCODE_NOP_IN) {
1055             /* NOP In */
1056             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1057                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1058             }
1059             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1060             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1061             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1062             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1063             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1064             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1065             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1066             offset = handleHeaderDigest(ti, tvb, offset, 48);
1067             offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
1068     } else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
1069             /* SCSI Command */
1070             guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
1071             {
1072                 gint b = tvb_get_guint8(tvb, offset + 1);
1073                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1074                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1075
1076                 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
1077                 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
1078                 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
1079                 proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
1080             }
1081             if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1082                 proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, FALSE);
1083             }
1084             proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1085             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1086             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1087             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1088             proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, FALSE);
1089             proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1090             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1091             {
1092                 if(ahsLen > 0) {
1093                     /* FIXME - disssect AHS? */
1094                     proto_tree_add_item(ti, hf_iscsi_AHS, tvb, offset + 48, ahsLen, FALSE);
1095                 }
1096                 offset = handleHeaderDigest(ti, tvb, offset, 48 + ahsLen);
1097             }
1098             offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
1099     } else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1100             /* SCSI Response */
1101             {
1102                 gint b = tvb_get_guint8(tvb, offset + 1);
1103                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1104                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1105
1106                 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
1107                 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
1108                 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
1109                 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
1110             }
1111             proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Response, tvb, offset + 2, 1, FALSE);
1112             proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
1113             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1114                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1115             }
1116             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1117             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1118             if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1119                 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 20, 4, FALSE);
1120             }
1121             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1122             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1123             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1124             proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1125             if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1126                 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, FALSE);
1127             }
1128             else {
1129                 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 40, 4, FALSE);
1130                 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 44, 4, FALSE);
1131             }
1132             offset = handleHeaderDigest(ti, tvb, offset, 48);
1133             /* do not update offset here because the data segment is
1134              * dissected below */
1135             handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1136     } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
1137             /* Task Management Function */
1138             proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, FALSE);
1139             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1140                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1141                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1142             }
1143             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1144             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1145             proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1146             proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1147             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1148             proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
1149             offset = handleHeaderDigest(ti, tvb, offset, 48);
1150     } else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
1151             /* Task Management Function Response */
1152             proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Response, tvb, offset + 2, 1, FALSE);
1153             if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1154                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1155                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1156             }
1157             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1158             if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1159                 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1160             }
1161             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1162             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1163             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1164             offset = handleHeaderDigest(ti, tvb, offset, 48);
1165     } else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
1166             /* Login Command */
1167             int digestsActive = 0;
1168             {
1169                 gint b = tvb_get_guint8(tvb, offset + 1);
1170                 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1171                     if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1172                         digestsActive = 1;
1173                 }
1174 #if 0
1175                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1176                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1177 #endif
1178
1179                 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1180                 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1181                     proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1182                 }
1183                 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1184                     proto_tree_add_boolean(ti, hf_iscsi_Login_X, tvb, offset + 1, 1, b);
1185                 }
1186                 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
1187
1188                 /* NSG is undefined unless T is set */
1189                 if(b&0x80){
1190                         proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
1191                 }
1192             }
1193             proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1194             proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
1195             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1196                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1197             }
1198             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1199             if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1200                 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1201                 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, FALSE);
1202             }
1203             else {
1204                 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
1205                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1206                 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1207                     proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, FALSE);
1208                     proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, FALSE);
1209                     proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, FALSE);
1210                 }
1211                 else {
1212                     proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, FALSE);
1213                     proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, FALSE);
1214                     proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, FALSE);
1215                     proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, FALSE);
1216                     proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, FALSE);
1217                 }
1218             }
1219             if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1220                 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1221             }
1222             else {
1223                 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, FALSE);
1224             }
1225             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1226             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1227                 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
1228             }
1229             proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1230             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1231             if(digestsActive)
1232                 offset = handleHeaderDigest(ti, tvb, offset, 48);
1233             else
1234                 offset += 48;
1235             offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1236     } else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1237             /* Login Response */
1238             int digestsActive = 0;
1239             {
1240                 gint b = tvb_get_guint8(tvb, offset + 1);
1241                 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1242                     if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1243                         digestsActive = 1;
1244                 }
1245 #if 0
1246                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1247                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1248 #endif
1249
1250                 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1251                 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1252                     proto_tree_add_boolean(ti, hf_iscsi_Login_C, tvb, offset + 1, 1, b);
1253                 }
1254                 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
1255                 /* NSG is undefined unless T is set */
1256                 if(b&0x80){
1257                         proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
1258                 }
1259             }
1260
1261             proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1262             proto_tree_add_item(ti, hf_iscsi_VersionActive, tvb, offset + 3, 1, FALSE);
1263             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1264                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1265             }
1266             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1267             if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1268                 proto_tree_add_item(ti, hf_iscsi_ISID8, tvb, offset + 12, 2, FALSE);
1269             }
1270             else {
1271                 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
1272                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1273                 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT09) {
1274                     proto_tree_add_item(tt, hf_iscsi_ISID_Type, tvb, offset + 8, 1, FALSE);
1275                     proto_tree_add_item(tt, hf_iscsi_ISID_NamingAuthority, tvb, offset + 9, 3, FALSE);
1276                     proto_tree_add_item(tt, hf_iscsi_ISID_Qualifier, tvb, offset + 12, 2, FALSE);
1277                 }
1278                 else {
1279                     proto_tree_add_item(tt, hf_iscsi_ISID_t, tvb, offset + 8, 1, FALSE);
1280                     proto_tree_add_item(tt, hf_iscsi_ISID_a, tvb, offset + 8, 1, FALSE);
1281                     proto_tree_add_item(tt, hf_iscsi_ISID_b, tvb, offset + 9, 2, FALSE);
1282                     proto_tree_add_item(tt, hf_iscsi_ISID_c, tvb, offset + 11, 1, FALSE);
1283                     proto_tree_add_item(tt, hf_iscsi_ISID_d, tvb, offset + 12, 2, FALSE);
1284                 }
1285             }
1286             if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT12) {
1287                 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1288             }
1289             else {
1290                 proto_tree_add_item(ti, hf_iscsi_TSIH, tvb, offset + 14, 2, FALSE);
1291             }
1292             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1293             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1294             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1295             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1296             proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, FALSE);
1297             if(digestsActive)
1298                 offset = handleHeaderDigest(ti, tvb, offset, 48);
1299             else
1300                 offset += 48;
1301             offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1302     } else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
1303             /* Text Command */
1304             {
1305                 gint b = tvb_get_guint8(tvb, offset + 1);
1306                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1307                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1308
1309                 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1310                 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1311                     proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1312                 }
1313             }
1314             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1315                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1316             }
1317             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1318             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1319                 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1320             }
1321             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1322             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, 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(ti, tvb, offset, 48);
1326             offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1327     } else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
1328             /* Text Response */
1329             {
1330                 gint b = tvb_get_guint8(tvb, offset + 1);
1331                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1332                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1333
1334                 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1335                 if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1336                     proto_tree_add_boolean(tt, hf_iscsi_Text_C, tvb, offset + 1, 1, b);
1337                 }
1338             }
1339             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1340                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1341             }
1342             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1343             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1344                 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1345             }
1346             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1347             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1348             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1349             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1350             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1351             offset = handleHeaderDigest(ti, tvb, offset, 48);
1352             offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1353     } else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
1354             /* SCSI Data Out (write) */
1355             {
1356                 gint b = tvb_get_guint8(tvb, offset + 1);
1357                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1358                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1359
1360                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1361             }
1362             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1363                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1364             }
1365             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1366             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1367             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1368             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1369             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1370             proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1371             proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1372             offset = handleHeaderDigest(ti, tvb, offset, 48);
1373             /* do not update offset here because the data segment is
1374              * dissected below */
1375             handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1376     } else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
1377             /* SCSI Data In (read) */
1378             {
1379                 gint b = tvb_get_guint8(tvb, offset + 1);
1380                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1381                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1382
1383                 if(b&ISCSI_SCSI_DATA_FLAG_S){
1384                    S_bit=TRUE;
1385                 }
1386                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1387                 if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1388                     proto_tree_add_boolean(tt, hf_iscsi_SCSIData_A, tvb, offset + 1, 1, b);
1389                 }
1390                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
1391                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
1392                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
1393             }
1394             proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
1395             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1396                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1397             }
1398             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1399             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1400                 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1401             }
1402             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1403             if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1404                 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 20, 4, FALSE);
1405             }
1406             else {
1407                 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1408             }
1409             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1410             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1411             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1412             proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1413             proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1414             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1415                 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 44, 4, FALSE);
1416             }
1417             offset = handleHeaderDigest(ti, tvb, offset, 48);
1418             /* do not update offset here because the data segment is
1419              * dissected below */
1420             handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1421     } else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
1422             /* Logout Command */
1423             if(iscsi_protocol_version >= ISCSI_PROTOCOL_DRAFT13) {
1424                 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 1, 1, FALSE);
1425             }
1426             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1427                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1428                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1429             }
1430             if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1431                 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1432                 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, FALSE);
1433             }
1434             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1435             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT08) {
1436                 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
1437                 if(iscsi_protocol_version < ISCSI_PROTOCOL_DRAFT13) {
1438                     proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 23, 1, FALSE);
1439                 }
1440             }
1441             proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1442             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1443             offset = handleHeaderDigest(ti, tvb, offset, 48);
1444     } else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
1445             /* Logout Response */
1446             proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, FALSE);
1447             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1448                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1449                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1450             }
1451             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1452             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1453             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1454             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1455             proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, FALSE);
1456             proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, FALSE);
1457             offset = handleHeaderDigest(ti, tvb, offset, 48);
1458     } else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
1459             /* SNACK Request */
1460             {
1461                 gint b = tvb_get_guint8(tvb, offset + 1);
1462 #if 0
1463                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1464                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1465 #endif
1466
1467                 proto_tree_add_item(ti, hf_iscsi_snack_type, tvb, offset + 1, 1, b);
1468             }
1469             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1470                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1471                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1472                 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1473             }
1474             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1475             if(iscsi_protocol_version <= ISCSI_PROTOCOL_DRAFT09) {
1476                 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, FALSE);
1477                 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, FALSE);
1478                 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1479                 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1480             }
1481             else {
1482                 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1483                 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1484                 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 40, 4, FALSE);
1485                 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 44, 4, FALSE);
1486             }
1487             offset = handleHeaderDigest(ti, tvb, offset, 48);
1488     } else if(opcode == ISCSI_OPCODE_R2T) {
1489             /* R2T */
1490             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1491                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1492                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1493                 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1494             }
1495             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1496             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1497             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1498             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1499             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1500             proto_tree_add_item(ti, hf_iscsi_R2TSN, tvb, offset + 36, 4, FALSE);
1501             proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1502             proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
1503             offset = handleHeaderDigest(ti, tvb, offset, 48);
1504     } else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1505             /* Asynchronous Message */
1506             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1507                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1508             }
1509             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1510             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1511             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1512             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1513             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1514             proto_tree_add_item(ti, hf_iscsi_AsyncEvent, tvb, offset + 36, 1, FALSE);
1515             proto_tree_add_item(ti, hf_iscsi_EventVendorCode, tvb, offset + 37, 1, FALSE);
1516             proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, FALSE);
1517             proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
1518             proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
1519             offset = handleHeaderDigest(ti, tvb, offset, 48);
1520             offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_async_message_data);
1521     } else if(opcode == ISCSI_OPCODE_REJECT) {
1522             /* Reject */
1523             proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
1524             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1525                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1526             }
1527             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1528             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1529             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1530             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1531             proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1532             offset = handleHeaderDigest(ti, tvb, offset, 48);
1533             offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_error_pdu_data);
1534     } else if(opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I0 ||
1535                 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I1 ||
1536                 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_I2 ||
1537                 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T0 ||
1538                 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T1 ||
1539                 opcode == ISCSI_OPCODE_VENDOR_SPECIFIC_T2) {
1540             /* Vendor specific opcodes */
1541             if(iscsi_protocol_version > ISCSI_PROTOCOL_DRAFT09) {
1542                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
1543             }
1544             proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1545             offset = handleHeaderDigest(ti, tvb, offset, 48);
1546             offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_vendor_specific_data);
1547     }
1548
1549
1550
1551     /* handle request/response matching */
1552     if (cdata){
1553         switch(opcode){
1554         case ISCSI_OPCODE_SCSI_RESPONSE:
1555             if (cdata->request_frame){
1556                 nstime_t delta_time;
1557                 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
1558                 delta_time.secs = pinfo->fd->abs_secs - cdata->req_time.secs;
1559                 delta_time.nsecs = pinfo->fd->abs_usecs*1000 - cdata->req_time.nsecs;
1560                 if (delta_time.nsecs<0){
1561                     delta_time.nsecs+=1000000000;
1562                     delta_time.secs--;
1563                 }
1564                 proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1565                 
1566             }
1567             if (cdata->data_in_frame)
1568                 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1569             if (cdata->data_out_frame)
1570                 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1571             break;
1572         case ISCSI_OPCODE_SCSI_DATA_IN:
1573             /* if we have phase collaps then we might have the
1574                response embedded in the last DataIn segment */
1575             if(!S_bit){
1576                 if (cdata->request_frame)
1577                     proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
1578                 if (cdata->response_frame)
1579                     proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->response_frame);
1580             } else {
1581                 if (cdata->request_frame){
1582                      nstime_t delta_time;
1583                      proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
1584                      delta_time.secs = pinfo->fd->abs_secs - cdata->req_time.secs;
1585                      delta_time.nsecs = pinfo->fd->abs_usecs*1000 - cdata->req_time.nsecs;
1586                      if (delta_time.nsecs<0){
1587                           delta_time.nsecs+=1000000000;
1588                           delta_time.secs--;
1589                      }
1590                      proto_tree_add_time(ti, hf_iscsi_time, tvb, 0, 0, &delta_time);
1591                 
1592                 }
1593             }
1594             if (cdata->data_out_frame)
1595                 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1596             break;
1597         case ISCSI_OPCODE_SCSI_DATA_OUT:
1598             if (cdata->request_frame)
1599                 proto_tree_add_uint(ti, hf_iscsi_request_frame, tvb, 0, 0, cdata->request_frame);
1600             if (cdata->data_in_frame)
1601                 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1602             if (cdata->response_frame)
1603                 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->response_frame);
1604             break;
1605         case ISCSI_OPCODE_SCSI_COMMAND:
1606             if (cdata->data_in_frame)
1607                 proto_tree_add_uint(ti, hf_iscsi_data_in_frame, tvb, 0, 0, cdata->data_in_frame);
1608             if (cdata->data_out_frame)
1609                 proto_tree_add_uint(ti, hf_iscsi_data_out_frame, tvb, 0, 0, cdata->data_out_frame);
1610             if (cdata->response_frame)
1611                 proto_tree_add_uint(ti, hf_iscsi_response_frame, tvb, 0, 0, cdata->response_frame);
1612             break;
1613         }
1614     }
1615
1616
1617
1618     proto_item_set_len(ti, offset - original_offset);
1619
1620     if((opcode & ((iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08)?
1621                   ~(X_BIT | I_BIT) :
1622                   ~I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND) {
1623         /* SCSI Command */
1624         dissect_scsi_cdb (tvb, pinfo, tree, cdb_offset, 16, SCSI_DEV_UNKNOWN);
1625     }
1626     else if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1627         if (scsi_status == 0x2) {
1628             /* A SCSI response with Check Condition contains sense data */
1629             /* offset is setup correctly by the iscsi code for response above */
1630             if((end_offset - offset) >= 2) {
1631                 int senseLen = tvb_get_ntohs(tvb, offset);
1632                 if(ti != NULL)
1633                     proto_tree_add_item(ti, hf_iscsi_SenseLength, tvb, offset, 2, FALSE);
1634                 offset += 2;
1635                 if(senseLen > 0)
1636                     dissect_scsi_snsinfo (tvb, pinfo, tree, offset,
1637                                           iscsi_min (senseLen,
1638                                                      end_offset-offset));
1639             }
1640         }
1641         else {
1642             dissect_scsi_rsp (tvb, pinfo, tree);
1643         }
1644     }
1645     else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
1646              (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
1647         /* offset is setup correctly by the iscsi code for response above */
1648         dissect_scsi_payload (tvb, pinfo, tree, offset, FALSE,
1649                               iscsi_min (data_segment_len, end_offset-offset));
1650     }
1651 }
1652
1653 static gboolean
1654 dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean check_port) {
1655     /* Set up structures needed to add the protocol subtree and manage it */
1656     guint iSCSIPdusDissected = 0;
1657     guint offset = 0;
1658     guint32 available_bytes = tvb_length_remaining(tvb, offset);
1659
1660     /* quick check to see if the packet is long enough to contain the
1661      * minimum amount of information we need */
1662     if (available_bytes < 48 && (!iscsi_desegment || available_bytes < 8)) {
1663         /* no, so give up */
1664         return FALSE;
1665     }
1666
1667     /* process multiple iSCSI PDUs per packet */
1668     while(available_bytes >= 48 || (iscsi_desegment && available_bytes >= 8)) {
1669         const char *opcode_str = NULL;
1670         guint32 data_segment_len;
1671         guint8 opcode = tvb_get_guint8(tvb, offset + 0);
1672         guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1);
1673         int badPdu = FALSE;
1674
1675         /* mask out any extra bits in the opcode byte */
1676         opcode &= OPCODE_MASK;
1677
1678         opcode_str = match_strval(opcode, iscsi_opcodes);
1679         if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION ||
1680            opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
1681            opcode == ISCSI_OPCODE_R2T ||
1682            opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
1683            opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
1684            opcode == ISCSI_OPCODE_SNACK_REQUEST)
1685             data_segment_len = 0;
1686         else
1687             data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
1688
1689         if(opcode_str == NULL) {
1690             badPdu = TRUE;
1691         }
1692         else if(check_port && iscsi_port != 0 &&
1693                 (((opcode & TARGET_OPCODE_BIT) && pinfo->srcport != iscsi_port) ||
1694                  (!(opcode & TARGET_OPCODE_BIT) && pinfo->destport != iscsi_port))) {
1695             badPdu = TRUE;
1696         }
1697         else if(enable_bogosity_filter) {
1698             /* try and distinguish between data and real headers */
1699             if(data_segment_len > bogus_pdu_data_length_threshold) {
1700                 badPdu = TRUE;
1701             }
1702             else if(demand_good_f_bit &&
1703                     !(secondPduByte & 0x80) &&
1704                     (opcode == ISCSI_OPCODE_NOP_OUT ||
1705                      opcode == ISCSI_OPCODE_NOP_IN ||
1706                      opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
1707                      opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
1708                      opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
1709                      opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
1710                      opcode == ISCSI_OPCODE_R2T ||
1711                      opcode == ISCSI_OPCODE_ASYNC_MESSAGE ||
1712                      opcode == ISCSI_OPCODE_SNACK_REQUEST ||
1713                      opcode == ISCSI_OPCODE_REJECT)) {
1714                 badPdu = TRUE;
1715             } else if(opcode==ISCSI_OPCODE_NOP_OUT) {
1716                 /* TransferTag for NOP-Out should either be -1 or
1717                    the tag value we want for a response. 
1718                    Assume 0 means we are just inside a big all zero
1719                    datablock.
1720                 */
1721                 if(tvb_get_ntohl(tvb, offset+20)==0){
1722                     badPdu = TRUE;
1723                 }
1724             }
1725         }
1726
1727         if(badPdu) {
1728             return iSCSIPdusDissected > 0;
1729         }
1730         else {
1731             guint32 pduLen = 48;
1732             int digestsActive = 1;
1733
1734             if(opcode == ISCSI_OPCODE_LOGIN_COMMAND ||
1735                opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1736                 if(iscsi_protocol_version == ISCSI_PROTOCOL_DRAFT08) {
1737                     if((secondPduByte & CSG_MASK) < ISCSI_CSG_OPERATIONAL_NEGOTIATION) {
1738                         /* digests are not yet turned on */
1739                         digestsActive = 0;
1740                     }
1741                 }
1742                 else {
1743                     digestsActive = 0;
1744                 }
1745             }
1746
1747             if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
1748                 /* ahsLen */
1749                 pduLen += tvb_get_guint8(tvb, offset + 4) * 4;
1750             }
1751
1752             pduLen += data_segment_len;
1753             if((pduLen & 3) != 0)
1754                 pduLen += 4 - (pduLen & 3);
1755
1756             if(digestsActive && enableHeaderDigests) {
1757                 if(headerDigestIsCRC32)
1758                     pduLen += 4;
1759                 else
1760                     pduLen += headerDigestSize;
1761             }
1762
1763             if(digestsActive && data_segment_len > 0 && enableDataDigests) {
1764                 if(dataDigestIsCRC32)
1765                     pduLen += 4;
1766                 else
1767                     pduLen += dataDigestSize;
1768             }
1769
1770             /*
1771              * Desegmentation check.
1772              */
1773             if(iscsi_desegment && pinfo->can_desegment) {
1774                 if(pduLen > available_bytes) {
1775                     /*
1776                      * This frame doesn't have all of the data for
1777                      * this message, but we can do reassembly on it.
1778                      *
1779                      * Tell the TCP dissector where the data for this
1780                      * message starts in the data it handed us, and
1781                      * how many more bytes we need, and return.
1782                      */
1783                     pinfo->desegment_offset = offset;
1784                     pinfo->desegment_len = pduLen - available_bytes;
1785                     return TRUE;
1786                 }
1787             }
1788
1789             /* This is to help TCP keep track of PDU boundaries
1790                and allows it to find PDUs that are not aligned to 
1791                the start of a TCP segments.
1792                Since it also allows TCP to know what is in the middle
1793                of a large PDU, it reduces the probability of a segment
1794                in the middle of a large PDU transfer being misdissected as
1795                a PDU.
1796             */
1797             if(!pinfo->fd->flags.visited){
1798                 if(pduLen>(guint32)tvb_reported_length_remaining(tvb, offset)){
1799                     pinfo->want_pdu_tracking=2;
1800                     pinfo->bytes_until_next_pdu=pduLen-tvb_reported_length_remaining(tvb, offset);
1801                 }
1802             }
1803
1804             if(check_col(pinfo->cinfo, COL_INFO)) {
1805                 if(iSCSIPdusDissected == 0)
1806                     col_set_str(pinfo->cinfo, COL_INFO, "");
1807                 else
1808                     col_append_str(pinfo->cinfo, COL_INFO, ", ");
1809             }
1810
1811             dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len);
1812             if(pduLen > available_bytes)
1813                 pduLen = available_bytes;
1814             offset += pduLen;
1815             available_bytes -= pduLen;
1816             ++iSCSIPdusDissected;
1817         }
1818     }
1819
1820     return iSCSIPdusDissected > 0;
1821 }
1822
1823 /* This is called for those sessions where we have explicitely said
1824    this to be iSCSI using "Decode As..."
1825    In this case we will not check the port number for sanity and just
1826    do as the user said.
1827 */
1828 static void
1829 dissect_iscsi_handle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1830     dissect_iscsi(tvb, pinfo, tree, FALSE);
1831 }
1832
1833 /* This is called through the heuristic handler.
1834    In this case we also want to check that the port matches the preference
1835    setting for iSCSI in order to reduce the number of
1836    false positives.
1837 */
1838 static gboolean
1839 dissect_iscsi_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1840     return dissect_iscsi(tvb, pinfo, tree, TRUE);
1841 }
1842
1843
1844 /* Register the protocol with Ethereal */
1845
1846 /*
1847  * this format is require because a script is used to build the C
1848  * function that calls all the protocol registration.
1849 */
1850
1851 void
1852 proto_register_iscsi(void)
1853 {
1854
1855     /* Setup list of header fields  See Section 1.6.1 for details*/
1856     static hf_register_info hf[] = {
1857         { &hf_iscsi_request_frame,
1858           { "Request in", "iscsi.request_frame",
1859             FT_FRAMENUM, BASE_NONE, NULL, 0,
1860             "The request to this transaction is in this frame", HFILL }},
1861
1862         { &hf_iscsi_time,
1863           { "Time from request", "iscsi.time",
1864             FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
1865             "Time between the Command and the Response", HFILL }},
1866
1867         { &hf_iscsi_data_in_frame,
1868           { "Data In in", "iscsi.data_in_frame",
1869             FT_FRAMENUM, BASE_NONE, NULL, 0,
1870             "The Data In for this transaction is in this frame", HFILL }},
1871
1872         { &hf_iscsi_data_out_frame,
1873           { "Data Out in", "iscsi.data_out_frame",
1874             FT_FRAMENUM, BASE_NONE, NULL, 0,
1875             "The Data Out for this transaction is in this frame", HFILL }},
1876
1877         { &hf_iscsi_response_frame,
1878           { "Response in", "iscsi.response_frame",
1879             FT_FRAMENUM, BASE_NONE, NULL, 0,
1880             "The response to this transaction is in this frame", HFILL }},
1881
1882         { &hf_iscsi_AHS,
1883           { "AHS", "iscsi.ahs",
1884             FT_BYTES, BASE_HEX, NULL, 0,
1885             "Additional header segment", HFILL }
1886         },
1887         { &hf_iscsi_Padding,
1888           { "Padding", "iscsi.padding",
1889             FT_BYTES, BASE_HEX, NULL, 0,
1890             "Padding to 4 byte boundary", HFILL }
1891         },
1892         { &hf_iscsi_ping_data,
1893           { "PingData", "iscsi.pingdata",
1894             FT_BYTES, BASE_HEX, NULL, 0,
1895             "Ping Data", HFILL }
1896         },
1897         { &hf_iscsi_immediate_data,
1898           { "ImmediateData", "iscsi.immediatedata",
1899             FT_BYTES, BASE_HEX, NULL, 0,
1900             "Immediate Data", HFILL }
1901         },
1902         { &hf_iscsi_write_data,
1903           { "WriteData", "iscsi.writedata",
1904             FT_BYTES, BASE_HEX, NULL, 0,
1905             "Write Data", HFILL }
1906         },
1907         { &hf_iscsi_read_data,
1908           { "ReadData", "iscsi.readdata",
1909             FT_BYTES, BASE_HEX, NULL, 0,
1910             "Read Data", HFILL }
1911         },
1912         { &hf_iscsi_error_pdu_data,
1913           { "ErrorPDUData", "iscsi.errorpdudata",
1914             FT_BYTES, BASE_HEX, NULL, 0,
1915             "Error PDU Data", HFILL }
1916         },
1917         { &hf_iscsi_async_message_data,
1918           { "AsyncMessageData", "iscsi.asyncmessagedata",
1919             FT_BYTES, BASE_HEX, NULL, 0,
1920             "Async Message Data", HFILL }
1921         },
1922         { &hf_iscsi_vendor_specific_data,
1923           { "VendorSpecificData", "iscsi.vendorspecificdata",
1924             FT_BYTES, BASE_HEX, NULL, 0,
1925             "Vendor Specific Data", HFILL }
1926         },
1927         { &hf_iscsi_HeaderDigest,
1928           { "HeaderDigest", "iscsi.headerdigest",
1929             FT_BYTES, BASE_HEX, NULL, 0,
1930             "Header Digest", HFILL }
1931         },
1932         { &hf_iscsi_HeaderDigest32,
1933           { "HeaderDigest", "iscsi.headerdigest32",
1934             FT_UINT32, BASE_HEX, NULL, 0,
1935             "Header Digest", HFILL }
1936         },
1937         { &hf_iscsi_DataDigest,
1938           { "DataDigest", "iscsi.datadigest",
1939             FT_BYTES, BASE_HEX, NULL, 0,
1940             "Data Digest", HFILL }
1941         },
1942         { &hf_iscsi_DataDigest32,
1943           { "DataDigest", "iscsi.datadigest32",
1944             FT_UINT32, BASE_HEX, NULL, 0,
1945             "Data Digest", HFILL }
1946         },
1947         { &hf_iscsi_Opcode,
1948           { "Opcode", "iscsi.opcode",
1949             FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
1950             "Opcode", HFILL }
1951         },
1952 /* #ifdef DRAFT08 */
1953         { &hf_iscsi_X,
1954           { "X", "iscsi.X",
1955             FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,
1956             "Command Retry", HFILL }
1957         },
1958 /* #endif */
1959         { &hf_iscsi_I,
1960           { "I", "iscsi.I",
1961             FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,
1962             "Immediate delivery", HFILL }
1963         },
1964         { &hf_iscsi_Flags,
1965           { "Flags", "iscsi.flags",
1966             FT_UINT8, BASE_HEX, NULL, 0,
1967             "Opcode specific flags", HFILL }
1968         },
1969         { &hf_iscsi_SCSICommand_F,
1970           { "F", "iscsi.scsicommand.F",
1971             FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
1972             "PDU completes command", HFILL }
1973         },
1974         { &hf_iscsi_SCSICommand_R,
1975           { "R", "iscsi.scsicommand.R",
1976             FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,
1977             "Command reads from SCSI target", HFILL }
1978         },
1979         { &hf_iscsi_SCSICommand_W,
1980           { "W", "iscsi.scsicommand.W",
1981             FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,
1982             "Command writes to SCSI target", HFILL }
1983         },
1984         { &hf_iscsi_SCSICommand_Attr,
1985           { "Attr", "iscsi.scsicommand.attr",
1986             FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07,
1987             "SCSI task attributes", HFILL }
1988         },
1989         { &hf_iscsi_SCSICommand_CRN,
1990           { "CRN", "iscsi.scsicommand.crn",
1991             FT_UINT8, BASE_HEX, NULL, 0,
1992             "SCSI command reference number", HFILL }
1993         },
1994         { &hf_iscsi_SCSICommand_AddCDB,
1995           { "AddCDB", "iscsi.scsicommand.addcdb",
1996             FT_UINT8, BASE_HEX, NULL, 0,
1997             "Additional CDB length (in 4 byte units)", HFILL }
1998         },
1999         { &hf_iscsi_DataSegmentLength,
2000           { "DataSegmentLength", "iscsi.datasegmentlength",
2001             FT_UINT32, BASE_HEX, NULL, 0,
2002             "Data segment length (bytes)", HFILL }
2003         },
2004         { &hf_iscsi_TotalAHSLength,
2005           { "TotalAHSLength", "iscsi.totalahslength",
2006             FT_UINT8, BASE_HEX, NULL, 0,
2007             "Total additional header segment length (4 byte words)", HFILL }
2008         },
2009         { &hf_iscsi_LUN,
2010           { "LUN", "iscsi.lun",
2011             FT_BYTES, BASE_HEX, NULL, 0,
2012             "Logical Unit Number", HFILL }
2013         },
2014         { &hf_iscsi_InitiatorTaskTag,
2015           { "InitiatorTaskTag", "iscsi.initiatortasktag",
2016             FT_UINT32, BASE_HEX, NULL, 0,
2017             "Initiator's task tag", HFILL }
2018         },
2019         { &hf_iscsi_ExpectedDataTransferLength,
2020           { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength",
2021             FT_UINT32, BASE_HEX, NULL, 0,
2022             "Expected length of data transfer", HFILL }
2023         },
2024         { &hf_iscsi_CmdSN,
2025           { "CmdSN", "iscsi.cmdsn",
2026             FT_UINT32, BASE_HEX, NULL, 0,
2027             "Sequence number for this command", HFILL }
2028         },
2029         { &hf_iscsi_ExpStatSN,
2030           { "ExpStatSN", "iscsi.expstatsn",
2031             FT_UINT32, BASE_HEX, NULL, 0,
2032             "Next expected status sequence number", HFILL }
2033         },
2034         { &hf_iscsi_SCSIResponse_ResidualCount,
2035           { "ResidualCount", "iscsi.scsiresponse.residualcount",
2036             FT_UINT32, BASE_HEX, NULL, 0,
2037             "Residual count", HFILL }
2038         },
2039         { &hf_iscsi_StatSN,
2040           { "StatSN", "iscsi.statsn",
2041             FT_UINT32, BASE_HEX, NULL, 0,
2042             "Status sequence number", HFILL }
2043         },
2044         { &hf_iscsi_ExpCmdSN,
2045           { "ExpCmdSN", "iscsi.expcmdsn",
2046             FT_UINT32, BASE_HEX, NULL, 0,
2047             "Next expected command sequence number", HFILL }
2048         },
2049         { &hf_iscsi_MaxCmdSN,
2050           { "MaxCmdSN", "iscsi.maxcmdsn",
2051             FT_UINT32, BASE_HEX, NULL, 0,
2052             "Maximum acceptable command sequence number", HFILL }
2053         },
2054         { &hf_iscsi_SCSIResponse_o,
2055           { "o", "iscsi.scsiresponse.o",
2056             FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,
2057             "Bi-directional read residual overflow", HFILL }
2058         },
2059         { &hf_iscsi_SCSIResponse_u,
2060           { "u", "iscsi.scsiresponse.u",
2061             FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08,
2062             "Bi-directional read residual underflow", HFILL }
2063         },
2064         { &hf_iscsi_SCSIResponse_O,
2065           { "O", "iscsi.scsiresponse.O",
2066             FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
2067             "Residual overflow", HFILL }
2068         },
2069         { &hf_iscsi_SCSIResponse_U,
2070           { "U", "iscsi.scsiresponse.U",
2071             FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
2072             "Residual underflow", HFILL }
2073         },
2074         { &hf_iscsi_SCSIResponse_Status,
2075           { "Status", "iscsi.scsiresponse.status",
2076             FT_UINT8, BASE_HEX, VALS(scsi_status_val), 0,
2077             "SCSI command status value", HFILL }
2078         },
2079         { &hf_iscsi_SCSIResponse_Response,
2080           { "Response", "iscsi.scsiresponse.response",
2081             FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
2082             "SCSI command response value", HFILL }
2083         },
2084         { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
2085           { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
2086             FT_UINT32, BASE_HEX, NULL, 0,
2087             "Bi-directional read residual count", HFILL }
2088         },
2089         { &hf_iscsi_SenseLength,
2090           { "SenseLength", "iscsi.scsiresponse.senselength",
2091             FT_UINT16, BASE_HEX, NULL, 0,
2092             "Sense data length", HFILL }
2093         },
2094         { &hf_iscsi_SCSIData_F,
2095           { "F", "iscsi.scsidata.F",
2096             FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), ISCSI_SCSI_DATA_FLAG_F,
2097             "Final PDU", HFILL }
2098         },
2099         { &hf_iscsi_SCSIData_A,
2100           { "A", "iscsi.scsidata.A",
2101             FT_BOOLEAN, 8, TFS(&iscsi_meaning_A), ISCSI_SCSI_DATA_FLAG_A,
2102             "Acknowledge Requested", HFILL }
2103         },
2104         { &hf_iscsi_SCSIData_S,
2105           { "S", "iscsi.scsidata.S",
2106             FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), ISCSI_SCSI_DATA_FLAG_S,
2107             "PDU Contains SCSI command status", HFILL }
2108         },
2109         { &hf_iscsi_SCSIData_U,
2110           { "U", "iscsi.scsidata.U",
2111             FT_BOOLEAN, 8,  TFS(&iscsi_meaning_U), ISCSI_SCSI_DATA_FLAG_U,
2112             "Residual underflow", HFILL }
2113         },
2114         { &hf_iscsi_SCSIData_O,
2115           { "O", "iscsi.scsidata.O",
2116             FT_BOOLEAN, 8,  TFS(&iscsi_meaning_O), ISCSI_SCSI_DATA_FLAG_O,
2117             "Residual overflow", HFILL }
2118         },
2119         { &hf_iscsi_TargetTransferTag,
2120           { "TargetTransferTag", "iscsi.targettransfertag",
2121             FT_UINT32, BASE_HEX, NULL, 0,
2122             "Target transfer tag", HFILL }
2123         },
2124         { &hf_iscsi_BufferOffset,
2125           { "BufferOffset", "iscsi.bufferOffset",
2126             FT_UINT32, BASE_HEX, NULL, 0,
2127             "Buffer offset", HFILL }
2128         },
2129         { &hf_iscsi_SCSIData_ResidualCount,
2130           { "ResidualCount", "iscsi.scsidata.readresidualcount",
2131             FT_UINT32, BASE_HEX, NULL, 0,
2132             "Residual count", HFILL }
2133         },
2134         { &hf_iscsi_DataSN,
2135           { "DataSN", "iscsi.datasn",
2136             FT_UINT32, BASE_HEX, NULL, 0,
2137             "Data sequence number", HFILL }
2138         },
2139         { &hf_iscsi_VersionMax,
2140           { "VersionMax", "iscsi.versionmax",
2141             FT_UINT8, BASE_HEX, NULL, 0,
2142             "Maximum supported protocol version", HFILL }
2143         },
2144         { &hf_iscsi_VersionMin,
2145           { "VersionMin", "iscsi.versionmin",
2146             FT_UINT8, BASE_HEX, NULL, 0,
2147             "Minimum supported protocol version", HFILL }
2148         },
2149         { &hf_iscsi_VersionActive,
2150           { "VersionActive", "iscsi.versionactive",
2151             FT_UINT8, BASE_HEX, NULL, 0,
2152             "Negotiated protocol version", HFILL }
2153         },
2154         { &hf_iscsi_CID,
2155           { "CID", "iscsi.cid",
2156             FT_UINT16, BASE_HEX, NULL, 0,
2157             "Connection identifier", HFILL }
2158         },
2159 /* #ifdef DRAFT08 */
2160         { &hf_iscsi_ISID8,
2161           { "ISID", "iscsi.isid",
2162             FT_UINT16, BASE_HEX, NULL, 0,
2163             "Initiator part of session identifier", HFILL }
2164         },
2165 /* #else */
2166         { &hf_iscsi_ISID,
2167           { "ISID", "iscsi.isid",
2168             FT_BYTES, BASE_HEX, NULL, 0,
2169             "Initiator part of session identifier", HFILL }
2170         },
2171 /* #ifdef DRAFT09 */
2172         { &hf_iscsi_ISID_Type,
2173           { "ISID_Type", "iscsi.isid.type",
2174             FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0,
2175             "Initiator part of session identifier - type", HFILL }
2176         },
2177         { &hf_iscsi_ISID_NamingAuthority,
2178           { "ISID_NamingAuthority", "iscsi.isid.namingauthority",
2179             FT_UINT24, BASE_HEX, NULL, 0,
2180             "Initiator part of session identifier - naming authority", HFILL }
2181         },
2182         { &hf_iscsi_ISID_Qualifier,
2183           { "ISID_Qualifier", "iscsi.isid.qualifier",
2184             FT_UINT8, BASE_HEX, NULL, 0,
2185             "Initiator part of session identifier - qualifier", HFILL }
2186         },
2187 /* #else */
2188         { &hf_iscsi_ISID_t,
2189           { "ISID_t", "iscsi.isid.t",
2190             FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0xc0,
2191             "Initiator part of session identifier - t", HFILL }
2192         },
2193         { &hf_iscsi_ISID_a,
2194           { "ISID_a", "iscsi.isid.a",
2195             FT_UINT8, BASE_HEX, NULL, 0x3f,
2196             "Initiator part of session identifier - a", HFILL }
2197         },
2198         { &hf_iscsi_ISID_b,
2199           { "ISID_b", "iscsi.isid.b",
2200             FT_UINT16, BASE_HEX, NULL, 0,
2201             "Initiator part of session identifier - b", HFILL }
2202         },
2203         { &hf_iscsi_ISID_c,
2204           { "ISID_c", "iscsi.isid.c",
2205             FT_UINT8, BASE_HEX, NULL, 0,
2206             "Initiator part of session identifier - c", HFILL }
2207         },
2208         { &hf_iscsi_ISID_d,
2209           { "ISID_d", "iscsi.isid.d",
2210             FT_UINT16, BASE_HEX, NULL, 0,
2211             "Initiator part of session identifier - d", HFILL }
2212         },
2213 /* #endif */
2214 /* #endif */
2215         { &hf_iscsi_TSID,
2216           { "TSID", "iscsi.tsid",
2217             FT_UINT16, BASE_HEX, NULL, 0,
2218             "Target part of session identifier", HFILL }
2219         },
2220         { &hf_iscsi_TSIH,
2221           { "TSIH", "iscsi.tsih",
2222             FT_UINT16, BASE_HEX, NULL, 0,
2223             "Target session identifying handle", HFILL }
2224         },
2225         { &hf_iscsi_InitStatSN,
2226           { "InitStatSN", "iscsi.initstatsn",
2227             FT_UINT32, BASE_HEX, NULL, 0,
2228             "Initial status sequence number", HFILL }
2229         },
2230         { &hf_iscsi_InitCmdSN,
2231           { "InitCmdSN", "iscsi.initcmdsn",
2232             FT_UINT32, BASE_HEX, NULL, 0,
2233             "Initial command sequence number", HFILL }
2234         },
2235         { &hf_iscsi_Login_T,
2236           { "T", "iscsi.login.T",
2237             FT_BOOLEAN, 8, TFS(&iscsi_meaning_T), 0x80,
2238             "Transit to next login stage",  HFILL }
2239         },
2240         { &hf_iscsi_Login_C,
2241           { "C", "iscsi.login.C",
2242             FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2243             "Text incomplete",  HFILL }
2244         },
2245 /* #ifdef DRAFT09 */
2246         { &hf_iscsi_Login_X,
2247           { "X", "iscsi.login.X",
2248             FT_BOOLEAN, 8, TFS(&iscsi_meaning_login_X), 0x40,
2249             "Restart Connection",  HFILL }
2250         },
2251 /* #endif */
2252         { &hf_iscsi_Login_CSG,
2253           { "CSG", "iscsi.login.csg",
2254             FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), CSG_MASK,
2255             "Current stage",  HFILL }
2256         },
2257         { &hf_iscsi_Login_NSG,
2258           { "NSG", "iscsi.login.nsg",
2259             FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), NSG_MASK,
2260             "Next stage",  HFILL }
2261         },
2262         { &hf_iscsi_Login_Status,
2263           { "Status", "iscsi.login.status",
2264             FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0,
2265             "Status class and detail", HFILL }
2266         },
2267         { &hf_iscsi_KeyValue,
2268           { "KeyValue", "iscsi.keyvalue",
2269             FT_STRING, 0, NULL, 0,
2270             "Key/value pair", HFILL }
2271         },
2272         { &hf_iscsi_Text_F,
2273           { "F", "iscsi.text.F",
2274             FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
2275             "Final PDU in text sequence", HFILL }
2276         },
2277         { &hf_iscsi_Text_C,
2278           { "C", "iscsi.text.C",
2279             FT_BOOLEAN, 8, TFS(&iscsi_meaning_C), 0x40,
2280             "Text incomplete", HFILL }
2281         },
2282         { &hf_iscsi_ExpDataSN,
2283           { "ExpDataSN", "iscsi.expdatasn",
2284             FT_UINT32, BASE_HEX, NULL, 0,
2285             "Next expected data sequence number", HFILL }
2286         },
2287         { &hf_iscsi_R2TSN,
2288           { "R2TSN", "iscsi.r2tsn",
2289             FT_UINT32, BASE_HEX, NULL, 0,
2290             "R2T PDU Number", HFILL }
2291         },
2292         { &hf_iscsi_TaskManagementFunction_Response,
2293           { "Response", "iscsi.taskmanfun.response",
2294             FT_UINT8, BASE_HEX, VALS(iscsi_task_management_responses), 0,
2295             "Response", HFILL }
2296         },
2297         { &hf_iscsi_TaskManagementFunction_ReferencedTaskTag,
2298           { "ReferencedTaskTag", "iscsi.taskmanfun.referencedtasktag",
2299             FT_UINT32, BASE_HEX, NULL, 0,
2300             "Referenced task tag", HFILL }
2301         },
2302         { &hf_iscsi_RefCmdSN,
2303           { "RefCmdSN", "iscsi.refcmdsn",
2304             FT_UINT32, BASE_HEX, NULL, 0,
2305             "Command sequence number for command to be aborted", HFILL }
2306         },
2307         { &hf_iscsi_TaskManagementFunction_Function,
2308           { "Function", "iscsi.taskmanfun.function",
2309             FT_UINT8, BASE_HEX, VALS(iscsi_task_management_functions), 0x7F,
2310             "Requested task function", HFILL }
2311         },
2312         { &hf_iscsi_Logout_Reason,
2313           { "Reason", "iscsi.logout.reason",
2314             FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0x7F,
2315             "Reason for logout", HFILL }
2316         },
2317         { &hf_iscsi_Logout_Response,
2318           { "Response", "iscsi.logout.response",
2319             FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
2320             "Logout response", HFILL }
2321         },
2322         { &hf_iscsi_Time2Wait,
2323           { "Time2Wait", "iscsi.time2wait",
2324             FT_UINT16, BASE_HEX, NULL, 0,
2325             "Time2Wait", HFILL }
2326         },
2327         { &hf_iscsi_Time2Retain,
2328           { "Time2Retain", "iscsi.time2retain",
2329             FT_UINT16, BASE_HEX, NULL, 0,
2330             "Time2Retain", HFILL }
2331         },
2332         { &hf_iscsi_DesiredDataLength,
2333           { "DesiredDataLength", "iscsi.desireddatalength",
2334             FT_UINT32, BASE_HEX, NULL, 0,
2335             "Desired data length (bytes)", HFILL }
2336         },
2337         { &hf_iscsi_AsyncEvent,
2338           { "AsyncEvent", "iscsi.asyncevent",
2339             FT_UINT8, BASE_HEX, VALS(iscsi_asyncevents), 0,
2340             "Async event type", HFILL }
2341         },
2342         { &hf_iscsi_EventVendorCode,
2343           { "EventVendorCode", "iscsi.eventvendorcode",
2344             FT_UINT8, BASE_HEX, NULL, 0,
2345             "Event vendor code", HFILL }
2346         },
2347         { &hf_iscsi_Parameter1,
2348           { "Parameter1", "iscsi.parameter1",
2349             FT_UINT16, BASE_HEX, NULL, 0,
2350             "Parameter 1", HFILL }
2351         },
2352         { &hf_iscsi_Parameter2,
2353           { "Parameter2", "iscsi.parameter2",
2354             FT_UINT16, BASE_HEX, NULL, 0,
2355             "Parameter 2", HFILL }
2356         },
2357         { &hf_iscsi_Parameter3,
2358           { "Parameter3", "iscsi.parameter3",
2359             FT_UINT16, BASE_HEX, NULL, 0,
2360             "Parameter 3", HFILL }
2361         },
2362         { &hf_iscsi_Reject_Reason,
2363           { "Reason", "iscsi.reject.reason",
2364             FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
2365             "Reason for command rejection", HFILL }
2366         },
2367         { &hf_iscsi_snack_type,
2368           { "S", "iscsi.snack.type",
2369             FT_UINT8, BASE_DEC, VALS(iscsi_snack_types), 0x0f,
2370             "Type of SNACK requested", HFILL }
2371         },
2372         { &hf_iscsi_BegRun,
2373           { "BegRun", "iscsi.snack.begrun",
2374             FT_UINT32, BASE_HEX, NULL, 0,
2375             "First missed DataSN or StatSN", HFILL }
2376         },
2377         { &hf_iscsi_RunLength,
2378           { "RunLength", "iscsi.snack.runlength",
2379             FT_UINT32, BASE_HEX, NULL, 0,
2380             "Number of additional missing status PDUs in this run", HFILL }
2381         },
2382     };
2383
2384     /* Setup protocol subtree array */
2385     static gint *ett[] = {
2386         &ett_iscsi,
2387         &ett_iscsi_KeyValues,
2388         &ett_iscsi_CDB,
2389         &ett_iscsi_Flags,
2390 /* #ifndef DRAFT08 */
2391         &ett_iscsi_ISID,
2392 /* #endif */
2393     };
2394
2395     /* Register the protocol name and description */
2396     proto_iscsi = proto_register_protocol("iSCSI", "iSCSI", "iscsi");
2397
2398     /* Required function calls to register the header fields and
2399      * subtrees used */
2400     proto_register_field_array(proto_iscsi, hf, array_length(hf));
2401     proto_register_subtree_array(ett, array_length(ett));
2402     register_init_routine (&iscsi_init_protocol);
2403
2404     {
2405         module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
2406
2407         prefs_register_enum_preference(iscsi_module,
2408                                        "protocol_version",
2409                                        "Protocol version",
2410                                        "The iSCSI protocol version",
2411                                        &iscsi_protocol_version,
2412                                        iscsi_protocol_versions,
2413                                        FALSE);
2414
2415         prefs_register_bool_preference(iscsi_module,
2416                                        "desegment_iscsi_messages",
2417                                        "Reassemble iSCSI messages\nspanning multiple TCP segments",
2418                                        "Whether the iSCSI dissector should reassemble messages spanning multiple TCP segments."
2419                                        " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2420                                        &iscsi_desegment);
2421
2422         prefs_register_bool_preference(iscsi_module,
2423                                        "bogus_pdu_filter",
2424                                        "Enable bogus pdu filter",
2425                                        "When enabled, packets that appear bogus are ignored",
2426                                        &enable_bogosity_filter);
2427
2428         prefs_register_bool_preference(iscsi_module,
2429                                        "demand_good_f_bit",
2430                                        "Ignore packets with bad F bit",
2431                                        "Ignore packets that haven't set the F bit when they should have",
2432                                        &demand_good_f_bit);
2433
2434         prefs_register_uint_preference(iscsi_module,
2435                                        "bogus_pdu_max_data_len",
2436                                        "Bogus pdu max data length threshold",
2437                                        "Treat packets whose data segment length is greater than this value as bogus",
2438                                        10,
2439                                        &bogus_pdu_data_length_threshold);
2440
2441
2442         prefs_register_uint_preference(iscsi_module,
2443                                        "target_port",
2444                                        "Target port",
2445                                        "Port number of iSCSI target",
2446                                        10,
2447                                        &iscsi_port);
2448
2449         prefs_register_bool_preference(iscsi_module,
2450                                        "enable_header_digests",
2451                                        "Enable header digests",
2452                                        "When enabled, pdus are assumed to contain a header digest",
2453                                        &enableHeaderDigests);
2454         prefs_register_bool_preference(iscsi_module,
2455                                        "enable_data_digests",
2456                                        "Enable data digests",
2457                                        "When enabled, pdus are assumed to contain a data digest",
2458                                        &enableDataDigests);
2459
2460         prefs_register_bool_preference(iscsi_module,
2461                                        "header_digest_is_crc32c",
2462                                        "Header digest is CRC32C",
2463                                        "When enabled, header digests are assumed to be CRC32C",
2464                                        &headerDigestIsCRC32);
2465         prefs_register_bool_preference(iscsi_module,
2466                                        "data_digest_is_crc32c",
2467                                        "Data digest is CRC32C",
2468                                        "When enabled, data digests are assumed to be CRC32C",
2469                                        &dataDigestIsCRC32);
2470
2471         prefs_register_uint_preference(iscsi_module,
2472                                        "header_digest_size",
2473                                        "Header digest size",
2474                                        "The size of a header digest (bytes)",
2475                                        10,
2476                                        &headerDigestSize);
2477         prefs_register_uint_preference(iscsi_module,
2478                                        "data_digest_size",
2479                                        "Data digest size",
2480                                        "The size of a data digest (bytes)",
2481                                        10,
2482                                        &dataDigestSize);
2483
2484         /* Preference supported in older versions.
2485            Register them as obsolete. */
2486         prefs_register_obsolete_preference(iscsi_module,
2487                                        "version_03_compatible");
2488         prefs_register_obsolete_preference(iscsi_module,
2489                                        "bogus_pdu_max_digest_padding");
2490     }
2491 }
2492
2493
2494 /*
2495  * If this dissector uses sub-dissector registration add a
2496  * registration routine.
2497  */
2498
2499 /*
2500  * This format is required because a script is used to find these
2501  * routines and create the code that calls these routines.
2502  */
2503 void
2504 proto_reg_handoff_iscsi(void)
2505 {
2506     dissector_handle_t iscsi_handle;
2507
2508     heur_dissector_add("tcp", dissect_iscsi_heur, proto_iscsi);
2509
2510     iscsi_handle = create_dissector_handle(dissect_iscsi_handle, proto_iscsi);
2511     dissector_add_handle("tcp.port", iscsi_handle);
2512 }