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-09.txt
6 * Optionally, may be compiled for compatibility with
7 * draft-ietf-ips-iscsi-08.txt by defining DRAFT08
9 * $Id: packet-iscsi.c,v 1.26 2002/02/13 01:17:58 guy Exp $
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@ethereal.com>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 #ifdef HAVE_SYS_TYPES_H
39 # include <sys/types.h>
42 #ifdef HAVE_NETINET_IN_H
43 # include <netinet/in.h>
48 #ifdef NEED_SNPRINTF_H
49 # include "snprintf.h"
52 #include <epan/packet.h>
54 #include <epan/conversation.h>
55 #include "packet-scsi.h"
57 static gboolean iscsi_desegment = TRUE;
59 static int demand_good_f_bit = FALSE;
60 static int enable_bogosity_filter = TRUE;
61 static guint32 bogus_pdu_data_length_threshold = 256 * 1024;
63 static int enableDataDigests = FALSE;
64 static int enableHeaderDigests = FALSE;
66 static int dataDigestIsCRC32 = TRUE;
67 static int headerDigestIsCRC32 = TRUE;
69 static int dataDigestSize = 4;
70 static int headerDigestSize = 4;
72 static guint iscsi_port = 3260;
74 /* Initialize the protocol and registered fields */
75 static int proto_iscsi = -1;
76 static int hf_iscsi_AHS = -1;
77 static int hf_iscsi_Padding = -1;
78 static int hf_iscsi_ping_data = -1;
79 static int hf_iscsi_immediate_data = -1;
80 static int hf_iscsi_write_data = -1;
81 static int hf_iscsi_read_data = -1;
82 static int hf_iscsi_error_pdu_data = -1;
83 static int hf_iscsi_Opcode = -1;
84 static int hf_iscsi_Flags = -1;
85 static int hf_iscsi_HeaderDigest = -1;
86 static int hf_iscsi_HeaderDigest32 = -1;
87 static int hf_iscsi_DataDigest = -1;
88 static int hf_iscsi_DataDigest32 = -1;
90 static int hf_iscsi_X = -1;
92 static int hf_iscsi_I = -1;
93 static int hf_iscsi_SCSICommand_F = -1;
94 static int hf_iscsi_SCSICommand_R = -1;
95 static int hf_iscsi_SCSICommand_W = -1;
96 static int hf_iscsi_SCSICommand_Attr = -1;
97 static int hf_iscsi_SCSICommand_CRN = -1;
98 static int hf_iscsi_SCSICommand_AddCDB = -1;
99 static int hf_iscsi_DataSegmentLength = -1;
100 static int hf_iscsi_TotalAHSLength = -1;
101 static int hf_iscsi_LUN = -1;
102 static int hf_iscsi_InitiatorTaskTag = -1;
103 static int hf_iscsi_ExpectedDataTransferLength = -1;
104 static int hf_iscsi_CmdSN = -1;
105 static int hf_iscsi_ExpStatSN = -1;
106 static int hf_iscsi_StatSN = -1;
107 static int hf_iscsi_ExpCmdSN = -1;
108 static int hf_iscsi_MaxCmdSN = -1;
109 static int hf_iscsi_SCSIResponse_o = -1;
110 static int hf_iscsi_SCSIResponse_u = -1;
111 static int hf_iscsi_SCSIResponse_O = -1;
112 static int hf_iscsi_SCSIResponse_U = -1;
113 static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1;
114 static int hf_iscsi_SCSIResponse_ResidualCount = -1;
115 static int hf_iscsi_SCSIResponse_Response = -1;
116 static int hf_iscsi_SCSIResponse_Status = -1;
117 static int hf_iscsi_SenseLength = -1;
118 static int hf_iscsi_SCSIData_F = -1;
119 static int hf_iscsi_SCSIData_S = -1;
120 static int hf_iscsi_SCSIData_O = -1;
121 static int hf_iscsi_SCSIData_U = -1;
122 static int hf_iscsi_TargetTransferTag = -1;
123 static int hf_iscsi_DataSN = -1;
124 static int hf_iscsi_BufferOffset = -1;
125 static int hf_iscsi_SCSIData_ResidualCount = -1;
126 static int hf_iscsi_VersionMin = -1;
127 static int hf_iscsi_VersionMax = -1;
128 static int hf_iscsi_VersionActive = -1;
129 static int hf_iscsi_CID = -1;
130 static int hf_iscsi_ISID = -1;
132 static int hf_iscsi_ISIDType = -1;
133 static int hf_iscsi_ISIDNamingAuthority = -1;
134 static int hf_iscsi_ISIDQualifier = -1;
136 static int hf_iscsi_TSID = -1;
137 static int hf_iscsi_InitStatSN = -1;
138 static int hf_iscsi_InitCmdSN = -1;
140 static int hf_iscsi_Login_X = -1;
142 static int hf_iscsi_Login_T = -1;
143 static int hf_iscsi_Login_CSG = -1;
144 static int hf_iscsi_Login_NSG = -1;
145 static int hf_iscsi_Login_Stage = -1;
146 static int hf_iscsi_Login_Status = -1;
147 static int hf_iscsi_KeyValue = -1;
148 static int hf_iscsi_Text_F = -1;
149 static int hf_iscsi_ExpDataSN = -1;
150 static int hf_iscsi_R2TSN = -1;
151 static int hf_iscsi_TaskManagementFunction_ReferencedTaskTag = -1;
152 static int hf_iscsi_RefCmdSN = -1;
153 static int hf_iscsi_TaskManagementFunction_Function = -1;
154 static int hf_iscsi_TaskManagementFunction_Response = -1;
155 static int hf_iscsi_Logout_Reason = -1;
156 static int hf_iscsi_Logout_Response = -1;
157 static int hf_iscsi_Time2Wait = -1;
158 static int hf_iscsi_Time2Retain = -1;
159 static int hf_iscsi_DesiredDataLength = -1;
160 static int hf_iscsi_AsyncEvent = -1;
161 static int hf_iscsi_EventVendorCode = -1;
162 static int hf_iscsi_Parameter1 = -1;
163 static int hf_iscsi_Parameter2 = -1;
164 static int hf_iscsi_Parameter3 = -1;
165 static int hf_iscsi_Reject_Reason = -1;
166 static int hf_iscsi_snack_type = -1;
167 static int hf_iscsi_BegRun = -1;
168 static int hf_iscsi_RunLength = -1;
170 /* Initialize the subtree pointers */
171 static gint ett_iscsi_KeyValues = -1;
172 static gint ett_iscsi_CDB = -1;
173 static gint ett_iscsi_Flags = -1;
175 static gint ett_iscsi_ISID = -1;
178 typedef struct _iscsi_conv_key {
183 typedef struct _iscsi_conv_data {
189 static GHashTable *iscsi_req_hash = NULL;
190 static GMemChunk *iscsi_req_keys = NULL;
191 static GMemChunk *iscsi_req_vals = NULL;
192 static guint32 iscsi_init_count = 25;
199 #define OPCODE_MASK 0x3f
201 #define TARGET_OPCODE_BIT 0x20
203 #define ISCSI_OPCODE_NOP_OUT 0x00
204 #define ISCSI_OPCODE_SCSI_COMMAND 0x01
205 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION 0x02
206 #define ISCSI_OPCODE_LOGIN_COMMAND 0x03
207 #define ISCSI_OPCODE_TEXT_COMMAND 0x04
208 #define ISCSI_OPCODE_SCSI_DATA_OUT 0x05
209 #define ISCSI_OPCODE_LOGOUT_COMMAND 0x06
210 #define ISCSI_OPCODE_SNACK_REQUEST 0x10
212 #define ISCSI_OPCODE_NOP_IN 0x20
213 #define ISCSI_OPCODE_SCSI_RESPONSE 0x21
214 #define ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE 0x22
215 #define ISCSI_OPCODE_LOGIN_RESPONSE 0x23
216 #define ISCSI_OPCODE_TEXT_RESPONSE 0x24
217 #define ISCSI_OPCODE_SCSI_DATA_IN 0x25
218 #define ISCSI_OPCODE_LOGOUT_RESPONSE 0x26
219 #define ISCSI_OPCODE_R2T 0x31
220 #define ISCSI_OPCODE_ASYNC_MESSAGE 0x32
221 #define ISCSI_OPCODE_REJECT 0x3f
224 #define CSG_MASK (0x03 << CSG_SHIFT)
225 #define NSG_MASK 0x03
227 #define ISCSI_CSG_SECURITY_NEGOTIATION (0 << CSG_SHIFT)
228 #define ISCSI_CSG_OPERATIONAL_NEGOTIATION (1 << CSG_SHIFT)
229 #define ISCSI_CSG_FULL_FEATURE_PHASE (3 << CSG_SHIFT)
231 #define ISCSI_SCSI_DATA_FLAG_S 0x01
232 #define ISCSI_SCSI_DATA_FLAG_U 0x02
233 #define ISCSI_SCSI_DATA_FLAG_O 0x04
234 #define ISCSI_SCSI_DATA_FLAG_F 0x80
236 static const value_string iscsi_opcodes[] = {
237 { ISCSI_OPCODE_NOP_OUT, "NOP Out" },
238 { ISCSI_OPCODE_SCSI_COMMAND, "SCSI Command" },
239 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION, "Task Management Function" },
240 { ISCSI_OPCODE_LOGIN_COMMAND, "Login Command" },
241 { ISCSI_OPCODE_TEXT_COMMAND, "Text Command" },
242 { ISCSI_OPCODE_SCSI_DATA_OUT, "SCSI Data Out" },
243 { ISCSI_OPCODE_LOGOUT_COMMAND, "Logout Command" },
244 { ISCSI_OPCODE_SNACK_REQUEST, "SNACK Request" },
246 { ISCSI_OPCODE_NOP_IN, "NOP In" },
247 { ISCSI_OPCODE_SCSI_RESPONSE, "SCSI Response" },
248 { ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE, "Task Management Function Response" },
249 { ISCSI_OPCODE_LOGIN_RESPONSE, "Login Response" },
250 { ISCSI_OPCODE_TEXT_RESPONSE, "Text Response" },
251 { ISCSI_OPCODE_SCSI_DATA_IN, "SCSI Data In" },
252 { ISCSI_OPCODE_LOGOUT_RESPONSE, "Logout Response" },
253 { ISCSI_OPCODE_R2T, "Ready To Transfer" },
254 { ISCSI_OPCODE_ASYNC_MESSAGE, "Asynchronous Message" },
255 { ISCSI_OPCODE_REJECT, "Reject"},
260 static const true_false_string iscsi_meaning_X = {
265 static const true_false_string iscsi_meaning_login_X = {
266 "Reinstate failed connection",
271 static const true_false_string iscsi_meaning_I = {
272 "Immediate delivery",
276 static const true_false_string iscsi_meaning_F = {
277 "Final PDU in sequence",
278 "Not final PDU in sequence"
281 static const true_false_string iscsi_meaning_T = {
282 "Transit to next login stage",
283 "Stay in current login stage"
286 static const true_false_string iscsi_meaning_S = {
287 "Response contains SCSI status",
288 "Response does not contain SCSI status"
291 static const true_false_string iscsi_meaning_R = {
292 "Data will be read from target",
293 "No data will be read from target"
296 static const true_false_string iscsi_meaning_W = {
297 "Data will be written to target",
298 "No data will be written to target"
301 static const true_false_string iscsi_meaning_o = {
302 "Read part of bi-directional command overflowed",
303 "No overflow of read part of bi-directional command",
306 static const true_false_string iscsi_meaning_u = {
307 "Read part of bi-directional command underflowed",
308 "No underflow of read part of bi-directional command",
311 static const true_false_string iscsi_meaning_O = {
312 "Residual overflow occurred",
313 "No residual overflow occurred",
316 static const true_false_string iscsi_meaning_U = {
317 "Residual underflow occurred",
318 "No residual underflow occurred",
321 static const value_string iscsi_scsi_responses[] = {
322 { 0, "Command completed at target" },
323 { 1, "Response does not contain SCSI status"},
327 static const value_string iscsi_scsicommand_taskattrs[] = {
331 {3, "Head of Queue"},
336 static const value_string iscsi_task_management_responses[] = {
337 {0, "Function complete"},
338 {1, "Task not in task set"},
339 {2, "LUN does not exist"},
340 {3, "Task still allegiant"},
341 {4, "Task failover not supported"},
342 {5, "Task management function not supported"},
343 {6, "Authorisation failed"},
344 {255, "Function rejected"},
348 static const value_string iscsi_task_management_functions[] = {
350 {2, "Abort Task Set"},
352 {4, "Clear Task Set"},
353 {5, "Logical Unit Reset"},
354 {6, "Target Warm Reset"},
355 {7, "Target Cold Reset"},
359 static const value_string iscsi_login_status[] = {
361 {0x0101, "Target moved temporarily"},
362 {0x0102, "Target moved permanently"},
363 {0x0200, "Initiator error (miscellaneous error)"},
364 {0x0201, "Athentication failed"},
365 {0x0202, "Authorisation failure"},
366 {0x0203, "Target not found"},
367 {0x0204, "Target removed"},
368 {0x0205, "Unsupported version"},
369 {0x0206, "Too many connections"},
370 {0x0207, "Missing parameter"},
371 {0x0208, "Can't include in session"},
372 {0x0209, "Session type not supported"},
373 {0x0300, "Target error (miscellaneous error)"},
374 {0x0301, "Service unavailable"},
375 {0x0302, "Out of resources"},
379 static const value_string iscsi_login_stage[] = {
380 {0, "Security negotiation"},
381 {1, "Operational negotiation"},
382 {3, "Full feature phase"},
387 static const value_string iscsi_isid_type[] = {
389 {0x01, "IANA Enterprise Number"},
395 static const value_string iscsi_logout_reasons[] = {
396 {0, "Close session"},
397 {1, "Close connection"},
398 {2, "Remove connection for recovery"},
402 static const value_string iscsi_logout_response[] = {
403 {0, "Connection closed successfully"},
404 {1, "CID not found"},
405 {2, "Connection recovery not supported"},
406 {3, "Cleanup failed for various reasons"},
410 static const value_string iscsi_asyncevents[] = {
411 {0, "A SCSI asynchronous event is reported in the sense data"},
412 {1, "Target requests logout"},
413 {2, "Target will/has dropped connection"},
414 {3, "Target will/has dropped all connections"},
418 static const value_string iscsi_snack_types[] = {
424 static const value_string iscsi_reject_reasons[] = {
425 {0x01, "Full feature phase command before login"},
426 {0x02, "Data (payload) digest error"},
427 {0x03, "Data SNACK reject"},
428 {0x04, "Protocol error"},
429 {0x05, "Command not supported in this session type"},
430 {0x06, "Immediate command reject (too many immediate commands)"},
431 {0x07, "Task in progress"},
432 {0x08, "Invalid SNACK"},
433 {0x09, "Bookmark reject (no bookmark for this initiator task tag)"},
434 {0x0a, "Bookmark reject (can't generate bookmark - out of resources)"},
435 {0x0b, "Negotiation reset"},
439 /*****************************************************************/
441 /* CRC LOOKUP TABLE */
442 /* ================ */
443 /* The following CRC lookup table was generated automagically */
444 /* by the Rocksoft^tm Model CRC Algorithm Table Generation */
445 /* Program V1.0 using the following model parameters: */
447 /* Width : 4 bytes. */
448 /* Poly : 0x1EDC6F41L */
449 /* Reverse : TRUE. */
451 /* For more information on the Rocksoft^tm Model CRC Algorithm, */
452 /* see the document titled "A Painless Guide to CRC Error */
453 /* Detection Algorithms" by Ross Williams */
454 /* (ross@guest.adelaide.edu.au.). This document is likely to be */
455 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
457 /*****************************************************************/
459 static guint32 crc32Table[256] = {
460 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
461 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
462 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
463 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
464 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
465 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
466 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
467 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
468 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
469 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
470 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
471 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
472 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
473 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
474 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
475 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
476 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
477 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
478 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
479 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
480 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
481 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
482 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
483 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
484 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
485 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
486 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
487 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
488 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
489 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
490 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
491 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
492 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
493 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
494 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
495 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
496 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
497 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
498 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
499 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
500 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
501 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
502 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
503 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
504 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
505 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
506 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
507 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
508 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
509 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
510 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
511 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
512 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
513 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
514 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
515 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
516 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
517 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
518 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
519 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
520 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
521 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
522 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
523 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
526 #define CRC32C_PRELOAD 0xffffffff
529 calculateCRC32(const void *buf, int len, guint32 crc) {
530 guint8 *p = (guint8 *)buf;
532 crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
540 iscsi_equal(gconstpointer v, gconstpointer w)
542 iscsi_conv_key_t *v1 = (iscsi_conv_key_t *)v;
543 iscsi_conv_key_t *v2 = (iscsi_conv_key_t *)w;
545 return (v1->conv_idx == v2->conv_idx);
549 iscsi_hash (gconstpointer v)
551 iscsi_conv_key_t *key = (iscsi_conv_key_t *)v;
560 * Protocol initialization
563 iscsi_init_protocol(void)
566 g_mem_chunk_destroy(iscsi_req_keys);
568 g_mem_chunk_destroy(iscsi_req_vals);
570 g_hash_table_destroy(iscsi_req_hash);
572 iscsi_req_hash = g_hash_table_new(iscsi_hash, iscsi_equal);
573 iscsi_req_keys = g_mem_chunk_new("iscsi_req_keys",
574 sizeof(iscsi_conv_key_t),
575 iscsi_init_count * sizeof(iscsi_conv_key_t),
577 iscsi_req_vals = g_mem_chunk_new("iscsi_req_vals",
578 sizeof(iscsi_conv_data_t),
579 iscsi_init_count * sizeof(iscsi_conv_data_t),
584 iscsi_min(int a, int b) {
585 return (a < b)? a : b;
589 addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
590 const gint limit = offset + text_len;
591 while(offset < limit) {
592 gint len = tvb_strnlen(tvb, offset, limit - offset);
594 len = limit - offset;
597 proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, FALSE);
604 handleHeaderDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
605 int available_bytes = tvb_length_remaining(tvb, offset);
606 if(enableHeaderDigests) {
607 if(headerDigestIsCRC32) {
608 if(available_bytes >= (headerLen + 4)) {
609 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
610 guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
612 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
615 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);
618 return offset + headerLen + 4;
620 if(available_bytes >= (headerLen + headerDigestSize)) {
621 proto_tree_add_item(ti, hf_iscsi_HeaderDigest, tvb, offset + headerLen, headerDigestSize, FALSE);
623 return offset + headerLen + headerDigestSize;
625 return offset + headerLen;
629 handleDataDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int dataLen) {
630 int available_bytes = tvb_length_remaining(tvb, offset);
631 if(enableDataDigests) {
632 if(dataDigestIsCRC32) {
633 if(available_bytes >= (dataLen + 4)) {
634 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, dataLen), dataLen, CRC32C_PRELOAD);
635 guint32 sent = tvb_get_ntohl(tvb, offset + dataLen);
637 proto_tree_add_uint_format(ti, hf_iscsi_DataDigest32, tvb, offset + dataLen, 4, sent, "DataDigest: 0x%08x (Good CRC32)", sent);
640 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);
643 return offset + dataLen + 4;
645 if(available_bytes >= (dataLen + dataDigestSize)) {
646 proto_tree_add_item(ti, hf_iscsi_DataDigest, tvb, offset + dataLen, dataDigestSize, FALSE);
648 return offset + dataLen + dataDigestSize;
650 return offset + dataLen;
654 handleDataSegment(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int hf_id) {
655 if(endOffset > offset) {
656 int dataOffset = offset;
657 int dataLen = iscsi_min(dataSegmentLen, endOffset - offset);
659 proto_tree_add_item(ti, hf_id, tvb, offset, dataLen, FALSE);
662 if(offset < endOffset && (offset & 3) != 0) {
663 int padding = 4 - (offset & 3);
664 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
667 if(dataSegmentLen > 0 && offset < endOffset)
668 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
675 handleDataSegmentAsTextKeys(proto_item *ti, tvbuff_t *tvb, guint offset, guint dataSegmentLen, guint endOffset, int digestsActive) {
676 if(endOffset > offset) {
677 int dataOffset = offset;
678 int textLen = iscsi_min(dataSegmentLen, endOffset - offset);
680 proto_item *tf = proto_tree_add_text(ti, tvb, offset, textLen, "Key/Value Pairs");
681 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
682 offset = addTextKeys(tt, tvb, offset, textLen);
684 if(offset < endOffset && (offset & 3) != 0) {
685 int padding = 4 - (offset & 3);
686 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
689 if(digestsActive && dataSegmentLen > 0 && offset < endOffset)
690 offset = handleDataDigest(ti, tvb, dataOffset, offset - dataOffset);
695 /* Code to actually dissect the packets */
697 dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 opcode, const char *opcode_str, guint32 data_segment_len) {
699 guint original_offset = offset;
700 proto_item *ti = NULL;
701 char *scsi_command_name = NULL;
702 guint8 scsi_status = 0;
703 guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
704 guint end_offset = offset + tvb_length_remaining(tvb, offset);
705 guint32 del_usecs = 0;
706 conversation_t *conversation = NULL;
707 iscsi_conv_data_t *cdata = NULL;
708 iscsi_conv_key_t ckey, *req_key;
709 scsi_task_id_t task_key;
710 int paddedDataSegmentLength = data_segment_len;
711 if(paddedDataSegmentLength & 3)
712 paddedDataSegmentLength += 4 - (paddedDataSegmentLength & 3);
714 /* Make entries in Protocol column and Info column on summary display */
715 if (check_col(pinfo->cinfo, COL_PROTOCOL))
716 col_set_str(pinfo->cinfo, COL_PROTOCOL, "iSCSI");
718 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
719 opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
720 scsi_status = tvb_get_guint8 (tvb, offset+3);
723 if ((opcode == ISCSI_OPCODE_SCSI_RESPONSE) ||
724 (opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
725 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
726 conversation = find_conversation (&pinfo->src, &pinfo->dst,
727 pinfo->ptype, pinfo->srcport,
730 ckey.conv_idx = conversation->index;
731 ckey.itt = tvb_get_ntohl (tvb, offset+16);
733 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_hash,
736 task_key.conv_id = ckey.conv_idx;
737 task_key.task_id = ckey.itt;
738 pinfo->private_data = &task_key;
740 /* no conversation, meaning we didn't see the request */
741 pinfo->private_data = NULL;
745 del_usecs = (pinfo->fd->abs_secs - cdata->abs_secs)* 1000000 +
746 (pinfo->fd->abs_usecs - cdata->abs_usecs);
749 else if (opcode == ISCSI_OPCODE_SCSI_COMMAND) {
750 conversation = find_conversation (&pinfo->src, &pinfo->dst,
751 pinfo->ptype, pinfo->srcport,
754 conversation = conversation_new (&pinfo->src, &pinfo->dst,
755 pinfo->ptype, pinfo->srcport,
759 ckey.conv_idx = conversation->index;
760 ckey.itt = tvb_get_ntohl (tvb, offset+16);
762 cdata = (iscsi_conv_data_t *)g_hash_table_lookup (iscsi_req_hash,
765 /* Since we never free the memory used by an exchange, this maybe a
766 * case of another request using the same exchange as a previous
769 cdata->abs_usecs = pinfo->fd->abs_usecs;
770 cdata->abs_secs = pinfo->fd->abs_secs;
773 req_key = g_mem_chunk_alloc (iscsi_req_keys);
774 req_key->conv_idx = conversation->index;
775 req_key->itt = tvb_get_ntohl (tvb, offset+16);
777 cdata = g_mem_chunk_alloc (iscsi_req_vals);
778 cdata->abs_usecs = pinfo->fd->abs_usecs;
779 cdata->abs_secs = pinfo->fd->abs_secs;
781 g_hash_table_insert (iscsi_req_hash, req_key, cdata);
784 /* The SCSI protocol uses this as the key to detect a
785 * SCSI-level conversation. */
786 task_key.conv_id = ckey.conv_idx;
787 task_key.task_id = ckey.itt;
788 pinfo->private_data = &task_key;
791 pinfo->private_data = NULL;
794 if (check_col(pinfo->cinfo, COL_INFO)) {
796 if (opcode != ISCSI_OPCODE_SCSI_COMMAND) {
798 col_append_str(pinfo->cinfo, COL_INFO, (char *)opcode_str);
800 if (opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
801 (opcode == ISCSI_OPCODE_SCSI_DATA_IN &&
802 (tvb_get_guint8(tvb, offset + 1) & ISCSI_SCSI_DATA_FLAG_S))) {
803 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
804 val_to_str (scsi_status, scsi_status_val, "0x%x"));
806 else if (opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
807 if(end_offset > (offset + 38)) {
808 guint16 login_status = tvb_get_ntohs(tvb, offset+36);
809 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
810 val_to_str (login_status, iscsi_login_status, "0x%x"));
813 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
814 guint8 tmf = tvb_get_guint8(tvb, offset + 1);
815 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
816 val_to_str (tmf, iscsi_task_management_functions, "0x%x"));
818 else if (opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
819 guint8 resp = tvb_get_guint8(tvb, offset + 2);
820 col_append_fstr (pinfo->cinfo, COL_INFO, " (%s)",
821 val_to_str (resp, iscsi_task_management_responses, "0x%x"));
826 /* In the interest of speed, if "tree" is NULL, don't do any
827 work not necessary to generate protocol tree items. */
830 /* create display subtree for the protocol */
831 ti = proto_tree_add_protocol_format(tree, proto_iscsi, tvb,
832 offset, -1, "iSCSI (%s)",
835 proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
836 offset + 0, 1, opcode);
837 if((opcode & TARGET_OPCODE_BIT) == 0) {
838 /* initiator -> target */
839 gint b = tvb_get_guint8(tvb, offset + 0);
841 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
842 opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
843 opcode != ISCSI_OPCODE_SNACK_REQUEST)
844 proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
846 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
847 opcode != ISCSI_OPCODE_LOGIN_COMMAND)
848 proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
851 if(opcode == ISCSI_OPCODE_NOP_OUT) {
853 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
854 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
855 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
856 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
857 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
858 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
859 offset = handleHeaderDigest(ti, tvb, offset, 48);
860 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
862 else if(opcode == ISCSI_OPCODE_NOP_IN) {
864 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
865 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
866 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
867 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
868 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
869 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
870 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
871 offset = handleHeaderDigest(ti, tvb, offset, 48);
872 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_ping_data);
874 else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
876 guint32 ahsLen = tvb_get_guint8(tvb, offset + 4) * 4;
878 gint b = tvb_get_guint8(tvb, offset + 1);
879 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
880 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
882 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
883 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
884 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
885 proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
887 proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, FALSE);
888 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
889 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
890 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
891 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
892 proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, FALSE);
893 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
894 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
897 /* FIXME - disssect AHS? */
898 proto_tree_add_item(ti, hf_iscsi_AHS, tvb, offset + 48, ahsLen, FALSE);
900 offset = handleHeaderDigest(ti, tvb, offset, 48 + ahsLen);
902 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_immediate_data);
904 else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
907 if (del_usecs > 1000)
908 proto_tree_add_text (ti, tvb, offset, 0,
909 "Cmd Response Time: %d msecs",
912 proto_tree_add_text (ti, tvb, offset, 0,
913 "Cmd Response Time: %d usecs",
917 gint b = tvb_get_guint8(tvb, offset + 1);
918 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
919 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
921 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
922 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
923 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
924 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
926 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Response, tvb, offset + 2, 1, FALSE);
927 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
928 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
929 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
930 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 20, 4, FALSE);
931 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
932 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
933 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
934 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
935 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, FALSE);
936 offset = handleHeaderDigest(ti, tvb, offset, 48);
937 /* do not update offset here because the data segment is
939 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
941 else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION) {
942 /* Task Management Function */
943 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Function, tvb, offset + 1, 1, FALSE);
944 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
945 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
946 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
947 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
948 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
949 proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
950 offset = handleHeaderDigest(ti, tvb, offset, 48);
952 else if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE) {
953 /* Task Management Function Response */
954 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_Response, tvb, offset + 2, 1, FALSE);
955 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
956 proto_tree_add_item(ti, hf_iscsi_TaskManagementFunction_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
957 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
958 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
959 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
960 offset = handleHeaderDigest(ti, tvb, offset, 48);
962 else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
964 int digestsActive = 0;
966 gint b = tvb_get_guint8(tvb, offset + 1);
968 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
972 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
973 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
976 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
978 proto_tree_add_boolean(ti, hf_iscsi_Login_X, tvb, offset + 1, 1, b);
980 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
981 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
983 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
984 proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
985 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
987 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
988 proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
991 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
992 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
993 proto_tree_add_item(tt, hf_iscsi_ISIDType, tvb, offset + 8, 1, FALSE);
994 proto_tree_add_item(tt, hf_iscsi_ISIDNamingAuthority, tvb, offset + 9, 3, FALSE);
995 proto_tree_add_item(tt, hf_iscsi_ISIDQualifier, tvb, offset + 12, 2, FALSE);
998 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
999 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1001 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 20, 2, FALSE);
1003 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1004 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1006 offset = handleHeaderDigest(ti, tvb, offset, 48);
1009 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1011 else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1012 /* Login Response */
1013 int digestsActive = 0;
1015 gint b = tvb_get_guint8(tvb, offset + 1);
1017 if((b & CSG_MASK) >= ISCSI_CSG_OPERATIONAL_NEGOTIATION)
1021 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1022 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1025 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
1026 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
1027 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
1030 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
1031 proto_tree_add_item(ti, hf_iscsi_VersionActive, tvb, offset + 3, 1, FALSE);
1032 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1034 proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
1037 proto_item *tf = proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 8, 6, FALSE);
1038 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_ISID);
1039 proto_tree_add_item(tt, hf_iscsi_ISIDType, tvb, offset + 8, 1, FALSE);
1040 proto_tree_add_item(tt, hf_iscsi_ISIDNamingAuthority, tvb, offset + 9, 3, FALSE);
1041 proto_tree_add_item(tt, hf_iscsi_ISIDQualifier, tvb, offset + 12, 2, FALSE);
1044 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
1045 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1046 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1047 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1048 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1049 proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, FALSE);
1051 offset = handleHeaderDigest(ti, tvb, offset, 48);
1054 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, digestsActive);
1056 else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
1059 gint b = tvb_get_guint8(tvb, offset + 1);
1060 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1061 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1063 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1064 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1066 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1067 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1068 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1069 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1070 offset = handleHeaderDigest(ti, tvb, offset, 48);
1071 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1073 else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
1076 gint b = tvb_get_guint8(tvb, offset + 1);
1077 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1078 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1080 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
1081 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1083 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1084 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1085 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1086 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1087 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1088 offset = handleHeaderDigest(ti, tvb, offset, 48);
1089 offset = handleDataSegmentAsTextKeys(ti, tvb, offset, data_segment_len, end_offset, TRUE);
1091 else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
1092 /* SCSI Data Out (write) */
1094 gint b = tvb_get_guint8(tvb, offset + 1);
1095 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1096 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1098 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1100 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1101 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1102 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1103 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1104 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1105 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1106 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1107 offset = handleHeaderDigest(ti, tvb, offset, 48);
1108 /* do not update offset here because the data segment is
1109 * dissected below */
1110 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1112 else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
1113 /* SCSI Data In (read) */
1115 gint b = tvb_get_guint8(tvb, offset + 1);
1116 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1117 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1119 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
1120 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
1121 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
1122 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
1124 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
1125 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1126 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1127 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 20, 4, FALSE);
1128 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1129 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1130 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1131 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1132 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1133 offset = handleHeaderDigest(ti, tvb, offset, 48);
1134 /* do not update offset here because the data segment is
1135 * dissected below */
1136 handleDataDigest(ti, tvb, offset, paddedDataSegmentLength);
1138 else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
1139 /* Logout Command */
1140 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1141 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, FALSE);
1142 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1143 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
1144 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1145 offset = handleHeaderDigest(ti, tvb, offset, 48);
1147 else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
1148 /* Logout Response */
1149 proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, FALSE);
1150 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1151 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1152 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1153 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1154 proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, FALSE);
1155 proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, FALSE);
1156 offset = handleHeaderDigest(ti, tvb, offset, 48);
1158 else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
1161 gint b = tvb_get_guint8(tvb, offset + 1);
1163 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1164 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1167 proto_tree_add_item(ti, hf_iscsi_snack_type, tvb, offset + 1, 1, b);
1169 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1170 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, FALSE);
1171 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, FALSE);
1172 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1173 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1174 offset = handleHeaderDigest(ti, tvb, offset, 48);
1176 else if(opcode == ISCSI_OPCODE_R2T) {
1178 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1179 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1180 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1181 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1182 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1183 proto_tree_add_item(ti, hf_iscsi_R2TSN, tvb, offset + 36, 4, FALSE);
1184 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1185 proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
1186 offset = handleHeaderDigest(ti, tvb, offset, 48);
1188 else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1189 /* Asynchronous Message */
1190 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1191 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1192 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1193 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1194 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1195 proto_tree_add_item(ti, hf_iscsi_AsyncEvent, tvb, offset + 36, 1, FALSE);
1196 proto_tree_add_item(ti, hf_iscsi_EventVendorCode, tvb, offset + 37, 1, FALSE);
1197 proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, FALSE);
1198 proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
1199 proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
1200 offset = handleHeaderDigest(ti, tvb, offset, 48);
1202 else if(opcode == ISCSI_OPCODE_REJECT) {
1204 proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
1205 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1206 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1207 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1208 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1209 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1210 offset = handleHeaderDigest(ti, tvb, offset, 48);
1211 offset = handleDataSegment(ti, tvb, offset, data_segment_len, end_offset, hf_iscsi_error_pdu_data);
1214 proto_item_set_len(ti, offset - original_offset);
1217 if((opcode & ~(X_BIT | I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND)
1219 if((opcode & ~I_BIT) == ISCSI_OPCODE_SCSI_COMMAND)
1223 dissect_scsi_cdb (tvb, pinfo, tree, cdb_offset, 16);
1225 else if (opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
1226 if (scsi_status == 0x2) {
1227 /* A SCSI response with Check Condition contains sense data */
1228 /* offset is setup correctly by the iscsi code for response above */
1229 if((end_offset - offset) >= 2) {
1230 int senseLen = tvb_get_ntohs(tvb, offset);
1232 proto_tree_add_item(ti, hf_iscsi_SenseLength, tvb, offset, 2, FALSE);
1235 dissect_scsi_snsinfo (tvb, pinfo, tree, offset,
1236 iscsi_min (senseLen,
1237 end_offset-offset));
1241 dissect_scsi_rsp (tvb, pinfo, tree);
1243 if (cdata && tree) {
1244 /* destroy the data structures for this SCSI task */
1246 g_mem_chunk_free (iscsi_req_vals, cdata);
1247 g_hash_table_remove (iscsi_req_hash, &ckey);
1248 pinfo->private_data = NULL;
1252 else if ((opcode == ISCSI_OPCODE_SCSI_DATA_IN) ||
1253 (opcode == ISCSI_OPCODE_SCSI_DATA_OUT)) {
1254 /* offset is setup correctly by the iscsi code for response above */
1255 dissect_scsi_payload (tvb, pinfo, tree, offset, FALSE,
1256 iscsi_min (data_segment_len, end_offset-offset));
1261 dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1262 /* Set up structures needed to add the protocol subtree and manage it */
1263 guint iSCSIPdusDissected = 0;
1265 guint32 available_bytes = tvb_length_remaining(tvb, offset);
1267 if (!proto_is_protocol_enabled(proto_iscsi))
1268 return FALSE; /* iSCSI has been disabled */
1270 /* quick check to see if the packet is long enough to contain the
1271 * minimum amount of information we need */
1272 if (available_bytes < 48 && (!iscsi_desegment || available_bytes < 8)) {
1273 /* no, so give up */
1277 /* process multiple iSCSI PDUs per packet */
1278 while(available_bytes >= 48 || (iscsi_desegment && available_bytes >= 8)) {
1279 const char *opcode_str = NULL;
1280 guint32 data_segment_len;
1281 guint8 opcode = tvb_get_guint8(tvb, offset + 0);
1282 guint8 secondPduByte = tvb_get_guint8(tvb, offset + 1);
1285 /* mask out any extra bits in the opcode byte */
1286 opcode &= OPCODE_MASK;
1288 opcode_str = match_strval(opcode, iscsi_opcodes);
1289 if(opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION ||
1290 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
1291 opcode == ISCSI_OPCODE_R2T ||
1292 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
1293 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
1294 opcode == ISCSI_OPCODE_SNACK_REQUEST)
1295 data_segment_len = 0;
1297 data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
1299 if(opcode_str == NULL) {
1302 else if(iscsi_port != 0 &&
1303 (((opcode & TARGET_OPCODE_BIT) && pinfo->srcport != iscsi_port) ||
1304 (!(opcode & TARGET_OPCODE_BIT) && pinfo->destport != iscsi_port))) {
1307 else if(enable_bogosity_filter) {
1308 /* try and distinguish between data and real headers */
1309 if(data_segment_len > bogus_pdu_data_length_threshold) {
1312 else if(demand_good_f_bit &&
1313 !(secondPduByte & 0x80) &&
1314 (opcode == ISCSI_OPCODE_NOP_OUT ||
1315 opcode == ISCSI_OPCODE_NOP_IN ||
1316 opcode == ISCSI_OPCODE_LOGOUT_COMMAND ||
1317 opcode == ISCSI_OPCODE_LOGOUT_RESPONSE ||
1318 opcode == ISCSI_OPCODE_SCSI_RESPONSE ||
1319 opcode == ISCSI_OPCODE_TASK_MANAGEMENT_FUNCTION_RESPONSE ||
1320 opcode == ISCSI_OPCODE_R2T ||
1321 opcode == ISCSI_OPCODE_ASYNC_MESSAGE ||
1322 opcode == ISCSI_OPCODE_SNACK_REQUEST ||
1323 opcode == ISCSI_OPCODE_REJECT)) {
1329 return iSCSIPdusDissected > 0;
1332 guint32 pduLen = 48;
1333 int digestsActive = 1;
1335 if(opcode == ISCSI_OPCODE_LOGIN_COMMAND ||
1336 opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
1338 if((secondPduByte & CSG_MASK) < ISCSI_CSG_OPERATIONAL_NEGOTIATION) {
1339 /* digests are not yet turned on */
1347 if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
1349 pduLen += tvb_get_guint8(tvb, offset + 4) * 4;
1352 pduLen += data_segment_len;
1353 if((pduLen & 3) != 0)
1354 pduLen += 4 - (pduLen & 3);
1356 if(digestsActive && enableHeaderDigests) {
1357 if(headerDigestIsCRC32)
1360 pduLen += headerDigestSize;
1363 if(digestsActive && data_segment_len > 0 && enableDataDigests) {
1364 if(dataDigestIsCRC32)
1367 pduLen += dataDigestSize;
1371 * Desegmentation check.
1373 if(iscsi_desegment && pinfo->can_desegment) {
1374 if(pduLen > available_bytes) {
1376 * This frame doesn't have all of the data for
1377 * this message, but we can do reassembly on it.
1379 * Tell the TCP dissector where the data for this
1380 * message starts in the data it handed us, and
1381 * how many more bytes we need, and return.
1383 pinfo->desegment_offset = offset;
1384 pinfo->desegment_len = pduLen - available_bytes;
1389 if(check_col(pinfo->cinfo, COL_INFO)) {
1390 if(iSCSIPdusDissected == 0)
1391 col_set_str(pinfo->cinfo, COL_INFO, "");
1393 col_append_str(pinfo->cinfo, COL_INFO, ", ");
1396 dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len);
1397 if(pduLen > available_bytes)
1398 pduLen = available_bytes;
1400 available_bytes -= pduLen;
1401 ++iSCSIPdusDissected;
1405 return iSCSIPdusDissected > 0;
1409 /* Register the protocol with Ethereal */
1412 * this format is require because a script is used to build the C
1413 * function that calls all the protocol registration.
1417 proto_register_iscsi(void)
1420 /* Setup list of header fields See Section 1.6.1 for details*/
1421 static hf_register_info hf[] = {
1423 { "AHS", "iscsi.ahs",
1424 FT_BYTES, BASE_HEX, NULL, 0,
1425 "Additional header segment", HFILL }
1427 { &hf_iscsi_Padding,
1428 { "Padding", "iscsi.padding",
1429 FT_BYTES, BASE_HEX, NULL, 0,
1430 "Padding to 4 byte boundary", HFILL }
1432 { &hf_iscsi_ping_data,
1433 { "PingData", "iscsi.pingdata",
1434 FT_BYTES, BASE_HEX, NULL, 0,
1435 "Ping Data", HFILL }
1437 { &hf_iscsi_immediate_data,
1438 { "ImmediateData", "iscsi.immediatedata",
1439 FT_BYTES, BASE_HEX, NULL, 0,
1440 "Immediate Data", HFILL }
1442 { &hf_iscsi_write_data,
1443 { "WriteData", "iscsi.writedata",
1444 FT_BYTES, BASE_HEX, NULL, 0,
1445 "Write Data", HFILL }
1447 { &hf_iscsi_read_data,
1448 { "ReadData", "iscsi.readdata",
1449 FT_BYTES, BASE_HEX, NULL, 0,
1450 "Read Data", HFILL }
1452 { &hf_iscsi_error_pdu_data,
1453 { "ErrorPDUData", "iscsi.errorpdudata",
1454 FT_BYTES, BASE_HEX, NULL, 0,
1455 "Error PDU Data", HFILL }
1457 { &hf_iscsi_HeaderDigest,
1458 { "HeaderDigest", "iscsi.headerdigest",
1459 FT_BYTES, BASE_HEX, NULL, 0,
1460 "Header Digest", HFILL }
1462 { &hf_iscsi_HeaderDigest32,
1463 { "HeaderDigest", "iscsi.headerdigest32",
1464 FT_UINT32, BASE_HEX, NULL, 0,
1465 "Header Digest", HFILL }
1467 { &hf_iscsi_DataDigest,
1468 { "DataDigest", "iscsi.datadigest",
1469 FT_BYTES, BASE_HEX, NULL, 0,
1470 "Data Digest", HFILL }
1472 { &hf_iscsi_DataDigest32,
1473 { "DataDigest", "iscsi.datadigest32",
1474 FT_UINT32, BASE_HEX, NULL, 0,
1475 "Data Digest", HFILL }
1478 { "Opcode", "iscsi.opcode",
1479 FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
1485 FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,
1486 "Command Retry", HFILL }
1491 FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,
1492 "Immediate delivery", HFILL }
1495 { "Flags", "iscsi.flags",
1496 FT_UINT8, BASE_HEX, NULL, 0,
1497 "Opcode specific flags", HFILL }
1499 { &hf_iscsi_SCSICommand_F,
1500 { "F", "iscsi.scsicommand.F",
1501 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
1502 "PDU completes command", HFILL }
1504 { &hf_iscsi_SCSICommand_R,
1505 { "R", "iscsi.scsicommand.R",
1506 FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,
1507 "Command reads from SCSI target", HFILL }
1509 { &hf_iscsi_SCSICommand_W,
1510 { "W", "iscsi.scsicommand.W",
1511 FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,
1512 "Command writes to SCSI target", HFILL }
1514 { &hf_iscsi_SCSICommand_Attr,
1515 { "Attr", "iscsi.scsicommand.attr",
1516 FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07,
1517 "SCSI task attributes", HFILL }
1519 { &hf_iscsi_SCSICommand_CRN,
1520 { "CRN", "iscsi.scsicommand.crn",
1521 FT_UINT8, BASE_HEX, NULL, 0,
1522 "SCSI command reference number", HFILL }
1524 { &hf_iscsi_SCSICommand_AddCDB,
1525 { "AddCDB", "iscsi.scsicommand.addcdb",
1526 FT_UINT8, BASE_HEX, NULL, 0,
1527 "Additional CDB length (in 4 byte units)", HFILL }
1529 { &hf_iscsi_DataSegmentLength,
1530 { "DataSegmentLength", "iscsi.datasegmentlength",
1531 FT_UINT32, BASE_HEX, NULL, 0,
1532 "Data segment length (bytes)", HFILL }
1534 { &hf_iscsi_TotalAHSLength,
1535 { "TotalAHSLength", "iscsi.totalahslength",
1536 FT_UINT8, BASE_HEX, NULL, 0,
1537 "Total additional header segment length (4 byte words)", HFILL }
1540 { "LUN", "iscsi.lun",
1541 FT_BYTES, BASE_HEX, NULL, 0,
1542 "Logical Unit Number", HFILL }
1544 { &hf_iscsi_InitiatorTaskTag,
1545 { "InitiatorTaskTag", "iscsi.initiatortasktag",
1546 FT_UINT32, BASE_HEX, NULL, 0,
1547 "Initiator's task tag", HFILL }
1549 { &hf_iscsi_ExpectedDataTransferLength,
1550 { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength",
1551 FT_UINT32, BASE_HEX, NULL, 0,
1552 "Expected length of data transfer", HFILL }
1555 { "CmdSN", "iscsi.cmdsn",
1556 FT_UINT32, BASE_HEX, NULL, 0,
1557 "Sequence number for this command (0 == immediate)", HFILL }
1559 { &hf_iscsi_ExpStatSN,
1560 { "ExpStatSN", "iscsi.expstatsn",
1561 FT_UINT32, BASE_HEX, NULL, 0,
1562 "Next expected status sequence number", HFILL }
1564 { &hf_iscsi_SCSIResponse_ResidualCount,
1565 { "ResidualCount", "iscsi.scsiresponse.residualcount",
1566 FT_UINT32, BASE_HEX, NULL, 0,
1567 "Residual count", HFILL }
1570 { "StatSN", "iscsi.statsn",
1571 FT_UINT32, BASE_HEX, NULL, 0,
1572 "Status sequence number", HFILL }
1574 { &hf_iscsi_ExpCmdSN,
1575 { "ExpCmdSN", "iscsi.expcmdsn",
1576 FT_UINT32, BASE_HEX, NULL, 0,
1577 "Next expected command sequence number", HFILL }
1579 { &hf_iscsi_MaxCmdSN,
1580 { "MaxCmdSN", "iscsi.maxcmdsn",
1581 FT_UINT32, BASE_HEX, NULL, 0,
1582 "Maximum acceptable command sequence number", HFILL }
1584 { &hf_iscsi_SCSIResponse_o,
1585 { "o", "iscsi.scsiresponse.o",
1586 FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,
1587 "Bi-directional read residual overflow", HFILL }
1589 { &hf_iscsi_SCSIResponse_u,
1590 { "u", "iscsi.scsiresponse.u",
1591 FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08,
1592 "Bi-directional read residual underflow", HFILL }
1594 { &hf_iscsi_SCSIResponse_O,
1595 { "O", "iscsi.scsiresponse.O",
1596 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
1597 "Residual overflow", HFILL }
1599 { &hf_iscsi_SCSIResponse_U,
1600 { "U", "iscsi.scsiresponse.U",
1601 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
1602 "Residual underflow", HFILL }
1604 { &hf_iscsi_SCSIResponse_Status,
1605 { "Status", "iscsi.scsiresponse.status",
1606 FT_UINT8, BASE_HEX, VALS(scsi_status_val), 0,
1607 "SCSI command status value", HFILL }
1609 { &hf_iscsi_SCSIResponse_Response,
1610 { "Response", "iscsi.scsiresponse.response",
1611 FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
1612 "SCSI command response value", HFILL }
1614 { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
1615 { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
1616 FT_UINT32, BASE_HEX, NULL, 0,
1617 "Bi-directional read residual count", HFILL }
1619 { &hf_iscsi_SenseLength,
1620 { "SenseLength", "iscsi.scsiresponse.senselength",
1621 FT_UINT16, BASE_HEX, NULL, 0,
1622 "Sense data length", HFILL }
1624 { &hf_iscsi_SCSIData_F,
1625 { "F", "iscsi.scsidata.F",
1626 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), ISCSI_SCSI_DATA_FLAG_F,
1627 "Final PDU", HFILL }
1629 { &hf_iscsi_SCSIData_S,
1630 { "S", "iscsi.scsidata.S",
1631 FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), ISCSI_SCSI_DATA_FLAG_S,
1632 "PDU Contains SCSI command status", HFILL }
1634 { &hf_iscsi_SCSIData_U,
1635 { "U", "iscsi.scsidata.U",
1636 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), ISCSI_SCSI_DATA_FLAG_U,
1637 "Residual underflow", HFILL }
1639 { &hf_iscsi_SCSIData_O,
1640 { "O", "iscsi.scsidata.O",
1641 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), ISCSI_SCSI_DATA_FLAG_O,
1642 "Residual overflow", HFILL }
1644 { &hf_iscsi_TargetTransferTag,
1645 { "TargetTransferTag", "iscsi.targettransfertag",
1646 FT_UINT32, BASE_HEX, NULL, 0,
1647 "Target transfer tag", HFILL }
1649 { &hf_iscsi_BufferOffset,
1650 { "BufferOffset", "iscsi.bufferOffset",
1651 FT_UINT32, BASE_HEX, NULL, 0,
1652 "Buffer offset", HFILL }
1654 { &hf_iscsi_SCSIData_ResidualCount,
1655 { "ResidualCount", "iscsi.scsidata.readresidualcount",
1656 FT_UINT32, BASE_HEX, NULL, 0,
1657 "Residual count", HFILL }
1660 { "DataSN", "iscsi.datasn",
1661 FT_UINT32, BASE_HEX, NULL, 0,
1662 "Data sequence number", HFILL }
1664 { &hf_iscsi_VersionMax,
1665 { "VersionMax", "iscsi.versionmax",
1666 FT_UINT8, BASE_HEX, NULL, 0,
1667 "Maximum supported protocol version", HFILL }
1669 { &hf_iscsi_VersionMin,
1670 { "VersionMin", "iscsi.versionmin",
1671 FT_UINT8, BASE_HEX, NULL, 0,
1672 "Minimum supported protocol version", HFILL }
1674 { &hf_iscsi_VersionActive,
1675 { "VersionActive", "iscsi.versionactive",
1676 FT_UINT8, BASE_HEX, NULL, 0,
1677 "Negotiated protocol version", HFILL }
1680 { "CID", "iscsi.cid",
1681 FT_UINT16, BASE_HEX, NULL, 0,
1682 "Connection identifier", HFILL }
1686 { "ISID", "iscsi.isid",
1687 FT_UINT16, BASE_HEX, NULL, 0,
1688 "Initiator part of session identifier", HFILL }
1692 { "ISID", "iscsi.isid",
1693 FT_BYTES, BASE_HEX, NULL, 0,
1694 "Initiator part of session identifier", HFILL }
1696 { &hf_iscsi_ISIDType,
1697 { "ISIDType", "iscsi.isid.type",
1698 FT_UINT8, BASE_HEX, VALS(iscsi_isid_type), 0,
1699 "Initiator part of session identifier - type", HFILL }
1701 { &hf_iscsi_ISIDNamingAuthority,
1702 { "ISIDNamingAuthority", "iscsi.isid.namingauthority",
1703 FT_UINT24, BASE_HEX, NULL, 0,
1704 "Initiator part of session identifier - naming authority", HFILL }
1706 { &hf_iscsi_ISIDQualifier,
1707 { "ISIDQualifier", "iscsi.isid.qualifier",
1708 FT_UINT8, BASE_HEX, NULL, 0,
1709 "Initiator part of session identifier - qualifier", HFILL }
1713 { "TSID", "iscsi.tsid",
1714 FT_UINT16, BASE_HEX, NULL, 0,
1715 "Target part of session identifier", HFILL }
1717 { &hf_iscsi_InitStatSN,
1718 { "InitStatSN", "iscsi.initstatsn",
1719 FT_UINT32, BASE_HEX, NULL, 0,
1720 "Initial status sequence number", HFILL }
1722 { &hf_iscsi_InitCmdSN,
1723 { "InitCmdSN", "iscsi.initcmdsn",
1724 FT_UINT32, BASE_HEX, NULL, 0,
1725 "Initial command sequence number", HFILL }
1727 { &hf_iscsi_Login_T,
1728 { "T", "iscsi.login.T",
1729 FT_BOOLEAN, 8, TFS(&iscsi_meaning_T), 0x80,
1730 "Transit to next login stage", HFILL }
1733 { &hf_iscsi_Login_X,
1734 { "X", "iscsi.login.X",
1735 FT_BOOLEAN, 8, TFS(&iscsi_meaning_login_X), 0x40,
1736 "Restart Connection", HFILL }
1739 { &hf_iscsi_Login_CSG,
1740 { "CSG", "iscsi.login.csg",
1741 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), CSG_MASK,
1742 "Current stage", HFILL }
1744 { &hf_iscsi_Login_NSG,
1745 { "NSG", "iscsi.login.nsg",
1746 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), NSG_MASK,
1747 "Next stage", HFILL }
1749 { &hf_iscsi_Login_Status,
1750 { "Status", "iscsi.login.status",
1751 FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0,
1752 "Status class and detail", HFILL }
1754 { &hf_iscsi_KeyValue,
1755 { "KeyValue", "iscsi.keyvalue",
1756 FT_STRING, 0, NULL, 0,
1757 "Key/value pair", HFILL }
1760 { "F", "iscsi.text.F",
1761 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
1762 "Final PDU in text sequence", HFILL }
1764 { &hf_iscsi_ExpDataSN,
1765 { "ExpDataSN", "iscsi.expdatasn",
1766 FT_UINT32, BASE_HEX, NULL, 0,
1767 "Next expected data sequence number", HFILL }
1770 { "R2TSN", "iscsi.r2tsn",
1771 FT_UINT32, BASE_HEX, NULL, 0,
1772 "R2T PDU Number", HFILL }
1774 { &hf_iscsi_TaskManagementFunction_Response,
1775 { "Response", "iscsi.taskmanfun.response",
1776 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_responses), 0,
1779 { &hf_iscsi_TaskManagementFunction_ReferencedTaskTag,
1780 { "ReferencedTaskTag", "iscsi.taskmanfun.referencedtasktag",
1781 FT_UINT32, BASE_HEX, NULL, 0,
1782 "Referenced task tag", HFILL }
1784 { &hf_iscsi_RefCmdSN,
1785 { "RefCmdSN", "iscsi.refcmdsn",
1786 FT_UINT32, BASE_HEX, NULL, 0,
1787 "Command sequence number for command to be aborted", HFILL }
1789 { &hf_iscsi_TaskManagementFunction_Function,
1790 { "Function", "iscsi.taskmanfun.function",
1791 FT_UINT8, BASE_HEX, VALS(iscsi_task_management_functions), 0x7F,
1792 "Requested task function", HFILL }
1794 { &hf_iscsi_Logout_Reason,
1795 { "Reason", "iscsi.logout.reason",
1796 FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0,
1797 "Reason for logout", HFILL }
1799 { &hf_iscsi_Logout_Response,
1800 { "Response", "iscsi.logout.response",
1801 FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
1802 "Logout response", HFILL }
1804 { &hf_iscsi_Time2Wait,
1805 { "Time2Wait", "iscsi.time2wait",
1806 FT_UINT16, BASE_HEX, NULL, 0,
1807 "Time2Wait", HFILL }
1809 { &hf_iscsi_Time2Retain,
1810 { "Time2Retain", "iscsi.time2retain",
1811 FT_UINT16, BASE_HEX, NULL, 0,
1812 "Time2Retain", HFILL }
1814 { &hf_iscsi_DesiredDataLength,
1815 { "DesiredDataLength", "iscsi.desireddatalength",
1816 FT_UINT32, BASE_HEX, NULL, 0,
1817 "Desired data length (bytes)", HFILL }
1819 { &hf_iscsi_AsyncEvent,
1820 { "AsyncEvent", "iscsi.asyncevent",
1821 FT_UINT8, BASE_HEX, VALS(iscsi_asyncevents), 0,
1822 "Async event type", HFILL }
1824 { &hf_iscsi_EventVendorCode,
1825 { "EventVendorCode", "iscsi.eventvendorcode",
1826 FT_UINT8, BASE_HEX, NULL, 0,
1827 "Event vendor code", HFILL }
1829 { &hf_iscsi_Parameter1,
1830 { "Parameter1", "iscsi.parameter1",
1831 FT_UINT16, BASE_HEX, NULL, 0,
1832 "Parameter 1", HFILL }
1834 { &hf_iscsi_Parameter2,
1835 { "Parameter2", "iscsi.parameter2",
1836 FT_UINT16, BASE_HEX, NULL, 0,
1837 "Parameter 2", HFILL }
1839 { &hf_iscsi_Parameter3,
1840 { "Parameter3", "iscsi.parameter3",
1841 FT_UINT16, BASE_HEX, NULL, 0,
1842 "Parameter 3", HFILL }
1844 { &hf_iscsi_Reject_Reason,
1845 { "Reason", "iscsi.reject.reason",
1846 FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
1847 "Reason for command rejection", HFILL }
1849 { &hf_iscsi_snack_type,
1850 { "S", "iscsi.snack.type",
1851 FT_UINT8, BASE_DEC, VALS(iscsi_snack_types), 0x0f,
1852 "Type of SNACK requested", HFILL }
1855 { "BegRun", "iscsi.snack.begrun",
1856 FT_UINT32, BASE_HEX, NULL, 0,
1857 "First missed DataSN or StatSN", HFILL }
1859 { &hf_iscsi_RunLength,
1860 { "RunLength", "iscsi.snack.runlength",
1861 FT_UINT32, BASE_HEX, NULL, 0,
1862 "Number of additional missing status PDUs in this run", HFILL }
1866 /* Setup protocol subtree array */
1867 static gint *ett[] = {
1868 &ett_iscsi_KeyValues,
1876 /* Register the protocol name and description */
1877 proto_iscsi = proto_register_protocol("iSCSI", "iSCSI", "iscsi");
1879 /* Required function calls to register the header fields and
1881 proto_register_field_array(proto_iscsi, hf, array_length(hf));
1882 proto_register_subtree_array(ett, array_length(ett));
1883 register_init_routine (&iscsi_init_protocol);
1886 module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
1888 prefs_register_bool_preference(iscsi_module,
1889 "desegment_iscsi_messages",
1890 "Desegment iSCSI messages",
1891 "When enabled, iSCSI messages that span multiple TCP segments are desegmented",
1894 prefs_register_bool_preference(iscsi_module,
1896 "Enable bogus pdu filter",
1897 "When enabled, packets that appear bogus are ignored",
1898 &enable_bogosity_filter);
1900 prefs_register_bool_preference(iscsi_module,
1901 "demand_good_f_bit",
1902 "Ignore packets with bad F bit",
1903 "Ignore packets that haven't set the F bit when they should have",
1904 &demand_good_f_bit);
1906 prefs_register_uint_preference(iscsi_module,
1907 "bogus_pdu_max_data_len",
1908 "Bogus pdu max data length threshold",
1909 "Treat packets whose data segment length is greater than this value as bogus",
1911 &bogus_pdu_data_length_threshold);
1913 prefs_register_uint_preference(iscsi_module,
1916 "Port number of iSCSI target",
1920 prefs_register_bool_preference(iscsi_module,
1921 "enable_header_digests",
1922 "Enable header digests",
1923 "When enabled, pdus are assumed to contain a header digest",
1924 &enableHeaderDigests);
1925 prefs_register_bool_preference(iscsi_module,
1926 "enable_data_digests",
1927 "Enable data digests",
1928 "When enabled, pdus are assumed to contain a data digest",
1929 &enableDataDigests);
1931 prefs_register_bool_preference(iscsi_module,
1932 "header_digest_is_crc32c",
1933 "Header digest is CRC32C",
1934 "When enabled, header digests are assumed to be CRC32C",
1935 &headerDigestIsCRC32);
1936 prefs_register_bool_preference(iscsi_module,
1937 "data_digest_is_crc32c",
1938 "Data digest is CRC32C",
1939 "When enabled, data digests are assumed to be CRC32C",
1940 &dataDigestIsCRC32);
1942 prefs_register_uint_preference(iscsi_module,
1943 "header_digest_size",
1944 "Header digest size",
1945 "The size of a header digest (bytes)",
1948 prefs_register_uint_preference(iscsi_module,
1951 "The size of a data digest (bytes)",
1955 /* Preference supported in older versions.
1956 Register them as obsolete. */
1957 prefs_register_obsolete_preference(iscsi_module,
1958 "version_03_compatible");
1959 prefs_register_obsolete_preference(iscsi_module,
1960 "bogus_pdu_max_digest_padding");
1966 * If this dissector uses sub-dissector registration add a
1967 * registration routine.
1971 * This format is required because a script is used to find these
1972 * routines and create the code that calls these routines.
1975 proto_reg_handoff_iscsi(void)
1977 heur_dissector_add("tcp", dissect_iscsi, proto_iscsi);