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