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