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