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