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