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