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