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