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