2 * Routines for iSCSI dissection
3 * Copyright 2001, Eurologic and Mark Burton <markb@ordern.com>
5 * Conforms to the protocol described in: draft-ietf-ips-iscsi-08.txt
7 * $Id: packet-iscsi.c,v 1.21 2002/01/20 22:12:26 guy Exp $
9 * Ethereal - Network traffic analyzer
10 * By Gerald Combs <gerald@ethereal.com>
11 * Copyright 1998 Gerald Combs
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.
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.
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.
29 #define ISCSI_CSG_DIGESTS_ACTIVE ISCSI_CSG_FULL_FEATURE_PHASE
31 #define ISCSI_CSG_DIGESTS_ACTIVE ISCSI_CSG_OPERATIONAL_NEGOTIATION
42 #ifdef HAVE_SYS_TYPES_H
43 # include <sys/types.h>
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
52 #ifdef NEED_SNPRINTF_H
53 # include "snprintf.h"
58 #include "conversation.h"
59 #include "packet-scsi.h"
61 static gboolean iscsi_desegment = TRUE;
63 static int demand_good_f_bit = FALSE;
64 static int enable_bogosity_filter = TRUE;
65 static guint32 bogus_pdu_data_length_threshold = 256 * 1024;
67 static int enableDataDigests = FALSE;
68 static int enableHeaderDigests = FALSE;
70 static int dataDigestIsCRC32 = TRUE;
71 static int headerDigestIsCRC32 = TRUE;
73 static int dataDigestSize = 4;
74 static int headerDigestSize = 4;
76 static guint iscsi_port = 5003;
78 /* Initialize the protocol and registered fields */
79 static int proto_iscsi = -1;
80 static int hf_iscsi_AHS = -1;
81 static int hf_iscsi_Padding = -1;
82 static int hf_iscsi_ping_data = -1;
83 static int hf_iscsi_immediate_data = -1;
84 static int hf_iscsi_write_data = -1;
85 static int hf_iscsi_read_data = -1;
86 static int hf_iscsi_error_pdu_data = -1;
87 static int hf_iscsi_Opcode = -1;
88 static int hf_iscsi_Flags = -1;
89 static int hf_iscsi_HeaderDigest = -1;
90 static int hf_iscsi_HeaderDigest32 = -1;
91 static int hf_iscsi_DataDigest = -1;
92 static int hf_iscsi_DataDigest32 = -1;
93 static int hf_iscsi_X = -1;
94 static int hf_iscsi_I = -1;
95 static int hf_iscsi_SCSICommand_F = -1;
96 static int hf_iscsi_SCSICommand_R = -1;
97 static int hf_iscsi_SCSICommand_W = -1;
98 static int hf_iscsi_SCSICommand_Attr = -1;
99 static int hf_iscsi_SCSICommand_CRN = -1;
100 static int hf_iscsi_SCSICommand_AddCDB = -1;
101 static int hf_iscsi_DataSegmentLength = -1;
102 static int hf_iscsi_TotalAHSLength = -1;
103 static int hf_iscsi_LUN = -1;
104 static int hf_iscsi_InitiatorTaskTag = -1;
105 static int hf_iscsi_ExpectedDataTransferLength = -1;
106 static int hf_iscsi_CmdSN = -1;
107 static int hf_iscsi_ExpStatSN = -1;
108 static int hf_iscsi_StatSN = -1;
109 static int hf_iscsi_ExpCmdSN = -1;
110 static int hf_iscsi_MaxCmdSN = -1;
111 static int hf_iscsi_SCSIResponse_o = -1;
112 static int hf_iscsi_SCSIResponse_u = -1;
113 static int hf_iscsi_SCSIResponse_O = -1;
114 static int hf_iscsi_SCSIResponse_U = -1;
115 static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1;
116 static int hf_iscsi_SCSIResponse_ResidualCount = -1;
117 static int hf_iscsi_SCSIResponse_Response = -1;
118 static int hf_iscsi_SCSIResponse_Status = -1;
119 static int hf_iscsi_SCSIData_F = -1;
120 static int hf_iscsi_SCSIData_S = -1;
121 static int hf_iscsi_SCSIData_O = -1;
122 static int hf_iscsi_SCSIData_U = -1;
123 static int hf_iscsi_TargetTransferTag = -1;
124 static int hf_iscsi_DataSN = -1;
125 static int hf_iscsi_BufferOffset = -1;
126 static int hf_iscsi_SCSIData_ResidualCount = -1;
127 static int hf_iscsi_VersionMin = -1;
128 static int hf_iscsi_VersionMax = -1;
129 static int hf_iscsi_VersionActive = -1;
130 static int hf_iscsi_CID = -1;
131 static int hf_iscsi_ISID = -1;
132 static int hf_iscsi_TSID = -1;
133 static int hf_iscsi_InitStatSN = -1;
134 static int hf_iscsi_InitCmdSN = -1;
135 static int hf_iscsi_Login_T = -1;
136 static int hf_iscsi_Login_CSG = -1;
137 static int hf_iscsi_Login_NSG = -1;
138 static int hf_iscsi_Login_Stage = -1;
139 static int hf_iscsi_Login_Status = -1;
140 static int hf_iscsi_KeyValue = -1;
141 static int hf_iscsi_Text_F = -1;
142 static int hf_iscsi_ExpDataSN = -1;
143 static int hf_iscsi_R2TSN = -1;
144 static int hf_iscsi_TaskManagementFunction_ReferencedTaskTag = -1;
145 static int hf_iscsi_RefCmdSN = -1;
146 static int hf_iscsi_TaskManagementFunction_Function = -1;
147 static int hf_iscsi_TaskManagementFunction_Response = -1;
148 static int hf_iscsi_Logout_Reason = -1;
149 static int hf_iscsi_Logout_Response = -1;
150 static int hf_iscsi_Time2Wait = -1;
151 static int hf_iscsi_Time2Retain = -1;
152 static int hf_iscsi_DesiredDataLength = -1;
153 static int hf_iscsi_AsyncEvent = -1;
154 static int hf_iscsi_EventVendorCode = -1;
155 static int hf_iscsi_Parameter1 = -1;
156 static int hf_iscsi_Parameter2 = -1;
157 static int hf_iscsi_Parameter3 = -1;
158 static int hf_iscsi_Reject_Reason = -1;
159 static int hf_iscsi_snack_type = -1;
160 static int hf_iscsi_BegRun = -1;
161 static int hf_iscsi_RunLength = -1;
163 /* Initialize the subtree pointers */
164 static gint ett_iscsi_KeyValues = -1;
165 static gint ett_iscsi_CDB = -1;
166 static gint ett_iscsi_Flags = -1;
168 typedef struct _iscsi_conv_key {
173 typedef struct _iscsi_conv_data {
179 static GHashTable *iscsi_req_hash = NULL;
180 static GMemChunk *iscsi_req_keys = NULL;
181 static GMemChunk *iscsi_req_vals = NULL;
182 static guint32 iscsi_init_count = 25;
187 #define TARGET_OPCODE_BIT 0x20
189 #define ISCSI_OPCODE_NOP_OUT 0x00
190 #define ISCSI_OPCODE_SCSI_COMMAND 0x01
191 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION 0x02
192 #define ISCSI_OPCODE_LOGIN_COMMAND 0x03
193 #define ISCSI_OPCODE_TEXT_COMMAND 0x04
194 #define ISCSI_OPCODE_SCSI_DATA_OUT 0x05
195 #define ISCSI_OPCODE_LOGOUT_COMMAND 0x06
196 #define ISCSI_OPCODE_SNACK_REQUEST 0x10
198 #define ISCSI_OPCODE_NOP_IN (0x20 | X_BIT | I_BIT)
199 #define ISCSI_OPCODE_SCSI_RESPONSE (0x21 | X_BIT | I_BIT)
200 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE (0x22 | X_BIT | I_BIT)
201 #define ISCSI_OPCODE_LOGIN_RESPONSE (0x23 | X_BIT | I_BIT)
202 #define ISCSI_OPCODE_TEXT_RESPONSE (0x24 | X_BIT | I_BIT)
203 #define ISCSI_OPCODE_SCSI_DATA_IN (0x25 | X_BIT | I_BIT)
204 #define ISCSI_OPCODE_LOGOUT_RESPONSE (0x26 | X_BIT | I_BIT)
205 #define ISCSI_OPCODE_R2T (0x31 | X_BIT | I_BIT)
206 #define ISCSI_OPCODE_ASYNC_MESSAGE (0x32 | X_BIT | I_BIT)
207 #define ISCSI_OPCODE_REJECT (0x3f | X_BIT | I_BIT)
210 #define CSG_MASK (0x03 << CSG_SHIFT)
212 #define ISCSI_CSG_SECURITY_NEGOTIATION (0 << CSG_SHIFT)
213 #define ISCSI_CSG_OPERATIONAL_NEGOTIATION (1 << CSG_SHIFT)
214 #define ISCSI_CSG_FULL_FEATURE_PHASE (3 << CSG_SHIFT)
216 static const value_string iscsi_opcodes[] = {
217 { ISCSI_OPCODE_NOP_OUT, "NOP Out" },
218 { ISCSI_OPCODE_SCSI_COMMAND, "SCSI Command" },
219 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION, "Task Management Function" },
220 { ISCSI_OPCODE_LOGIN_COMMAND, "Login Command" },
221 { ISCSI_OPCODE_TEXT_COMMAND, "Text Command" },
222 { ISCSI_OPCODE_SCSI_DATA_OUT, "SCSI Data Out" },
223 { ISCSI_OPCODE_LOGOUT_COMMAND, "Logout Command" },
224 { ISCSI_OPCODE_SNACK_REQUEST, "SNACK Request" },
226 { ISCSI_OPCODE_NOP_IN, "NOP In" },
227 { ISCSI_OPCODE_SCSI_RESPONSE, "SCSI Response" },
228 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE, "Task Management Function Response" },
229 { ISCSI_OPCODE_LOGIN_RESPONSE, "Login Response" },
230 { ISCSI_OPCODE_TEXT_RESPONSE, "Text Response" },
231 { ISCSI_OPCODE_SCSI_DATA_IN, "SCSI Data In" },
232 { ISCSI_OPCODE_LOGOUT_RESPONSE, "Logout Response" },
233 { ISCSI_OPCODE_R2T, "Ready To Transfer" },
234 { ISCSI_OPCODE_ASYNC_MESSAGE, "Asynchronous Message" },
235 { ISCSI_OPCODE_REJECT, "Reject"},
239 static const true_false_string iscsi_meaning_X = {
244 static const true_false_string iscsi_meaning_I = {
245 "Immediate delivery",
249 static const true_false_string iscsi_meaning_F = {
250 "Final PDU in sequence",
251 "Not final PDU in sequence"
254 static const true_false_string iscsi_meaning_T = {
255 "Transit to next login stage",
256 "Stay in current login stage"
259 static const true_false_string iscsi_meaning_S = {
260 "Response contains SCSI status",
261 "Response does not contain SCSI status"
264 static const true_false_string iscsi_meaning_R = {
265 "Data will be read from target",
266 "No data will be read from target"
269 static const true_false_string iscsi_meaning_W = {
270 "Data will be written to target",
271 "No data will be written to target"
274 static const true_false_string iscsi_meaning_o = {
275 "Read part of bi-directional command overflowed",
276 "No overflow of read part of bi-directional command",
279 static const true_false_string iscsi_meaning_u = {
280 "Read part of bi-directional command underflowed",
281 "No underflow of read part of bi-directional command",
284 static const true_false_string iscsi_meaning_O = {
285 "Residual overflow occurred",
286 "No residual overflow occurred",
289 static const true_false_string iscsi_meaning_U = {
290 "Residual underflow occurred",
291 "No residual underflow occurred",
294 static const value_string iscsi_scsi_responses[] = {
295 { 0, "Command completed at target" },
296 { 1, "Response does not contain SCSI status"},
300 static const value_string iscsi_scsicommand_taskattrs[] = {
304 {3, "Head of Queue"},
309 static const value_string iscsi_task_responses[] = {
310 {0, "Function complete"},
311 {1, "Task not in task set"},
312 {2, "LUN does not exist"},
313 {3, "Task still allegiant"},
314 {4, "Task failover not supported"},
315 {5, "Task management function not supported"},
316 {255, "Function rejected"},
320 static const value_string iscsi_task_management_functions[] = {
322 {2, "Abort Task Set"},
324 {4, "Clear Task Set"},
325 {5, "Logical Unit Reset"},
326 {6, "Target Warm Reset"},
327 {7, "Target Cold Reset"},
331 static const value_string iscsi_login_status[] = {
333 {0x0101, "Target moved temporarily"},
334 {0x0102, "Target moved permanently"},
335 {0x0200, "Initiator error (miscellaneous error)"},
336 {0x0201, "Athentication failed"},
337 {0x0202, "Authorisation failure"},
338 {0x0203, "Target not found"},
339 {0x0204, "Target removed"},
340 {0x0205, "Unsupported version"},
341 {0x0206, "Too many connections"},
342 {0x0207, "Missing parameter"},
343 {0x0208, "Can't include in session"},
344 {0x0209, "Session type not supported"},
345 {0x0300, "Target error (miscellaneous error)"},
346 {0x0301, "Service unavailable"},
347 {0x0302, "Out of resources"},
351 static const value_string iscsi_login_stage[] = {
352 {0, "Security negotiation"},
353 {1, "Operational negotiation"},
354 {3, "Full feature phase"},
358 static const value_string iscsi_logout_reasons[] = {
359 {0, "Close session"},
360 {1, "Close connection"},
361 {2, "Remove connection for recovery"},
365 static const value_string iscsi_logout_response[] = {
366 {0, "Connection closed successfully"},
367 {1, "CID not found"},
368 {2, "Connection recovery not supported"},
369 {3, "Cleanup failed for various reasons"},
373 static const value_string iscsi_asyncevents[] = {
374 {0, "A SCSI asynchronous event is reported in the sense data"},
375 {1, "Target requests logout"},
376 {2, "Target will/has dropped connection"},
377 {3, "Target will/has dropped all connections"},
381 static const value_string iscsi_snack_types[] = {
387 static const value_string iscsi_reject_reasons[] = {
388 {0x01, "Full feature phase command before login"},
389 {0x02, "Data (payload) digest error"},
390 {0x03, "Data SNACK reject"},
391 {0x04, "Protocol error"},
392 {0x05, "Command not supported in this session type"},
393 {0x06, "Immediate command reject (too many immediate commands)"},
394 {0x07, "Task in progress"},
395 {0x08, "Invalid SNACK"},
396 {0x09, "Bookmark reject (no bookmark for this initiator task tag)"},
397 {0x0a, "Bookmark reject (can't generate bookmark - out of resources)"},
398 {0x0b, "Negotiation reset"},
402 /*****************************************************************/
404 /* CRC LOOKUP TABLE */
405 /* ================ */
406 /* The following CRC lookup table was generated automagically */
407 /* by the Rocksoft^tm Model CRC Algorithm Table Generation */
408 /* Program V1.0 using the following model parameters: */
410 /* Width : 4 bytes. */
411 /* Poly : 0x1EDC6F41L */
412 /* Reverse : TRUE. */
414 /* For more information on the Rocksoft^tm Model CRC Algorithm, */
415 /* see the document titled "A Painless Guide to CRC Error */
416 /* Detection Algorithms" by Ross Williams */
417 /* (ross@guest.adelaide.edu.au.). This document is likely to be */
418 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
420 /*****************************************************************/
422 static guint32 crc32Table[256] = {
423 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
424 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
425 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
426 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
427 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
428 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
429 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
430 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
431 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
432 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
433 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
434 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
435 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
436 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
437 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
438 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
439 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
440 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
441 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
442 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
443 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
444 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
445 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
446 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
447 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
448 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
449 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
450 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
451 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
452 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
453 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
454 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
455 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
456 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
457 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
458 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
459 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
460 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
461 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
462 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
463 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
464 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
465 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
466 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
467 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
468 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
469 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
470 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
471 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
472 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
473 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
474 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
475 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
476 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
477 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
478 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
479 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
480 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
481 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
482 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
483 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
484 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
485 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
486 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
489 #define CRC32C_PRELOAD 0xffffffff
495 iscsi_equal(gconstpointer v, gconstpointer w)
497 iscsi_conv_key_t *v1 = (iscsi_conv_key_t *)v;
498 iscsi_conv_key_t *v2 = (iscsi_conv_key_t *)w;
500 return (v1->conv_idx == v2->conv_idx);
504 iscsi_hash (gconstpointer v)
506 iscsi_conv_key_t *key = (iscsi_conv_key_t *)v;
515 * Protocol initialization
518 iscsi_init_protocol(void)
521 g_mem_chunk_destroy(iscsi_req_keys);
523 g_mem_chunk_destroy(iscsi_req_vals);
525 g_hash_table_destroy(iscsi_req_hash);
527 iscsi_req_hash = g_hash_table_new(iscsi_hash, iscsi_equal);
528 iscsi_req_keys = g_mem_chunk_new("iscsi_req_keys",
529 sizeof(iscsi_conv_key_t),
530 iscsi_init_count * sizeof(iscsi_conv_key_t),
532 iscsi_req_vals = g_mem_chunk_new("iscsi_req_vals",
533 sizeof(iscsi_conv_data_t),
534 iscsi_init_count * sizeof(iscsi_conv_data_t),
539 calculateCRC32(const void *buf, int len, guint32 crc) {
540 guint8 *p = (guint8 *)buf;
542 crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
547 iscsi_min(int a, int b) {
548 return (a < b)? a : b;
552 addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
553 const gint limit = offset + text_len;
554 while(offset < limit) {
555 gint len = tvb_strnlen(tvb, offset, limit - offset);
557 len = limit - offset;
560 proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, FALSE);
567 handleHeaderDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
568 int available_bytes = tvb_length_remaining(tvb, offset);
569 if(enableHeaderDigests) {
570 if(headerDigestIsCRC32) {
571 if(available_bytes >= (headerLen + 4)) {
572 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
573 guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
575 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
578 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Bad CRC32, should be 0x%08x)", sent, crc);
581 return offset + headerLen + 4;
583 if(available_bytes >= (headerLen + headerDigestSize)) {
584 proto_tree_add_item(ti, hf_iscsi_HeaderDigest, tvb, offset + headerLen, headerDigestSize, FALSE);
586 return offset + headerLen + headerDigestSize;
588 return offset + headerLen;
592 handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) {
593 int available_bytes = tvb_length_remaining(tvb, offset);
594 if(enableDataDigests) {
595 if(dataDigestIsCRC32) {
596 if(available_bytes >= (dataLen + 4)) {
597 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
598 guint32 sent = tvb_get_ntohl(tvb, offset + dataLen);
600 proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Good CRC32)", sent);
603 proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Bad CRC32, should be 0x%08x)", sent, crc);
606 return offset + dataLen + 4;
608 if(available_bytes >= (dataLen + dataDigestSize)) {
609 proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, FALSE);
611 return offset + dataLen + dataDigestSize;
613 return offset + dataLen;
617 handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) {
618 if(endOffset > offset) {
619 int dataOffset = offset;
620 int dataLen = iscsi_min(dataSegmentLen, endOffset - offset);
622 proto_tree_add_item(ti, hf_id, tvb, offset, dataLen, FALSE);
625 if(offset < endOffset && (offset & 3) != 0) {
626 int padding = 4 - (offset & 3);
627 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
630 if(dataSegmentLen > 0 && offset < endOffset)
631 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
638 handleDataSegmentAsTextKeys(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) {
639 if(endOffset > offset) {
640 int dataOffset = offset;
641 int textLen = iscsi_min(dataSegmentLen, endOffset - offset);
643 proto_item *tf = proto_tree_add_text(ti, tvb, offset, textLen, "Key/Value Pairs");
644 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
645 offset = addTextKeys(tt, tvb, offset, textLen);
647 if(offset < endOffset && (offset & 3) != 0) {
648 int padding = 4 - (offset & 3);
649 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
652 if(digestsActive && dataSegmentLen > 0 && offset < endOffset)
653 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
658 /* Code to actually dissect the packets */
660 dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 opcode, const char *opcode_str, guint32 data_segment_len) {
662 guint original_offset = offset;
664 char *scsi_command_name = NULL;
665 guint8 scsi_status = 0;
666 guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
667 guint end_offset = offset + tvb_length_remaining(tvb, offset);
668 guint32 del_usecs = 0;
669 conversation_t *conversation = NULL;
670 iscsi_conv_data_t *cdata = NULL;
671 iscsi_conv_key_t ckey, *req_key;
672 int paddedDataSegmentLength = data_segment_len;
673 if(paddedDataSegmentLength & 3)
674 paddedDataSegmentLength += 4 - (paddedDataSegmentLength & 3);
676 /* Make entries in Protocol column and Info column on summary display */
677 if (check_col(pinfo->cinfo, COL_PROTOCOL))
678 col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
680 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
681 scsi_status = tvb_get_guint8 (tvb, offset+3);
684 if ((opcode == ISCSI_OPCODE_SCSI_RESPONSE) ||
685 (opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
686 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
687 conversation = find_conversation (&pinfo->src, &pinfo->dst,
688 pinfo->ptype, pinfo->srcport,
691 ckey.conv_idx = conversation->index;
692 ckey.itt = tvb_get_ntohl (tvb, offset+16);
694 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_hash,
697 pinfo->private_data = cdata;
700 del_usecs = (pinfo->fd->abs_secs - cdata->abs_secs)* 1000000 +
701 (pinfo->fd->abs_usecs - cdata->abs_usecs);
704 else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
705 conversation = find_conversation (&pinfo->src, &pinfo->dst,
706 pinfo->ptype, pinfo->srcport,
709 conversation = conversation_new (&pinfo->src, &pinfo->dst,
710 pinfo->ptype, pinfo->srcport,
714 ckey.conv_idx = conversation->index;
715 ckey.itt = tvb_get_ntohl (tvb, offset+16);
717 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_hash,
720 /* Since we never free the memory used by an exchange, this maybe a
721 * case of another request using the same exchange as a previous
724 cdata->abs_usecs = pinfo->fd->abs_usecs;
725 cdata->abs_secs = pinfo->fd->abs_secs;
726 /* The SCSI protocol uses this as the key to detect a
727 * SCSI-level conversation. */
730 req_key = g_mem_chunk_alloc (iscsi_req_keys);
731 req_key->conv_idx = conversation->index;
732 req_key->itt = tvb_get_ntohl (tvb, offset+16);
734 cdata = g_mem_chunk_alloc (iscsi_req_vals);
735 cdata->abs_usecs = pinfo->fd->abs_usecs;
736 cdata->abs_secs = pinfo->fd->abs_secs;
738 g_hash_table_insert (iscsi_req_hash, req_key, cdata);
739 /* The SCSI protocol uses this as the key to detect a
740 * SCSI-level conversation. */
742 pinfo->private_data = cdata;
745 pinfo->private_data = NULL;
748 if (check_col(pinfo->cinfo, COL_INFO)) {
750 if (opcode != ISCSI_OPCODE_SCSI_COMMAND) {
751 col_append_str(pinfo->cinfo, COL_INFO, (char *)opcode_str);
753 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
754 col_append_fstr (pinfo->cinfo, COL_INFO, " %s",
755 val_to_str (scsi_status, scsi_status_val, "0x%x"));
759 /* In the interest of speed, if "tree" is NULL, don't do any
760 work not necessary to generate protocol tree items. */
763 /* create display subtree for the protocol */
764 ti = proto_tree_add_protocol_format(tree, proto_iscsi, tvb,
765 offset, -1, "iSCSI (%s)",
768 proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
769 offset + 0, 1, opcode);
770 if((opcode & TARGET_OPCODE_BIT) == 0) {
771 /* initiator -> target */
772 gint b = tvb_get_guint8(tvb, offset + 0);
773 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
774 opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
775 opcode != ISCSI_OPCODE_SNACK_REQUEST)
776 proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
777 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT)
778 proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
781 if(opcode == ISCSI_OPCODE_NOP_OUT) {
783 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
784 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
785 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
786 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
787 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
788 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
789 offset = handleHeaderDigest(ti, tvb, offset, 48);
790 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
792 else if(opcode == ISCSI_OPCODE_NOP_IN) {
794 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
795 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
796 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
797 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
798 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
799 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
800 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
801 offset = handleHeaderDigest(ti, tvb, offset, 48);
802 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
804 else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
806 guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
808 gint b = tvb_get_guint8(tvb, offset + 1);
809 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
810 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
812 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
813 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
814 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
815 proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
817 proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, FALSE);
818 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
819 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
820 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
821 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
822 proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, FALSE);
823 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
824 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
827 /* FIXME - disssect AHS? */
828 proto_tree_add_item(ti, hf_iscsi_AHS, tvb, offset + 48, ahsLen, FALSE);
830 offset = handleHeaderDigest(ti, tvb, offset, 48 + ahsLen);
832 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
834 else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
837 if (del_usecs > 1000)
838 proto_tree_add_text (ti, tvb, offset, 0,
839 "Cmd Response Time: %d msecs",
842 proto_tree_add_text (ti, tvb, offset, 0,
843 "Cmd Response Time: %d usecs",
847 gint b = tvb_get_guint8(tvb, offset + 1);
848 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
849 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
851 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
852 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
853 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
854 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
856 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Response, tvb, offset + 2, 1, FALSE);
857 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
858 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
859 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
860 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 20, 4, FALSE);
861 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
862 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
863 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
864 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
865 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, FALSE);
866 offset = handleHeaderDigest(ti, tvb, offset, 48);
867 /* do not update offset here because the data segment is
869 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
871 else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
872 /* Task Management Function */
873 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, FALSE);
874 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
875 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
876 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
877 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
878 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
879 proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
880 offset = handleHeaderDigest(ti, tvb, offset, 48);
882 else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
883 /* Task Management Function Response */
884 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Response, tvb, offset + 2, 1, FALSE);
885 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
886 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
887 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
888 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
889 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
890 offset = handleHeaderDigest(ti, tvb, offset, 48);
892 else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
894 int digestsActive = 0;
896 gint b = tvb_get_guint8(tvb, offset + 1);
897 #if ISCSI_CSG_DIGESTS_ACTIVE < ISCSI_CSG_FULL_FEATURE_PHASE
898 if((b & CSG_MASK) >= ISCSI_CSG_DIGESTS_ACTIVE)
902 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
903 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
906 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
907 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
908 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
910 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
911 proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
912 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
913 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
914 proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
915 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
916 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
917 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
918 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
920 offset = handleHeaderDigest(ti, tvb, offset, 48);
923 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
925 else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
927 int digestsActive = 0;
929 gint b = tvb_get_guint8(tvb, offset + 1);
930 #if ISCSI_CSG_DIGESTS_ACTIVE < ISCSI_CSG_FULL_FEATURE_PHASE
931 if((b & CSG_MASK) >= ISCSI_CSG_DIGESTS_ACTIVE)
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);
939 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
940 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
941 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
944 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
945 proto_tree_add_item(ti, hf_iscsi_VersionActive, tvb, offset + 3, 1, FALSE);
946 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
947 proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
948 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
949 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
950 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
951 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
952 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
953 proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, FALSE);
955 offset = handleHeaderDigest(ti, tvb, offset, 48);
958 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
960 else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
963 gint b = tvb_get_guint8(tvb, offset + 1);
964 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
965 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
967 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
968 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
970 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
971 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
972 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
973 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
974 offset = handleHeaderDigest(ti, tvb, offset, 48);
975 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
977 else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
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);
984 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
985 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
987 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
988 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
989 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
990 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
991 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
992 offset = handleHeaderDigest(ti, tvb, offset, 48);
993 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
995 else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
996 /* SCSI Data Out (write) */
998 gint b = tvb_get_guint8(tvb, offset + 1);
999 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1000 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1002 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1004 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1005 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1006 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1007 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1008 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1009 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1010 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1011 offset = handleHeaderDigest(ti, tvb, offset, 48);
1012 /* do not update offset here because the data segment is
1013 * dissected below */
1014 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1016 else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
1017 /* SCSI Data In (read) */
1019 gint b = tvb_get_guint8(tvb, offset + 1);
1020 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1021 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1023 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1024 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
1025 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
1026 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
1028 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
1029 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1030 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1031 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 20, 4, FALSE);
1032 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1033 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1034 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1035 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1036 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1037 offset = handleHeaderDigest(ti, tvb, offset, 48);
1038 /* do not update offset here because the data segment is
1039 * dissected below */
1040 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1042 else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
1043 /* Logout Command */
1044 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1045 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, FALSE);
1046 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1047 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1048 offset = handleHeaderDigest(ti, tvb, offset, 48);
1050 else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
1051 /* Logout Response */
1052 proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, FALSE);
1053 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1054 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1055 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1056 proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, FALSE);
1057 proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, FALSE);
1058 offset = handleHeaderDigest(ti, tvb, offset, 48);
1060 else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
1063 gint b = tvb_get_guint8(tvb, offset + 1);
1065 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1066 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1069 proto_tree_add_item(ti, hf_iscsi_snack_type, tvb, offset + 1, 1, b);
1071 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1072 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, FALSE);
1073 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, FALSE);
1074 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1075 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1076 offset = handleHeaderDigest(ti, tvb, offset, 48);
1078 else if(opcode == ISCSI_OPCODE_R2T) {
1080 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1081 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1082 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1083 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1084 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1085 proto_tree_add_item(ti, hf_iscsi_R2TSN, tvb, offset + 36, 4, FALSE);
1086 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1087 proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
1088 offset = handleHeaderDigest(ti, tvb, offset, 48);
1090 else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1091 /* Asynchronous Message */
1092 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1093 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1094 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1095 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1096 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1097 proto_tree_add_item(ti, hf_iscsi_AsyncEvent, tvb, offset + 36, 1, FALSE);
1098 proto_tree_add_item(ti, hf_iscsi_EventVendorCode, tvb, offset + 37, 1, FALSE);
1099 proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, FALSE);
1100 proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
1101 proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
1102 offset = handleHeaderDigest(ti, tvb, offset, 48);
1104 else if(opcode == ISCSI_OPCODE_REJECT) {
1106 proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
1107 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1108 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1109 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1110 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1111 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1112 offset = handleHeaderDigest(ti, tvb, offset, 48);
1113 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_error_pdu_data);
1116 proto_item_set_len(ti, offset - original_offset);
1118 if((opcode & ~(X_BIT | I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND) {
1120 dissect_scsi_cdb (tvb, pinfo, tree, cdb_offset, 16);
1122 else if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1123 if (scsi_status == 0x2) {
1124 /* A SCSI response with Check Condition contains sense data */
1125 /* offset is setup correctly by the iscsi code for response above */
1126 dissect_scsi_snsinfo (tvb, pinfo, tree, offset,
1127 iscsi_min (data_segment_len,
1128 end_offset-offset));
1131 dissect_scsi_rsp (tvb, pinfo, tree);
1133 if (cdata && tree) {
1134 /* destroy the data structures for this SCSI task */
1136 g_mem_chunk_free (iscsi_req_vals, cdata);
1137 g_hash_table_remove (iscsi_req_hash, &ckey);
1138 pinfo->private_data = NULL;
1142 else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
1143 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
1144 /* offset is setup correctly by the iscsi code for response above */
1145 dissect_scsi_payload (tvb, pinfo, tree, offset, FALSE,
1146 iscsi_min (data_segment_len, end_offset-offset));
1151 dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1152 /* Set up structures needed to add the protocol subtree and manage it */
1153 guint iSCSIPdusDissected = 0;
1155 guint32 available_bytes = tvb_length_remaining(tvb, offset);
1157 if (!proto_is_protocol_enabled(proto_iscsi))
1158 return FALSE; /* iSCSI has been disabled */
1160 /* quick check to see if the packet is long enough to contain the
1161 * minimum amount of information we need */
1162 if (available_bytes < 48 && (!iscsi_desegment || available_bytes < 8)) {
1163 /* no, so give up */
1167 /* process multiple iSCSI PDUs per packet */
1168 while(available_bytes >= 48 || (iscsi_desegment && available_bytes >= 8)) {
1169 const char *opcode_str = NULL;
1170 guint32 data_segment_len;
1171 guint8 opcode = tvb_get_guint8(tvb, offset + 0);
1172 guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1);
1175 if((opcode & TARGET_OPCODE_BIT) == 0) {
1176 /* initiator -> target */
1177 /* mask out X and I bits */
1178 opcode &= ~(X_BIT | I_BIT);
1180 opcode_str = match_strval(opcode, iscsi_opcodes);
1181 if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION ||
1182 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
1183 opcode == ISCSI_OPCODE_R2T ||
1184 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
1185 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
1186 opcode == ISCSI_OPCODE_SNACK_REQUEST)
1187 data_segment_len = 0;
1189 data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
1191 if(opcode_str == NULL) {
1194 else if(iscsi_port != 0 &&
1195 (((opcode & TARGET_OPCODE_BIT) && pinfo->srcport != iscsi_port) ||
1196 (!(opcode & TARGET_OPCODE_BIT) && pinfo->destport != iscsi_port))) {
1199 else if(enable_bogosity_filter) {
1200 /* try and distinguish between data and real headers */
1201 if(data_segment_len > bogus_pdu_data_length_threshold) {
1204 else if(demand_good_f_bit &&
1205 !(secondPduByte & 0x80) &&
1206 (opcode == ISCSI_OPCODE_NOP_OUT ||
1207 opcode == ISCSI_OPCODE_NOP_IN ||
1208 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
1209 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
1210 opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
1211 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
1212 opcode == ISCSI_OPCODE_R2T ||
1213 opcode == ISCSI_OPCODE_ASYNC_MESSAGE ||
1214 opcode == ISCSI_OPCODE_SNACK_REQUEST ||
1215 opcode == ISCSI_OPCODE_REJECT)) {
1221 return iSCSIPdusDissected > 0;
1224 guint32 pduLen = 48;
1225 int digestsActive = 1;
1227 if(opcode == ISCSI_OPCODE_LOGIN_COMMAND ||
1228 opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1229 #if ISCSI_CSG_DIGESTS_ACTIVE < ISCSI_CSG_FULL_FEATURE_PHASE
1230 if((secondPduByte & CSG_MASK) < ISCSI_CSG_DIGESTS_ACTIVE) {
1231 /* digests are not yet turned on */
1239 if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
1241 pduLen += tvb_get_guint8(tvb, offset + 4) * 4;
1244 pduLen += data_segment_len;
1245 if((pduLen & 3) != 0)
1246 pduLen += 4 - (pduLen & 3);
1248 if(digestsActive && enableHeaderDigests) {
1249 if(headerDigestIsCRC32)
1252 pduLen += headerDigestSize;
1255 if(digestsActive && data_segment_len > 0 && enableDataDigests) {
1256 if(dataDigestIsCRC32)
1259 pduLen += dataDigestSize;
1263 * Desegmentation check.
1265 if(iscsi_desegment && pinfo->can_desegment) {
1266 if(pduLen > available_bytes) {
1268 * This frame doesn't have all of the data for
1269 * this message, but we can do reassembly on it.
1271 * Tell the TCP dissector where the data for this
1272 * message starts in the data it handed us, and
1273 * how many more bytes we need, and return.
1275 pinfo->desegment_offset = offset;
1276 pinfo->desegment_len = pduLen - available_bytes;
1281 if(check_col(pinfo->cinfo, COL_INFO)) {
1282 if(iSCSIPdusDissected == 0)
1283 col_set_str(pinfo->cinfo, COL_INFO, "");
1285 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1288 dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len);
1289 if(pduLen > available_bytes)
1290 pduLen = available_bytes;
1292 available_bytes -= pduLen;
1293 ++iSCSIPdusDissected;
1297 return iSCSIPdusDissected > 0;
1301 /* Register the protocol with Ethereal */
1304 * this format is require because a script is used to build the C
1305 * function that calls all the protocol registration.
1309 proto_register_iscsi(void)
1312 /* Setup list of header fields See Section 1.6.1 for details*/
1313 static hf_register_info hf[] = {
1315 { "AHS", "iscsi.ahs",
1316 FT_BYTES, BASE_HEX, NULL, 0,
1317 "Additional header segment", HFILL }
1319 { &hf_iscsi_Padding,
1320 { "Padding", "iscsi.padding",
1321 FT_BYTES, BASE_HEX, NULL, 0,
1322 "Padding to 4 byte boundary", HFILL }
1324 { &hf_iscsi_ping_data,
1325 { "PingData", "iscsi.pingdata",
1326 FT_BYTES, BASE_HEX, NULL, 0,
1327 "Ping Data", HFILL }
1329 { &hf_iscsi_immediate_data,
1330 { "ImmediateData", "iscsi.immediatedata",
1331 FT_BYTES, BASE_HEX, NULL, 0,
1332 "Immediate Data", HFILL }
1334 { &hf_iscsi_write_data,
1335 { "WriteData", "iscsi.writedata",
1336 FT_BYTES, BASE_HEX, NULL, 0,
1337 "Write Data", HFILL }
1339 { &hf_iscsi_read_data,
1340 { "ReadData", "iscsi.readdata",
1341 FT_BYTES, BASE_HEX, NULL, 0,
1342 "Read Data", HFILL }
1344 { &hf_iscsi_error_pdu_data,
1345 { "ErrorPDUData", "iscsi.errorpdudata",
1346 FT_BYTES, BASE_HEX, NULL, 0,
1347 "Error PDU Data", HFILL }
1349 { &hf_iscsi_HeaderDigest,
1350 { "HeaderDigest", "iscsi.headerdigest",
1351 FT_BYTES, BASE_HEX, NULL, 0,
1352 "Header Digest", HFILL }
1354 { &hf_iscsi_HeaderDigest32,
1355 { "HeaderDigest", "iscsi.headerdigest32",
1356 FT_UINT32, BASE_HEX, NULL, 0,
1357 "Header Digest", HFILL }
1359 { &hf_iscsi_DataDigest,
1360 { "DataDigest", "iscsi.datadigest",
1361 FT_BYTES, BASE_HEX, NULL, 0,
1362 "Data Digest", HFILL }
1364 { &hf_iscsi_DataDigest32,
1365 { "DataDigest", "iscsi.datadigest32",
1366 FT_UINT32, BASE_HEX, NULL, 0,
1367 "Data Digest", HFILL }
1370 { "Opcode", "iscsi.opcode",
1371 FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
1376 FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,
1377 "Command Retry", HFILL }
1381 FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,
1382 "Immediate delivery", HFILL }
1385 { "Flags", "iscsi.flags",
1386 FT_UINT8, BASE_HEX, NULL, 0,
1387 "Opcode specific flags", HFILL }
1389 { &hf_iscsi_SCSICommand_F,
1390 { "F", "iscsi.scsicommand.F",
1391 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
1392 "PDU completes command", HFILL }
1394 { &hf_iscsi_SCSICommand_R,
1395 { "R", "iscsi.scsicommand.R",
1396 FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,
1397 "Command reads from SCSI target", HFILL }
1399 { &hf_iscsi_SCSICommand_W,
1400 { "W", "iscsi.scsicommand.W",
1401 FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,
1402 "Command writes to SCSI target", HFILL }
1404 { &hf_iscsi_SCSICommand_Attr,
1405 { "Attr", "iscsi.scsicommand.attr",
1406 FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07,
1407 "SCSI task attributes", HFILL }
1409 { &hf_iscsi_SCSICommand_CRN,
1410 { "CRN", "iscsi.scsicommand.crn",
1411 FT_UINT8, BASE_HEX, NULL, 0,
1412 "SCSI command reference number", HFILL }
1414 { &hf_iscsi_SCSICommand_AddCDB,
1415 { "AddCDB", "iscsi.scsicommand.addcdb",
1416 FT_UINT8, BASE_HEX, NULL, 0,
1417 "Additional CDB length (in 4 byte units)", HFILL }
1419 { &hf_iscsi_DataSegmentLength,
1420 { "DataSegmentLength", "iscsi.datasegmentlength",
1421 FT_UINT32, BASE_HEX, NULL, 0,
1422 "Data segment length (bytes)", HFILL }
1424 { &hf_iscsi_TotalAHSLength,
1425 { "TotalAHSLength", "iscsi.totalahslength",
1426 FT_UINT8, BASE_HEX, NULL, 0,
1427 "Total additional header segment length (4 byte words)", HFILL }
1430 { "LUN", "iscsi.lun",
1431 FT_BYTES, BASE_HEX, NULL, 0,
1432 "Logical Unit Number", HFILL }
1434 { &hf_iscsi_InitiatorTaskTag,
1435 { "InitiatorTaskTag", "iscsi.initiatortasktag",
1436 FT_UINT32, BASE_HEX, NULL, 0,
1437 "Initiator's task tag", HFILL }
1439 { &hf_iscsi_ExpectedDataTransferLength,
1440 { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength",
1441 FT_UINT32, BASE_HEX, NULL, 0,
1442 "Expected length of data transfer", HFILL }
1445 { "CmdSN", "iscsi.cmdsn",
1446 FT_UINT32, BASE_HEX, NULL, 0,
1447 "Sequence number for this command (0 == immediate)", HFILL }
1449 { &hf_iscsi_ExpStatSN,
1450 { "ExpStatSN", "iscsi.expstatsn",
1451 FT_UINT32, BASE_HEX, NULL, 0,
1452 "Next expected status sequence number", HFILL }
1454 { &hf_iscsi_SCSIResponse_ResidualCount,
1455 { "ResidualCount", "iscsi.scsiresponse.residualcount",
1456 FT_UINT32, BASE_HEX, NULL, 0,
1457 "Residual count", HFILL }
1460 { "StatSN", "iscsi.statsn",
1461 FT_UINT32, BASE_HEX, NULL, 0,
1462 "Status sequence number", HFILL }
1464 { &hf_iscsi_ExpCmdSN,
1465 { "ExpCmdSN", "iscsi.expcmdsn",
1466 FT_UINT32, BASE_HEX, NULL, 0,
1467 "Next expected command sequence number", HFILL }
1469 { &hf_iscsi_MaxCmdSN,
1470 { "MaxCmdSN", "iscsi.maxcmdsn",
1471 FT_UINT32, BASE_HEX, NULL, 0,
1472 "Maximum acceptable command sequence number", HFILL }
1474 { &hf_iscsi_SCSIResponse_o,
1475 { "o", "iscsi.scsiresponse.o",
1476 FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,
1477 "Bi-directional read residual overflow", HFILL }
1479 { &hf_iscsi_SCSIResponse_u,
1480 { "u", "iscsi.scsiresponse.u",
1481 FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08,
1482 "Bi-directional read residual underflow", HFILL }
1484 { &hf_iscsi_SCSIResponse_O,
1485 { "O", "iscsi.scsiresponse.O",
1486 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
1487 "Residual overflow", HFILL }
1489 { &hf_iscsi_SCSIResponse_U,
1490 { "U", "iscsi.scsiresponse.U",
1491 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
1492 "Residual underflow", HFILL }
1494 { &hf_iscsi_SCSIResponse_Status,
1495 { "Status", "iscsi.scsiresponse.status",
1496 FT_UINT8, BASE_HEX, VALS(scsi_status_val), 0,
1497 "SCSI command status value", HFILL }
1499 { &hf_iscsi_SCSIResponse_Response,
1500 { "Response", "iscsi.scsiresponse.response",
1501 FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
1502 "SCSI command response value", HFILL }
1504 { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
1505 { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
1506 FT_UINT32, BASE_HEX, NULL, 0,
1507 "Bi-directional read residual count", HFILL }
1509 { &hf_iscsi_SCSIData_F,
1510 { "F", "iscsi.scsidata.F",
1511 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
1512 "Final PDU", HFILL }
1514 { &hf_iscsi_SCSIData_S,
1515 { "S", "iscsi.scsidata.S",
1516 FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), 0x01,
1517 "PDU Contains SCSI command status", HFILL }
1519 { &hf_iscsi_SCSIData_U,
1520 { "U", "iscsi.scsidata.U",
1521 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
1522 "Residual underflow", HFILL }
1524 { &hf_iscsi_SCSIData_O,
1525 { "O", "iscsi.scsidata.O",
1526 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
1527 "Residual overflow", HFILL }
1529 { &hf_iscsi_TargetTransferTag,
1530 { "TargetTransferTag", "iscsi.targettransfertag",
1531 FT_UINT32, BASE_HEX, NULL, 0,
1532 "Target transfer tag", HFILL }
1534 { &hf_iscsi_BufferOffset,
1535 { "BufferOffset", "iscsi.bufferOffset",
1536 FT_UINT32, BASE_HEX, NULL, 0,
1537 "Buffer offset", HFILL }
1539 { &hf_iscsi_SCSIData_ResidualCount,
1540 { "ResidualCount", "iscsi.scsidata.readresidualcount",
1541 FT_UINT32, BASE_HEX, NULL, 0,
1542 "Residual count", HFILL }
1545 { "DataSN", "iscsi.datasn",
1546 FT_UINT32, BASE_HEX, NULL, 0,
1547 "Data sequence number", HFILL }
1549 { &hf_iscsi_VersionMax,
1550 { "VersionMax", "iscsi.versionmax",
1551 FT_UINT8, BASE_HEX, NULL, 0,
1552 "Maximum supported protocol version", HFILL }
1554 { &hf_iscsi_VersionMin,
1555 { "VersionMin", "iscsi.versionmin",
1556 FT_UINT8, BASE_HEX, NULL, 0,
1557 "Minimum supported protocol version", HFILL }
1559 { &hf_iscsi_VersionActive,
1560 { "VersionActive", "iscsi.versionactive",
1561 FT_UINT8, BASE_HEX, NULL, 0,
1562 "Negotiated protocol version", HFILL }
1565 { "CID", "iscsi.cid",
1566 FT_UINT16, BASE_HEX, NULL, 0,
1567 "Connection identifier", HFILL }
1570 { "ISID", "iscsi.isid",
1571 FT_UINT16, BASE_HEX, NULL, 0,
1572 "Initiator part of session identifier", HFILL }
1575 { "TSID", "iscsi.tsid",
1576 FT_UINT16, BASE_HEX, NULL, 0,
1577 "Target part of session identifier", HFILL }
1579 { &hf_iscsi_InitStatSN,
1580 { "InitStatSN", "iscsi.initstatsn",
1581 FT_UINT32, BASE_HEX, NULL, 0,
1582 "Initial status sequence number", HFILL }
1584 { &hf_iscsi_InitCmdSN,
1585 { "InitCmdSN", "iscsi.initcmdsn",
1586 FT_UINT32, BASE_HEX, NULL, 0,
1587 "Initial command sequence number", HFILL }
1589 { &hf_iscsi_Login_T,
1590 { "T", "iscsi.login.T",
1591 FT_BOOLEAN, 8, TFS(&iscsi_meaning_T), 0x80,
1592 "Transit to next login stage", HFILL }
1594 { &hf_iscsi_Login_CSG,
1595 { "CSG", "iscsi.login.csg",
1596 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), CSG_MASK,
1597 "Current stage", HFILL }
1599 { &hf_iscsi_Login_NSG,
1600 { "NSG", "iscsi.login.nsg",
1601 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), 0x03,
1602 "Next stage", HFILL }
1604 { &hf_iscsi_Login_Status,
1605 { "Status", "iscsi.login.status",
1606 FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0,
1607 "Status class and detail", HFILL }
1609 { &hf_iscsi_KeyValue,
1610 { "KeyValue", "iscsi.keyvalue",
1611 FT_STRING, 0, NULL, 0,
1612 "Key/value pair", HFILL }
1615 { "F", "iscsi.text.F",
1616 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
1617 "Final PDU in text sequence", HFILL }
1619 { &hf_iscsi_ExpDataSN,
1620 { "ExpDataSN", "iscsi.expdatasn",
1621 FT_UINT32, BASE_HEX, NULL, 0,
1622 "Next expected data sequence number", HFILL }
1625 { "R2TSN", "iscsi.r2tsn",
1626 FT_UINT32, BASE_HEX, NULL, 0,
1627 "R2T PDU Number", HFILL }
1629 { &hf_iscsi_TaskManagementFunction_Response,
1630 { "Response", "iscsi.taskmanfun.response",
1631 FT_UINT8, BASE_HEX, VALS(iscsi_task_responses), 0,
1634 { &hf_iscsi_TaskManagementFunction_ReferencedTaskTag,
1635 { "InitiatorTaskTag", "iscsi.taskmanfun.referencedtasktag",
1636 FT_UINT32, BASE_HEX, NULL, 0,
1637 "Task's initiator task tag", HFILL }
1639 { &hf_iscsi_RefCmdSN,
1640 { "RefCmdSN", "iscsi.refcmdsn",
1641 FT_UINT32, BASE_HEX, NULL, 0,
1642 "Command sequence number for command to be aborted", HFILL }
1644 { &hf_iscsi_TaskManagementFunction_Function,
1645 { "Function", "iscsi.taskmanfun.function",
1646 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_functions), 0x7F,
1647 "Requested task function", HFILL }
1649 { &hf_iscsi_Logout_Reason,
1650 { "Reason", "iscsi.logout.reason",
1651 FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0,
1652 "Reason for logout", HFILL }
1654 { &hf_iscsi_Logout_Response,
1655 { "Response", "iscsi.logout.response",
1656 FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
1657 "Logout response", HFILL }
1659 { &hf_iscsi_Time2Wait,
1660 { "Time2Wait", "iscsi.time2wait",
1661 FT_UINT16, BASE_HEX, NULL, 0,
1662 "Time2Wait", HFILL }
1664 { &hf_iscsi_Time2Retain,
1665 { "Time2Retain", "iscsi.time2retain",
1666 FT_UINT16, BASE_HEX, NULL, 0,
1667 "Time2Retain", HFILL }
1669 { &hf_iscsi_DesiredDataLength,
1670 { "DesiredDataLength", "iscsi.desireddatalength",
1671 FT_UINT32, BASE_HEX, NULL, 0,
1672 "Desired data length (bytes)", HFILL }
1674 { &hf_iscsi_AsyncEvent,
1675 { "AsyncEvent", "iscsi.asyncevent",
1676 FT_UINT8, BASE_HEX, VALS(iscsi_asyncevents), 0,
1677 "Async event type", HFILL }
1679 { &hf_iscsi_EventVendorCode,
1680 { "EventVendorCode", "iscsi.eventvendorcode",
1681 FT_UINT8, BASE_HEX, NULL, 0,
1682 "Event vendor code", HFILL }
1684 { &hf_iscsi_Parameter1,
1685 { "Parameter1", "iscsi.parameter1",
1686 FT_UINT16, BASE_HEX, NULL, 0,
1687 "Parameter 1", HFILL }
1689 { &hf_iscsi_Parameter2,
1690 { "Parameter2", "iscsi.parameter2",
1691 FT_UINT16, BASE_HEX, NULL, 0,
1692 "Parameter 2", HFILL }
1694 { &hf_iscsi_Parameter3,
1695 { "Parameter3", "iscsi.parameter3",
1696 FT_UINT16, BASE_HEX, NULL, 0,
1697 "Parameter 3", HFILL }
1699 { &hf_iscsi_Reject_Reason,
1700 { "Reason", "iscsi.reject.reason",
1701 FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
1702 "Reason for command rejection", HFILL }
1704 { &hf_iscsi_snack_type,
1705 { "S", "iscsi.snack.type",
1706 FT_UINT8, BASE_DEC, VALS(iscsi_snack_types), 0x0f,
1707 "Type of SNACK requested", HFILL }
1710 { "BegRun", "iscsi.snack.begrun",
1711 FT_UINT32, BASE_HEX, NULL, 0,
1712 "First missed DataSN or StatSN", HFILL }
1714 { &hf_iscsi_RunLength,
1715 { "RunLength", "iscsi.snack.runlength",
1716 FT_UINT32, BASE_HEX, NULL, 0,
1717 "Number of additional missing status PDUs in this run", HFILL }
1721 /* Setup protocol subtree array */
1722 static gint *ett[] = {
1723 &ett_iscsi_KeyValues,
1728 /* Register the protocol name and description */
1729 proto_iscsi = proto_register_protocol("iSCSI", "iSCSI", "iscsi");
1731 /* Required function calls to register the header fields and
1733 proto_register_field_array(proto_iscsi, hf, array_length(hf));
1734 proto_register_subtree_array(ett, array_length(ett));
1735 register_init_routine (&iscsi_init_protocol);
1738 module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
1740 prefs_register_bool_preference(iscsi_module,
1741 "desegment_iscsi_messages",
1742 "Desegment iSCSI messages",
1743 "When enabled, iSCSI messages that span multiple TCP segments are desegmented",
1746 prefs_register_bool_preference(iscsi_module,
1748 "Enable bogus pdu filter",
1749 "When enabled, packets that appear bogus are ignored",
1750 &enable_bogosity_filter);
1752 prefs_register_bool_preference(iscsi_module,
1753 "demand_good_f_bit",
1754 "Ignore packets with bad F bit",
1755 "Ignore packets that haven't set the F bit when they should have",
1756 &demand_good_f_bit);
1758 prefs_register_uint_preference(iscsi_module,
1759 "bogus_pdu_max_data_len",
1760 "Bogus pdu max data length threshold",
1761 "Treat packets whose data segment length is greater than this value as bogus",
1763 &bogus_pdu_data_length_threshold);
1765 prefs_register_uint_preference(iscsi_module,
1768 "Port number of iSCSI target",
1772 prefs_register_bool_preference(iscsi_module,
1773 "enable_header_digests",
1774 "Enable header digests",
1775 "When enabled, pdus are assumed to contain a header digest",
1776 &enableHeaderDigests);
1777 prefs_register_bool_preference(iscsi_module,
1778 "enable_data_digests",
1779 "Enable data digests",
1780 "When enabled, pdus are assumed to contain a data digest",
1781 &enableDataDigests);
1783 prefs_register_bool_preference(iscsi_module,
1784 "header_digest_is_crc32c",
1785 "Header digest is CRC32C",
1786 "When enabled, header digests are assumed to be CRC32C",
1787 &headerDigestIsCRC32);
1788 prefs_register_bool_preference(iscsi_module,
1789 "data_digest_is_crc32c",
1790 "Data digest is CRC32C",
1791 "When enabled, data digests are assumed to be CRC32C",
1792 &dataDigestIsCRC32);
1794 prefs_register_uint_preference(iscsi_module,
1795 "header_digest_size",
1796 "Header digest size",
1797 "The size of a header digest (bytes)",
1800 prefs_register_uint_preference(iscsi_module,
1803 "The size of a data digest (bytes)",
1807 /* Preference supported in older versions.
1808 Register them as obsolete. */
1809 prefs_register_obsolete_preference(iscsi_module,
1810 "version_03_compatible");
1811 prefs_register_obsolete_preference(iscsi_module,
1812 "bogus_pdu_max_digest_padding");
1818 * If this dissector uses sub-dissector registration add a
1819 * registration routine.
1823 * This format is required because a script is used to find these
1824 * routines and create the code that calls these routines.
1827 proto_reg_handoff_iscsi(void)
1829 heur_dissector_add("tcp", dissect_iscsi, proto_iscsi);