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