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