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