Damn the torpedos[1], commit it anyway.
[obnox/wireshark/wip.git] / packet-iscsi.c
1 /* packet-iscsi.c
2  * Routines for iSCSI dissection
3  * Copyright 2001, Eurologic and Mark Burton <markb@ordern.com>
4  *
5  * Conforms to the protocol described in: draft-ietf-ips-iscsi-06.txt
6  * but uses the 07 opcodes (as used at the July 2001 UNH plugfest)
7  *
8  * Optionally, supports the protocol described in: draft-ietf-ips-iscsi-03.txt
9  *
10  * $Id: packet-iscsi.c,v 1.10 2001/07/22 20:02:23 guy Exp $
11  *
12  * Ethereal - Network traffic analyzer
13  * By Gerald Combs <gerald@ethereal.com>
14  * Copyright 1998 Gerald Combs
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  * 
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * 
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif
42
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46
47 #include <glib.h>
48
49 #ifdef NEED_SNPRINTF_H
50 # include "snprintf.h"
51 #endif
52
53 #include "packet.h"
54 #include "prefs.h"
55
56 /*#define USE_06_OPCODES*/
57
58 static int enable_03_mode = FALSE;
59 static int enable_bogosity_filter = TRUE;
60 static guint32 bogus_pdu_data_length_threshold = 1024 * 1024;
61 static guint32 bogus_pdu_max_digest_padding = 20;
62
63 static int enable_force_header_digest_crc32 = FALSE;
64
65 /* Initialize the protocol and registered fields */
66 static int proto_iscsi = -1;
67 static int hf_iscsi_Padding = -1;
68 static int hf_iscsi_Payload = -1;
69 static int hf_iscsi_Opcode = -1;
70 static int hf_iscsi_Opcode_03 = -1;
71 static int hf_iscsi_Flags = -1;
72 static int hf_iscsi_HeaderDigest32 = -1;
73 static int hf_iscsi_X = -1;
74 static int hf_iscsi_I = -1;
75 static int hf_iscsi_SCSICommand_X03 = -1;
76 static int hf_iscsi_SCSICommand_F = -1;
77 static int hf_iscsi_SCSICommand_R = -1;
78 static int hf_iscsi_SCSICommand_W = -1;
79 static int hf_iscsi_SCSICommand_Attr = -1;
80 static int hf_iscsi_SCSICommand_CRN = -1;
81 static int hf_iscsi_SCSICommand_AddCDB = -1;
82 static int hf_iscsi_Length03 = -1;
83 static int hf_iscsi_DataSegmentLength = -1;
84 static int hf_iscsi_TotalAHSLength = -1;
85 static int hf_iscsi_LUN = -1;
86 static int hf_iscsi_InitiatorTaskTag = -1;
87 static int hf_iscsi_ExpectedDataTransferLength = -1;
88 static int hf_iscsi_CmdSN = -1;
89 static int hf_iscsi_ExpStatSN = -1;
90 static int hf_iscsi_SCSICommand_CDB = -1;
91 static int hf_iscsi_SCSICommand_CDB0 = -1;
92 static int hf_iscsi_StatSN = -1;
93 static int hf_iscsi_ExpCmdSN = -1;
94 static int hf_iscsi_MaxCmdSN = -1;
95 static int hf_iscsi_SCSIResponse_o03 = -1;
96 static int hf_iscsi_SCSIResponse_u03 = -1;
97 static int hf_iscsi_SCSIResponse_O03 = -1;
98 static int hf_iscsi_SCSIResponse_U03 = -1;
99 static int hf_iscsi_SCSIResponse_o = -1;
100 static int hf_iscsi_SCSIResponse_u = -1;
101 static int hf_iscsi_SCSIResponse_O = -1;
102 static int hf_iscsi_SCSIResponse_U = -1;
103 static int hf_iscsi_SCSIResponse_S = -1;
104 static int hf_iscsi_CommandStatus03 = -1;
105 static int hf_iscsi_StatusResponse_is_status = -1;
106 static int hf_iscsi_StatusResponse_is_response = -1;
107 static int hf_iscsi_SCSIResponse_SenseLength = -1;
108 static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1;
109 static int hf_iscsi_SCSIResponse_BasicResidualCount = -1;
110 static int hf_iscsi_SCSIData_F = -1;
111 static int hf_iscsi_SCSIData_P03 = -1;
112 static int hf_iscsi_SCSIData_S03 = -1;
113 static int hf_iscsi_SCSIData_O03 = -1;
114 static int hf_iscsi_SCSIData_U03 = -1;
115 static int hf_iscsi_SCSIData_S = -1;
116 static int hf_iscsi_SCSIData_O = -1;
117 static int hf_iscsi_SCSIData_U = -1;
118 static int hf_iscsi_TargetTransferTag = -1;
119 static int hf_iscsi_DataSN = -1;
120 static int hf_iscsi_BufferOffset = -1;
121 static int hf_iscsi_SCSIData_ResidualCount = -1;
122 static int hf_iscsi_VersionMin = -1;
123 static int hf_iscsi_VersionMax = -1;
124 static int hf_iscsi_CID = -1;
125 static int hf_iscsi_ISID = -1;
126 static int hf_iscsi_TSID = -1;
127 static int hf_iscsi_InitStatSN = -1;
128 static int hf_iscsi_InitCmdSN = -1;
129 static int hf_iscsi_Login_F = -1;
130 static int hf_iscsi_Login_Status03 = -1;
131 static int hf_iscsi_Login_Status = -1;
132 static int hf_iscsi_KeyValue = -1;
133 static int hf_iscsi_Text_F = -1;
134 static int hf_iscsi_NOP_P = -1;
135 static int hf_iscsi_ExpDataSN = -1;
136 static int hf_iscsi_R2TExpDataSN = -1;
137 static int hf_iscsi_SCSITask_ReferencedTaskTag = -1;
138 static int hf_iscsi_SCSITask_Function = -1;
139 static int hf_iscsi_SCSITask_Response = -1;
140 static int hf_iscsi_Logout_Reason03 = -1;
141 static int hf_iscsi_Logout_Reason = -1;
142 static int hf_iscsi_Logout_Response = -1;
143 static int hf_iscsi_DesiredDataLength = -1;
144 static int hf_iscsi_SCSIEvent = -1;
145 static int hf_iscsi_iSCSIEvent = -1;
146 static int hf_iscsi_SCSIEvent03 = -1;
147 static int hf_iscsi_iSCSIEvent03 = -1;
148 static int hf_iscsi_Parameter1 = -1;
149 static int hf_iscsi_Parameter2 = -1;
150 static int hf_iscsi_Parameter3 = -1;
151 static int hf_iscsi_Reject_Reason = -1;
152 static int hf_iscsi_Reject_FirstBadByte = -1;
153 static int hf_iscsi_Reject_Reason03 = -1;
154 static int hf_iscsi_SNACK_S = -1;
155 static int hf_iscsi_AddRuns = -1;
156 static int hf_iscsi_BegRun = -1;
157 static int hf_iscsi_RunLength = -1;
158 static int hf_iscsi_AdditionalRuns = -1;
159
160 /* Initialize the subtree pointers */
161 static gint ett_iscsi_KeyValues = -1;
162 static gint ett_iscsi_CDB = -1;
163 static gint ett_iscsi_Flags = -1;
164
165 static const value_string iscsi_opcodes[] = {
166 #ifdef USE_06_OPCODES
167   {0x00, "NOP Out"},
168   {0x40, "NOP Out (Immediate)"},
169   {0x80, "NOP Out (Retry)"},
170
171   {0x01, "SCSI Command"},
172   {0x41, "SCSI Command (Immediate)"},
173   {0x81, "SCSI Command (Retry)"},
174
175   {0x02, "SCSI Task Management Command"},
176   {0x42, "SCSI Task Management Command (Immediate)"},
177   {0x82, "SCSI Task Management Command (Retry)"},
178
179   {0x03, "Login Command"},
180   {0x83, "Login Command (Retry)"},
181
182   {0x04, "Text Command"},
183   {0x44, "Text Command (Immediate)"},
184   {0x84, "Text Command (Retry)"},
185
186   {0x05, "SCSI Write Data"},
187
188   {0x06, "Logout Command"},
189   {0x46, "Logout Command (Immediate)"},
190
191   {0x10, "SNACK Request (Missing Immediate bit)"},
192   {0x50, "SNACK Request"},
193
194   {0xc0, "NOP In"},
195   {0xc1, "SCSI Command Response"},
196   {0xc2, "SCSI Task Management Response"},
197   {0xc3, "Login Response"},
198   {0xc4, "Text Response"},
199   {0xc5, "SCSI Read Data"},
200   {0xc6, "Logout Response"},
201   {0xd0, "Ready To Transfer"},
202   {0xd1, "Asynchronous Message"},
203   {0xef, "Reject"},
204 #else
205   {0x00, "NOP Out"},
206   {0x01, "SCSI Command"},
207   {0x02, "SCSI Task Management Command"},
208   {0x03, "Login Command"},
209   {0x04, "Text Command"},
210   {0x05, "SCSI Write Data"},
211   {0x06, "Logout Command"},
212   {0x10, "SNACK Request"},
213
214   {0xe0, "NOP In"},
215   {0xe1, "SCSI Command Response"},
216   {0xe2, "SCSI Task Management Response"},
217   {0xe3, "Login Response"},
218   {0xe4, "Text Response"},
219   {0xe5, "SCSI Read Data"},
220   {0xe6, "Logout Response"},
221   {0xf1, "Ready To Transfer"},
222   {0xf2, "Asynchronous Message"},
223   {0xff, "Reject"},
224 #endif
225   {0, NULL},
226 };
227
228 static const value_string iscsi_opcodes_03[] = {
229   {0x00, "NOP Out"},
230   {0x01, "SCSI Command"},
231   {0x02, "SCSI Task Management Command"},
232   {0x03, "Login Command"},
233   {0x04, "Text Command"},
234   {0x05, "SCSI Write Data"},
235   {0x06, "Logout Command"},
236   {0x80, "NOP In"},
237   {0x81, "SCSI Command Response"},
238   {0x82, "SCSI Task Management Response"},
239   {0x83, "Login Response"},
240   {0x84, "Text Response"},
241   {0x85, "SCSI Read Data"},
242   {0x86, "Logout Response"},
243   {0x90, "Ready To Transfer"},
244   {0x91, "Asynchronous Event"},
245   {0xef, "Reject"},
246   {0, NULL},
247 };
248
249 static const true_false_string iscsi_meaning_X = {
250     "Retry",
251     "Not retry"
252 };
253
254 static const true_false_string iscsi_meaning_I = {
255     "Immediate delivery",
256     "Queued delivery"
257 };
258
259 static const true_false_string iscsi_meaning_F = {
260     "Final PDU in sequence",
261     "Not final PDU in sequence"
262 };
263
264 static const true_false_string iscsi_meaning_P = {
265     "Poll requested",
266     "No poll requested"
267 };
268
269 static const true_false_string iscsi_meaning_S = {
270     "Response contains SCSI status",
271     "Response does not contain SCSI status"
272 };
273
274 static const true_false_string iscsi_meaning_R = {
275     "Data will be read from target",
276     "No data will be read from target"
277 };
278
279 static const true_false_string iscsi_meaning_W = {
280     "Data will be written to target",
281     "No data will be written to target"
282 };
283
284 static const true_false_string iscsi_meaning_o = {
285     "Read part of bi-directional command overflowed",
286     "No overflow of read part of bi-directional command",
287 };
288
289 static const true_false_string iscsi_meaning_u = {
290     "Read part of bi-directional command underflowed",
291     "No underflow of read part of bi-directional command",
292 };
293
294 static const true_false_string iscsi_meaning_O = {
295     "Residual overflow occurred",
296     "No residual overflow occurred",
297 };
298
299 static const true_false_string iscsi_meaning_U = {
300     "Residual underflow occurred",
301     "No residual underflow occurred",
302 };
303
304 static const true_false_string iscsi_meaning_scsiresponse_S = {
305     "Status/Response field contains SCSI status",
306     "Status/Response field contains iSCSI response",
307 };
308
309 static const true_false_string iscsi_meaning_SNACK_S = {
310     "Status SNACK",
311     "Data SNACK",
312 };
313
314 static const value_string iscsi_scsicommand_taskattrs[] = {
315     {0, "Untagged"},
316     {1, "Simple"},
317     {2, "Ordered"},
318     {3, "Head of Queue"},
319     {4, "ACA"},
320     {0, NULL},
321 };
322
323 static const value_string iscsi_scsi_cdb0[] = {
324     {0x00, "TEST_UNIT_READY"},
325     {0x01, "REZERO_UNIT"},
326     {0x03, "REQUEST_SENSE"},
327     {0x04, "FORMAT_UNIT"},
328     {0x05, "READ_BLOCK_LIMITS"},
329     {0x07, "REASSIGN_BLOCKS"},
330     {0x08, "READ_6"},
331     {0x0a, "WRITE_6"},
332     {0x0b, "SEEK_6"},
333     {0x0f, "READ_REVERSE"},
334     {0x10, "WRITE_FILEMARKS"},
335     {0x11, "SPACE"},
336     {0x12, "INQUIRY"},
337     {0x14, "RECOVER_BUFFERED_DATA"},
338     {0x15, "MODE_SELECT"},
339     {0x16, "RESERVE"},
340     {0x17, "RELEASE"},
341     {0x18, "COPY"},
342     {0x19, "ERASE"},
343     {0x1a, "MODE_SENSE"},
344     {0x1b, "START_STOP"},
345     {0x1c, "RECEIVE_DIAGNOSTIC"},
346     {0x1d, "SEND_DIAGNOSTIC"},
347     {0x1e, "ALLOW_MEDIUM_REMOVAL"},
348     {0x24, "SET_WINDOW"},
349     {0x25, "READ_CAPACITY"},
350     {0x28, "READ_10"},
351     {0x2a, "WRITE_10"},
352     {0x2b, "SEEK_10"},
353     {0x2e, "WRITE_VERIFY"},
354     {0x2f, "VERIFY"},
355     {0x30, "SEARCH_HIGH"},
356     {0x31, "SEARCH_EQUAL"},
357     {0x32, "SEARCH_LOW"},
358     {0x33, "SET_LIMITS"},
359     {0x34, "PRE_FETCH"},
360     {0x34, "READ_POSITION"},
361     {0x35, "SYNCHRONIZE_CACHE"},
362     {0x36, "LOCK_UNLOCK_CACHE"},
363     {0x37, "READ_DEFECT_DATA"},
364     {0x38, "MEDIUM_SCAN"},
365     {0x39, "COMPARE"},
366     {0x3a, "COPY_VERIFY"},
367     {0x3b, "WRITE_BUFFER"},
368     {0x3c, "READ_BUFFER"},
369     {0x3d, "UPDATE_BLOCK"},
370     {0x3e, "READ_LONG"},
371     {0x3f, "WRITE_LONG"},
372     {0x40, "CHANGE_DEFINITION"},
373     {0x41, "WRITE_SAME"},
374     {0x43, "READ_TOC"},
375     {0x4c, "LOG_SELECT"},
376     {0x4d, "LOG_SENSE"},
377     {0x55, "MODE_SELECT_10"},
378     {0x5a, "MODE_SENSE_10"},
379     {0xa5, "MOVE_MEDIUM"},
380     {0xa8, "READ_12"},
381     {0xaa, "WRITE_12"},
382     {0xae, "WRITE_VERIFY_12"},
383     {0xb0, "SEARCH_HIGH_12"},
384     {0xb1, "SEARCH_EQUAL_12"},
385     {0xb2, "SEARCH_LOW_12"},
386     {0xb8, "READ_ELEMENT_STATUS"},
387     {0xb6, "SEND_VOLUME_TAG"},
388     {0xea, "WRITE_LONG_2"},
389     {0, NULL},
390 };
391
392 static const value_string iscsi_scsi_statuses[] = {
393     {0x00, "Good"},
394     {0x01, "Check condition"},
395     {0x02, "Condition good"},
396     {0x04, "Busy"},
397     {0x08, "Intermediate good"},
398     {0x0a, "Intermediate c good"},
399     {0x0c, "Reservation conflict"},
400     {0x11, "Command terminated"},
401     {0x14, "Queue full"},
402     {0, NULL},
403 };
404
405 static const value_string iscsi_scsi_responses[] = {
406     {0x01, "Target failure"},
407     {0x02, "Delivery subsystem failure"},
408     {0x03, "Unsolicited data rejected"},
409     {0x04, "SNACK rejected"},
410     {0, NULL},
411 };
412
413 static const value_string iscsi_task_responses[] = {
414     {0, "Function complete"},
415     {1, "Task not in task set"},
416     {2, "LUN does not exist"},
417     {255, "Function rejected"},
418     {0, NULL},
419 };
420
421 static const value_string iscsi_task_functions[] = {
422     {1, "Abort Task"},
423     {2, "Abort Task Set"},
424     {3, "Clear ACA"},
425     {4, "Clear Task Set"},
426     {5, "Logical Unit Reset"},
427     {6, "Target Warm Reset"},
428     {7, "Target Cold Reset"},
429     {0, NULL},
430 };
431
432 static const value_string iscsi_login_status03[] = {
433     {0, "Accept Login"},
434     {1, "Reject Login - unsupported version"},
435     {2, "Reject Login - failed authentication"},
436     {3, "Reject Login - incompatible parameters"},
437     {0, NULL},
438 };
439
440 static const value_string iscsi_login_status[] = {
441     {0x0000, "Success - Accept login"},
442     {0x0001, "Success - Athenticate"},
443     {0x0002, "Success - iSCSI target name required"},
444     {0x0101, "Redirection - Target moved temporarily"},
445     {0x0102, "Redirection - Target moved permanently"},
446     {0x0103, "Redirection - Proxy required"},
447     {0x0201, "Initiator error - Athentication failed"},
448     {0x0202, "Initiator error - Forbidden target"},
449     {0x0203, "Initiator error - Target not found"},
450     {0x0204, "Initiator error - Target removed"},
451     {0x0205, "Initiator error - Target conflict"},
452     {0x0206, "Initiator error - Initiator SID error"},
453     {0x0207, "Initiator error - Missing parameter"},
454     {0x0300, "Target error - Target error"},
455     {0x0301, "Target error - Service unavailable"},
456     {0x0302, "Target error - Unsupported version"},
457     {0, NULL},
458 };
459
460 static const value_string iscsi_logout_reasons03[] = {
461     {0, "Remove connection - session is closing"},
462     {1, "Remove connection - for recovery"},
463     {2, "Remove connection - at target's request"},
464     {0, NULL},
465 };
466
467 static const value_string iscsi_logout_reasons[] = {
468     {0, "Session is closing"},
469     {1, "Close connections"},
470     {2, "Remove connection for recovery"},
471     {3, "Remove connection at target's request"},
472     {0, NULL},
473 };
474
475 static const value_string iscsi_logout_response[] = {
476     {0, "Connection closed successfully"},
477     {1, "Cleanup failed"},
478     {0, NULL},
479 };
480
481 static const value_string iscsi_scsievents03[] = {
482     {0, "No SCSI asynchronous event has occurred"},
483     {1, "Error condition encountered after command completion"},
484     {2, "A newly initialised device is available to the initiator"},
485     {3, "All task sets are being reset by another initiator"},
486     {5, "Some other type of unit attention condition has occurred"},
487     {6, "An asynchronous event has occurred"},
488     {0, NULL},
489 };
490
491 static const value_string iscsi_iscsievents03[] = {
492     {0, "No iSCSI event has occurred"},
493     {1, "Target is being reset"},
494     {2, "Target requests logout"},
495     {3, "Target will drop connection"},
496     {0, NULL},
497 };
498
499 static const value_string iscsi_scsievents[] = {
500     {0, "No SCSI asynchronous event has occurred"},
501     {1, "A SCSI asynchronous event is reported in the sense data"},
502     {0, NULL},
503 };
504
505 static const value_string iscsi_iscsievents[] = {
506     {0, "No iSCSI event has occurred"},
507     {1, "Target is being reset"},
508     {2, "Target requests logout"},
509     {3, "Target will/has dropped connection"},
510     {4, "Target will/has dropped all connections"},
511     {0, NULL},
512 };
513
514 static const value_string iscsi_reject_reasons03[] = {
515     {1, "Format error"},
516     {2, "Header digest error"},
517     {3, "Payload digest error"},
518     {0, NULL},
519 };
520
521 static const value_string iscsi_reject_reasons[] = {
522     {1, "Format error"},
523     {2, "Header digest error"},
524     {3, "Payload digest error"},
525     {4, "Data SNACK reject"},
526     {5, "Command retry reject"},
527     {15, "Full feature phase command before login"},
528     {0, NULL},
529 };
530
531 /*****************************************************************/
532 /*                                                               */
533 /* CRC LOOKUP TABLE                                              */
534 /* ================                                              */
535 /* The following CRC lookup table was generated automagically    */
536 /* by the Rocksoft^tm Model CRC Algorithm Table Generation       */
537 /* Program V1.0 using the following model parameters:            */
538 /*                                                               */
539 /*    Width   : 4 bytes.                                         */
540 /*    Poly    : 0x1EDC6F41L                                      */
541 /*    Reverse : TRUE.                                            */
542 /*                                                               */
543 /* For more information on the Rocksoft^tm Model CRC Algorithm,  */
544 /* see the document titled "A Painless Guide to CRC Error        */
545 /* Detection Algorithms" by Ross Williams                        */
546 /* (ross@guest.adelaide.edu.au.). This document is likely to be  */
547 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".        */
548 /*                                                               */
549 /*****************************************************************/
550
551 static guint32 crc32Table[256] = {
552     0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
553     0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
554     0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
555     0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
556     0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
557     0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
558     0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
559     0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
560     0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
561     0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
562     0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
563     0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
564     0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
565     0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
566     0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
567     0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
568     0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
569     0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
570     0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
571     0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
572     0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
573     0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
574     0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
575     0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
576     0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
577     0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
578     0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
579     0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
580     0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
581     0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
582     0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
583     0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
584     0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
585     0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
586     0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
587     0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
588     0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
589     0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
590     0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
591     0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
592     0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
593     0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
594     0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
595     0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
596     0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
597     0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
598     0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
599     0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
600     0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
601     0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
602     0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
603     0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
604     0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
605     0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
606     0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
607     0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
608     0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
609     0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
610     0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
611     0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
612     0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
613     0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
614     0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
615     0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
616 };
617
618 #define CRC32C_PRELOAD 0xffffffff
619
620 static guint32
621 calculateCRC32(const void *buf, int len, guint32 crc) {
622     guint8 *p = (guint8 *)buf;
623     while(len-- > 0)
624         crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
625     return crc;
626 }
627
628 static int
629 iscsi_min(int a, int b) {
630     return (a < b)? a : b;
631 }
632
633 static gint
634 addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
635     const gint limit = offset + text_len;
636     while(offset < limit) {
637         gint len = tvb_strnlen(tvb, offset, limit - offset);
638         if(len == -1)
639             len = limit - offset;
640         else
641             len = len + 1;
642         proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, FALSE);
643         offset += len;
644     }
645     return offset;
646 }
647
648 static gint
649 handleHeaderDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
650     int packet_len = tvb_length_remaining(tvb, offset);
651     if(packet_len >= (headerLen + 4)) {
652         guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
653         guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
654         if(crc == sent || enable_force_header_digest_crc32) {
655             if(crc == sent) {
656                 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
657                 return 4;
658             }
659             else {
660                 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Bad CRC32)", sent);
661                 return 4;
662             }
663         }
664     }
665     return 0;
666 }
667
668 /* Code to actually dissect the packets */
669 static gboolean
670 dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
671
672     /* Set up structures needed to add the protocol subtree and manage it */
673     proto_item *ti;
674     guint32 data_segment_len;
675     guint8 opcode;
676     guint offset = 0;
677     guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
678     const char *opcode_str = NULL;
679     char *scsi_command_name = NULL;
680     guint32 packet_len = tvb_length_remaining(tvb, offset);
681
682     /* quick check to see if the packet is long enough to contain a
683      * whole iSCSI header segment */
684     if (packet_len < 48) {
685         /* no, so give up */
686         return FALSE;
687     }
688
689     opcode = tvb_get_guint8(tvb, offset + 0);
690
691     if(enable_03_mode) {
692         opcode_str = match_strval(opcode, iscsi_opcodes_03);
693         data_segment_len = tvb_get_ntohl(tvb, offset + 4);
694     }
695     else {
696 #ifndef USE_06_OPCODES
697         if((opcode & 0x20) == 0) {
698             /* initiator -> target */
699             /* mask out X and I bits */
700             opcode &= 0x3f;
701         }
702 #endif
703         opcode_str = match_strval(opcode, iscsi_opcodes);
704         data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
705     }
706
707     /* try and distinguish between data and real headers */
708     if(opcode_str == NULL ||
709        (enable_bogosity_filter &&
710         (data_segment_len > bogus_pdu_data_length_threshold ||
711          packet_len > (data_segment_len + 48 + bogus_pdu_max_digest_padding)))) {
712         return FALSE;
713     }
714
715     /* Make entries in Protocol column and Info column on summary display */
716     if (check_col(pinfo->fd, COL_PROTOCOL))
717         col_set_str(pinfo->fd, COL_PROTOCOL, "iSCSI");
718
719     if (check_col(pinfo->fd, COL_INFO)) {
720
721         col_add_str(pinfo->fd, COL_INFO, (char *)opcode_str);
722
723         if((opcode & 0xbf) == 0x01) {
724             /* SCSI Command */
725             guint8 cdb0 = tvb_get_guint8(tvb, cdb_offset);
726             scsi_command_name = match_strval(cdb0, iscsi_scsi_cdb0);
727             if(cdb0 == 0x08 || cdb0 == 0x0a) {
728                 /* READ_6 and WRITE_6 */
729                 guint lba = tvb_get_ntohl(tvb, cdb_offset) & 0x1fffff;
730                 guint len = tvb_get_guint8(tvb, cdb_offset + 4);
731                 col_append_fstr(pinfo->fd, COL_INFO, " (%s LBA 0x%06x len 0x%02x)", scsi_command_name, lba, len);
732             }
733             else if(cdb0 == 0x28 || cdb0 == 0x2a) {
734                 /* READ_10 and WRITE_10 */
735                 guint lba = tvb_get_ntohl(tvb, cdb_offset + 2);
736                 guint len = tvb_get_ntohs(tvb, cdb_offset + 7);
737                 col_append_fstr(pinfo->fd, COL_INFO, " (%s LBA 0x%08x len 0x%04x)", scsi_command_name, lba, len);
738             }
739             else if(scsi_command_name != NULL)
740                 col_append_fstr(pinfo->fd, COL_INFO, " (%s)", scsi_command_name);
741         }
742         else if(enable_03_mode && opcode == 0x81) {
743             /* SCSI Command Response */
744             const char *blurb = match_strval(tvb_get_guint8(tvb, offset + 36), iscsi_scsi_statuses);
745             if(blurb != NULL)
746                 col_append_fstr(pinfo->fd, COL_INFO, " (%s)", blurb);
747         }
748         else if(!enable_03_mode &&
749 #ifdef USE_06_OPCODES
750                 opcode == 0xc1
751 #else
752                 opcode == 0x21
753 #endif
754             ) {
755             /* SCSI Command Response */
756             const char *blurb = NULL;
757             if(tvb_get_guint8(tvb, offset + 1) & 0x01)
758                 blurb = match_strval(tvb_get_guint8(tvb, offset + 3), iscsi_scsi_statuses);
759             else
760                 blurb = match_strval(tvb_get_guint8(tvb, offset + 3), iscsi_scsi_responses);
761             if(blurb != NULL)
762                 col_append_fstr(pinfo->fd, COL_INFO, " (%s)", blurb);
763         }
764     }
765
766     /* In the interest of speed, if "tree" is NULL, don't do any
767        work not necessary to generate protocol tree items. */
768     if (tree) {
769
770         /* create display subtree for the protocol */
771         ti = proto_tree_add_protocol_format(tree, proto_iscsi, tvb, offset,
772                                  packet_len, "iSCSI (%s)", (char *)opcode_str);
773
774         if(enable_03_mode) {
775             proto_tree_add_uint(ti, hf_iscsi_Opcode_03, tvb, 
776                                 offset + 0, 1, opcode);
777         }
778         else {
779             proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
780                                 offset + 0, 1, opcode);
781 #ifndef USE_06_OPCODES
782             if((opcode & 0x20) == 0) {
783                 /* initiator -> target */
784                 gint b = tvb_get_guint8(tvb, offset + 0);
785                 if(opcode != 0x05 &&
786                    opcode != 0x06 &&
787                    opcode != 0x10)
788                     proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
789                 if(opcode != 0x03 &&
790                    opcode != 0x05)
791                     proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
792             }
793 #endif
794         }
795
796         if((enable_03_mode && opcode == 0x00) ||
797 #ifdef USE_06_OPCODES
798            (!enable_03_mode && (opcode == 0x00 ||
799                                 opcode == 0x40 ||
800                                 opcode == 0x80))
801 #else
802            (!enable_03_mode && opcode == 0x00)
803 #endif
804             ) {
805             /* NOP Out */
806             {
807                 gint b = tvb_get_guint8(tvb, offset + 1);
808                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
809                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
810                 proto_tree_add_boolean(tt, hf_iscsi_NOP_P, tvb, offset + 1, 1, b);
811             }
812             if(enable_03_mode) {
813                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
814             }
815             else {
816                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
817             }
818             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
819             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
820             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
821             proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
822             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
823             if(enable_03_mode) {
824                 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 32, 4, FALSE);
825             }
826             proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
827             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
828         }
829         else if((enable_03_mode && opcode == 0x80) ||
830 #ifdef USE_06_OPCODES
831                 (!enable_03_mode && opcode == 0xc0)
832 #else
833                 (!enable_03_mode && opcode == 0xe0)
834 #endif
835             ) {
836             /* NOP In */
837             {
838                 gint b = tvb_get_guint8(tvb, offset + 1);
839                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
840                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
841                 proto_tree_add_boolean(tt, hf_iscsi_NOP_P, tvb, offset + 1, 1, b);
842             }
843             if(enable_03_mode) {
844                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
845             }
846             else {
847                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
848             }
849             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
850             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
851             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
852             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
853             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
854             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
855         }
856         else if((enable_03_mode && opcode == 0x01) ||
857 #ifdef USE_06_OPCODES
858                 (!enable_03_mode && (opcode == 0x01 ||
859                                      opcode == 0x41 ||
860                                      opcode == 0x81))
861 #else
862                 (!enable_03_mode && opcode == 0x01)
863 #endif
864             ) {
865             /* SCSI Command */
866             if(enable_03_mode) {
867                 {
868                     gint b = tvb_get_guint8(tvb, offset + 1);
869                     proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
870                     proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
871
872                     proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_X03, tvb, offset + 1, 1, b);
873                     proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
874                     proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
875                     proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
876                 }
877                 proto_tree_add_item(ti, hf_iscsi_SCSICommand_AddCDB, tvb, offset + 3, 1, FALSE);
878                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
879             }
880             else {
881                 {
882                     gint b = tvb_get_guint8(tvb, offset + 1);
883                     proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
884                     proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
885
886                     proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
887                     proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
888                     proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
889                     proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
890                 }
891                 proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, FALSE);
892                 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
893                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
894             }
895             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
896             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
897             proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, FALSE);
898             proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
899             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
900             {
901                 /* dissect a little of the CDB for the most common
902                  * commands */
903                 guint8 cdb0 = tvb_get_guint8(tvb, cdb_offset);
904                 gint cdb_len = 16;
905                 proto_item *tf;
906                 if(enable_03_mode) {
907                     cdb_len += tvb_get_guint8(tvb, offset + 3) * 4;
908                 }
909                 else {
910                     /* FIXME - extended CDB */
911                 }
912                 if(scsi_command_name == NULL)
913                     scsi_command_name = match_strval(cdb0, iscsi_scsi_cdb0);
914                 if(cdb0 == 0x08 || cdb0 == 0x0a) {
915                     /* READ_6 and WRITE_6 */
916                     guint lba = tvb_get_ntohl(tvb, cdb_offset) & 0x1fffff;
917                     guint len = tvb_get_guint8(tvb, cdb_offset + 4);
918                     tf = proto_tree_add_uint_format(ti, hf_iscsi_SCSICommand_CDB0, tvb, cdb_offset, cdb_len, cdb0, "CDB: %s LBA 0x%06x len 0x%02x", scsi_command_name, lba, len);
919                 }
920                 else if(cdb0 == 0x28 || cdb0 == 0x2a) {
921                     /* READ_10 and WRITE_10 */
922                     guint lba = tvb_get_ntohl(tvb, cdb_offset + 2);
923                     guint len = tvb_get_ntohs(tvb, cdb_offset + 7);
924                     tf = proto_tree_add_uint_format(ti, hf_iscsi_SCSICommand_CDB0, tvb, cdb_offset, cdb_len, cdb0, "CDB: %s LBA 0x%08x len 0x%04x", scsi_command_name, lba, len);
925                 }
926                 else
927                     tf = proto_tree_add_uint(ti, hf_iscsi_SCSICommand_CDB0, tvb, cdb_offset, cdb_len, cdb0);
928                 {
929                     proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_CDB);
930                     proto_tree_add_item(tt, hf_iscsi_SCSICommand_CDB, tvb, cdb_offset, cdb_len, FALSE);
931                 }
932                 offset = cdb_offset + cdb_len + handleHeaderDigest(ti, tvb, offset, cdb_offset + cdb_len);
933             }
934         }
935         else if((enable_03_mode && opcode == 0x81) ||
936 #ifdef USE_06_OPCODES
937                 (!enable_03_mode && opcode == 0xc1)
938 #else
939                 (!enable_03_mode && opcode == 0xe1)
940 #endif
941             ) {
942             /* SCSI Response */
943             if(enable_03_mode) {
944                 {
945                     gint b = tvb_get_guint8(tvb, offset + 1);
946                     proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
947                     proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
948
949                     proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o03, tvb, offset + 1, 1, b);
950                     proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u03, tvb, offset + 1, 1, b);
951                     proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O03, tvb, offset + 1, 1, b);
952                     proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U03, tvb, offset + 1, 1, b);
953                 }
954                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
955             }
956             else {
957                 {
958                     gint b = tvb_get_guint8(tvb, offset + 1);
959                     proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
960                     proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
961
962                     proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
963                     proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
964                     proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
965                     proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
966                     proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_S, tvb, offset + 1, 1, b);
967                     if(b & 0x01)
968                         proto_tree_add_item(ti, hf_iscsi_StatusResponse_is_status, tvb, offset + 3, 1, FALSE);
969                     else
970                         proto_tree_add_item(ti, hf_iscsi_StatusResponse_is_response, tvb, offset + 3, 1, FALSE);
971                 }
972                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
973             }
974             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
975             proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BasicResidualCount, tvb, offset + 20, 4, FALSE);
976             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
977             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
978             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
979             if(enable_03_mode) {
980                 proto_tree_add_item(ti, hf_iscsi_CommandStatus03, tvb, offset + 36, 1, FALSE);
981                 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_SenseLength, tvb, offset + 40, 2, FALSE);
982             }
983             else {
984                 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
985                 proto_tree_add_item(ti, hf_iscsi_R2TExpDataSN, tvb, offset + 40, 4, FALSE);
986             }
987             proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, FALSE);
988             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
989         }
990         else if((enable_03_mode && opcode == 0x02) ||
991 #ifdef USE_06_OPCODES
992                 (!enable_03_mode && (opcode == 0x02 ||
993                                      opcode == 0x42 ||
994                                      opcode == 0x82))
995 #else
996                 (!enable_03_mode && opcode == 0x02)
997 #endif
998             ) {
999             /* SCSI Task Command */
1000             proto_tree_add_item(ti, hf_iscsi_SCSITask_Function, tvb, offset + 1, 1, FALSE);
1001             if(enable_03_mode) {
1002                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1003             }
1004             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1005             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1006             proto_tree_add_item(ti, hf_iscsi_SCSITask_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1007             proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1008             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1009             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1010         }
1011         else if((enable_03_mode && opcode == 0x82) ||
1012 #ifdef USE_06_OPCODES
1013                 (!enable_03_mode && opcode == 0xc2)
1014 #else
1015                 (!enable_03_mode && opcode == 0xe2)
1016 #endif
1017 ) {
1018             /* SCSI Task Response */
1019             if(enable_03_mode) {
1020                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1021             }
1022             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1023             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1024             proto_tree_add_item(ti, hf_iscsi_SCSITask_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
1025             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1026             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1027             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1028             proto_tree_add_item(ti, hf_iscsi_SCSITask_Response, tvb, offset + 36, 1, FALSE);
1029             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1030         }
1031         else if((enable_03_mode && opcode == 0x03) ||
1032 #ifdef USE_06_OPCODES
1033                 (!enable_03_mode && (opcode == 0x03 ||
1034                                      opcode == 0x83))
1035 #else
1036                 (!enable_03_mode && opcode == 0x03)
1037 #endif
1038             ) {
1039             /* Login Command */
1040             if(!enable_03_mode) {
1041                 gint b = tvb_get_guint8(tvb, offset + 1);
1042                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1043                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1044                 
1045                 proto_tree_add_boolean(tt, hf_iscsi_Login_F, tvb, offset + 1, 1, b);
1046             }
1047             proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1048             proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
1049             if(enable_03_mode) {
1050                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1051             }
1052             else {
1053                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1054             }
1055             proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1056             proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
1057             proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1058             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1059             if(enable_03_mode) {
1060                 proto_tree_add_item(ti, hf_iscsi_InitCmdSN, tvb, offset + 24, 4, FALSE);
1061             }
1062             else {
1063                 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1064                 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1065             }
1066             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1067             if(packet_len > offset) {
1068                 int text_len = iscsi_min(data_segment_len, packet_len - offset);
1069                 proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
1070                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
1071                 offset = addTextKeys(tt, tvb, offset, text_len);
1072                 if(offset < packet_len) {
1073                     int padding = 4 - (offset & 3);
1074                     proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
1075                     offset += padding;
1076                 }
1077             }
1078         }
1079         else if((enable_03_mode && opcode == 0x83) ||
1080 #ifdef USE_06_OPCODES
1081                 (!enable_03_mode && opcode == 0xc3)
1082 #else
1083                 (!enable_03_mode && opcode == 0xe3)
1084 #endif
1085             ) {
1086             /* Login Response */
1087             {
1088                 gint b = tvb_get_guint8(tvb, offset + 1);
1089                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1090                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1091
1092                 proto_tree_add_boolean(tt, hf_iscsi_Login_F, tvb, offset + 1, 1, b);
1093             }
1094             proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1095             proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
1096             if(enable_03_mode) {
1097                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1098             }
1099             else {
1100                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1101             }
1102             proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
1103             proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1104             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1105             proto_tree_add_item(ti, hf_iscsi_InitStatSN, tvb, offset + 24, 4, FALSE);
1106             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1107             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1108             if(enable_03_mode) {
1109                 proto_tree_add_item(ti, hf_iscsi_Login_Status03, tvb, offset + 36, 1, FALSE);
1110             }
1111             else {
1112                 proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 1, FALSE);
1113             }
1114             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1115             if(packet_len > offset) {
1116                 int text_len = iscsi_min(data_segment_len, packet_len - offset);
1117                 proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
1118                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
1119                 offset = addTextKeys(tt, tvb, offset, text_len);
1120                 if(offset < packet_len) {
1121                     int padding = 4 - (offset & 3);
1122                     proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
1123                     offset += padding;
1124                 }
1125             }
1126         }
1127         else if((enable_03_mode && opcode == 0x04) ||
1128 #ifdef USE_06_OPCODES
1129                 (!enable_03_mode && (opcode == 0x04 ||
1130                                      opcode == 0x44 ||
1131                                      opcode == 0x84))
1132 #else
1133                 (!enable_03_mode && opcode == 0x04)
1134 #endif
1135             ) {
1136             /* Text Command */
1137             if(enable_03_mode) {
1138                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1139             }
1140             else {
1141                 gint b = tvb_get_guint8(tvb, offset + 1);
1142                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1143                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1144                 
1145                 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1146                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1147             }
1148             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1149             proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1150             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1151             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1152             if(packet_len > offset) {
1153                 int text_len = iscsi_min(data_segment_len, packet_len - offset);
1154                 proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
1155                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
1156                 offset = addTextKeys(tt, tvb, offset, text_len);
1157                 if(offset < packet_len) {
1158                     int padding = 4 - (offset & 3);
1159                     proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
1160                     offset += padding;
1161                 }
1162             }
1163         }
1164         else if((enable_03_mode && opcode == 0x84) ||
1165 #ifdef USE_06_OPCODES
1166                 (!enable_03_mode && (opcode == 0xc4))
1167 #else
1168                 (!enable_03_mode && opcode == 0xe4)
1169 #endif
1170             ) {
1171             /* Text Response */
1172             if(enable_03_mode) {
1173                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1174             }
1175             else {
1176                 gint b = tvb_get_guint8(tvb, offset + 1);
1177                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1178                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1179                 
1180                 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1181                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1182             }
1183             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1184             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1185             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1186             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1187             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1188             if(packet_len > offset) {
1189                 int text_len = iscsi_min(data_segment_len, packet_len - offset);
1190                 proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
1191                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
1192                 offset = addTextKeys(tt, tvb, offset, text_len);
1193                 if(offset < packet_len) {
1194                     int padding = 4 - (offset & 3);
1195                     proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
1196                     offset += padding;
1197                 }
1198             }
1199         }
1200         else if(opcode == 0x05) {
1201             /* SCSI Data (write) */
1202             {
1203                 gint b = tvb_get_guint8(tvb, offset + 1);
1204                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1205                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1206
1207                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1208             }
1209             if(enable_03_mode) {
1210                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1211             }
1212             else {
1213                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1214             }
1215             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1216             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1217             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1218             proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1219             if(!enable_03_mode)
1220                 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1221             proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1222             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1223         }
1224         else if((enable_03_mode && opcode == 0x85) ||
1225 #ifdef USE_06_OPCODES
1226                 (!enable_03_mode && opcode == 0xc5)
1227 #else
1228                 (!enable_03_mode && opcode == 0xe5)
1229 #endif
1230             ) {
1231             /* SCSI Data (read) */
1232             if(enable_03_mode) {
1233                 gint b = tvb_get_guint8(tvb, offset + 1);
1234                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1235                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1236
1237                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_P03, tvb, offset + 1, 1, b);
1238                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S03, tvb, offset + 1, 1, b);
1239                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O03, tvb, offset + 1, 1, b);
1240                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U03, tvb, offset + 1, 1, b);
1241                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1242             }
1243             else {
1244                 gint b = tvb_get_guint8(tvb, offset + 1);
1245                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1246                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1247
1248                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1249                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
1250                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
1251                 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
1252                 proto_tree_add_item(ti, hf_iscsi_StatusResponse_is_status, tvb, offset + 3, 1, FALSE);
1253                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1254             }
1255             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1256             if(enable_03_mode) {
1257                 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1258             }
1259             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1260             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1261             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1262             if(enable_03_mode) {
1263                 proto_tree_add_item(ti, hf_iscsi_CommandStatus03, tvb, offset + 36, 1, FALSE);
1264             }
1265             else {
1266                 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1267             }
1268             proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1269             proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 44, 4, FALSE);
1270             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1271         }
1272         else if((enable_03_mode && opcode == 0x06) ||
1273 #ifdef USE_06_OPCODES
1274                 (!enable_03_mode && (opcode == 0x06 || opcode == 0x46))
1275 #else
1276                 (!enable_03_mode && opcode == 0x06)
1277 #endif
1278             ) {
1279             /* Logout Command */
1280             if(enable_03_mode) {
1281                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1282             }
1283             else {
1284                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1285             }
1286             proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1287             if(enable_03_mode)
1288                 proto_tree_add_item(ti, hf_iscsi_Logout_Reason03, tvb, offset + 11, 1, FALSE);
1289             else
1290                 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, FALSE);
1291             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1292             if(!enable_03_mode) {
1293                 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1294             }
1295             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1296         }
1297         else if((enable_03_mode && opcode == 0x86) ||
1298 #ifdef USE_06_OPCODES
1299                 (!enable_03_mode && opcode == 0xc6)
1300 #else
1301                 (!enable_03_mode && opcode == 0xe6)
1302 #endif
1303             ) {
1304             /* Logout Response */
1305             if(enable_03_mode) {
1306                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1307             }
1308             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1309             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1310             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1311             proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 36, 1, FALSE);
1312             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1313         }
1314         else if(
1315 #ifdef USE_06_OPCODES
1316             (!enable_03_mode && (opcode == 0x10 || opcode == 0x50))
1317 #else
1318             (!enable_03_mode && opcode == 0x10)
1319 #endif
1320             ) {
1321             int S = 0;
1322             /* SNACK Request */
1323             {
1324                 gint b = tvb_get_guint8(tvb, offset + 1);
1325                 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1326                 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1327
1328                 proto_tree_add_boolean(tt, hf_iscsi_SNACK_S, tvb, offset + 1, 1, b);
1329                 S = b & 0x01;
1330             }
1331             proto_tree_add_item(ti, hf_iscsi_AddRuns, tvb, offset + 3, 1, FALSE);
1332             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1333             proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, FALSE);
1334             proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, FALSE);
1335             if(S) {
1336                 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1337             }
1338             else {
1339                 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 28, 4, FALSE);
1340             }
1341             proto_tree_add_item(ti, hf_iscsi_AdditionalRuns, tvb, offset + 32, 16, FALSE);
1342             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1343         }
1344         else if((enable_03_mode && opcode == 0x90) ||
1345 #ifdef USE_06_OPCODES
1346                 (!enable_03_mode && opcode == 0xd0)
1347 #else
1348                 (!enable_03_mode && opcode == 0xf1)
1349 #endif
1350             ) {
1351             /* R2T */
1352             if(enable_03_mode) {
1353                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1354             }
1355             proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1356             proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1357             if(!enable_03_mode) {
1358                 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1359             }
1360             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1361             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1362             if(enable_03_mode) {
1363                 proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 36, 4, FALSE);
1364                 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1365             }
1366             else {
1367                 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1368                 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1369                 proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
1370             }
1371             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1372         }
1373         else if((enable_03_mode && opcode == 0x91) || 
1374 #ifdef USE_06_OPCODES
1375                 (!enable_03_mode && opcode == 0xd1)
1376 #else
1377                 (!enable_03_mode && opcode == 0xf2)
1378 #endif
1379             ) {
1380             /* Asynchronous Message */
1381             if(enable_03_mode) {
1382                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1383             }
1384             else {
1385                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1386             }
1387             proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1388             proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1389             proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1390             proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1391             if(enable_03_mode) {
1392                 proto_tree_add_item(ti, hf_iscsi_SCSIEvent03, tvb, offset + 36, 1, FALSE);
1393                 proto_tree_add_item(ti, hf_iscsi_iSCSIEvent03, tvb, offset + 37, 1, FALSE);
1394             }
1395             else {
1396                 proto_tree_add_item(ti, hf_iscsi_SCSIEvent, tvb, offset + 36, 1, FALSE);
1397                 proto_tree_add_item(ti, hf_iscsi_iSCSIEvent, tvb, offset + 37, 1, FALSE);
1398             }
1399             proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, FALSE);
1400             proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
1401             if(!enable_03_mode)
1402                 proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
1403             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1404         }
1405         else if((enable_03_mode && opcode == 0xef) ||
1406 #ifdef USE_06_OPCODES
1407                 (!enable_03_mode && opcode == 0xef)
1408 #else
1409                 (!enable_03_mode && opcode == 0xff)
1410 #endif
1411             ) {
1412             /* Reject */
1413             if(enable_03_mode) {
1414                 proto_tree_add_uint(ti, hf_iscsi_Length03, tvb, offset + 4, 4, data_segment_len);
1415                 proto_tree_add_item(ti, hf_iscsi_Reject_Reason03, tvb, offset + 36, 1, FALSE);
1416             }
1417             else {
1418                 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1419                 proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 40, 1, FALSE);
1420                 proto_tree_add_item(ti, hf_iscsi_Reject_FirstBadByte, tvb, offset + 42, 1, FALSE);
1421             }
1422             offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1423         }
1424
1425         if(packet_len > offset)
1426             proto_tree_add_item(ti, hf_iscsi_Payload, tvb, offset, packet_len - offset, FALSE);
1427     }
1428
1429     return TRUE;
1430 }
1431
1432 /* Register the protocol with Ethereal */
1433
1434 /* this format is require because a script is used to build the C function
1435    that calls all the protocol registration.
1436 */
1437
1438 void
1439 proto_register_iscsi(void)
1440 {                 
1441
1442         /* Setup list of header fields  See Section 1.6.1 for details*/
1443     static hf_register_info hf[] = {
1444         { &hf_iscsi_Padding,
1445           { "Padding", "iscsi.padding",
1446             FT_BYTES, BASE_HEX, NULL, 0,
1447             "Padding to 4 byte boundary", HFILL }
1448         },
1449         { &hf_iscsi_Payload,
1450           { "Payload", "iscsi.payload",
1451             FT_BYTES, BASE_HEX, NULL, 0,
1452             "Payload", HFILL }
1453         },
1454         { &hf_iscsi_HeaderDigest32,
1455           { "HeaderDigest", "iscsi.headerdigest",
1456             FT_UINT32, BASE_HEX, NULL, 0,
1457             "Header Digest", HFILL }
1458         },
1459         { &hf_iscsi_Opcode,
1460           { "Opcode", "iscsi.opcode",
1461             FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,          
1462             "Opcode", HFILL }
1463         },
1464         { &hf_iscsi_Opcode_03,
1465           { "Opcode", "iscsi.opcode",
1466             FT_UINT8, BASE_HEX, VALS(iscsi_opcodes_03), 0,          
1467             "Opcode", HFILL }
1468         },
1469         { &hf_iscsi_X,
1470           { "X", "iscsi.X",
1471             FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,          
1472             "Command Retry", HFILL }
1473         },
1474         { &hf_iscsi_I,
1475           { "I", "iscsi.I",
1476             FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,          
1477             "Immediate delivery", HFILL }
1478         },
1479         { &hf_iscsi_Flags,
1480           { "Flags", "iscsi.flags",
1481             FT_UINT8, BASE_HEX, NULL, 0,          
1482             "Opcode specific flags", HFILL }
1483         },
1484         { &hf_iscsi_SCSICommand_X03,
1485           { "X", "iscsi.scsicommand.X",
1486             FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,          
1487             "Command Retry", HFILL }
1488         },
1489         { &hf_iscsi_SCSICommand_F,
1490           { "F", "iscsi.scsicommand.F",
1491             FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,          
1492             "PDU completes command", HFILL }
1493         },
1494         { &hf_iscsi_SCSICommand_R,
1495           { "R", "iscsi.scsicommand.R",
1496             FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,          
1497             "Command reads from SCSI target", HFILL }
1498         },
1499         { &hf_iscsi_SCSICommand_W,
1500           { "W", "iscsi.scsicommand.W",
1501             FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,          
1502             "Command writes to SCSI target", HFILL }
1503         },
1504         { &hf_iscsi_SCSICommand_Attr,
1505           { "Attr", "iscsi.scsicommand.attr",
1506             FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07,          
1507             "SCSI task attributes", HFILL }
1508         },
1509         { &hf_iscsi_SCSICommand_CRN,
1510           { "CRN", "iscsi.scsicommand.crn",
1511             FT_UINT8, BASE_HEX, NULL, 0,          
1512             "SCSI command reference number", HFILL }
1513         },
1514         { &hf_iscsi_SCSICommand_AddCDB,
1515           { "AddCDB", "iscsi.scsicommand.addcdb",
1516             FT_UINT8, BASE_HEX, NULL, 0,
1517             "Additional CDB length (in 4 byte units)", HFILL }
1518         },
1519         { &hf_iscsi_Length03,
1520           { "Length", "iscsi.length",
1521             FT_UINT32, BASE_HEX, NULL, 0,
1522             "Data length (bytes)", HFILL }
1523         },
1524         { &hf_iscsi_DataSegmentLength,
1525           { "DataSegmentLength", "iscsi.datasegmentlength",
1526             FT_UINT32, BASE_HEX, NULL, 0,
1527             "Data segment length (bytes)", HFILL }
1528         },
1529         { &hf_iscsi_TotalAHSLength,
1530           { "TotalAHSLength", "iscsi.totalahslength",
1531             FT_UINT8, BASE_HEX, NULL, 0,
1532             "Total additional header segment length (4 byte words)", HFILL }
1533         },
1534         { &hf_iscsi_LUN,
1535           { "LUN", "iscsi.lun",
1536             FT_BYTES, BASE_HEX, NULL, 0,
1537             "Logical Unit Number", HFILL }
1538         },
1539         { &hf_iscsi_InitiatorTaskTag,
1540           { "InitiatorTaskTag", "iscsi.initiatortasktag",
1541             FT_UINT32, BASE_HEX, NULL, 0,
1542             "Initiator's task tag", HFILL }
1543         },
1544         { &hf_iscsi_ExpectedDataTransferLength,
1545           { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength",
1546             FT_UINT32, BASE_HEX, NULL, 0,
1547             "Expected length of data transfer", HFILL }
1548         },
1549         { &hf_iscsi_CmdSN,
1550           { "CmdSN", "iscsi.cmdsn",
1551             FT_UINT32, BASE_HEX, NULL, 0,
1552             "Sequence number for this command (0 == immediate)", HFILL }
1553         },
1554         { &hf_iscsi_ExpStatSN,
1555           { "ExpStatSN", "iscsi.expstatsn",
1556             FT_UINT32, BASE_HEX, NULL, 0,
1557             "Next expected status sequence number", HFILL }
1558         },
1559         { &hf_iscsi_SCSICommand_CDB,
1560           { "CDB", "iscsi.scsicommand.cdb",
1561             FT_BYTES, BASE_HEX, NULL, 0,
1562             "SCSI CDB", HFILL }
1563         },
1564         { &hf_iscsi_SCSICommand_CDB0,
1565           { "CDB", "iscsi.scsicommand.cdb0",
1566             FT_UINT8, BASE_HEX, VALS(iscsi_scsi_cdb0), 0,
1567             "SCSI CDB[0]", HFILL }
1568         },
1569         { &hf_iscsi_SCSIResponse_BasicResidualCount,
1570           { "BasicResidualCount", "iscsi.scsiresponse.basicresidualcount",
1571             FT_UINT32, BASE_HEX, NULL, 0,
1572             "Residual count", HFILL }
1573         },
1574         { &hf_iscsi_StatSN,
1575           { "StatSN", "iscsi.statsn",
1576             FT_UINT32, BASE_HEX, NULL, 0,
1577             "Status sequence number", HFILL }
1578         },
1579         { &hf_iscsi_ExpCmdSN,
1580           { "ExpCmdSN", "iscsi.expcmdsn",
1581             FT_UINT32, BASE_HEX, NULL, 0,
1582             "Next expected command sequence number", HFILL }
1583         },
1584         { &hf_iscsi_MaxCmdSN,
1585           { "MaxCmdSN", "iscsi.maxcmdsn",
1586             FT_UINT32, BASE_HEX, NULL, 0,
1587             "Maximum acceptable command sequence number", HFILL }
1588         },
1589         { &hf_iscsi_SCSIResponse_o03,
1590           { "o", "iscsi.scsiresponse.o",
1591             FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x08,          
1592             "Bi-directional read residual overflow", HFILL }
1593         },
1594         { &hf_iscsi_SCSIResponse_u03,
1595           { "u", "iscsi.scsiresponse.u",
1596             FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x04,          
1597             "Bi-directional read residual underflow", HFILL }
1598         },
1599         { &hf_iscsi_SCSIResponse_O03,
1600           { "O", "iscsi.scsiresponse.O",
1601             FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x02,          
1602             "Residual overflow", HFILL }
1603         },
1604         { &hf_iscsi_SCSIResponse_U03,
1605           { "U", "iscsi.scsiresponse.U",
1606             FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x01,          
1607             "Residual underflow", HFILL }
1608         },
1609         { &hf_iscsi_SCSIResponse_o,
1610           { "o", "iscsi.scsiresponse.o",
1611             FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,          
1612             "Bi-directional read residual overflow", HFILL }
1613         },
1614         { &hf_iscsi_SCSIResponse_u,
1615           { "u", "iscsi.scsiresponse.u",
1616             FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08,          
1617             "Bi-directional read residual underflow", HFILL }
1618         },
1619         { &hf_iscsi_SCSIResponse_O,
1620           { "O", "iscsi.scsiresponse.O",
1621             FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,          
1622             "Residual overflow", HFILL }
1623         },
1624         { &hf_iscsi_SCSIResponse_U,
1625           { "U", "iscsi.scsiresponse.U",
1626             FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,          
1627             "Residual underflow", HFILL }
1628         },
1629         { &hf_iscsi_SCSIResponse_S,
1630           { "S", "iscsi.scsiresponse.S",
1631             FT_BOOLEAN, 8, TFS(&iscsi_meaning_scsiresponse_S), 0x01,          
1632             "Status/Response", HFILL }
1633         },
1634         { &hf_iscsi_CommandStatus03,
1635           { "CommandStatus", "iscsi.commandstatus",
1636             FT_UINT8, BASE_HEX, VALS(iscsi_scsi_statuses), 0,
1637             "SCSI command status value", HFILL }
1638         },
1639         { &hf_iscsi_StatusResponse_is_status,
1640           { "Status/Response", "iscsi.scsiresponse.statusresponse",
1641             FT_UINT8, BASE_HEX, VALS(iscsi_scsi_statuses), 0,
1642             "SCSI command status value", HFILL }
1643         },
1644         { &hf_iscsi_StatusResponse_is_response,
1645           { "Status/Response", "iscsi.scsiresponse.statusresponse",
1646             FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
1647             "iSCSI response value", HFILL }
1648         },
1649         { &hf_iscsi_SCSIResponse_SenseLength,
1650           { "SenseLength", "iscsi.scsiresponse.senselength",
1651             FT_UINT16, BASE_HEX, NULL, 0,
1652             "SCSI sense data length", HFILL }
1653         },
1654         { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
1655           { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
1656             FT_UINT32, BASE_HEX, NULL, 0,
1657             "Bi-directional read residual count", HFILL }
1658         },
1659         { &hf_iscsi_SCSIData_F,
1660           { "F", "iscsi.scsidata.F",
1661             FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,          
1662             "Final PDU", HFILL }
1663         },
1664         { &hf_iscsi_SCSIData_P03,
1665           { "P", "iscsi.scsidata.P",
1666             FT_BOOLEAN, 8,  TFS(&iscsi_meaning_P), 0x80,          
1667             "Poll requested", HFILL }
1668         },
1669         { &hf_iscsi_SCSIData_S03,
1670           { "S", "iscsi.scsidata.S",
1671             FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), 0x04,          
1672             "PDU Contains SCSI command status", HFILL }
1673         },
1674         { &hf_iscsi_SCSIData_O03,
1675           { "O", "iscsi.scsidata.O",
1676             FT_BOOLEAN, 8,  TFS(&iscsi_meaning_O), 0x02,          
1677             "Residual overflow", HFILL }
1678         },
1679         { &hf_iscsi_SCSIData_U03,
1680           { "U", "iscsi.scsidata.U",
1681             FT_BOOLEAN, 8,  TFS(&iscsi_meaning_U), 0x01,          
1682             "Residual underflow", HFILL }
1683         },
1684         { &hf_iscsi_SCSIData_S,
1685           { "S", "iscsi.scsidata.S",
1686             FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), 0x01,          
1687             "PDU Contains SCSI command status", HFILL }
1688         },
1689         { &hf_iscsi_SCSIData_U,
1690           { "U", "iscsi.scsidata.U",
1691             FT_BOOLEAN, 8,  TFS(&iscsi_meaning_U), 0x02,          
1692             "Residual underflow", HFILL }
1693         },
1694         { &hf_iscsi_SCSIData_O,
1695           { "O", "iscsi.scsidata.O",
1696             FT_BOOLEAN, 8,  TFS(&iscsi_meaning_O), 0x04,          
1697             "Residual overflow", HFILL }
1698         },
1699         { &hf_iscsi_TargetTransferTag,
1700           { "TargetTransferTag", "iscsi.targettransfertag",
1701             FT_UINT32, BASE_HEX, NULL, 0,
1702             "Target transfer tag", HFILL }
1703         },
1704         { &hf_iscsi_BufferOffset,
1705           { "BufferOffset", "iscsi.bufferOffset",
1706             FT_UINT32, BASE_HEX, NULL, 0,
1707             "Buffer offset", HFILL }
1708         },
1709         { &hf_iscsi_SCSIData_ResidualCount,
1710           { "ResidualCount", "iscsi.scsidata.readresidualcount",
1711             FT_UINT32, BASE_HEX, NULL, 0,
1712             "Residual count", HFILL }
1713         },
1714         { &hf_iscsi_DataSN,
1715           { "DataSN", "iscsi.datasn",
1716             FT_UINT32, BASE_HEX, NULL, 0,
1717             "Data sequence number", HFILL }
1718         },
1719         { &hf_iscsi_VersionMax,
1720           { "VersionMax", "iscsi.versionmax",
1721             FT_UINT8, BASE_HEX, NULL, 0,
1722             "Maximum supported protocol version", HFILL }
1723         },
1724         { &hf_iscsi_VersionMin,
1725           { "VersionMin", "iscsi.versionmin",
1726             FT_UINT8, BASE_HEX, NULL, 0,
1727             "Minimum supported protocol version", HFILL }
1728         },
1729         { &hf_iscsi_CID,
1730           { "CID", "iscsi.cid",
1731             FT_UINT16, BASE_HEX, NULL, 0,
1732             "Connection identifier", HFILL }
1733         },
1734         { &hf_iscsi_ISID,
1735           { "ISID", "iscsi.isid",
1736             FT_UINT16, BASE_HEX, NULL, 0,
1737             "Initiator part of session identifier", HFILL }
1738         },
1739         { &hf_iscsi_TSID,
1740           { "TSID", "iscsi.tsid",
1741             FT_UINT16, BASE_HEX, NULL, 0,
1742             "Target part of session identifier", HFILL }
1743         },
1744         { &hf_iscsi_InitStatSN,
1745           { "InitStatSN", "iscsi.initstatsn",
1746             FT_UINT32, BASE_HEX, NULL, 0,
1747             "Initial status sequence number", HFILL }
1748         },
1749         { &hf_iscsi_InitCmdSN,
1750           { "InitCmdSN", "iscsi.initcmdsn",
1751             FT_UINT32, BASE_HEX, NULL, 0,
1752             "Initial command sequence number", HFILL }
1753         },
1754         { &hf_iscsi_Login_F,
1755           { "F", "iscsi.login.F",
1756             FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,          
1757             "Final PDU in login sequence", HFILL }
1758         },
1759         { &hf_iscsi_Login_Status03,
1760           { "Status", "iscsi.login.status",
1761             FT_UINT8, BASE_HEX, VALS(iscsi_login_status03), 0,
1762             "Status", HFILL }
1763         },
1764         { &hf_iscsi_Login_Status,
1765           { "Status", "iscsi.login.status",
1766             FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0,
1767             "Status class and detail", HFILL }
1768         },
1769         { &hf_iscsi_KeyValue,
1770           { "KeyValue", "iscsi.keyvalue",
1771             FT_STRING, 0, NULL, 0,
1772             "Key/value pair", HFILL }
1773         },
1774         { &hf_iscsi_Text_F,
1775           { "F", "iscsi.text.F",
1776             FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,          
1777             "Final PDU in text sequence", HFILL }
1778         },
1779         { &hf_iscsi_NOP_P,
1780           { "P", "iscsi.nop.P",
1781             FT_BOOLEAN, 8, TFS(&iscsi_meaning_P), 0x80,          
1782             "Poll requested", HFILL }
1783         },
1784         { &hf_iscsi_ExpDataSN,
1785           { "ExpDataSN", "iscsi.expdatasn",
1786             FT_UINT32, BASE_HEX, NULL, 0,
1787             "Next expected data sequence number", HFILL }
1788         },
1789         { &hf_iscsi_R2TExpDataSN,
1790           { "R2TExpDataSN", "iscsi.r2texpdatasn",
1791             FT_UINT32, BASE_HEX, NULL, 0,
1792             "Next expected R2T data sequence number", HFILL }
1793         },
1794         { &hf_iscsi_SCSITask_Response,
1795           { "Response", "iscsi.scsitask.response",
1796             FT_UINT8, BASE_HEX, VALS(iscsi_task_responses), 0,
1797             "Response", HFILL }
1798         },
1799         { &hf_iscsi_SCSITask_ReferencedTaskTag,
1800           { "InitiatorTaskTag", "iscsi.scsitask.referencedtasktag",
1801             FT_UINT32, BASE_HEX, NULL, 0,
1802             "Task's initiator task tag", HFILL }
1803         },
1804         { &hf_iscsi_SCSITask_Function,
1805           { "Function", "iscsi.scsitask.function",
1806             FT_UINT8, BASE_HEX, VALS(iscsi_task_functions), 0x7F,
1807             "Requested task function", HFILL }
1808         },
1809         { &hf_iscsi_Logout_Reason03,
1810           { "Reason", "iscsi.logout.reason",
1811             FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons03), 0,
1812             "Reason for logout", HFILL }
1813         },
1814         { &hf_iscsi_Logout_Reason,
1815           { "Reason", "iscsi.logout.reason",
1816             FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0,
1817             "Reason for logout", HFILL }
1818         },
1819         { &hf_iscsi_Logout_Response,
1820           { "Response", "iscsi.logout.response",
1821             FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
1822             "Logout response", HFILL }
1823         },
1824         { &hf_iscsi_DesiredDataLength,
1825           { "DesiredDataLength", "iscsi.desireddatalength",
1826             FT_UINT32, BASE_HEX, NULL, 0,
1827             "Desired data length (bytes)", HFILL }
1828         },
1829         { &hf_iscsi_SCSIEvent03,
1830           { "SCSIEvent", "iscsi.scsievent",
1831             FT_UINT8, BASE_HEX, VALS(iscsi_scsievents03), 0,
1832             "SCSI event indicator", HFILL }
1833         },
1834         { &hf_iscsi_iSCSIEvent03,
1835           { "iSCSIEvent", "iscsi.iscsievent",
1836             FT_UINT8, BASE_HEX, VALS(iscsi_iscsievents03), 0,
1837             "iSCSI event indicator", HFILL }
1838         },
1839         { &hf_iscsi_SCSIEvent,
1840           { "SCSIEvent", "iscsi.scsievent",
1841             FT_UINT8, BASE_HEX, VALS(iscsi_scsievents), 0,
1842             "SCSI event indicator", HFILL }
1843         },
1844         { &hf_iscsi_iSCSIEvent,
1845           { "iSCSIEvent", "iscsi.iscsievent",
1846             FT_UINT8, BASE_HEX, VALS(iscsi_iscsievents), 0,
1847             "iSCSI event indicator", HFILL }
1848         },
1849         { &hf_iscsi_Parameter1,
1850           { "Parameter1", "iscsi.parameter1",
1851             FT_UINT16, BASE_HEX, NULL, 0,
1852             "Parameter 1", HFILL }
1853         },
1854         { &hf_iscsi_Parameter2,
1855           { "Parameter2", "iscsi.parameter2",
1856             FT_UINT16, BASE_HEX, NULL, 0,
1857             "Parameter 2", HFILL }
1858         },
1859         { &hf_iscsi_Parameter3,
1860           { "Parameter3", "iscsi.parameter3",
1861             FT_UINT16, BASE_HEX, NULL, 0,
1862             "Parameter 3", HFILL }
1863         },
1864         { &hf_iscsi_Reject_Reason,
1865           { "Reason", "iscsi.reject.reason",
1866             FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
1867             "Reason for command rejection", HFILL }
1868         },
1869         { &hf_iscsi_Reject_FirstBadByte,
1870           { "FirstBadByte", "iscsi.reject.firstbadbyte",
1871             FT_UINT16, BASE_HEX, NULL, 0,
1872             "Offset of first bad byte in PDU when reason is 'format error'", HFILL }
1873         },
1874         { &hf_iscsi_Reject_Reason03,
1875           { "Reason", "iscsi.reject.reason",
1876             FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons03), 0,
1877             "Reason for command rejection", HFILL }
1878         },
1879         { &hf_iscsi_SNACK_S,
1880           { "S", "iscsi.snack.S",
1881             FT_BOOLEAN, 8, TFS(&iscsi_meaning_SNACK_S), 0x01,          
1882             "Status not data SNACK requested", HFILL }
1883         },
1884         { &hf_iscsi_AddRuns,
1885           { "AddRuns", "iscsi.snack.addruns",
1886             FT_UINT8, BASE_HEX, NULL, 0,
1887             "Number of additional runs", HFILL }
1888         },
1889         { &hf_iscsi_BegRun,
1890           { "BegRun", "iscsi.snack.begrun",
1891             FT_UINT32, BASE_HEX, NULL, 0,
1892             "First missed DataSN or StatSN", HFILL }
1893         },
1894         { &hf_iscsi_RunLength,
1895           { "RunLength", "iscsi.snack.runlength",
1896             FT_UINT32, BASE_HEX, NULL, 0,
1897             "Number of additional missing status PDUs in this run", HFILL }
1898         },
1899         { &hf_iscsi_AdditionalRuns,
1900           { "AdditionalRuns", "iscsi.snack.additionalruns",
1901             FT_BYTES, BASE_HEX, NULL, 0,
1902             "Additional runs of missing status PDUs", HFILL }
1903         },
1904     };
1905
1906     /* Setup protocol subtree array */
1907     static gint *ett[] = {
1908         &ett_iscsi_KeyValues,
1909         &ett_iscsi_CDB,
1910         &ett_iscsi_Flags,
1911     };
1912
1913     /* Register the protocol name and description */
1914     proto_iscsi = proto_register_protocol("iSCSI", "ISCSI", "iscsi");
1915
1916     /* Required function calls to register the header fields and subtrees used */
1917     proto_register_field_array(proto_iscsi, hf, array_length(hf));
1918     proto_register_subtree_array(ett, array_length(ett));
1919
1920     {
1921         module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
1922
1923         prefs_register_bool_preference(iscsi_module,
1924                                        "version_03_compatible", 
1925                                        "Enable 03 compatibility mode",
1926                                        "When enabled, assume packets conform to the legacy 03 version of the iSCSI specification",
1927                                        &enable_03_mode);
1928         prefs_register_bool_preference(iscsi_module,
1929                                        "bogus_pdu_filter", 
1930                                        "Enable bogus pdu filter",
1931                                        "When enabled, packets that appear bogus are ignored",
1932                                        &enable_bogosity_filter);
1933
1934         prefs_register_uint_preference(iscsi_module,
1935                                        "bogus_pdu_max_data_len", 
1936                                        "Bogus pdu max data length threshold",
1937                                        "Treat packets whose data segment length is greater than this value as bogus",
1938                                        10,
1939                                        &bogus_pdu_data_length_threshold);
1940         prefs_register_uint_preference(iscsi_module,
1941                                        "bogus_pdu_max_digest_padding", 
1942                                        "Bogus pdu max digest padding",
1943                                        "Treat packets whose apparent total digest size is greater than this value as bogus",
1944                                        10,
1945                                        &bogus_pdu_max_digest_padding);
1946     }
1947 }
1948
1949
1950 /* If this dissector uses sub-dissector registration add a registration routine.
1951    This format is required because a script is used to find these routines and
1952    create the code that calls these routines.
1953 */
1954 void
1955 proto_reg_handoff_iscsi(void)
1956 {
1957     heur_dissector_add("tcp", dissect_iscsi, proto_iscsi);
1958 }