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