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