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.11 2001/10/19 20:53:14 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 int enable_bogosity_filter = TRUE;
54 static guint32 bogus_pdu_data_length_threshold = 1024 * 1024;
55 static guint32 bogus_pdu_max_digest_padding = 20;
57 static int enable_force_header_digest_crc32 = FALSE;
59 /* Initialize the protocol and registered fields */
60 static int proto_iscsi = -1;
61 static int hf_iscsi_Padding = -1;
62 static int hf_iscsi_ping_data = -1;
63 static int hf_iscsi_immediate_data = -1;
64 static int hf_iscsi_sense_data = -1;
65 static int hf_iscsi_write_data = -1;
66 static int hf_iscsi_read_data = -1;
67 static int hf_iscsi_error_pdu_data = -1;
68 static int hf_iscsi_Opcode = -1;
69 static int hf_iscsi_Flags = -1;
70 static int hf_iscsi_HeaderDigest32 = -1;
71 static int hf_iscsi_X = -1;
72 static int hf_iscsi_I = -1;
73 static int hf_iscsi_SCSICommand_F = -1;
74 static int hf_iscsi_SCSICommand_R = -1;
75 static int hf_iscsi_SCSICommand_W = -1;
76 static int hf_iscsi_SCSICommand_Attr = -1;
77 static int hf_iscsi_SCSICommand_CRN = -1;
78 static int hf_iscsi_SCSICommand_AddCDB = -1;
79 static int hf_iscsi_DataSegmentLength = -1;
80 static int hf_iscsi_TotalAHSLength = -1;
81 static int hf_iscsi_LUN = -1;
82 static int hf_iscsi_InitiatorTaskTag = -1;
83 static int hf_iscsi_ExpectedDataTransferLength = -1;
84 static int hf_iscsi_CmdSN = -1;
85 static int hf_iscsi_ExpStatSN = -1;
86 static int hf_iscsi_SCSICommand_CDB = -1;
87 static int hf_iscsi_SCSICommand_CDB0 = -1;
88 static int hf_iscsi_StatSN = -1;
89 static int hf_iscsi_ExpCmdSN = -1;
90 static int hf_iscsi_MaxCmdSN = -1;
91 static int hf_iscsi_SCSIResponse_o = -1;
92 static int hf_iscsi_SCSIResponse_u = -1;
93 static int hf_iscsi_SCSIResponse_O = -1;
94 static int hf_iscsi_SCSIResponse_U = -1;
95 static int hf_iscsi_SCSIResponse_BidiReadResidualCount = -1;
96 static int hf_iscsi_SCSIResponse_ResidualCount = -1;
97 static int hf_iscsi_SCSIResponse_Response = -1;
98 static int hf_iscsi_SCSIResponse_Status = -1;
99 static int hf_iscsi_SCSIData_F = -1;
100 static int hf_iscsi_SCSIData_S = -1;
101 static int hf_iscsi_SCSIData_O = -1;
102 static int hf_iscsi_SCSIData_U = -1;
103 static int hf_iscsi_TargetTransferTag = -1;
104 static int hf_iscsi_DataSN = -1;
105 static int hf_iscsi_BufferOffset = -1;
106 static int hf_iscsi_SCSIData_ResidualCount = -1;
107 static int hf_iscsi_VersionMin = -1;
108 static int hf_iscsi_VersionMax = -1;
109 static int hf_iscsi_VersionActive = -1;
110 static int hf_iscsi_CID = -1;
111 static int hf_iscsi_ISID = -1;
112 static int hf_iscsi_TSID = -1;
113 static int hf_iscsi_InitStatSN = -1;
114 static int hf_iscsi_InitCmdSN = -1;
115 static int hf_iscsi_Login_T = -1;
116 static int hf_iscsi_Login_CSG = -1;
117 static int hf_iscsi_Login_NSG = -1;
118 static int hf_iscsi_Login_Stage = -1;
119 static int hf_iscsi_Login_Status = -1;
120 static int hf_iscsi_KeyValue = -1;
121 static int hf_iscsi_Text_F = -1;
122 static int hf_iscsi_ExpDataSN = -1;
123 static int hf_iscsi_R2TSN = -1;
124 static int hf_iscsi_SCSITask_ReferencedTaskTag = -1;
125 static int hf_iscsi_RefCmdSN = -1;
126 static int hf_iscsi_SCSITask_Function = -1;
127 static int hf_iscsi_SCSITask_Response = -1;
128 static int hf_iscsi_Logout_Reason = -1;
129 static int hf_iscsi_Logout_Response = -1;
130 static int hf_iscsi_Time2Wait = -1;
131 static int hf_iscsi_Time2Retain = -1;
132 static int hf_iscsi_DesiredDataLength = -1;
133 static int hf_iscsi_AsyncEvent = -1;
134 static int hf_iscsi_EventVendorCode = -1;
135 static int hf_iscsi_Parameter1 = -1;
136 static int hf_iscsi_Parameter2 = -1;
137 static int hf_iscsi_Parameter3 = -1;
138 static int hf_iscsi_Reject_Reason = -1;
139 static int hf_iscsi_snack_type = -1;
140 static int hf_iscsi_BegRun = -1;
141 static int hf_iscsi_RunLength = -1;
143 /* Initialize the subtree pointers */
144 static gint ett_iscsi_KeyValues = -1;
145 static gint ett_iscsi_CDB = -1;
146 static gint ett_iscsi_Flags = -1;
151 #define TARGET_OPCODE_BIT 0x20
153 #define ISCSI_OPCODE_NOP_OUT 0x00
154 #define ISCSI_OPCODE_SCSI_COMMAND 0x01
155 #define ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_COMMAND 0x02
156 #define ISCSI_OPCODE_LOGIN_COMMAND 0x03
157 #define ISCSI_OPCODE_TEXT_COMMAND 0x04
158 #define ISCSI_OPCODE_SCSI_DATA_OUT 0x05
159 #define ISCSI_OPCODE_LOGOUT_COMMAND 0x06
160 #define ISCSI_OPCODE_SNACK_REQUEST 0x10
162 #define ISCSI_OPCODE_NOP_IN (0x20 | X_BIT | I_BIT)
163 #define ISCSI_OPCODE_SCSI_RESPONSE (0x21 | X_BIT | I_BIT)
164 #define ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_RESPONSE (0x22 | X_BIT | I_BIT)
165 #define ISCSI_OPCODE_LOGIN_RESPONSE (0x23 | X_BIT | I_BIT)
166 #define ISCSI_OPCODE_TEXT_RESPONSE (0x24 | X_BIT | I_BIT)
167 #define ISCSI_OPCODE_SCSI_DATA_IN (0x25 | X_BIT | I_BIT)
168 #define ISCSI_OPCODE_LOGOUT_RESPONSE (0x26 | X_BIT | I_BIT)
169 #define ISCSI_OPCODE_R2T (0x31 | X_BIT | I_BIT)
170 #define ISCSI_OPCODE_ASYNC_MESSAGE (0x32 | X_BIT | I_BIT)
171 #define ISCSI_OPCODE_REJECT (0x3f | X_BIT | I_BIT)
173 static const value_string iscsi_opcodes[] = {
174 { ISCSI_OPCODE_NOP_OUT, "NOP Out" },
175 { ISCSI_OPCODE_SCSI_COMMAND, "SCSI Command" },
176 { ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_COMMAND, "SCSI Task Management Command" },
177 { ISCSI_OPCODE_LOGIN_COMMAND, "Login Command" },
178 { ISCSI_OPCODE_TEXT_COMMAND, "Text Command" },
179 { ISCSI_OPCODE_SCSI_DATA_OUT, "SCSI Write Data" },
180 { ISCSI_OPCODE_LOGOUT_COMMAND, "Logout Command" },
181 { ISCSI_OPCODE_SNACK_REQUEST, "SNACK Request" },
183 { ISCSI_OPCODE_NOP_IN, "NOP In" },
184 { ISCSI_OPCODE_SCSI_RESPONSE, "SCSI Command Response" },
185 { ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_RESPONSE, "SCSI Task Management Response" },
186 { ISCSI_OPCODE_LOGIN_RESPONSE, "Login Response" },
187 { ISCSI_OPCODE_TEXT_RESPONSE, "Text Response" },
188 { ISCSI_OPCODE_SCSI_DATA_IN, "SCSI Read Data" },
189 { ISCSI_OPCODE_LOGOUT_RESPONSE, "Logout Response" },
190 { ISCSI_OPCODE_R2T, "Ready To Transfer" },
191 { ISCSI_OPCODE_ASYNC_MESSAGE, "Asynchronous Message" },
192 { ISCSI_OPCODE_REJECT, "Reject"},
196 static const true_false_string iscsi_meaning_X = {
201 static const true_false_string iscsi_meaning_I = {
202 "Immediate delivery",
206 static const true_false_string iscsi_meaning_F = {
207 "Final PDU in sequence",
208 "Not final PDU in sequence"
211 static const true_false_string iscsi_meaning_T = {
212 "Transit to next login stage",
213 "Stay in current login stage"
216 static const true_false_string iscsi_meaning_S = {
217 "Response contains SCSI status",
218 "Response does not contain SCSI status"
221 static const true_false_string iscsi_meaning_R = {
222 "Data will be read from target",
223 "No data will be read from target"
226 static const true_false_string iscsi_meaning_W = {
227 "Data will be written to target",
228 "No data will be written to target"
231 static const true_false_string iscsi_meaning_o = {
232 "Read part of bi-directional command overflowed",
233 "No overflow of read part of bi-directional command",
236 static const true_false_string iscsi_meaning_u = {
237 "Read part of bi-directional command underflowed",
238 "No underflow of read part of bi-directional command",
241 static const true_false_string iscsi_meaning_O = {
242 "Residual overflow occurred",
243 "No residual overflow occurred",
246 static const true_false_string iscsi_meaning_U = {
247 "Residual underflow occurred",
248 "No residual underflow occurred",
251 static const value_string iscsi_scsi_responses[] = {
252 { 0, "Command completed at target" },
253 { 1, "Response does not contain SCSI status"},
257 static const value_string iscsi_scsicommand_taskattrs[] = {
261 {3, "Head of Queue"},
266 static const value_string iscsi_scsi_cdb0[] = {
267 {0x00, "TEST_UNIT_READY"},
268 {0x01, "REZERO_UNIT"},
269 {0x03, "REQUEST_SENSE"},
270 {0x04, "FORMAT_UNIT"},
271 {0x05, "READ_BLOCK_LIMITS"},
272 {0x07, "REASSIGN_BLOCKS"},
276 {0x0f, "READ_REVERSE"},
277 {0x10, "WRITE_FILEMARKS"},
280 {0x14, "RECOVER_BUFFERED_DATA"},
281 {0x15, "MODE_SELECT"},
286 {0x1a, "MODE_SENSE"},
287 {0x1b, "START_STOP"},
288 {0x1c, "RECEIVE_DIAGNOSTIC"},
289 {0x1d, "SEND_DIAGNOSTIC"},
290 {0x1e, "ALLOW_MEDIUM_REMOVAL"},
291 {0x24, "SET_WINDOW"},
292 {0x25, "READ_CAPACITY"},
296 {0x2e, "WRITE_VERIFY"},
298 {0x30, "SEARCH_HIGH"},
299 {0x31, "SEARCH_EQUAL"},
300 {0x32, "SEARCH_LOW"},
301 {0x33, "SET_LIMITS"},
303 {0x34, "READ_POSITION"},
304 {0x35, "SYNCHRONIZE_CACHE"},
305 {0x36, "LOCK_UNLOCK_CACHE"},
306 {0x37, "READ_DEFECT_DATA"},
307 {0x38, "MEDIUM_SCAN"},
309 {0x3a, "COPY_VERIFY"},
310 {0x3b, "WRITE_BUFFER"},
311 {0x3c, "READ_BUFFER"},
312 {0x3d, "UPDATE_BLOCK"},
314 {0x3f, "WRITE_LONG"},
315 {0x40, "CHANGE_DEFINITION"},
316 {0x41, "WRITE_SAME"},
318 {0x4c, "LOG_SELECT"},
320 {0x55, "MODE_SELECT_10"},
321 {0x5a, "MODE_SENSE_10"},
322 {0xa5, "MOVE_MEDIUM"},
325 {0xae, "WRITE_VERIFY_12"},
326 {0xb0, "SEARCH_HIGH_12"},
327 {0xb1, "SEARCH_EQUAL_12"},
328 {0xb2, "SEARCH_LOW_12"},
329 {0xb8, "READ_ELEMENT_STATUS"},
330 {0xb6, "SEND_VOLUME_TAG"},
331 {0xea, "WRITE_LONG_2"},
335 static const value_string iscsi_scsi_statuses[] = {
337 {0x01, "Check condition"},
338 {0x02, "Condition good"},
340 {0x08, "Intermediate good"},
341 {0x0a, "Intermediate c good"},
342 {0x0c, "Reservation conflict"},
343 {0x11, "Command terminated"},
344 {0x14, "Queue full"},
348 static const value_string iscsi_task_responses[] = {
349 {0, "Function complete"},
350 {1, "Task not in task set"},
351 {2, "LUN does not exist"},
352 {255, "Function rejected"},
356 static const value_string iscsi_task_functions[] = {
358 {2, "Abort Task Set"},
360 {4, "Clear Task Set"},
361 {5, "Logical Unit Reset"},
362 {6, "Target Warm Reset"},
363 {7, "Target Cold Reset"},
367 static const value_string iscsi_login_status[] = {
369 {0x0101, "Target moved temporarily"},
370 {0x0102, "Target moved permanently"},
371 {0x0200, "Initiator error (miscellaneous error)"},
372 {0x0201, "Athentication failed"},
373 {0x0202, "Authorisation failure"},
374 {0x0203, "Target not found"},
375 {0x0204, "Target removed"},
376 {0x0205, "Unsupported version"},
377 {0x0206, "Too many connections"},
378 {0x0207, "Missing parameter"},
379 {0x0208, "Can't include in session"},
380 {0x0209, "Session type not supported"},
381 {0x0300, "Target error (miscellaneous error)"},
382 {0x0301, "Service unavailable"},
383 {0x0302, "Out of resources"},
387 static const value_string iscsi_login_stage[] = {
388 {0, "Security negotiation"},
389 {1, "Operational negotiation"},
390 {3, "Full feature phase"},
394 static const value_string iscsi_logout_reasons[] = {
395 {0, "Close session"},
396 {1, "Close connection"},
397 {2, "Remove connection for recovery"},
401 static const value_string iscsi_logout_response[] = {
402 {0, "Connection closed successfully"},
403 {1, "CID not found"},
404 {2, "Connection recovery not supported"},
405 {3, "Cleanup failed for various reasons"},
409 static const value_string iscsi_asyncevents[] = {
410 {0, "A SCSI asynchronous event is reported in the sense data"},
411 {1, "Target requests logout"},
412 {2, "Target will/has dropped connection"},
413 {3, "Target will/has dropped all connections"},
417 static const value_string iscsi_snack_types[] = {
423 static const value_string iscsi_reject_reasons[] = {
424 {0x01, "Full feature phase command before login"},
425 {0x02, "Data (payload) digest error"},
426 {0x03, "Data SNACK reject"},
427 {0x04, "Protocol error"},
428 {0x05, "Command not supported in this session type"},
429 {0x06, "Immediate command reject (too many immediate commands)"},
430 {0x07, "Task in progress"},
431 {0x08, "Invalid SNACK"},
432 {0x09, "Bookmark reject (no bookmark for this initiator task tag)"},
433 {0x0a, "Bookmark reject (can't generate bookmark - out of resources)"},
434 {0x0b, "Negotiation reset"},
438 /*****************************************************************/
440 /* CRC LOOKUP TABLE */
441 /* ================ */
442 /* The following CRC lookup table was generated automagically */
443 /* by the Rocksoft^tm Model CRC Algorithm Table Generation */
444 /* Program V1.0 using the following model parameters: */
446 /* Width : 4 bytes. */
447 /* Poly : 0x1EDC6F41L */
448 /* Reverse : TRUE. */
450 /* For more information on the Rocksoft^tm Model CRC Algorithm, */
451 /* see the document titled "A Painless Guide to CRC Error */
452 /* Detection Algorithms" by Ross Williams */
453 /* (ross@guest.adelaide.edu.au.). This document is likely to be */
454 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
456 /*****************************************************************/
458 static guint32 crc32Table[256] = {
459 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
460 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
461 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
462 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
463 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
464 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
465 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
466 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
467 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
468 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
469 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
470 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
471 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
472 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
473 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
474 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
475 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
476 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
477 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
478 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
479 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
480 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
481 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
482 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
483 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
484 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
485 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
486 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
487 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
488 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
489 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
490 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
491 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
492 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
493 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
494 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
495 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
496 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
497 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
498 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
499 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
500 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
501 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
502 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
503 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
504 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
505 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
506 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
507 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
508 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
509 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
510 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
511 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
512 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
513 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
514 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
515 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
516 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
517 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
518 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
519 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
520 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
521 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
522 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
525 #define CRC32C_PRELOAD 0xffffffff
528 calculateCRC32(const void *buf, int len, guint32 crc) {
529 guint8 *p = (guint8 *)buf;
531 crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
536 iscsi_min(int a, int b) {
537 return (a < b)? a : b;
541 addTextKeys(proto_tree *tt, tvbuff_t *tvb, gint offset, guint32 text_len) {
542 const gint limit = offset + text_len;
543 while(offset < limit) {
544 gint len = tvb_strnlen(tvb, offset, limit - offset);
546 len = limit - offset;
549 proto_tree_add_item(tt, hf_iscsi_KeyValue, tvb, offset, len, FALSE);
556 handleHeaderDigest(proto_item *ti, tvbuff_t *tvb, guint offset, int headerLen) {
557 int available_bytes = tvb_length_remaining(tvb, offset);
558 if(available_bytes >= (headerLen + 4)) {
559 guint32 crc = ~calculateCRC32(tvb_get_ptr(tvb, offset, headerLen), headerLen, CRC32C_PRELOAD);
560 guint32 sent = tvb_get_ntohl(tvb, offset + headerLen);
561 if(crc == sent || enable_force_header_digest_crc32) {
563 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Good CRC32)", sent);
567 proto_tree_add_uint_format(ti, hf_iscsi_HeaderDigest32, tvb, offset + headerLen, 4, sent, "HeaderDigest: 0x%08x (Bad CRC32)", sent);
575 /* Code to actually dissect the packets */
577 dissect_iscsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 opcode, const char *opcode_str, guint32 data_segment_len) {
578 guint original_offset = offset;
580 char *scsi_command_name = NULL;
581 guint cdb_offset = offset + 32; /* offset of CDB from start of PDU */
582 guint end_offset = offset + tvb_length_remaining(tvb, offset);
584 /* Make entries in Protocol column and Info column on summary display */
585 if (check_col(pinfo->fd, COL_PROTOCOL))
586 col_set_str(pinfo->fd, COL_PROTOCOL, "iSCSI");
588 if (check_col(pinfo->fd, COL_INFO)) {
590 col_add_str(pinfo->fd, COL_INFO, (char *)opcode_str);
592 if((opcode & ~(X_BIT | I_BIT)) == ISCSI_OPCODE_SCSI_COMMAND) {
594 guint8 cdb0 = tvb_get_guint8(tvb, cdb_offset);
595 scsi_command_name = match_strval(cdb0, iscsi_scsi_cdb0);
596 if(cdb0 == 0x08 || cdb0 == 0x0a) {
597 /* READ_6 and WRITE_6 */
598 guint lba = tvb_get_ntohl(tvb, cdb_offset) & 0x1fffff;
599 guint len = tvb_get_guint8(tvb, cdb_offset + 4);
600 col_append_fstr(pinfo->fd, COL_INFO, " (%s LBA 0x%06x len 0x%02x)", scsi_command_name, lba, len);
602 else if(cdb0 == 0x28 || cdb0 == 0x2a) {
603 /* READ_10 and WRITE_10 */
604 guint lba = tvb_get_ntohl(tvb, cdb_offset + 2);
605 guint len = tvb_get_ntohs(tvb, cdb_offset + 7);
606 col_append_fstr(pinfo->fd, COL_INFO, " (%s LBA 0x%08x len 0x%04x)", scsi_command_name, lba, len);
608 else if(scsi_command_name != NULL)
609 col_append_fstr(pinfo->fd, COL_INFO, " (%s)", scsi_command_name);
611 else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
612 /* SCSI Command Response */
613 const char *blurb = NULL;
614 /* look at response byte */
615 if(tvb_get_guint8(tvb, offset + 2) == 0) {
616 /* command completed at target */
617 blurb = match_strval(tvb_get_guint8(tvb, offset + 3) >> 1, iscsi_scsi_statuses);
620 blurb = "Target Failure";
622 col_append_fstr(pinfo->fd, COL_INFO, " (%s)", blurb);
626 /* In the interest of speed, if "tree" is NULL, don't do any
627 work not necessary to generate protocol tree items. */
630 /* create display subtree for the protocol */
631 ti = proto_tree_add_protocol_format(tree, proto_iscsi, tvb,
632 offset, 0, "iSCSI (%s)",
635 proto_tree_add_uint(ti, hf_iscsi_Opcode, tvb,
636 offset + 0, 1, opcode);
637 if((opcode & TARGET_OPCODE_BIT) == 0) {
638 /* initiator -> target */
639 gint b = tvb_get_guint8(tvb, offset + 0);
640 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT &&
641 opcode != ISCSI_OPCODE_LOGOUT_COMMAND &&
642 opcode != ISCSI_OPCODE_SNACK_REQUEST)
643 proto_tree_add_boolean(ti, hf_iscsi_X, tvb, offset + 0, 1, b);
644 if(opcode != ISCSI_OPCODE_SCSI_DATA_OUT)
645 proto_tree_add_boolean(ti, hf_iscsi_I, tvb, offset + 0, 1, b);
648 if(opcode == ISCSI_OPCODE_NOP_OUT) {
650 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
651 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
652 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
653 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
654 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
655 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
656 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
657 if(end_offset > offset) {
658 int ping_data_len = iscsi_min(data_segment_len, end_offset - offset);
659 if(ping_data_len > 0) {
660 proto_tree_add_item(ti, hf_iscsi_ping_data, tvb, offset, ping_data_len, FALSE);
661 offset += ping_data_len;
663 if(offset < end_offset && (offset & 3) != 0) {
664 int padding = 4 - (offset & 3);
665 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
670 else if(opcode == ISCSI_OPCODE_NOP_IN) {
672 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
673 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
674 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
675 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
676 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
677 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
678 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
679 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
680 if(end_offset > offset) {
681 int ping_data_len = iscsi_min(data_segment_len, end_offset - offset);
682 if(ping_data_len > 0) {
683 proto_tree_add_item(ti, hf_iscsi_ping_data, tvb, offset, ping_data_len, FALSE);
684 offset += ping_data_len;
686 if(offset < end_offset && (offset & 3) != 0) {
687 int padding = 4 - (offset & 3);
688 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
693 else if(opcode == ISCSI_OPCODE_SCSI_COMMAND) {
696 gint b = tvb_get_guint8(tvb, offset + 1);
697 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
698 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
700 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_F, tvb, offset + 1, 1, b);
701 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_R, tvb, offset + 1, 1, b);
702 proto_tree_add_boolean(tt, hf_iscsi_SCSICommand_W, tvb, offset + 1, 1, b);
703 proto_tree_add_uint(tt, hf_iscsi_SCSICommand_Attr, tvb, offset + 1, 1, b);
705 proto_tree_add_item(ti, hf_iscsi_SCSICommand_CRN, tvb, offset + 3, 1, FALSE);
706 proto_tree_add_item(ti, hf_iscsi_TotalAHSLength, tvb, offset + 4, 1, FALSE);
707 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
708 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
709 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
710 proto_tree_add_item(ti, hf_iscsi_ExpectedDataTransferLength, tvb, offset + 20, 4, FALSE);
711 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
712 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
714 /* dissect a little of the CDB for the most common
716 guint8 cdb0 = tvb_get_guint8(tvb, cdb_offset);
719 /* FIXME - extended CDB */
720 if(scsi_command_name == NULL)
721 scsi_command_name = match_strval(cdb0, iscsi_scsi_cdb0);
722 if(cdb0 == 0x08 || cdb0 == 0x0a) {
723 /* READ_6 and WRITE_6 */
724 guint lba = tvb_get_ntohl(tvb, cdb_offset) & 0x1fffff;
725 guint len = tvb_get_guint8(tvb, cdb_offset + 4);
726 tf = proto_tree_add_uint_format(ti, hf_iscsi_SCSICommand_CDB0, tvb, cdb_offset, cdb_len, cdb0, "CDB: %s LBA 0x%06x len 0x%02x", scsi_command_name, lba, len);
728 else if(cdb0 == 0x28 || cdb0 == 0x2a) {
729 /* READ_10 and WRITE_10 */
730 guint lba = tvb_get_ntohl(tvb, cdb_offset + 2);
731 guint len = tvb_get_ntohs(tvb, cdb_offset + 7);
732 tf = proto_tree_add_uint_format(ti, hf_iscsi_SCSICommand_CDB0, tvb, cdb_offset, cdb_len, cdb0, "CDB: %s LBA 0x%08x len 0x%04x", scsi_command_name, lba, len);
735 tf = proto_tree_add_uint(ti, hf_iscsi_SCSICommand_CDB0, tvb, cdb_offset, cdb_len, cdb0);
737 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_CDB);
738 proto_tree_add_item(tt, hf_iscsi_SCSICommand_CDB, tvb, cdb_offset, cdb_len, FALSE);
740 offset = cdb_offset + cdb_len + handleHeaderDigest(ti, tvb, offset, cdb_offset + cdb_len);
742 if(end_offset > offset) {
743 int immediate_data_len = iscsi_min(data_segment_len, end_offset - offset);
744 if(immediate_data_len > 0) {
745 proto_tree_add_item(ti, hf_iscsi_immediate_data, tvb, offset, immediate_data_len, FALSE);
746 offset += immediate_data_len;
748 if(offset < end_offset && (offset & 3) != 0) {
749 int padding = 4 - (offset & 3);
750 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
755 else if(opcode == ISCSI_OPCODE_SCSI_RESPONSE) {
758 gint b = tvb_get_guint8(tvb, offset + 1);
759 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
760 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
762 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_o, tvb, offset + 1, 1, b);
763 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_u, tvb, offset + 1, 1, b);
764 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_O, tvb, offset + 1, 1, b);
765 proto_tree_add_boolean(tt, hf_iscsi_SCSIResponse_U, tvb, offset + 1, 1, b);
767 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Response, tvb, offset + 2, 1, FALSE);
768 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
769 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
770 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
771 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_ResidualCount, tvb, offset + 20, 4, FALSE);
772 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
773 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
774 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
775 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
776 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_BidiReadResidualCount, tvb, offset + 44, 4, FALSE);
777 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
778 if(end_offset > offset) {
779 int sense_data_len = iscsi_min(data_segment_len, end_offset - offset);
780 if(sense_data_len > 0) {
781 proto_tree_add_item(ti, hf_iscsi_sense_data, tvb, offset, sense_data_len, FALSE);
782 offset += sense_data_len;
784 if(offset < end_offset && (offset & 3) != 0) {
785 int padding = 4 - (offset & 3);
786 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
791 else if(opcode == ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_COMMAND) {
792 /* SCSI Task Command */
793 proto_tree_add_item(ti, hf_iscsi_SCSITask_Function, tvb, offset + 1, 1, FALSE);
794 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
795 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
796 proto_tree_add_item(ti, hf_iscsi_SCSITask_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
797 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
798 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
799 proto_tree_add_item(ti, hf_iscsi_RefCmdSN, tvb, offset + 32, 4, FALSE);
800 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
802 else if(opcode == ISCSI_OPCODE_SCSI_TASK_MANAGEMENT_RESPONSE) {
803 /* SCSI Task Response */
804 proto_tree_add_item(ti, hf_iscsi_SCSITask_Response, tvb, offset + 2, 1, FALSE);
805 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
806 proto_tree_add_item(ti, hf_iscsi_SCSITask_ReferencedTaskTag, tvb, offset + 20, 4, FALSE);
807 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
808 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
809 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
810 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
812 else if(opcode == ISCSI_OPCODE_LOGIN_COMMAND) {
815 gint b = tvb_get_guint8(tvb, offset + 1);
817 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
818 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
821 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
822 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
823 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
825 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
826 proto_tree_add_item(ti, hf_iscsi_VersionMin, tvb, offset + 3, 1, FALSE);
827 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
828 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
829 proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
830 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
831 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
832 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
833 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
834 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
835 if(end_offset > offset) {
836 int text_len = iscsi_min(data_segment_len, end_offset - offset);
838 proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
839 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
840 offset = addTextKeys(tt, tvb, offset, text_len);
842 if(offset < end_offset && (offset & 3) != 0) {
843 int padding = 4 - (offset & 3);
844 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
849 else if(opcode == ISCSI_OPCODE_LOGIN_RESPONSE) {
852 gint b = tvb_get_guint8(tvb, offset + 1);
854 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
855 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
858 proto_tree_add_boolean(ti, hf_iscsi_Login_T, tvb, offset + 1, 1, b);
859 proto_tree_add_item(ti, hf_iscsi_Login_CSG, tvb, offset + 1, 1, FALSE);
860 proto_tree_add_item(ti, hf_iscsi_Login_NSG, tvb, offset + 1, 1, FALSE);
863 proto_tree_add_item(ti, hf_iscsi_VersionMax, tvb, offset + 2, 1, FALSE);
864 proto_tree_add_item(ti, hf_iscsi_VersionActive, tvb, offset + 3, 1, FALSE);
865 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
866 proto_tree_add_item(ti, hf_iscsi_ISID, tvb, offset + 12, 2, FALSE);
867 proto_tree_add_item(ti, hf_iscsi_TSID, tvb, offset + 14, 2, FALSE);
868 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
869 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
870 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
871 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
872 proto_tree_add_item(ti, hf_iscsi_Login_Status, tvb, offset + 36, 2, FALSE);
873 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
874 if(end_offset > offset) {
875 int text_len = iscsi_min(data_segment_len, end_offset - offset);
877 proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
878 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
879 offset = addTextKeys(tt, tvb, offset, text_len);
881 if(offset < end_offset && (offset & 3) != 0) {
882 int padding = 4 - (offset & 3);
883 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
888 else if(opcode == ISCSI_OPCODE_TEXT_COMMAND) {
891 gint b = tvb_get_guint8(tvb, offset + 1);
892 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
893 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
895 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
896 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
898 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
899 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
900 proto_tree_add_item(ti, hf_iscsi_CmdSN, tvb, offset + 24, 4, FALSE);
901 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
902 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
903 if(end_offset > offset) {
904 int text_len = iscsi_min(data_segment_len, end_offset - offset);
906 proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
907 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
908 offset = addTextKeys(tt, tvb, offset, text_len);
910 if(offset < end_offset && (offset & 3) != 0) {
911 int padding = 4 - (offset & 3);
912 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
917 else if(opcode == ISCSI_OPCODE_TEXT_RESPONSE) {
920 gint b = tvb_get_guint8(tvb, offset + 1);
921 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
922 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
924 proto_tree_add_boolean(tt, hf_iscsi_Text_F, tvb, offset + 1, 1, b);
925 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
927 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
928 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
929 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
930 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
931 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
932 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
933 if(end_offset > offset) {
934 int text_len = iscsi_min(data_segment_len, end_offset - offset);
936 proto_item *tf = proto_tree_add_text(ti, tvb, offset, text_len, "Key/Value Pairs");
937 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_KeyValues);
938 offset = addTextKeys(tt, tvb, offset, text_len);
940 if(offset < end_offset && (offset & 3) != 0) {
941 int padding = 4 - (offset & 3);
942 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
947 else if(opcode == ISCSI_OPCODE_SCSI_DATA_OUT) {
948 /* SCSI Data Out (write) */
950 gint b = tvb_get_guint8(tvb, offset + 1);
951 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
952 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
954 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
956 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
957 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
958 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
959 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
960 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
961 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
962 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
963 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
964 if(end_offset > offset) {
965 int write_data_len = iscsi_min(data_segment_len, end_offset - offset);
966 if(write_data_len > 0) {
967 proto_tree_add_item(ti, hf_iscsi_write_data, tvb, offset, write_data_len, FALSE);
968 offset += write_data_len;
970 if(offset < end_offset && (offset & 3) != 0) {
971 int padding = 4 - (offset & 3);
972 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
977 else if(opcode == ISCSI_OPCODE_SCSI_DATA_IN) {
978 /* SCSI Data In (read) */
980 gint b = tvb_get_guint8(tvb, offset + 1);
981 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
982 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
984 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_F, tvb, offset + 1, 1, b);
985 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_O, tvb, offset + 1, 1, b);
986 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_U, tvb, offset + 1, 1, b);
987 proto_tree_add_boolean(tt, hf_iscsi_SCSIData_S, tvb, offset + 1, 1, b);
989 proto_tree_add_item(ti, hf_iscsi_SCSIResponse_Status, tvb, offset + 3, 1, FALSE);
990 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
991 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
992 proto_tree_add_item(ti, hf_iscsi_SCSIData_ResidualCount, tvb, offset + 20, 4, FALSE);
993 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
994 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
995 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
996 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
997 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
998 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
999 if(end_offset > offset) {
1000 int read_data_len = iscsi_min(data_segment_len, end_offset - offset);
1001 if(read_data_len > 0) {
1002 proto_tree_add_item(ti, hf_iscsi_read_data, tvb, offset, read_data_len, FALSE);
1003 offset += read_data_len;
1005 if(offset < end_offset && (offset & 3) != 0) {
1006 int padding = 4 - (offset & 3);
1007 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
1012 else if(opcode == ISCSI_OPCODE_LOGOUT_COMMAND) {
1013 /* Logout Command */
1014 proto_tree_add_item(ti, hf_iscsi_CID, tvb, offset + 8, 2, FALSE);
1015 proto_tree_add_item(ti, hf_iscsi_Logout_Reason, tvb, offset + 11, 1, FALSE);
1016 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1017 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1018 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1020 else if(opcode == ISCSI_OPCODE_LOGOUT_RESPONSE) {
1021 /* Logout Response */
1022 proto_tree_add_item(ti, hf_iscsi_Logout_Response, tvb, offset + 2, 1, FALSE);
1023 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1024 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1025 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1026 proto_tree_add_item(ti, hf_iscsi_Time2Wait, tvb, offset + 40, 2, FALSE);
1027 proto_tree_add_item(ti, hf_iscsi_Time2Retain, tvb, offset + 42, 2, FALSE);
1028 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1030 else if(opcode == ISCSI_OPCODE_SNACK_REQUEST) {
1033 gint b = tvb_get_guint8(tvb, offset + 1);
1035 proto_item *tf = proto_tree_add_uint(ti, hf_iscsi_Flags, tvb, offset + 1, 1, b);
1036 proto_tree *tt = proto_item_add_subtree(tf, ett_iscsi_Flags);
1039 proto_tree_add_item(ti, hf_iscsi_snack_type, tvb, offset + 1, 1, b);
1041 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1042 proto_tree_add_item(ti, hf_iscsi_BegRun, tvb, offset + 20, 4, FALSE);
1043 proto_tree_add_item(ti, hf_iscsi_RunLength, tvb, offset + 24, 4, FALSE);
1044 proto_tree_add_item(ti, hf_iscsi_ExpStatSN, tvb, offset + 28, 4, FALSE);
1045 proto_tree_add_item(ti, hf_iscsi_ExpDataSN, tvb, offset + 36, 4, FALSE);
1046 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1048 else if(opcode == ISCSI_OPCODE_R2T) {
1050 proto_tree_add_item(ti, hf_iscsi_InitiatorTaskTag, tvb, offset + 16, 4, FALSE);
1051 proto_tree_add_item(ti, hf_iscsi_TargetTransferTag, tvb, offset + 20, 4, FALSE);
1052 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1053 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1054 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1055 proto_tree_add_item(ti, hf_iscsi_R2TSN, tvb, offset + 36, 4, FALSE);
1056 proto_tree_add_item(ti, hf_iscsi_BufferOffset, tvb, offset + 40, 4, FALSE);
1057 proto_tree_add_item(ti, hf_iscsi_DesiredDataLength, tvb, offset + 44, 4, FALSE);
1058 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1060 else if(opcode == ISCSI_OPCODE_ASYNC_MESSAGE) {
1061 /* Asynchronous Message */
1062 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1063 proto_tree_add_item(ti, hf_iscsi_LUN, tvb, offset + 8, 8, FALSE);
1064 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1065 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1066 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1067 proto_tree_add_item(ti, hf_iscsi_AsyncEvent, tvb, offset + 36, 1, FALSE);
1068 proto_tree_add_item(ti, hf_iscsi_EventVendorCode, tvb, offset + 37, 1, FALSE);
1069 proto_tree_add_item(ti, hf_iscsi_Parameter1, tvb, offset + 38, 2, FALSE);
1070 proto_tree_add_item(ti, hf_iscsi_Parameter2, tvb, offset + 40, 2, FALSE);
1071 proto_tree_add_item(ti, hf_iscsi_Parameter3, tvb, offset + 42, 2, FALSE);
1072 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1074 else if(opcode == ISCSI_OPCODE_REJECT) {
1076 proto_tree_add_item(ti, hf_iscsi_Reject_Reason, tvb, offset + 2, 1, FALSE);
1077 proto_tree_add_uint(ti, hf_iscsi_DataSegmentLength, tvb, offset + 5, 3, data_segment_len);
1078 proto_tree_add_item(ti, hf_iscsi_StatSN, tvb, offset + 24, 4, FALSE);
1079 proto_tree_add_item(ti, hf_iscsi_ExpCmdSN, tvb, offset + 28, 4, FALSE);
1080 proto_tree_add_item(ti, hf_iscsi_MaxCmdSN, tvb, offset + 32, 4, FALSE);
1081 proto_tree_add_item(ti, hf_iscsi_DataSN, tvb, offset + 36, 4, FALSE);
1082 offset += 48 + handleHeaderDigest(ti, tvb, offset, 48);
1083 if(end_offset > offset) {
1084 int error_pdu_len = iscsi_min(data_segment_len, end_offset - offset);
1085 if(error_pdu_len > 0) {
1086 proto_tree_add_item(ti, hf_iscsi_error_pdu_data, tvb, offset, error_pdu_len, FALSE);
1087 offset += error_pdu_len;
1089 if(offset < end_offset && (offset & 3) != 0) {
1090 int padding = 4 - (offset & 3);
1091 proto_tree_add_item(ti, hf_iscsi_Padding, tvb, offset, padding, FALSE);
1097 proto_item_set_len(ti, offset - original_offset);
1100 /* FIXME - this really should gobble up digests and data segment */
1104 return offset - original_offset;
1108 dissect_iscsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
1110 /* Set up structures needed to add the protocol subtree and manage it */
1112 guint32 available_bytes = tvb_length_remaining(tvb, offset);
1114 /* quick check to see if the packet is long enough to contain a
1115 * whole iSCSI header segment */
1116 if (available_bytes < 48) {
1117 /* no, so give up */
1121 /* (potentially) process multiple iSCSI PDUs per packet */
1122 while(available_bytes >= 48) {
1123 const char *opcode_str = NULL;
1124 guint32 data_segment_len;
1125 guint8 opcode = tvb_get_guint8(tvb, offset + 0);
1127 if((opcode & TARGET_OPCODE_BIT) == 0) {
1128 /* initiator -> target */
1129 /* mask out X and I bits */
1130 opcode &= ~(X_BIT | I_BIT);
1132 opcode_str = match_strval(opcode, iscsi_opcodes);
1133 data_segment_len = tvb_get_ntohl(tvb, offset + 4) & 0x00ffffff;
1135 /* try and distinguish between data and real headers */
1136 if(opcode_str == NULL ||
1137 (enable_bogosity_filter &&
1138 (data_segment_len > bogus_pdu_data_length_threshold ||
1139 available_bytes > (data_segment_len + 48 + bogus_pdu_max_digest_padding)))) {
1141 /* scanning a packet for a valid header is very slow so
1142 * for the moment we just give up */
1145 /* see if the next word starts a header */
1148 available_bytes -= inc;
1152 dissect_iscsi_pdu(tvb, pinfo, tree, offset, opcode, opcode_str, data_segment_len);
1161 /* Register the protocol with Ethereal */
1163 /* this format is require because a script is used to build the C function
1164 that calls all the protocol registration.
1168 proto_register_iscsi(void)
1171 /* Setup list of header fields See Section 1.6.1 for details*/
1172 static hf_register_info hf[] = {
1173 { &hf_iscsi_Padding,
1174 { "Padding", "iscsi.padding",
1175 FT_BYTES, BASE_HEX, NULL, 0,
1176 "Padding to 4 byte boundary", HFILL }
1178 { &hf_iscsi_ping_data,
1179 { "PingData", "iscsi.pingdata",
1180 FT_BYTES, BASE_HEX, NULL, 0,
1181 "Ping Data", HFILL }
1183 { &hf_iscsi_immediate_data,
1184 { "ImmediateData", "iscsi.immediatedata",
1185 FT_BYTES, BASE_HEX, NULL, 0,
1186 "Immediate Data", HFILL }
1188 { &hf_iscsi_sense_data,
1189 { "SenseData", "iscsi.sensedata",
1190 FT_BYTES, BASE_HEX, NULL, 0,
1191 "Sense Data", HFILL }
1193 { &hf_iscsi_write_data,
1194 { "WriteData", "iscsi.writedata",
1195 FT_BYTES, BASE_HEX, NULL, 0,
1196 "Write Data", HFILL }
1198 { &hf_iscsi_read_data,
1199 { "ReadData", "iscsi.readdata",
1200 FT_BYTES, BASE_HEX, NULL, 0,
1201 "Read Data", HFILL }
1203 { &hf_iscsi_error_pdu_data,
1204 { "ErrorPDUData", "iscsi.errorpdudata",
1205 FT_BYTES, BASE_HEX, NULL, 0,
1206 "Error PDU Data", HFILL }
1208 { &hf_iscsi_HeaderDigest32,
1209 { "HeaderDigest", "iscsi.headerdigest",
1210 FT_UINT32, BASE_HEX, NULL, 0,
1211 "Header Digest", HFILL }
1214 { "Opcode", "iscsi.opcode",
1215 FT_UINT8, BASE_HEX, VALS(iscsi_opcodes), 0,
1220 FT_BOOLEAN, 8, TFS(&iscsi_meaning_X), 0x80,
1221 "Command Retry", HFILL }
1225 FT_BOOLEAN, 8, TFS(&iscsi_meaning_I), 0x40,
1226 "Immediate delivery", HFILL }
1229 { "Flags", "iscsi.flags",
1230 FT_UINT8, BASE_HEX, NULL, 0,
1231 "Opcode specific flags", HFILL }
1233 { &hf_iscsi_SCSICommand_F,
1234 { "F", "iscsi.scsicommand.F",
1235 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
1236 "PDU completes command", HFILL }
1238 { &hf_iscsi_SCSICommand_R,
1239 { "R", "iscsi.scsicommand.R",
1240 FT_BOOLEAN, 8, TFS(&iscsi_meaning_R), 0x40,
1241 "Command reads from SCSI target", HFILL }
1243 { &hf_iscsi_SCSICommand_W,
1244 { "W", "iscsi.scsicommand.W",
1245 FT_BOOLEAN, 8, TFS(&iscsi_meaning_W), 0x20,
1246 "Command writes to SCSI target", HFILL }
1248 { &hf_iscsi_SCSICommand_Attr,
1249 { "Attr", "iscsi.scsicommand.attr",
1250 FT_UINT8, BASE_HEX, VALS(iscsi_scsicommand_taskattrs), 0x07,
1251 "SCSI task attributes", HFILL }
1253 { &hf_iscsi_SCSICommand_CRN,
1254 { "CRN", "iscsi.scsicommand.crn",
1255 FT_UINT8, BASE_HEX, NULL, 0,
1256 "SCSI command reference number", HFILL }
1258 { &hf_iscsi_SCSICommand_AddCDB,
1259 { "AddCDB", "iscsi.scsicommand.addcdb",
1260 FT_UINT8, BASE_HEX, NULL, 0,
1261 "Additional CDB length (in 4 byte units)", HFILL }
1263 { &hf_iscsi_DataSegmentLength,
1264 { "DataSegmentLength", "iscsi.datasegmentlength",
1265 FT_UINT32, BASE_HEX, NULL, 0,
1266 "Data segment length (bytes)", HFILL }
1268 { &hf_iscsi_TotalAHSLength,
1269 { "TotalAHSLength", "iscsi.totalahslength",
1270 FT_UINT8, BASE_HEX, NULL, 0,
1271 "Total additional header segment length (4 byte words)", HFILL }
1274 { "LUN", "iscsi.lun",
1275 FT_BYTES, BASE_HEX, NULL, 0,
1276 "Logical Unit Number", HFILL }
1278 { &hf_iscsi_InitiatorTaskTag,
1279 { "InitiatorTaskTag", "iscsi.initiatortasktag",
1280 FT_UINT32, BASE_HEX, NULL, 0,
1281 "Initiator's task tag", HFILL }
1283 { &hf_iscsi_ExpectedDataTransferLength,
1284 { "ExpectedDataTransferLength", "iscsi.scsicommand.expecteddatatransferlength",
1285 FT_UINT32, BASE_HEX, NULL, 0,
1286 "Expected length of data transfer", HFILL }
1289 { "CmdSN", "iscsi.cmdsn",
1290 FT_UINT32, BASE_HEX, NULL, 0,
1291 "Sequence number for this command (0 == immediate)", HFILL }
1293 { &hf_iscsi_ExpStatSN,
1294 { "ExpStatSN", "iscsi.expstatsn",
1295 FT_UINT32, BASE_HEX, NULL, 0,
1296 "Next expected status sequence number", HFILL }
1298 { &hf_iscsi_SCSICommand_CDB,
1299 { "CDB", "iscsi.scsicommand.cdb",
1300 FT_BYTES, BASE_HEX, NULL, 0,
1303 { &hf_iscsi_SCSICommand_CDB0,
1304 { "CDB", "iscsi.scsicommand.cdb0",
1305 FT_UINT8, BASE_HEX, VALS(iscsi_scsi_cdb0), 0,
1306 "SCSI CDB[0]", HFILL }
1308 { &hf_iscsi_SCSIResponse_ResidualCount,
1309 { "ResidualCount", "iscsi.scsiresponse.residualcount",
1310 FT_UINT32, BASE_HEX, NULL, 0,
1311 "Residual count", HFILL }
1314 { "StatSN", "iscsi.statsn",
1315 FT_UINT32, BASE_HEX, NULL, 0,
1316 "Status sequence number", HFILL }
1318 { &hf_iscsi_ExpCmdSN,
1319 { "ExpCmdSN", "iscsi.expcmdsn",
1320 FT_UINT32, BASE_HEX, NULL, 0,
1321 "Next expected command sequence number", HFILL }
1323 { &hf_iscsi_MaxCmdSN,
1324 { "MaxCmdSN", "iscsi.maxcmdsn",
1325 FT_UINT32, BASE_HEX, NULL, 0,
1326 "Maximum acceptable command sequence number", HFILL }
1328 { &hf_iscsi_SCSIResponse_o,
1329 { "o", "iscsi.scsiresponse.o",
1330 FT_BOOLEAN, 8, TFS(&iscsi_meaning_o), 0x10,
1331 "Bi-directional read residual overflow", HFILL }
1333 { &hf_iscsi_SCSIResponse_u,
1334 { "u", "iscsi.scsiresponse.u",
1335 FT_BOOLEAN, 8, TFS(&iscsi_meaning_u), 0x08,
1336 "Bi-directional read residual underflow", HFILL }
1338 { &hf_iscsi_SCSIResponse_O,
1339 { "O", "iscsi.scsiresponse.O",
1340 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
1341 "Residual overflow", HFILL }
1343 { &hf_iscsi_SCSIResponse_U,
1344 { "U", "iscsi.scsiresponse.U",
1345 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
1346 "Residual underflow", HFILL }
1348 { &hf_iscsi_SCSIResponse_Status,
1349 { "Status", "iscsi.scsiresponse.status",
1350 FT_UINT8, BASE_HEX, VALS(iscsi_scsi_statuses), 0,
1351 "SCSI command status value", HFILL }
1353 { &hf_iscsi_SCSIResponse_Response,
1354 { "Response", "iscsi.scsiresponse.response",
1355 FT_UINT8, BASE_HEX, VALS(iscsi_scsi_responses), 0,
1356 "SCSI command response value", HFILL }
1358 { &hf_iscsi_SCSIResponse_BidiReadResidualCount,
1359 { "BidiReadResidualCount", "iscsi.scsiresponse.bidireadresidualcount",
1360 FT_UINT32, BASE_HEX, NULL, 0,
1361 "Bi-directional read residual count", HFILL }
1363 { &hf_iscsi_SCSIData_F,
1364 { "F", "iscsi.scsidata.F",
1365 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
1366 "Final PDU", HFILL }
1368 { &hf_iscsi_SCSIData_S,
1369 { "S", "iscsi.scsidata.S",
1370 FT_BOOLEAN, 8, TFS(&iscsi_meaning_S), 0x01,
1371 "PDU Contains SCSI command status", HFILL }
1373 { &hf_iscsi_SCSIData_U,
1374 { "U", "iscsi.scsidata.U",
1375 FT_BOOLEAN, 8, TFS(&iscsi_meaning_U), 0x02,
1376 "Residual underflow", HFILL }
1378 { &hf_iscsi_SCSIData_O,
1379 { "O", "iscsi.scsidata.O",
1380 FT_BOOLEAN, 8, TFS(&iscsi_meaning_O), 0x04,
1381 "Residual overflow", HFILL }
1383 { &hf_iscsi_TargetTransferTag,
1384 { "TargetTransferTag", "iscsi.targettransfertag",
1385 FT_UINT32, BASE_HEX, NULL, 0,
1386 "Target transfer tag", HFILL }
1388 { &hf_iscsi_BufferOffset,
1389 { "BufferOffset", "iscsi.bufferOffset",
1390 FT_UINT32, BASE_HEX, NULL, 0,
1391 "Buffer offset", HFILL }
1393 { &hf_iscsi_SCSIData_ResidualCount,
1394 { "ResidualCount", "iscsi.scsidata.readresidualcount",
1395 FT_UINT32, BASE_HEX, NULL, 0,
1396 "Residual count", HFILL }
1399 { "DataSN", "iscsi.datasn",
1400 FT_UINT32, BASE_HEX, NULL, 0,
1401 "Data sequence number", HFILL }
1403 { &hf_iscsi_VersionMax,
1404 { "VersionMax", "iscsi.versionmax",
1405 FT_UINT8, BASE_HEX, NULL, 0,
1406 "Maximum supported protocol version", HFILL }
1408 { &hf_iscsi_VersionMin,
1409 { "VersionMin", "iscsi.versionmin",
1410 FT_UINT8, BASE_HEX, NULL, 0,
1411 "Minimum supported protocol version", HFILL }
1413 { &hf_iscsi_VersionActive,
1414 { "VersionActive", "iscsi.versionactive",
1415 FT_UINT8, BASE_HEX, NULL, 0,
1416 "Negotiated protocol version", HFILL }
1419 { "CID", "iscsi.cid",
1420 FT_UINT16, BASE_HEX, NULL, 0,
1421 "Connection identifier", HFILL }
1424 { "ISID", "iscsi.isid",
1425 FT_UINT16, BASE_HEX, NULL, 0,
1426 "Initiator part of session identifier", HFILL }
1429 { "TSID", "iscsi.tsid",
1430 FT_UINT16, BASE_HEX, NULL, 0,
1431 "Target part of session identifier", HFILL }
1433 { &hf_iscsi_InitStatSN,
1434 { "InitStatSN", "iscsi.initstatsn",
1435 FT_UINT32, BASE_HEX, NULL, 0,
1436 "Initial status sequence number", HFILL }
1438 { &hf_iscsi_InitCmdSN,
1439 { "InitCmdSN", "iscsi.initcmdsn",
1440 FT_UINT32, BASE_HEX, NULL, 0,
1441 "Initial command sequence number", HFILL }
1443 { &hf_iscsi_Login_T,
1444 { "T", "iscsi.login.T",
1445 FT_BOOLEAN, 8, TFS(&iscsi_meaning_T), 0x80,
1446 "Transit to next login stage", HFILL }
1448 { &hf_iscsi_Login_CSG,
1449 { "CSG", "iscsi.login.csg",
1450 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), 0x0c,
1451 "Current stage", HFILL }
1453 { &hf_iscsi_Login_NSG,
1454 { "NSG", "iscsi.login.nsg",
1455 FT_UINT8, BASE_HEX, VALS(iscsi_login_stage), 0x03,
1456 "Next stage", HFILL }
1458 { &hf_iscsi_Login_Status,
1459 { "Status", "iscsi.login.status",
1460 FT_UINT16, BASE_HEX, VALS(iscsi_login_status), 0,
1461 "Status class and detail", HFILL }
1463 { &hf_iscsi_KeyValue,
1464 { "KeyValue", "iscsi.keyvalue",
1465 FT_STRING, 0, NULL, 0,
1466 "Key/value pair", HFILL }
1469 { "F", "iscsi.text.F",
1470 FT_BOOLEAN, 8, TFS(&iscsi_meaning_F), 0x80,
1471 "Final PDU in text sequence", HFILL }
1473 { &hf_iscsi_ExpDataSN,
1474 { "ExpDataSN", "iscsi.expdatasn",
1475 FT_UINT32, BASE_HEX, NULL, 0,
1476 "Next expected data sequence number", HFILL }
1479 { "R2TSN", "iscsi.r2tsn",
1480 FT_UINT32, BASE_HEX, NULL, 0,
1481 "R2T PDU Number", HFILL }
1483 { &hf_iscsi_SCSITask_Response,
1484 { "Response", "iscsi.scsitask.response",
1485 FT_UINT8, BASE_HEX, VALS(iscsi_task_responses), 0,
1488 { &hf_iscsi_SCSITask_ReferencedTaskTag,
1489 { "InitiatorTaskTag", "iscsi.scsitask.referencedtasktag",
1490 FT_UINT32, BASE_HEX, NULL, 0,
1491 "Task's initiator task tag", HFILL }
1493 { &hf_iscsi_RefCmdSN,
1494 { "RefCmdSN", "iscsi.refcmdsn",
1495 FT_UINT32, BASE_HEX, NULL, 0,
1496 "Command sequence number for command to be aborted", HFILL }
1498 { &hf_iscsi_SCSITask_Function,
1499 { "Function", "iscsi.scsitask.function",
1500 FT_UINT8, BASE_HEX, VALS(iscsi_task_functions), 0x7F,
1501 "Requested task function", HFILL }
1503 { &hf_iscsi_Logout_Reason,
1504 { "Reason", "iscsi.logout.reason",
1505 FT_UINT8, BASE_HEX, VALS(iscsi_logout_reasons), 0,
1506 "Reason for logout", HFILL }
1508 { &hf_iscsi_Logout_Response,
1509 { "Response", "iscsi.logout.response",
1510 FT_UINT8, BASE_HEX, VALS(iscsi_logout_response), 0,
1511 "Logout response", HFILL }
1513 { &hf_iscsi_Time2Wait,
1514 { "Time2Wait", "iscsi.time2wait",
1515 FT_UINT16, BASE_HEX, NULL, 0,
1516 "Time2Wait", HFILL }
1518 { &hf_iscsi_Time2Retain,
1519 { "Time2Retain", "iscsi.time2retain",
1520 FT_UINT16, BASE_HEX, NULL, 0,
1521 "Time2Retain", HFILL }
1523 { &hf_iscsi_DesiredDataLength,
1524 { "DesiredDataLength", "iscsi.desireddatalength",
1525 FT_UINT32, BASE_HEX, NULL, 0,
1526 "Desired data length (bytes)", HFILL }
1528 { &hf_iscsi_AsyncEvent,
1529 { "AsyncEvent", "iscsi.asyncevent",
1530 FT_UINT8, BASE_HEX, VALS(iscsi_asyncevents), 0,
1531 "Async event type", HFILL }
1533 { &hf_iscsi_EventVendorCode,
1534 { "EventVendorCode", "iscsi.eventvendorcode",
1535 FT_UINT8, BASE_HEX, NULL, 0,
1536 "Event vendor code", HFILL }
1538 { &hf_iscsi_Parameter1,
1539 { "Parameter1", "iscsi.parameter1",
1540 FT_UINT16, BASE_HEX, NULL, 0,
1541 "Parameter 1", HFILL }
1543 { &hf_iscsi_Parameter2,
1544 { "Parameter2", "iscsi.parameter2",
1545 FT_UINT16, BASE_HEX, NULL, 0,
1546 "Parameter 2", HFILL }
1548 { &hf_iscsi_Parameter3,
1549 { "Parameter3", "iscsi.parameter3",
1550 FT_UINT16, BASE_HEX, NULL, 0,
1551 "Parameter 3", HFILL }
1553 { &hf_iscsi_Reject_Reason,
1554 { "Reason", "iscsi.reject.reason",
1555 FT_UINT8, BASE_HEX, VALS(iscsi_reject_reasons), 0,
1556 "Reason for command rejection", HFILL }
1558 { &hf_iscsi_snack_type,
1559 { "S", "iscsi.snack.type",
1560 FT_UINT8, 8, VALS(iscsi_snack_types), 0x0f,
1561 "Type of SNACK requested", HFILL }
1564 { "BegRun", "iscsi.snack.begrun",
1565 FT_UINT32, BASE_HEX, NULL, 0,
1566 "First missed DataSN or StatSN", HFILL }
1568 { &hf_iscsi_RunLength,
1569 { "RunLength", "iscsi.snack.runlength",
1570 FT_UINT32, BASE_HEX, NULL, 0,
1571 "Number of additional missing status PDUs in this run", HFILL }
1575 /* Setup protocol subtree array */
1576 static gint *ett[] = {
1577 &ett_iscsi_KeyValues,
1582 /* Register the protocol name and description */
1583 proto_iscsi = proto_register_protocol("iSCSI", "ISCSI", "iscsi");
1585 /* Required function calls to register the header fields and subtrees used */
1586 proto_register_field_array(proto_iscsi, hf, array_length(hf));
1587 proto_register_subtree_array(ett, array_length(ett));
1590 module_t *iscsi_module = prefs_register_protocol(proto_iscsi, NULL);
1592 prefs_register_bool_preference(iscsi_module,
1594 "Enable bogus pdu filter",
1595 "When enabled, packets that appear bogus are ignored",
1596 &enable_bogosity_filter);
1598 prefs_register_uint_preference(iscsi_module,
1599 "bogus_pdu_max_data_len",
1600 "Bogus pdu max data length threshold",
1601 "Treat packets whose data segment length is greater than this value as bogus",
1603 &bogus_pdu_data_length_threshold);
1604 prefs_register_uint_preference(iscsi_module,
1605 "bogus_pdu_max_digest_padding",
1606 "Bogus pdu max digest padding",
1607 "Treat packets whose apparent total digest size is greater than this value as bogus",
1609 &bogus_pdu_max_digest_padding);
1614 /* If this dissector uses sub-dissector registration add a registration routine.
1615 This format is required because a script is used to find these routines and
1616 create the code that calls these routines.
1619 proto_reg_handoff_iscsi(void)
1621 heur_dissector_add("tcp", dissect_iscsi, proto_iscsi);